<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
  <title>ghickman</title>
  <link href="http://ghickman.co.uk/" />
  
  <updated>2011-10-01T18:57:56+01:00</updated>
  <id>tag:ghickman.co.uk,2007-07-03:1</id>
  <author>
    <name>George Hickman</name>
  </author>
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/ghickman" /><feedburner:info uri="ghickman" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
    <title>Setup Gitalist with Gitolite on Nginx</title>
    <link href="http://feedproxy.google.com/~r/ghickman/~3/nlYwlNaOvtU/gitolite-gitalist-nginx.html" />
    <updated>2011-07-24T00:00:00+01:00</updated>
    <id>tag:ghickman.co.uk,2011-07-24:/2011/07/24/gitolite-gitalist-nginx.html</id>
    <content type="html">
      &lt;p&gt;I recently gave &lt;a href="https://github.com/"&gt;Github's&lt;/a&gt; paid service a go when my vimrc ended up needing some passwords in it. While I'm a big fan of Github and what it's done for the Git community as a whole I just can't justify paying the £5 a month so I can use my vimrc at home, work and a few servers. Of course the downside is the loss of being able to quickly view code on the web, but as fate would have it Twitter came to my rescue within a couple of days via the sagely &lt;a href="http://developwithstyle.com/"&gt;Joel Moss&lt;/a&gt;.&lt;/p&gt;
      
      &lt;!-- https://twitter.com/joelmoss/status/89637329731461121 --&gt;
      
      
      &lt;!-- https://twitter.com/joelmoss/status/89637329731461121 --&gt;
      
      
      &lt;p&gt; &lt;style type='text/css'&gt;.bbpBox89637329731461121 {background:url(http://a1.twimg.com/images/themes/theme5/bg.gif) #352726;padding:20px;} p.bbpTweet{background:#fff;padding:10px 12px 10px 12px;margin:0;min-height:48px;color:#000;font-size:18px !important;line-height:22px;-moz-border-radius:5px;-webkit-border-radius:5px} p.bbpTweet span.metadata{display:block;width:100%;clear:both;margin-top:8px;padding-top:12px;height:40px;border-top:1px solid #fff;border-top:1px solid #e6e6e6} p.bbpTweet span.metadata span.author{line-height:19px} p.bbpTweet span.metadata span.author img{float:left;margin:0 7px 0 0px;width:38px;height:38px} p.bbpTweet a:hover{text-decoration:underline}p.bbpTweet span.timestamp{font-size:12px;display:block}&lt;/style&gt; &lt;div class='bbpBox89637329731461121'&gt;&lt;p class='bbpTweet'&gt;Gitalist - a modern git web viewer &lt;a href="http://j.mp/pJEQtN" rel="nofollow"&gt;http://j.mp/pJEQtN&lt;/a&gt;&lt;span class='timestamp'&gt;&lt;a title='Sat Jul 09 10:09:39 +0000 2011' href='https://twitter.com/joelmoss/status/89637329731461121'&gt;less than a minute ago&lt;/a&gt; via &lt;a href="http://reederapp.com" rel="nofollow"&gt;Reeder&lt;/a&gt; &lt;a href='http://twitter.com/intent/favorite?tweet_id=89637329731461121'&gt;&lt;img src='http://si0.twimg.com/images/dev/cms/intents/icons/favorite.png' /&gt; Favorite&lt;/a&gt; &lt;a href='http://twitter.com/intent/retweet?tweet_id=89637329731461121'&gt;&lt;img src='http://si0.twimg.com/images/dev/cms/intents/icons/retweet.png' /&gt; Retweet&lt;/a&gt; &lt;a href='http://twitter.com/intent/tweet?in_reply_to=89637329731461121'&gt;&lt;img src='http://si0.twimg.com/images/dev/cms/intents/icons/reply.png' /&gt; Reply&lt;/a&gt;&lt;/span&gt;&lt;span class='metadata'&gt;&lt;span class='author'&gt;&lt;a href='http://twitter.com/joelmoss'&gt;&lt;img src='http://a2.twimg.com/profile_images/1208340303/pocoyo_avatar_normal.png' /&gt;&lt;/a&gt;&lt;strong&gt;&lt;a href='http://twitter.com/joelmoss'&gt;Joel Moss&lt;/a&gt;&lt;/strong&gt;&lt;br/&gt;joelmoss&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt; &lt;!-- end of tweet --&gt;&lt;/p&gt;
      
      &lt;p&gt;Diving into &lt;a href="http://www.gitalist.com/"&gt;Gitalist&lt;/a&gt; there were a couple of surprises, least of all it's written in Perl. &lt;em&gt;Perl?! That's a dead language right? (Unless you're slashdot)&lt;/em&gt;. However playing around with the demo (guys, please up whatever server you're running that on, it's dire) was great, not to mention it looks really slick.&lt;/p&gt;
      &lt;p&gt;Gitalist also presented an opportunity to coax my workplace from Mercurial/Bitbucket (Github's corporate pricing has so far been the major reason not to use Git) onto Git, but to do so some sort of access control would be needed, thus &lt;a href="https://github.com/sitaramc/gitolite"&gt;Gitolite&lt;/a&gt;.&lt;/p&gt;
      
      &lt;p&gt;I've tested these instructions on Ubuntu Server 10.04 so they should work reasonably well on other Ubuntu versions and child distros.&lt;/p&gt;
      
      &lt;h2&gt;Gitolite&lt;/h2&gt;
      
      &lt;p&gt;Gitolite is an access control system for Git repositories, a natural successor to &lt;a href="http://scie.nti.st/2007/11/14/hosting-git-repositories-the-easy-and-secure-way"&gt;Gitosis&lt;/a&gt;, providing fine grained control on a per branch basis. I won't bother going into much detail as there's so much to it and &lt;a href="http://sitaramc.blogspot.com/"&gt;Sitraramc&lt;/a&gt; provides a far more comprehensive description on the Github &lt;a href="https://github.com/sitaramc/gitolite/wiki/"&gt;page&lt;/a&gt;.&lt;/p&gt;
      
      &lt;p&gt;I followed the &lt;a href="http://sitaramc.github.com/gitolite/doc/1-INSTALL.html#_root_method"&gt;root install instructions&lt;/a&gt; with a couple of caveats:&lt;/p&gt;
      
      &lt;p&gt;I specify the folder locations when running &lt;code&gt;src/gl-system-install&lt;/code&gt; as it didn't seem to use the default one's listed for me:&lt;/p&gt;
      
      &lt;p&gt;&lt;code&gt;src/gl-system-install /usr/local/bin /usr/local/share/gitolite/conf /usr/local/share/gitolite/hooks&lt;/code&gt;&lt;/p&gt;
      
      &lt;p&gt;When adding the git user, rather than just doing a plain &lt;code&gt;useradd git&lt;/code&gt; I set some options:&lt;/p&gt;
      
      &lt;p&gt;&lt;code&gt;sudo adduser --system --shell /bin/bash --gecos 'git version control' --group --disabled-password --home /home/git git&lt;/code&gt;&lt;/p&gt;
      
      &lt;p&gt;and then run the &lt;code&gt;su - git&lt;/code&gt; command with &lt;code&gt;sudo&lt;/code&gt; so you can enter your own password.&lt;/p&gt;
      
      &lt;p&gt;Check you can push your projects to the server and you're away!&lt;/p&gt;
      
      &lt;h2&gt;Gitalist&lt;/h2&gt;
      
      &lt;h3&gt;Installation (CPAN)&lt;/h3&gt;
      
      &lt;p&gt;After some fruitless attempts to install from source and &lt;a href="http://search.cpan.org/dist/Gitalist/lib/Gitalist.pm#BOOTSTRAPPING"&gt;bootstrap&lt;/a&gt; I turned to the IRC channel where a Big Damn Hero pointed me at CPAN as the "Way to Go".&lt;/p&gt;
      
      &lt;p&gt;First of all CPAN needs a little love. By default it asks you what to do when it finds a dependency it doesn't have.&lt;/p&gt;
      
      &lt;!-- http://twitter.com/ghickman/statuses/89982230209904641 --&gt;
      
      
      &lt;!-- http://twitter.com/ghickman/statuses/89982230209904641 --&gt;
      
      
      &lt;p&gt; &lt;style type='text/css'&gt;.bbpBox89982230209904641 {background:url(http://a1.twimg.com/images/themes/theme2/bg.gif) #C6E2EE;padding:20px;} p.bbpTweet{background:#fff;padding:10px 12px 10px 12px;margin:0;min-height:48px;color:#000;font-size:18px !important;line-height:22px;-moz-border-radius:5px;-webkit-border-radius:5px} p.bbpTweet span.metadata{display:block;width:100%;clear:both;margin-top:8px;padding-top:12px;height:40px;border-top:1px solid #fff;border-top:1px solid #e6e6e6} p.bbpTweet span.metadata span.author{line-height:19px} p.bbpTweet span.metadata span.author img{float:left;margin:0 7px 0 0px;width:38px;height:38px} p.bbpTweet a:hover{text-decoration:underline}p.bbpTweet span.timestamp{font-size:12px;display:block}&lt;/style&gt; &lt;div class='bbpBox89982230209904641'&gt;&lt;p class='bbpTweet'&gt;"Module X is required, shall I install it?" Well… yea…&lt;span class='timestamp'&gt;&lt;a title='Sun Jul 10 09:00:10 +0000 2011' href='http://twitter.com/ghickman/statuses/89982230209904641'&gt;less than a minute ago&lt;/a&gt; via &lt;a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow"&gt;Twitter for Mac&lt;/a&gt; &lt;a href='http://twitter.com/intent/favorite?tweet_id=89982230209904641'&gt;&lt;img src='http://si0.twimg.com/images/dev/cms/intents/icons/favorite.png' /&gt; Favorite&lt;/a&gt; &lt;a href='http://twitter.com/intent/retweet?tweet_id=89982230209904641'&gt;&lt;img src='http://si0.twimg.com/images/dev/cms/intents/icons/retweet.png' /&gt; Retweet&lt;/a&gt; &lt;a href='http://twitter.com/intent/tweet?in_reply_to=89982230209904641'&gt;&lt;img src='http://si0.twimg.com/images/dev/cms/intents/icons/reply.png' /&gt; Reply&lt;/a&gt;&lt;/span&gt;&lt;span class='metadata'&gt;&lt;span class='author'&gt;&lt;a href='http://twitter.com/ghickman'&gt;&lt;img src='http://a0.twimg.com/profile_images/1258522839/gravatar_normal.jpeg' /&gt;&lt;/a&gt;&lt;strong&gt;&lt;a href='http://twitter.com/ghickman'&gt;George Hickman&lt;/a&gt;&lt;/strong&gt;&lt;br/&gt;ghickman&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt; &lt;!-- end of tweet --&gt;&lt;/p&gt;
      
      &lt;p&gt;Thankfully it's easy enough to configure CPAN to follow the default options with the &lt;code&gt;prerequisites_policy&lt;/code&gt; option. Open the CPAN console by running &lt;code&gt;cpan&lt;/code&gt;.&lt;/p&gt;
      
      &lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If CPAN hasn't been configured before you'll be asked if you want it to "configure as much as possible automatically", choose yes then follow the instructions below. However if you do want to go through them manually you'll be asked for a &lt;a href="http://www.cpan.org/SITES.html"&gt;local CPAN mirror&lt;/a&gt; after the proxies section.&lt;/p&gt;
      
      &lt;p&gt;To configure type the following into the CPAN console:&lt;/p&gt;
      
      &lt;p&gt;&lt;code&gt;o conf prerequisites_policy follow&lt;/code&gt;&lt;/p&gt;
      
      &lt;p&gt;then&lt;/p&gt;
      
      &lt;p&gt;&lt;code&gt;o conf commit&lt;/code&gt;&lt;/p&gt;
      
      &lt;p&gt;This sets the &lt;code&gt;prerequisites_policy&lt;/code&gt; to &lt;code&gt;follow&lt;/code&gt; the default option for each dependency. Thanks to Mithaldu on #gitalist for helping me out and saving hours of tedium.&lt;/p&gt;
      
      &lt;p&gt;Finally it's time for some installations! First up is &lt;a href="http://yaml.org"&gt;YAML&lt;/a&gt;, which isn't required, but every install complains that it's not there because all the package descriptors are written in it. Installing packages from CPAN is as easy as:&lt;/p&gt;
      
      &lt;p&gt;&lt;code&gt;install YAML&lt;/code&gt;&lt;/p&gt;
      
      &lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; CPAN might update itself at this point, which can take a significant amount of time depending on the power of your machine.&lt;/p&gt;
      
      &lt;p&gt;When that's done, it's time for Gitalist:&lt;/p&gt;
      
      &lt;p&gt;&lt;code&gt;install Gitalist&lt;/code&gt;&lt;/p&gt;
      
      &lt;p&gt;Unfortunately some questions still come up, so it's not a completely unattended installation and did take quite a while for me (at least an hour). Default answers seem fine though.&lt;/p&gt;
      
      &lt;p&gt;Test the install by running &lt;code&gt;sudo gitalist_server.pl&lt;/code&gt; and having a look at &lt;code&gt;http://&amp;lt;server&amp;gt;:3000/&lt;/code&gt;.&lt;/p&gt;
      
      &lt;p&gt;If you get an error about the location of the config then try the methods suggested &lt;a href="http://search.cpan.org/dist/Gitalist/lib/Gitalist.pm#FOR_CPAN_INSTALLS"&gt;here&lt;/a&gt;. I found none of these worked for me so I grabbed the source from &lt;a href="https://github.com/broquaint/Gitalist"&gt;Github&lt;/a&gt; and copied &lt;code&gt;gitalist.conf&lt;/code&gt; to &lt;code&gt;/usr/local/share/perl/5.10.x/Gitalist/&lt;/code&gt;.&lt;/p&gt;
      
      &lt;p&gt;Later on we'll setup Gitalist with FastCGI, at which point you'll need Perl's &lt;code&gt;FCGI::ProcManager&lt;/code&gt; installed as it's the default "Process Manager" for the Gitalist FastCGI script:&lt;/p&gt;
      
      &lt;p&gt;&lt;code&gt;install FCGI::ProcManager&lt;/code&gt;&lt;/p&gt;
      
      &lt;h3&gt;Combining with Gitolite&lt;/h3&gt;
      
      &lt;p&gt;Combining Gitolite and Gitalist is as "simple" as pointing Gitalist at Gitolite's repository directory. Gitolite is running under the &lt;code&gt;git&lt;/code&gt; user and stores the repositories under &lt;code&gt;/home/git/repositories/&lt;/code&gt; which won't be accessible to you under another user. The easiest way around this is to run the &lt;code&gt;gitalist_server.pl&lt;/code&gt; command as the git user like so:&lt;/p&gt;
      
      &lt;p&gt;&lt;code&gt;sudo -u git gitalist_server.pl --repo_dir /home/git/repositories/&lt;/code&gt;&lt;/p&gt;
      
      &lt;p&gt;Of course you don't want to be stuck with a command running in the terminal all the time, or having to suffix it with &lt;code&gt;&amp;amp;&lt;/code&gt; just to have it run in the background so we'll setup &lt;a href="http://supervisord.org/"&gt;Supervisor&lt;/a&gt; to handle all of that for us.&lt;/p&gt;
      
      &lt;h4&gt;Supervisor&lt;/h4&gt;
      
      &lt;p&gt;Supervisor looks after a process and can be configured to perform useful duties like autorestarting and running your process under a different user, both of which we're going to take advantage of. Thankfully supervisor can be installed with ease, like so:&lt;/p&gt;
      
      &lt;p&gt;&lt;code&gt;sudo aptitude install supervisor&lt;/code&gt;&lt;/p&gt;
      
      &lt;p&gt;Next you'll need a config file for Gitalist:&lt;/p&gt;
      
      &lt;p&gt;&lt;code&gt;sudo vim /etc/supervisor/conf.d/gitalist.conf&lt;/code&gt;&lt;/p&gt;
      
      &lt;p&gt;Paste in the following - setting the path to your gitalist_server.pl to the appropriate place if it's not in the default location.&lt;/p&gt;
      
      &lt;div class="gist"&gt;                                              &lt;div class="gist-file"&gt;          &lt;div class="gist-data gist-syntax"&gt;                                                  &lt;div class="gist-highlight"&gt;&lt;pre&gt;&lt;span class=line id=LC1&gt;[program:gitalist]&lt;/span&gt;&lt;span class=line id=LC2&gt;command=/usr/local/bin/gitalist_fastcgi.pl --listen /var/run/gitalist/gitalist.sock --nproc 2 --pidfile /var/run/gitalist/gitalist.pid&lt;/span&gt;&lt;span class=line id=LC3&gt;user=git&lt;/span&gt;&lt;span class=line id=LC4&gt;autostart=true&lt;/span&gt;&lt;span class=line id=LC5&gt;autorestart=true&lt;/span&gt;&lt;span class=line id=LC6&gt;redirect_stderr=true&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;                      &lt;/div&gt;          &lt;div class="gist-meta"&gt;            &lt;a href="https://gist.github.com/raw/1084154/a600ba4b8b76c4e238513debfe72227d94434442/supervisor" style="float:right;"&gt;view raw&lt;/a&gt;            &lt;a href="https://gist.github.com/1084154#file_supervisor" style="float:right;margin-right:10px;color:#666"&gt;supervisor&lt;/a&gt;            &lt;a href="https://gist.github.com/1084154"&gt;This Gist&lt;/a&gt; brought to you by &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt;.          &lt;/div&gt;        &lt;/div&gt;                    &lt;/div&gt;
      
      
      &lt;p&gt;I've put the socket and pid files in &lt;code&gt;/var/run/&lt;/code&gt; since Gitalist is installed via CPAN into and &lt;a href="#gitalist-install-dir"&gt;doesn't really&lt;/a&gt; have an install directory as such so that's the next logical place. However you'll need to create the gitalist directory there and &lt;code&gt;chown&lt;/code&gt; it to your &lt;code&gt;git&lt;/code&gt; user so it can be written to by the FastCGI script (which is now running under the &lt;code&gt;git&lt;/code&gt; user). The &lt;code&gt;--nproc&lt;/code&gt; switch tells the script how many processes to run, like Nginx's workers directive. To see all the options run &lt;code&gt;/usr/local/bin/gitalist_fastcgi.pl --help&lt;/code&gt; in your terminal.&lt;/p&gt;
      
      &lt;p&gt;Open up Supervisor's nifty console with &lt;code&gt;sudo supervisorctl&lt;/code&gt; and tell it to &lt;code&gt;update&lt;/code&gt; so that it uses your Gitalist config (you'll need to do this after any updates to a configuration file). &lt;code&gt;status&lt;/code&gt; will show you a list programs you've setup which you can &lt;code&gt;start&lt;/code&gt;, &lt;code&gt;stop&lt;/code&gt;, &lt;code&gt;restart&lt;/code&gt; and &lt;code&gt;tail&lt;/code&gt; (for program output, with &lt;code&gt;-f&lt;/code&gt; for continuous output). The gitatlist server should now be running under Supervisor, check with the &lt;code&gt;tail gitalist&lt;/code&gt; to make sure there are no errors in the output.&lt;/p&gt;
      
      &lt;h4&gt;Gitalist Config&lt;/h4&gt;
      
      &lt;p&gt;Since we're using FastCGI to pass requests from Nginx through to Gitalist we'll use the Gitalist config file (you can't pass Gitalist configuration values to the FastCGI script). Open it up in your favourite editor:&lt;/p&gt;
      
      &lt;p&gt;&lt;code&gt;sudo vim /usr/local/share/perl/5.10.1/Gitalist/gitalist.conf&lt;/code&gt;&lt;/p&gt;
      
      &lt;p&gt;and set the &lt;code&gt;repo_dir&lt;/code&gt; option to &lt;code&gt;/home/git/repositories/&lt;/code&gt;:&lt;/p&gt;
      
      &lt;div class="gist"&gt;                                      &lt;div class="gist-file"&gt;          &lt;div class="gist-data gist-syntax"&gt;                                                  &lt;div class="gist-highlight"&gt;&lt;pre&gt;&lt;span class=line id=LC1&gt;name Gitalist&lt;/span&gt;&lt;span class=line id=LC2&gt;&lt;br/&gt;&lt;/span&gt;&lt;span class=line id=LC3&gt;&amp;lt;Model::CollectionOfRepos&amp;gt;&lt;/span&gt;&lt;span class=line id=LC4&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#git /path/to/git&lt;/span&gt;&lt;span class=line id=LC5&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;# Configure this to where your repositories are.&lt;/span&gt;&lt;span class=line id=LC6&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;repo_dir /home/git/repositories/&lt;/span&gt;&lt;span class=line id=LC7&gt;&amp;lt;/Model::CollectionOfRepos&amp;gt;&lt;/span&gt;&lt;span class=line id=LC8&gt;&lt;br/&gt;&lt;/span&gt;&lt;span class=line id=LC9&gt;sitename &amp;quot;Gitalist&amp;quot;&lt;/span&gt;&lt;span class=line id=LC10&gt;&lt;br/&gt;&lt;/span&gt;&lt;span class=line id=LC11&gt;&amp;lt;paging&amp;gt;&lt;/span&gt;&lt;span class=line id=LC12&gt;&amp;nbsp;&amp;nbsp;log = 20&lt;/span&gt;&lt;span class=line id=LC13&gt;&amp;nbsp;&amp;nbsp;summary = 17&lt;/span&gt;&lt;span class=line id=LC14&gt;&amp;lt;/paging&amp;gt;&lt;/span&gt;&lt;span class=line id=LC15&gt;&lt;br/&gt;&lt;/span&gt;&lt;span class=line id=LC16&gt;# Support gitweb patches action.&lt;/span&gt;&lt;span class=line id=LC17&gt;&amp;lt;patches&amp;gt;&lt;/span&gt;&lt;span class=line id=LC18&gt;&amp;nbsp;&amp;nbsp;max = 16&lt;/span&gt;&lt;span class=line id=LC19&gt;&amp;lt;/patches&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;                      &lt;/div&gt;          &lt;div class="gist-meta"&gt;            &lt;a href="https://gist.github.com/raw/1084154/bf2c8661deb4fe844d6bdacb3b71b70e09bb379e/gitalist.conf" style="float:right;"&gt;view raw&lt;/a&gt;            &lt;a href="https://gist.github.com/1084154#file_gitalist.conf" style="float:right;margin-right:10px;color:#666"&gt;gitalist.conf&lt;/a&gt;            &lt;a href="https://gist.github.com/1084154"&gt;This Gist&lt;/a&gt; brought to you by &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt;.          &lt;/div&gt;        &lt;/div&gt;                            &lt;/div&gt;
      
      
      &lt;h4&gt;Nginx&lt;/h4&gt;
      
      &lt;p&gt;Create yourself a virtual host in nginx's sites-available directory and add the following, changing the server name to something suitable:&lt;/p&gt;
      
      &lt;div class="gist"&gt;                                                      &lt;div class="gist-file"&gt;          &lt;div class="gist-data gist-syntax"&gt;                                                  &lt;div class="gist-highlight"&gt;&lt;pre&gt;&lt;span class=line id=LC1&gt;server {&lt;/span&gt;&lt;span class=line id=LC2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;server_name www.example.com;&lt;/span&gt;&lt;span class=line id=LC3&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;rewrite ^/(.*) http://git.example.com/$1 permanent;&lt;/span&gt;&lt;span class=line id=LC4&gt;}   &lt;/span&gt;&lt;span class=line id=LC5&gt;&lt;br/&gt;&lt;/span&gt;&lt;span class=line id=LC6&gt;server {&lt;/span&gt;&lt;span class=line id=LC7&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;server_name example.com;&lt;/span&gt;&lt;span class=line id=LC8&gt;&lt;br/&gt;&lt;/span&gt;&lt;span class=line id=LC9&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;access_log /var/log/gitalist/access.log combined;&lt;/span&gt;&lt;span class=line id=LC10&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;error_log /var/log/gitalist/error.log;&lt;/span&gt;&lt;span class=line id=LC11&gt;&lt;br/&gt;&lt;/span&gt;&lt;span class=line id=LC12&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;location / {&lt;/span&gt;&lt;span class=line id=LC13&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;include /etc/nginx/fastcgi_params;&lt;/span&gt;&lt;span class=line id=LC14&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fastcgi_pass unix:/var/run/gitalist/gitalist.sock;&lt;/span&gt;&lt;span class=line id=LC15&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;span class=line id=LC16&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;                      &lt;/div&gt;          &lt;div class="gist-meta"&gt;            &lt;a href="https://gist.github.com/raw/1084154/72d9a9c9a9df9ea5f99e77601ca6e1048a1ab4d5/vhost" style="float:right;"&gt;view raw&lt;/a&gt;            &lt;a href="https://gist.github.com/1084154#file_vhost" style="float:right;margin-right:10px;color:#666"&gt;vhost&lt;/a&gt;            &lt;a href="https://gist.github.com/1084154"&gt;This Gist&lt;/a&gt; brought to you by &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt;.          &lt;/div&gt;        &lt;/div&gt;            &lt;/div&gt;
      
      
      &lt;p&gt;I've setup the logs under &lt;code&gt;/var/log/gitalist/&lt;/code&gt; for the same reason as the socket and the pid files, again you'll have to create that directory but make it writable by &lt;code&gt;www-data&lt;/code&gt; so Nginx has access to it.&lt;/p&gt;
      
      &lt;p&gt;Link the virtual host into sites-enabled and test with &lt;code&gt;sudo nginx -t&lt;/code&gt; to check there are no errors, then reload nginx &lt;code&gt;sudo /etc/init.d/nginx reload&lt;/code&gt; (or use upstart) and your Gitalist should now be accessible on your domain!&lt;/p&gt;
      
      &lt;h2&gt;Notes&lt;/h2&gt;
      
      &lt;h4&gt;FastCGI vs. Reverse Proxying&lt;/h4&gt;
      
      &lt;p&gt;While getting FastCGI setup I toyed with Nginx as a reverse proxy to the one or more instances of the Catalyst development server, but had issues with hiding the port number and it felt a bit wrong to use a development server in production.&lt;/p&gt;
      
      &lt;h4 id="gitalist-install-dir"&gt;Gitalist Install Directory&lt;/h4&gt;
      
      
      &lt;p&gt;Having installed Gitalist via CPAN it lives under &lt;code&gt;/usr/local/share/perl/5.10.1/Gitalist/&lt;/code&gt; which seems a bad place to store a socket file, a pid file or any logs which is why I chose to put them all under &lt;code&gt;/var/&lt;/code&gt;.&lt;/p&gt;
      
      &lt;h2&gt;Extra Reading&lt;/h2&gt;
      
      &lt;ul&gt;
      &lt;li&gt;&lt;a href="http://wiki.catalystframework.org/wiki/adventcalendararticles/2008/02-catalyst_and_nginx"&gt;Catalyst and Nginx (Catalyst Docs)&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="http://search.cpan.org/~bobtfish/Catalyst-Runtime-5.80032/lib/Catalyst/Engine/FastCGI.pm#nginx"&gt;Gitalist, FastCGI and Nginx (Catalyst Docs on CPAN)&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="http://search.cpan.org/dist/Catalyst-Manual/lib/Catalyst/Manual/Cookbook.pod#Standalone_server_mode"&gt;Catalyst Standalone Server (Gitalist Docs on CPAN)&lt;/a&gt;&lt;/li&gt;
      &lt;/ul&gt;
    &lt;img src="http://feeds.feedburner.com/~r/ghickman/~4/nlYwlNaOvtU" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://ghickman.co.uk//2011/07/24/gitolite-gitalist-nginx.html</feedburner:origLink></entry>
  <entry>
    <title>Adding Django Inline Forms with Javascript</title>
    <link href="http://feedproxy.google.com/~r/ghickman/~3/Ux7BUuouGgk/adding-django-inline-forms-with-javascript.html" />
    <updated>2011-07-10T00:00:00+01:00</updated>
    <id>tag:ghickman.co.uk,2011-07-10:/2011/07/10/adding-django-inline-forms-with-javascript.html</id>
    <content type="html">
      &lt;p&gt;Using Django formsets on a new section for a project at work I came across something I haven't considered before: adding new inline forms to a formset without reloading the page. Javascript was the obvious choice. Two pages required the functionality: one with six formsets, the other with one, which meant the solution needed to take into account formset prefixes. I found various solutions around the Internet, but all were outdated (lots of table based layouts!) or not generic enough (didn't deal with multiple formsets).&lt;/p&gt;
      &lt;p&gt;The idea behind the script is pretty simple: duplicate an existing form then update the form counter.&lt;/p&gt;
      
      &lt;div class="gist"&gt;                                      &lt;div class="gist-file"&gt;          &lt;div class="gist-data gist-syntax"&gt;                                                  &lt;div class="gist-highlight"&gt;&lt;pre&gt;&lt;span class=line id=LC1&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;add_inline_form&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#id_&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;-TOTAL_FORMS&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC3&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;last_form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;:last&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC4&gt;&lt;br/&gt;&lt;/span&gt;&lt;span class=line id=LC5&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;new_form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;last_form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;last_form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC6&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;-\\\\\\\\d-&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;g&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC7&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nx"&gt;new_form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;input[type=&amp;quot;text&amp;quot;], textarea&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC8&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC9&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;});&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC10&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nx"&gt;new_form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hide&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;insertAfter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;last_form&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;slideDown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC11&gt;&lt;br/&gt;&lt;/span&gt;&lt;span class=line id=LC12&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1"&gt;// Update the total form count&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC13&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#id_&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;-TOTAL_FORMS&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC14&gt;&lt;br/&gt;&lt;/span&gt;&lt;span class=line id=LC15&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1"&gt;// re-initialise triggers&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC16&gt;&lt;br/&gt;&lt;/span&gt;&lt;span class=line id=LC17&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC18&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC19&gt;&lt;br/&gt;&lt;/span&gt;&lt;span class=line id=LC20&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;regex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/(?:inline\\-form) ([\\\\w\\-]*) (?:add|existing)/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC21&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.add-inline&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC22&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;closest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.body&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.inline-form&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;class&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC23&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC24&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC25&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;add_inline_form&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC26&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;});&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC27&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC28&gt;&lt;span class="p"&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;                      &lt;/div&gt;          &lt;div class="gist-meta"&gt;            &lt;a href="https://gist.github.com/raw/1020463/8358e3b4a4d9e5916a857686332cf9d36078b2b6/add_inline.js" style="float:right;"&gt;view raw&lt;/a&gt;            &lt;a href="https://gist.github.com/1020463#file_add_inline.js" style="float:right;margin-right:10px;color:#666"&gt;add_inline.js&lt;/a&gt;            &lt;a href="https://gist.github.com/1020463"&gt;This Gist&lt;/a&gt; brought to you by &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt;.          &lt;/div&gt;        &lt;/div&gt;                    &lt;/div&gt;
      
      
      &lt;p&gt;Which is setup to work on html that looks like this:&lt;/p&gt;
      
      &lt;p&gt;&lt;em&gt;Note: I'm using &lt;a href="https://github.com/pydanny/django-uni-form"&gt;Django UniForm&lt;/a&gt; to output the form in &lt;code&gt;&amp;lt;div&amp;gt;'s&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;
      
      &lt;div class="gist"&gt;                                              &lt;div class="gist-file"&gt;          &lt;div class="gist-data gist-syntax"&gt;                                                  &lt;div class="gist-highlight"&gt;&lt;pre&gt;&lt;span class=line id=LC1&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;body&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{{ prefix_formset.management_form }}&lt;/span&gt;&lt;span class=line id=LC3&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{{ prefix_formset.non_form_errors }}&lt;/span&gt;&lt;span class=line id=LC4&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{% for form in prefix_formset.forms %}&lt;/span&gt;&lt;span class=line id=LC5&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;inline-form prefix&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC6&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{{ form|as_uni_form }}&lt;/span&gt;&lt;span class=line id=LC7&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC8&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{% endfor %}&lt;/span&gt;&lt;span class=line id=LC9&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;new-inline&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC10&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;button&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;add-inline&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Add another form&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC11&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC12&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC13&gt;&lt;br/&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;                      &lt;/div&gt;          &lt;div class="gist-meta"&gt;            &lt;a href="https://gist.github.com/raw/1020463/a5269200d0d18ceb076ee970af8ab8eea0cf2ee5/forms.html" style="float:right;"&gt;view raw&lt;/a&gt;            &lt;a href="https://gist.github.com/1020463#file_forms.html" style="float:right;margin-right:10px;color:#666"&gt;forms.html&lt;/a&gt;            &lt;a href="https://gist.github.com/1020463"&gt;This Gist&lt;/a&gt; brought to you by &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt;.          &lt;/div&gt;        &lt;/div&gt;            &lt;/div&gt;
      
      
      &lt;h3&gt;So How Does it Work?&lt;/h3&gt;
      
      &lt;p&gt;&lt;em&gt;Skip to &lt;a href="#gotchas"&gt;Gotchas&lt;/a&gt; if you already understand my javascript&lt;/em&gt;&lt;/p&gt;
      
      &lt;p&gt;I start by looping my form class &lt;code&gt;add-inline&lt;/code&gt; (you can call it anything you like) and then running the regular expression from line 20 to find the form prefix, which is another class on the form. It expects the classes applied to the form in the order &lt;code&gt;add-inline &amp;lt;formset prefix&amp;gt; add/existing&lt;/code&gt;. The add/existing bit on the end isn't necessary but gives you an example of where to put any other classes that might exist on your form. If you don't want to use it, just remember to remove it from the regex! Inside the &lt;code&gt;add_inline_form&lt;/code&gt; function I'm grabbing the count from the hidden div and the last form with jQuery's &lt;code&gt;:last&lt;/code&gt; selector.&lt;/p&gt;
      
      &lt;p&gt;When new_form is set I'm using jQuery's &lt;a href="http://api.jquery.com/clone/"&gt;clone&lt;/a&gt; method to take a copy of the last form and grab the raw html. The false passed into clone tells it to ignore any triggers and binds. The regex sets the correct count in the element ids. The next line clears the contents of every element in the new form since clone will pull this in with the elements. The new form is hidden then added after the last form with a nice little bit of &lt;a href="http://api.jquery.com/slideDown/"&gt;slideDown&lt;/a&gt; candy for some UI goodness.&lt;/p&gt;
      
      &lt;p&gt;Finally increment the form count and return false so the form isn't submitted.&lt;/p&gt;
      
      &lt;h2 id="gotchas"&gt;Gotchas&lt;/h2&gt;
      
      
      &lt;p&gt;So now you've got your nice little bit of javascript (if I don't say so myself) all setup to grab the last form in each formset, duplicate it and add it below the last form. However there are some caveats to this...&lt;/p&gt;
      
      &lt;p&gt;The script grabs the last form in the formset &lt;em&gt;every&lt;/em&gt; time so say you want the first form to differ from the rest (as I did) and implement this in the templates then you'll get the non-standard first form duplicated each time. The easiest way around this is to check the count and add an if to look for the first form.&lt;/p&gt;
    &lt;img src="http://feeds.feedburner.com/~r/ghickman/~4/Ux7BUuouGgk" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://ghickman.co.uk//2011/07/10/adding-django-inline-forms-with-javascript.html</feedburner:origLink></entry>
  <entry>
    <title>Nose Tests - no such option</title>
    <link href="http://feedproxy.google.com/~r/ghickman/~3/gcXiW7et6Y4/nosetests-no-such-option.html" />
    <updated>2011-04-30T00:00:00+01:00</updated>
    <id>tag:ghickman.co.uk,2011-04-30:/2011/04/30/nosetests-no-such-option.html</id>
    <content type="html">
      &lt;p&gt;Some time ago now I added proper command line options to &lt;a href="http://github.com/ghickman/tvrenamr"&gt;Tv Renamr&lt;/a&gt;, followed shortly by a test suite with Python's &lt;a href="http://somethingaboutorange.com/mrl/projects/nose/1.0.0/"&gt;Nose&lt;/a&gt;. Along the way I ran into a bug that has frustrated me for a long long time, until today when I finally found a work around - hooray, go me!&lt;/p&gt;
      
      &lt;p&gt;The bug is hardly a game stopper as it only affects the UI candy on my tests. Simply put, I couldn't use options with nose. Every time I did, an error was thrown saying no such option existed for nose while displaying the usage string for tvr:&lt;/p&gt;
      
      &lt;div&gt;
        &lt;img src="http://ghickman.s3.amazonaws.com/posts/2011-04-30-nosetest-no-such-option/screenshot.png" width="700"&gt;
      &lt;/div&gt;
      &lt;p&gt;This initially prompted me to split the front end script's options into a &lt;a href="https://github.com/ghickman/tvrenamr/commit/b77e16d97f7712de38625381e194d43e090a3fde"&gt;separate&lt;/a&gt; file which didn't solve the issue, but did wonders for cleaning up the codebase.&lt;/p&gt;
      
      &lt;p&gt;This seems to have affected at least &lt;a href="http://ionelmc.wordpress.com/2008/04/24/setuptools-nosetests-oddness/"&gt;one&lt;/a&gt; other person, whose post finally gave me the lightbulb today. &lt;a href="http://ionelmc.wordpress.com/"&gt;Ionel&lt;/a&gt; mentions in his post "Luckily, setuptools has aliases for commands and instead of" and a snippet of a config file. It's only taken me a couple of years (I've tried to fix this at least 3 times now and always drawn blanks sadly) to realise that he was using a config file. A quick google for the appropriate section in the &lt;a href="http://somethingaboutorange.com/mrl/projects/nose/1.0.0/man.html#configuration"&gt;nose docs&lt;/a&gt; turned up enough information to construct a useful rc file:&lt;/p&gt;
      
      &lt;div class="gist"&gt;                                      &lt;div class="gist-file"&gt;          &lt;div class="gist-data gist-syntax"&gt;                                                  &lt;div class="gist-highlight"&gt;&lt;pre&gt;&lt;span class=line id=LC1&gt;[nosetests]&lt;/span&gt;&lt;span class=line id=LC2&gt;with-spec=1&lt;/span&gt;&lt;span class=line id=LC3&gt;spec-color=1&lt;/span&gt;&lt;span class=line id=LC4&gt;with-growl=1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;                      &lt;/div&gt;          &lt;div class="gist-meta"&gt;            &lt;a href="https://gist.github.com/raw/949702/00816eda5cdb9c9f348915e30a95b2b3f28145a8/.noserc" style="float:right;"&gt;view raw&lt;/a&gt;            &lt;a href="https://gist.github.com/949702#file_.noserc" style="float:right;margin-right:10px;color:#666"&gt;.noserc&lt;/a&gt;            &lt;a href="https://gist.github.com/949702"&gt;This Gist&lt;/a&gt; brought to you by &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt;.          &lt;/div&gt;        &lt;/div&gt;            &lt;/div&gt;
      
      
      &lt;p&gt;And so I finally have my lovely coloured output, with &lt;a href="https://bitbucket.org/crankycoder/nosegrowl"&gt;Growl&lt;/a&gt; integration, back. This is shaping up to be quite the productive weekend.&lt;/p&gt;
    &lt;img src="http://feeds.feedburner.com/~r/ghickman/~4/gcXiW7et6Y4" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://ghickman.co.uk//2011/04/30/nosetests-no-such-option.html</feedburner:origLink></entry>
  <entry>
    <title>Using Passenger with RVM and Sinatra</title>
    <link href="http://feedproxy.google.com/~r/ghickman/~3/V_2lAdppJ9I/passenger-with-rvm-and-sinatra.html" />
    <updated>2011-04-04T00:00:00+01:00</updated>
    <id>tag:ghickman.co.uk,2011-04-04:/2011/04/04/passenger-with-rvm-and-sinatra.html</id>
    <content type="html">
      &lt;p&gt;After making the move to &lt;a href="http://linode.com"&gt;Linode&lt;/a&gt; (finally!) I had some issues with getting the contact pages on this site and &lt;a href="http://Penderry.com"&gt;Penderry&lt;/a&gt; up and running. RVM was throwing an error about the sinatra gem missing. A quick scan of the error message and it was obvious that Passenger wasn't using my gemsets.&lt;/p&gt;
      
      &lt;p&gt;A bit of googling turned up this little snippet which, when placed in &lt;code&gt;app/config/&lt;/code&gt;, will tell RVM to use the gemset associated with the folder.&lt;/p&gt;
      
      &lt;div class="gist"&gt;                                      &lt;div class="gist-file"&gt;          &lt;div class="gist-data gist-syntax"&gt;                                                  &lt;div class="gist-highlight"&gt;&lt;pre&gt;&lt;span class=line id=LC1&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;MY_RUBY_HOME&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;MY_RUBY_HOME&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;rvm&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC2&gt;&amp;nbsp;&amp;nbsp;&lt;span class="k"&gt;begin&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC3&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="n"&gt;rvm_path&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;MY_RUBY_HOME&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC4&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="n"&gt;rvm_lib_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rvm_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;lib&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC5&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="vg"&gt;$LOAD_PATH&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unshift&lt;/span&gt; &lt;span class="n"&gt;rvm_lib_path&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC6&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rvm&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC7&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="no"&gt;RVM&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;use_from_path!&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC8&gt;&amp;nbsp;&amp;nbsp;&lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;LoadError&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC9&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1"&gt;# RVM is unavailable at this point.&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC10&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;RVM ruby lib is currently unavailable.&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC11&gt;&amp;nbsp;&amp;nbsp;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC12&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;                      &lt;/div&gt;          &lt;div class="gist-meta"&gt;            &lt;a href="https://gist.github.com/raw/900934/2f78a2c0e9e8f2f61531278b50166a9a1616b753/config/setup_load_paths.rb" style="float:right;"&gt;view raw&lt;/a&gt;            &lt;a href="https://gist.github.com/900934#file_config/setup_load_paths.rb" style="float:right;margin-right:10px;color:#666"&gt;config/setup_load_paths.rb&lt;/a&gt;            &lt;a href="https://gist.github.com/900934"&gt;This Gist&lt;/a&gt; brought to you by &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt;.          &lt;/div&gt;        &lt;/div&gt;            &lt;/div&gt;
    &lt;img src="http://feeds.feedburner.com/~r/ghickman/~4/V_2lAdppJ9I" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://ghickman.co.uk//2011/04/04/passenger-with-rvm-and-sinatra.html</feedburner:origLink></entry>
  <entry>
    <title>Ecohandle Shopping Bag</title>
    <link href="http://feedproxy.google.com/~r/ghickman/~3/o7WeCtqZ2Po/ecohandle-shopping-bag.html" />
    <updated>2011-01-08T00:00:00+00:00</updated>
    <id>tag:ghickman.co.uk,2011-01-08:/2011/01/08/ecohandle-shopping-bag.html</id>
    <content type="html">
      &lt;div class="right photo"&gt;
          &lt;img src="https://s3-eu-west-1.amazonaws.com/ghickman/ecohandle.jpg" width="300" title="Ecohandle" alt="Ecohandle Shopping Bag"&gt;
      &lt;/div&gt;
      
      
      &lt;p&gt;This year's Christmas Haul brought me an interesting little gem: The Ecohandle Shopping Bag. I got round to giving it a bit of a go today when I did a veg shop and thought doing a review on it would be fun.&lt;/p&gt;
      
      &lt;p&gt;So, first things first - what is it?&lt;/p&gt;
      
      &lt;p&gt;It's a shopping bag, duh. The bonus here though is that the bag part compacts down into the handle for when you're going to the shop. Nice and neat. If you feel like a real glutton for punishment on your forearms (I'll get to that properly in a minute) you can add extra bags. There are two slots with retractable clips that you can put the bags into, assuming you can carry them of course. I managed to get at least 5 kg into the Ecohandle bag alone without pushing it's limits! Getting it home was the bigger issue issue as I had to keep swapping hands when my grip muscles died.&lt;/p&gt;
      &lt;h2&gt;The Good&lt;/h2&gt;
      
      &lt;p&gt;You're saving bags...thus, Puppies.&lt;/p&gt;
      
      &lt;p&gt;The bag is really quite strong. I was worried that packing it full might have put too much strain on it, but it held up surprisingly well.&lt;/p&gt;
      
      &lt;h2&gt;The Bad&lt;/h2&gt;
      
      &lt;p&gt;The embossed name. When holding it in my left hand I found the edge of the embossed text rubbed against my finger tips in such a small way that it left them raw within a couple of minutes of use. It's certainly not a deal breaker, but smoother letters would be appreciated.&lt;/p&gt;
      
      &lt;h2&gt;The Fence&lt;/h2&gt;
      
      &lt;p&gt;It's a handle. Whereas you would normally have your bags cutting a nice line across your fingers - pulling directly down on your arm, you've got to actually grip the Ecohandle. I ended up swapping hands every few minutes and cursing my decision to put 5Kg+ of shopping in it. Good workout though (thus why it's on The Fence&amp;copy;).&lt;/p&gt;
      
      &lt;h2&gt;TL;DR&lt;/h2&gt;
      
      &lt;p&gt;It's a reusable shopping bag that packs down into it's own handle. You can attach other shopping bags and it'll give you a great workout on your grip muscles.&lt;/p&gt;
    &lt;img src="http://feeds.feedburner.com/~r/ghickman/~4/o7WeCtqZ2Po" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://ghickman.co.uk//2011/01/08/ecohandle-shopping-bag.html</feedburner:origLink></entry>
  <entry>
    <title>Creating a Contact Page for Jekyll with Sinatra</title>
    <link href="http://feedproxy.google.com/~r/ghickman/~3/H-BsVoWpFgA/creating-a-contact-page-for-jekyll-with-sinatra.html" />
    <updated>2010-09-26T00:00:00+01:00</updated>
    <id>tag:ghickman.co.uk,2010-09-26:/2010/09/26/creating-a-contact-page-for-jekyll-with-sinatra.html</id>
    <content type="html">
      &lt;div class="right photo"&gt;
          &lt;img src="https://s3-eu-west-1.amazonaws.com/ghickman/jekyll.jpg" width="300" height="169" title="Jekyll" alt="James Nesbitt in Jekyll"&gt;
          &lt;p class="photo"&gt;
              &lt;a href="http://thetvdb.com/?tab=artistbanners&amp;amp;id=513"&gt;Freneticvirus&lt;/a&gt;
              &lt;img class="cc" src="/images/cc.png" width="16" height="16" title="Creative Commons Icon" alt="CC"&gt;
          &lt;/p&gt;
      &lt;/div&gt;
      
      
      &lt;p&gt;Jekyll is a fantastic static site generator with a great little community of modifications around it and I've used it for my own &lt;a href="http://ghickman.co.uk"&gt;blog&lt;/a&gt; and &lt;a href="http://penderry.com"&gt;Penderry.com&lt;/a&gt;. However my biggest problem with it is the lack of a way to deal with a contact form. Of course, this really isn't Jekyll's fault as it's only built to create HTML pages.&lt;/p&gt;
      
      &lt;p&gt;Enter Sinatra stage left.&lt;/p&gt;
      
      &lt;p&gt;&lt;a href="http://www.sinatrarb.com/"&gt;Sinatra&lt;/a&gt; is a rad little web framework, well a micro framework really - in fact it's so small the Hello World app is 5 lines long! It's also perfect for creating a contact form.&lt;/p&gt;
      
      &lt;p&gt;To combine the two I needed both of them to display the same layout since I didn't want to have to maintain two. The contact page needed the same layout as the portfolio page, so no sidebar. The easiest way to do this is to plug your Sinatra application into Jekyll's layout mocking up any Jekyll specific objects/variables you need to (like page). I did give using a header and footer includes a go but it broke validation, pah.&lt;/p&gt;
      &lt;p&gt;My test app is hosted on &lt;a href="http://github.com/ghickman/jekyll_contact"&gt;Github&lt;/a&gt; for your viewing pleasure but I'll go through the important parts here too.&lt;/p&gt;
      
      &lt;div class="gist"&gt;                                                              &lt;div class="gist-file"&gt;          &lt;div class="gist-data gist-syntax"&gt;                                                  &lt;div class="gist-highlight"&gt;&lt;pre&gt;&lt;span class=line id=LC1&gt;&lt;span class="nn"&gt;!!!&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC2&gt;&lt;span class="nt"&gt;%html&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC3&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%head&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC4&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%title&lt;/span&gt; Jekyll&amp;#39;s Contact Form&lt;/span&gt;&lt;span class=line id=LC5&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%meta&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:&amp;quot;http-equiv&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Content-type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:content&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;text/html; charset=utf-8&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC6&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class=line id=LC7&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%link&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:rel&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;shortcut icon&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:href&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/favicon.ico&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:type&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;image/x-icon&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC8&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%link&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:rel&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;stylesheet&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:type&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;text/css&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:href&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/stylesheets/master.css&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:media&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;screen&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC9&gt;&lt;br/&gt;&lt;/span&gt;&lt;span class=line id=LC10&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%body&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC11&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%header&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC12&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%h1&lt;/span&gt; Jekyll&amp;#39;s Contact From brought to you by Sinatra&lt;/span&gt;&lt;span class=line id=LC13&gt;&lt;br/&gt;&lt;/span&gt;&lt;span class=line id=LC14&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%nav&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC15&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%ul&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC16&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%li&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC17&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%a&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:href&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Home&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; Blog&lt;/span&gt;&lt;span class=line id=LC18&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%li&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC19&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%a&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:href&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;http://localhost:4567/contact&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Contact&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; Contact&lt;/span&gt;&lt;span class=line id=LC20&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class=line id=LC21&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%section&lt;/span&gt;&lt;span class="nf"&gt;#content&lt;/span&gt;&lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC22&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class=line id=LC23&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%footer&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC24&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%div&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC25&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%section&lt;/span&gt;&lt;span class="nf"&gt;#jekyll&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC26&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Powered by &lt;/span&gt;&lt;span class=line id=LC27&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%a&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:href&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;http://github.com/richguk/jekyll&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Jekyll&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; Jekyll&lt;/span&gt;&lt;span class=line id=LC28&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%section&lt;/span&gt;&lt;span class="nf"&gt;#from&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC29&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;A&lt;/span&gt;&lt;span class=line id=LC30&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%a&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:href&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;http://ghickman.co.uk&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;GHickman Blog&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; GHickman&lt;/span&gt;&lt;span class=line id=LC31&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;project&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;                      &lt;/div&gt;          &lt;div class="gist-meta"&gt;            &lt;a href="https://gist.github.com/raw/463598/c7007e119fa8315e07d4be17f4839afe30edc240/default.haml" style="float:right;"&gt;view raw&lt;/a&gt;            &lt;a href="https://gist.github.com/463598#file_default.haml" style="float:right;margin-right:10px;color:#666"&gt;default.haml&lt;/a&gt;            &lt;a href="https://gist.github.com/463598"&gt;This Gist&lt;/a&gt; brought to you by &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt;.          &lt;/div&gt;        &lt;/div&gt;                    &lt;/div&gt;
      
      
      &lt;p&gt;Nothing special here, just a bog standard Jekyll layout (well almost, this one is in HAML as I use &lt;a href="http://github.com/richguk/jekyll"&gt;RickGuk's Jekyll fork&lt;/a&gt;) with a HAML interpreter bolted on.&lt;/p&gt;
      
      &lt;p&gt;The contact page itself is an HTML(5) form that displays some extra bits if we find errors. The test app is done using some HTML 5 specific elements like the email input box but there's no big leaps from HTML 4.&lt;/p&gt;
      
      &lt;div class="gist"&gt;                                                      &lt;div class="gist-file"&gt;          &lt;div class="gist-data gist-syntax"&gt;                                                  &lt;div class="gist-highlight"&gt;&lt;pre&gt;&lt;span class=line id=LC1&gt;&lt;span class="nf"&gt;#contact&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC2&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%form&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:method&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;post&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC3&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%fieldset&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC4&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nc"&gt;.input&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC5&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%label&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:for&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; Name&lt;/span&gt;&lt;span class=line id=LC6&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%input&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:type&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:class&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;error&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="vi"&gt;@errors&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;nil?&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="ss"&gt;:required&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;}&lt;/span&gt;&lt;span class=line id=LC7&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="vi"&gt;@errors&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;nil?&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC8&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nc"&gt;.error&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC9&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%p&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="vi"&gt;@errors&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC10&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class=line id=LC11&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nc"&gt;.input&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC12&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%label&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:for&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; Email Address&lt;/span&gt;&lt;span class=line id=LC13&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%input&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:type&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:class&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;error&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="vi"&gt;@errors&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;nil?&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="ss"&gt;:required&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;}&lt;/span&gt;&lt;span class=line id=LC14&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="vi"&gt;@errors&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;nil?&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC15&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nc"&gt;.error&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC16&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%p&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="vi"&gt;@errors&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC17&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class=line id=LC18&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nc"&gt;.input&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC19&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%label&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:for&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; Message&lt;/span&gt;&lt;span class=line id=LC20&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%textarea&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:rows&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;5&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:class&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;error&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="vi"&gt;@errors&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:message&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;nil?&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="ss"&gt;:required&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;}&lt;/span&gt;&lt;span class=line id=LC21&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="vi"&gt;@errors&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:message&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;nil?&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC22&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nc"&gt;.error&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC23&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%p&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="vi"&gt;@errors&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:message&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC24&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class=line id=LC25&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nf"&gt;#submit&lt;/span&gt;&lt;span class="nc"&gt;.input&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC26&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;%input&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:type&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;submit&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:value&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Send&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;                      &lt;/div&gt;          &lt;div class="gist-meta"&gt;            &lt;a href="https://gist.github.com/raw/463598/72248e3fb77fccb92e2e8c4d16e6ddad78e597db/contact.haml" style="float:right;"&gt;view raw&lt;/a&gt;            &lt;a href="https://gist.github.com/463598#file_contact.haml" style="float:right;margin-right:10px;color:#666"&gt;contact.haml&lt;/a&gt;            &lt;a href="https://gist.github.com/463598"&gt;This Gist&lt;/a&gt; brought to you by &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt;.          &lt;/div&gt;        &lt;/div&gt;                            &lt;/div&gt;
      
      
      &lt;p&gt;The actual Sinatra application is nice and simple given that we're plugging it into a different layout.&lt;/p&gt;
      
      &lt;div class="gist"&gt;                                      &lt;div class="gist-file"&gt;          &lt;div class="gist-data gist-syntax"&gt;                                                  &lt;div class="gist-highlight"&gt;&lt;pre&gt;&lt;span class=line id=LC1&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rubygems&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC2&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;sinatra&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC3&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;pony&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC4&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;haml&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC5&gt;&lt;br/&gt;&lt;/span&gt;&lt;span class=line id=LC6&gt;&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:haml&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:format&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:html5&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC7&gt;&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:public&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC8&gt;&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:views&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC9&gt;&lt;br/&gt;&lt;/span&gt;&lt;span class=line id=LC10&gt;&lt;span class="c1"&gt;# Create the page class and give it a title of Contact for the layout&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC11&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Page&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC12&gt;&amp;nbsp;&amp;nbsp;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;title&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC13&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="s1"&gt;&amp;#39;Contact&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC14&gt;&amp;nbsp;&amp;nbsp;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC15&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC16&gt;&lt;br/&gt;&lt;/span&gt;&lt;span class=line id=LC17&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;contact&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC18&gt;&amp;nbsp;&amp;nbsp;&lt;span class="c1"&gt;# create the variables that the layout will expect&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC19&gt;&amp;nbsp;&amp;nbsp;&lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC20&gt;&amp;nbsp;&amp;nbsp;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;haml&lt;/span&gt; &lt;span class="ss"&gt;:contact&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC21&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class=line id=LC22&gt;&amp;nbsp;&amp;nbsp;&lt;span class="c1"&gt;# render the contact page using jekyll&amp;#39;s layout and with our mock jekyll vars&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC23&gt;&amp;nbsp;&amp;nbsp;&lt;span class="n"&gt;haml&lt;/span&gt; &lt;span class="ss"&gt;:contact&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:layout&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;:&amp;#39;_layouts/default&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:locals&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:page&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:content&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC24&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC25&gt;&lt;br/&gt;&lt;/span&gt;&lt;span class=line id=LC26&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/contact&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC27&gt;&amp;nbsp;&amp;nbsp;&lt;span class="vi"&gt;@errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC28&gt;&amp;nbsp;&amp;nbsp;&lt;span class="n"&gt;contact&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC29&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC30&gt;&lt;br/&gt;&lt;/span&gt;&lt;span class=line id=LC31&gt;&lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/contact&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC32&gt;&amp;nbsp;&amp;nbsp;&lt;span class="vi"&gt;@errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC33&gt;&amp;nbsp;&amp;nbsp;&lt;span class="vi"&gt;@errors&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;No Anon allowed here.&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;nil?&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;empty?&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC34&gt;&amp;nbsp;&amp;nbsp;&lt;span class="vi"&gt;@errors&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Sinatra needs an email to send your message from!&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;nil?&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;empty?&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC35&gt;&amp;nbsp;&amp;nbsp;&lt;span class="vi"&gt;@errors&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:message&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;No message?! Sounds like heavy breathing on the phone to me.&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:message&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;nil?&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:message&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;empty?&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC36&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class=line id=LC37&gt;&amp;nbsp;&amp;nbsp;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty?&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC38&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="no"&gt;Pony&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:to&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;george@ghickman.co.uk&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:from&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:subject&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Contact Message&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:body&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:message&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC39&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="n"&gt;redirect&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;http://localhost:4000/index.html&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC40&gt;&amp;nbsp;&amp;nbsp;&lt;span class="k"&gt;else&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC41&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="n"&gt;contact&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC42&gt;&amp;nbsp;&amp;nbsp;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC43&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;                      &lt;/div&gt;          &lt;div class="gist-meta"&gt;            &lt;a href="https://gist.github.com/raw/463598/13a675bab89cd0789d535360f1d57e62a2e1ac18/_contact.rb" style="float:right;"&gt;view raw&lt;/a&gt;            &lt;a href="https://gist.github.com/463598#file__contact.rb" style="float:right;margin-right:10px;color:#666"&gt;_contact.rb&lt;/a&gt;            &lt;a href="https://gist.github.com/463598"&gt;This Gist&lt;/a&gt; brought to you by &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt;.          &lt;/div&gt;        &lt;/div&gt;                                            &lt;/div&gt;
      
      
      &lt;p&gt;I've started off by setting the views path to Jekyll's source directory so Sinatra knows where to find the contact page and since you can specify a subdirectory the site layout can easily be found later.&lt;/p&gt;
      
      &lt;p&gt;The &lt;code&gt;Page&lt;/code&gt; class is there to emulate the page class that Jekyll uses. Here I've created a title method as my site (what this was originally created for) checks to see what the title of the page is before rendering the sidebar. You can use this method to mock up any of the Jekyll specific objects you wanted, i.e. &lt;code&gt;site&lt;/code&gt;.&lt;/p&gt;
      
      &lt;p&gt;The &lt;code&gt;contact&lt;/code&gt; method is where the &lt;em&gt;magic&lt;/em&gt; really happens. Here we're rending the contact page with Jekyll's layout and passing it our mocked up variables so that Sinatra doesn't freak out when the layout asks for them.&lt;/p&gt;
      
      &lt;p&gt;The script is finished off by the get and post methods that both call contact when they want to render a page (making my code nice and DRY). Voila! Jekyll has a contact page!&lt;/p&gt;
      
      &lt;p&gt;The last thing to note in the script is the redirect on a successful submission. Since your Sinatra is running on a different port to Jekyll (likely the default 4567) you'll want to redirect back to your Jekyll setup during development. In production this can be changed to &lt;code&gt;redirect '/index.html'&lt;/code&gt;.&lt;/p&gt;
      
      &lt;h3&gt;Setting it up in a Production Environment&lt;/h3&gt;
      
      &lt;p&gt;Setting this all up in production requires a bit more than Jekyll since you're running a ruby application in the background now. Luckily this is where &lt;a href="http://www.modrails.com/"&gt;Phusion Passenger&lt;/a&gt; comes in. You'll need a rack file in your Jekyll root that looks like this:&lt;/p&gt;
      
      &lt;div class="gist"&gt;                                              &lt;div class="gist-file"&gt;          &lt;div class="gist-data gist-syntax"&gt;                                                  &lt;div class="gist-highlight"&gt;&lt;pre&gt;&lt;span class=line id=LC1&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;source/_contact&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC2&gt;&lt;br/&gt;&lt;/span&gt;&lt;span class=line id=LC3&gt;&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:run&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC4&gt;&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:environment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:production&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC5&gt;&lt;br/&gt;&lt;/span&gt;&lt;span class=line id=LC6&gt;&lt;span class="no"&gt;FileUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mkdir_p&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;log&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exists?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;log&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC7&gt;&lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;log/sinatra.log&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC8&gt;&lt;span class="vg"&gt;$stdout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC9&gt;&lt;span class="vg"&gt;$stderr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC10&gt;&lt;br/&gt;&lt;/span&gt;&lt;span class=line id=LC11&gt;&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="no"&gt;Sinatra&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;                      &lt;/div&gt;          &lt;div class="gist-meta"&gt;            &lt;a href="https://gist.github.com/raw/463598/5a6806d949bf55474729991f1a8918e657667c5d/config.ru" style="float:right;"&gt;view raw&lt;/a&gt;            &lt;a href="https://gist.github.com/463598#file_config.ru" style="float:right;margin-right:10px;color:#666"&gt;config.ru&lt;/a&gt;            &lt;a href="https://gist.github.com/463598"&gt;This Gist&lt;/a&gt; brought to you by &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt;.          &lt;/div&gt;        &lt;/div&gt;                                    &lt;/div&gt;
      
      
      &lt;p&gt;Don't forget to update the redirect path back from Sinatra to Jekyll, then you're good to go!&lt;/p&gt;
    &lt;img src="http://feeds.feedburner.com/~r/ghickman/~4/H-BsVoWpFgA" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://ghickman.co.uk//2010/09/26/creating-a-contact-page-for-jekyll-with-sinatra.html</feedburner:origLink></entry>
  <entry>
    <title>Mumbai</title>
    <link href="http://feedproxy.google.com/~r/ghickman/~3/DXxBFIylbeQ/mumbai.html" />
    <updated>2010-09-18T00:00:00+01:00</updated>
    <id>tag:ghickman.co.uk,2010-09-18:/2010/09/18/mumbai.html</id>
    <content type="html">
      &lt;p&gt;Coming into Mumbai's domestic airport we got to see a fair number of shanty town looking dwellings, contrasting what I'd read about the metropolitan downtown area. We booked a prepay taxi and headed outside to the taxi rank where, to my surprise and child like joy, they had incredibly stereotypical Indian taxis that look like they are from the 50's. They are called Black and Yellows (for their paint job...), have bench seats, usually no wing mirrors and are dented to hell. We took a ride in one of the mini van type ones to our hotel in Downtown. Alas, this was an hour and a half away... Sweaty!&lt;/p&gt;
      &lt;h2&gt;MEAT and Other Delectables&lt;/h2&gt;
      
      &lt;p&gt;As previously mentioned Gujerat is predominately a vegetarian province and we'd miss meat, along with cheese and eggs at the school. Thus, as in Rajkot, we promptly pigged out on the heaviest meat/cheese/egg dishes we could find. Mumbai is very much like Bangkok in some ways, there are lots of market stalls down the main Bazaar road in Colaba (the district we were staying in), street vendors are everywhere and my favourite - juice bars. Freshly squeezed juice practically on tap. Nom nom nom. On our last day we picked up a selection of spices to take home from a local supermarket. Damn it's cheap to buy spices in India. We bought about 4 or 5 kilos split between a variety of spices and the bill was barely £5. Win! Garam Masala seems to be the thing to get, it's a mix of a selection of spices that you can just chuck in with some meat and you've got a full curry.&lt;/p&gt;
      
      &lt;h2&gt;Hotel Bentleys&lt;/h2&gt;
      
      &lt;p&gt;I couldn't talk about our time in Mumbai without mentioning our awesome hotel. Hidden away down a side street in central Colaba, Hotel Bentleys is a few minutes away from the Gateway to India and completely secluded from the hubbub of the main road. It even had an old school lift. So. Much. Fun. We were the first people to use our room since it had been refurbished which meant it was possibly the cleanest room we'd stayed in all trip. The only downside was the pretty solid 'mattresses' we had to sleep on, but there was free breakfast so who can complain?!&lt;/p&gt;
      
      &lt;h2&gt;Bon Voyage&lt;/h2&gt;
      
      &lt;p&gt;Aaaaaaaaand home time! An interesting journey to the airport... Our 'booked' taxi involved the hotel front-gate-man getting us a taxi on the day. The driver turned out to be pretty drunk with reaction speeds to match which wasn't so bad until he clipped a guy knocking his phone out of his hand. Rather than stop he just gave the guy an angry look, shouted and carried on driving. He was a very angry man. So very very angry. Once again the airport was rammed with armed guards, even a mounted sentry post on the way in! Then it was home time on our nine and a half hour flight home.&lt;/p&gt;
      
      &lt;p&gt;BYE INDIA!!!&lt;/p&gt;
    &lt;img src="http://feeds.feedburner.com/~r/ghickman/~4/DXxBFIylbeQ" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://ghickman.co.uk//2010/09/18/mumbai.html</feedburner:origLink></entry>
  <entry>
    <title>Back to School</title>
    <link href="http://feedproxy.google.com/~r/ghickman/~3/sRT6Hf8-5hg/back-to-school.html" />
    <updated>2010-09-17T00:00:00+01:00</updated>
    <id>tag:ghickman.co.uk,2010-09-17:/2010/09/17/back-to-school.html</id>
    <content type="html">
      &lt;p&gt;One of our main aims in India was to help out at a school we had vague ties to. The school had been variously described to us as an orphanage (and is indeed for children who have not had the best start in life, but also for others) and a hostel. We had assumed, before arrival, that it was a small school with 200 girls attending where we could help with teaching English. It actually turns out the 'school' is more of a community. Based on 5000 acres of land it is a charity run organisation with a large school, hostel for the children, various (large scale) cooking facilities, a water treatment plant, enough farm land to be self sufficient for 9 months of the year, a college/university, an old peoples home, a blind school, a general farm and more. Our initial figure of 200 girls is about right, however no-one thought to mention the other 2000 male students living here! Almost all staff live on-site and their are a good number of administrators and other personnel for things like building, farming, cooking, etc.&lt;/p&gt;
      &lt;p&gt;This post is going to differ a bit from my previous India ones in that I'm going to pick on various parts of our stay and talk about them. Two weeks here has left me with far too much to talk about!&lt;/p&gt;
      
      &lt;h2&gt;Meal Times&lt;/h2&gt;
      
      &lt;p&gt;Being guests we ate in a different kitchen to either the elderly/blind or the main school body and mostly ate by ourselves - sometimes being joined. We were served by the same kitchen as the elderly/blind school just in a different room and I don't think either of us have been so voraciously offered food in our lives. At first I felt a bit beseeched having to defend my platter from being filled every time I looked away but slowly learnt the game of covering my food while pushing the cook and his serving away. It's a hard life being a guest in Gujerat! Water had to be filtered to make it drinkable, for us at least, and most people drink far more butter milk than water anyway. I gave butter milk a go, it was not a great experience. Poppy was a little sick in her mouth when she tried it. She did not try it again. I gave curd a go which was like plain/greek yoghurt when mixed up. I had some sort of brown powder added to it (possibly cinnamon) that added a sweet edge. Unfortunately this was probably the source of my day of bad bowels (rusty water much?!). After expressing a like for potato, a few days in, the cook jumped at the opportunity and every meal time onward had some sort of potato (aloo in Hindi) in one of the dishes - yes, even breakfast.&lt;/p&gt;
      
      &lt;p&gt;It would be prudent to note at this point that every meal consists of 3+ dishes essentially, called a Gujerati Thali - it's like a set meal. Your main plate is a platter with edges and on it you have 2 or 3 bowls and a cup. All metal of course. You are served with a variety of dishes. We got a lot of lentil based dishes that I loved and generally there was theme to the meal. Dal (a kind of broth made from lentils) was served with almost every meal and I loved it at first but went off it after having it for two meals a day for a week. We discovered that chapatis and rotis are basically the same thing - having an english speaking chaperone was great as I asked about every dish we got served and learnt the rest of the dish names that I hadn't worked out. My favourite was by far the mash potato with chopped potato bits in it (me likey aloo) and butter. Fresh butter is the best thing. Ever. They make it daily (from what I could tell) and use unthinkable amounts of it in everything. I was in heaven. It's not salted and is almost like whipped cream. Pancakes would have gone very, &lt;em&gt;very&lt;/em&gt; well with the butter. Nom nom nom.&lt;/p&gt;
      
      &lt;h2&gt;[Farm] Animals&lt;/h2&gt;
      
      &lt;p&gt;Like everywhere else animals roamed freely at the school. The main difference is that the cows are farmed. Gujerat is both a dry and vegetarian state in honour of it being Ghandi's birth place. There are of course exceptions to this, mostly meat being available (chicken and mutton) primarily for tourists. So we were a little surprised to see cows being farmed when we arrived. It was later explained to use that while cows are a sacred animal they can be farmed for their produce. The cows at the school are the biggest healthiest cows I've ever seen (all adult cows were a match, if not bigger, than prime bulls I've seen in the UK...). On average they produce 70 litres of milk per day over two sittings (explains why dairy products feature so heavily in the diet there!) and the herd is roughly 200 strong. Any cow that can grow horns has got an epic set of people stabbers on their head and as with all the cows we'd seen - they go where they please. We had one cow in the field outside our room for a few days who would randomly wander through a flower bed to get there before stuffing his face from dawn til dusk.&lt;/p&gt;
      
      &lt;p&gt;A lot of equipment used to farm is mechanical but it blends seamlessly in with the Ox drawn carts and ploughs. Having never seen oxen before we first thought they were just humungous cows with even better horns (these look like your stereotypical devil/fully grown hellboy horns). Got a little schooling on that....get it schooling, at a school... #terriblejoke&lt;/p&gt;
      
      &lt;p&gt;Dogs randomly potter around the place but are some of the skinniest we'd seen. It turned out that residents were told not to feed the dogs in an attempt to keep them away but the elderly, doing as they pleased (some things never change), seemed to break this almost constantly - giving them a permanent pooch presence.&lt;/p&gt;
      
      &lt;h2&gt;Teaching Techniques&lt;/h2&gt;
      
      &lt;p&gt;I am no teacher. This is clearly evident if you have ever met me. I am happy to wander off on random tangents of thought and end up with cotton mouth 5 minutes into any public speaking (there is never any water around). So I do not, by any means, presume to pass judgement on the teaching techniques of the school. However I found them quite interesting. Theory and textbooks rule. Everywhere I went textbooks are being used by staff and students alike and whenever I tried to lend my expertise (only at the college/university - software engineering doesn't have much application for 3-16 year olds) the question that constantly popped up is: What book should I consult about this? This is not my way of doing things. I am a very practical person - something my academic career can attest to and books are by no means my preferred method of learning. In my opinion they are for stories, which has probably never helped me with textbooks! So I found this culture of text books hard to understand. Of course I don't think it's wrong, just very alien! I certainly know of a number of people who would flourish in the environment.&lt;/p&gt;
      
      &lt;h2&gt;Leaving&lt;/h2&gt;
      
      &lt;p&gt;We were fortunate to be driven up to Rajkot when it came time to leave. Which was no doubt for the best, it probably would have taken us the whole day if we'd tried to do it ourselves. We said goodbye to everyone, which was no quick thing and grabbed pictures of everything we could think of (still managed to forget the room of course) and headed off for the night in Rajkot before jetting over to Mumbai.&lt;/p&gt;
      
      &lt;p&gt;To anyone reading this from the Institute - thank you so very much for a wonderful two weeks. I hope the lab is still working!&lt;/p&gt;
    &lt;img src="http://feeds.feedburner.com/~r/ghickman/~4/sRT6Hf8-5hg" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://ghickman.co.uk//2010/09/17/back-to-school.html</feedburner:origLink></entry>
  <entry>
    <title>Diu - Home of Sand, Sea and Forts</title>
    <link href="http://feedproxy.google.com/~r/ghickman/~3/UxCxEo-vCh0/diu.html" />
    <updated>2010-09-16T00:00:00+01:00</updated>
    <id>tag:ghickman.co.uk,2010-09-16:/2010/09/16/diu.html</id>
    <content type="html">
      &lt;p&gt;Diu is a little island off the south coast of Gujarat that was under Portuguese control until some point (I'm vague on any actual sort of date or time frame....I'm no history buff). The general architecture is a weird mix of Indian construction with the loud colours that you see in a lot of Portuguese culture, made even more obvious when you see the grey pure concrete buildings being constructed next to the ADHD coloured buildings. Connected to the mainland by a bridge the whole island is pretty tiny at 14km in length. Apparently it's a big holiday destination in the high season but this is &lt;em&gt;MONSOON&lt;/em&gt; so it randomly rained like rain is going out of fashion and everything was a fraction of the price (our hotel was 500 rupees a night instead of 1500).&lt;/p&gt;
      &lt;h2&gt;Highway to HELL&lt;/h2&gt;
      
      &lt;p&gt;Allow me, if you will, to take you on a literary journey. Close your eyes and imagine the worst smell you can think of, throw in a heavy over tone of body odour, if this makes you gag/throw up in your mouth a little then you're on the right track. Now infuse that very smell into a cold, ever so slightly, damp mattress and put a blanket over the top. The blanket is dry but has the same smell and is covered in bits of general muck that stick to you the minute you touch it along with it's fluff. Now take a 10 hour night bus on that very mattress and blanket and try very hard not to think or talk about your situation. It will make you sick.&lt;/p&gt;
      
      &lt;p&gt;This was our bus journey from Ahmedabad to Diu. We covered ourselves in our sleeping bag liners. It was terrible. I'm still trying to repress the memory.&lt;/p&gt;
      
      &lt;h2&gt;La Dolce Vita Music Garden&lt;/h2&gt;
      
      &lt;p&gt;The first night in Diu we went for something budget-as-hell that the book said was cheap but okish. We were craving a shower/bleach after the bus so didn't look too closely when showed the room and ended up in Jay Shankar. While perusing the balcony [read: bored] I noticed a little restaurant over the road call La Dolce Vita Music Garden. It looked nice enough as being the lazy person I am I made sure we ate their first rather than trying to find somewhere else. Best decision of the trip.&lt;/p&gt;
      
      &lt;p&gt;La Dolce Vita is a collection of tables under a thatched reed roof attached to the owners' house. They have a fairly large selection of dishes on the menu that they cook in their own kitchen and were always happy to see us - probably because we were their only customers 99% of the time. They even helped us to learn a lot of the dish names, which became invaluable in other restaurants as up until that point I'd mostly picked dishes based on either randomly pointing at one or whichever had the coolest name. This had mixed results... I found a dish there, that was much like the first one I had in Delhi, called Aloo Gobi which means Potato Cauliflower. It didn't have much sauce but tasted great and mixed with one of their mammoth portions of rice formed more of a feast than a single meal. Nom nom nom!&lt;/p&gt;
      
      &lt;p&gt;My favourite part of La Dolce Vita is how the dishes always vary from day to day. This can be seen more explicitly in the lassis (like a milkshake but with yoghurt) and milkshakes that were practically a different drink every time we had one and just adds to the homely vibe of the place.&lt;/p&gt;
      
      &lt;h2&gt;Fort Boyard and Fort Bill&lt;/h2&gt;
      
      &lt;p&gt;In various places around Diu I've seen pictures of the sea fort in the main port bay. I promptly named it Fort Bouyard in my head and would strongly recommend the Diu authorities follow suit. You can't visit the actual fort so the only way to see it is to take a fishing boat around the outside and since the weather took a turn for the worse it got sacked off. Of course there are totally tigers in there for people who don't make it out of the cage fast enough, this I am sure of.&lt;/p&gt;
      
      &lt;p&gt;We did go and see the main fort regardless of the rain. It's one bad ass fort! Built into the bedrock of the peninsula, surrounded on three sides by sea and a double moat on the final side it seems pretty impenetrable. Somehow the Portuguese were ousted by the Indian army though. Fail. The two moats are backed by walls with with three bastions on the outer wall and four on the inner, each bastion packed to bursting with cannons...how the Portuguese lost is beyond me. L for love! The fort is still in use as the local prison and for some government offices since these existed back when it was built so it does make sense, but it does mean some parts are off limits which is a shame.&lt;/p&gt;
      
      &lt;p&gt;The first spectacle as you enter the fort proper is St George's Bastion which, apart from being named the best, overlooks the landing pier ready to bombard any marauding pirates. We saw another random bastion after this, St Luzia I think, which was more of the same, an armoury which seemed to have some rather more modern (post WWI) artillery pieces and a chapel before we got historied out (ADHD much?) and left.&lt;/p&gt;
      
      &lt;p&gt;We saw some restorative work had been done to walls here and there and some workmen were fixing up a wall but it's nothing like you'd see in England at say an English Heritage or National Trust site. The new brick work seems far less long lasting than the 500 year old stuff they are removing, which is a shame. There's a general feel of disrepair about the place which isn't helped by the large patches (old buildings that have since fallen down possibly) of overgrowth. Had English Heritage got their hands on it we could have at least had an overpriced coffee at the end.&lt;/p&gt;
      
      &lt;p&gt;Overall the fort can be summed up as RAD&lt;sup&gt;Sick&lt;/sup&gt; especially if you're into history but I'd forgotten most of the broken english translation of it's history by the first bastion. The slippery steep slope (stairs anyone?) up to each bastion was enough to pique my Fear of Heights into rearing it's ugly head. Flip flops were a bad choice.&lt;/p&gt;
      
      &lt;p&gt;I couldn't help but think that had the place been done up it would have been amazing for paintballing or airsofting on an epic scale. Pirates attack the fort anyone?!&lt;/p&gt;
      
      &lt;h2&gt;Reservoir Dogs&lt;/h2&gt;
      
      &lt;p&gt;Towards the end of our Diu tour we were, once again, visiting our favourite restaurant when the second group of people we'd ever seen there appeared. Six shifty looking indian fellas came in and perused the menu before sitting down. I didn't pay them much attention after the initial shock at seeing someone other than the owners in &lt;em&gt;my&lt;/em&gt; restaurant. After we'd finished yet another scrumptious gut busting meal I popped out my iPhone to look up a route from the restaurant to the local fort when one of the shifty gentlemen appeared at my shoulder giving me a pretty good fright. This put me on edge a bit until I later found out they had all been watching us the whole time and seemed especially interested in our wallets when it came time to pay up. Worse still the wife had stayed inside and when one of them approached us to ask for, what we thought, was a photo of the group the husband had told Poppy to sit down almost the moment she stood up. I found most of this out as we were walking away and immediately felt uneasy, promptly topped off by one of the guys coming out of the restaurant to watch us walk down the road. He was still there when we went round the corner a few hundred metres away. With paranoia rising we walked back to the hotel at almost running pace and promptly hid in the room for the next few hours, leaving the fort for another day.&lt;/p&gt;
      
      &lt;p&gt;Looking back on the experience the group were probably not muggers/the mafia and simply really leery guys which would explain the wife staying inside and the husband barely talking to us after they arrived (he was too busy keeping an eye on them). The worst part of the whole thing is we'd both become very comfortable in Diu, with Poppy venturing out unaccompanied occasionally and me using various tech in public but we were a little on edge afterwards and it took us a couple of days to get comfortable again.&lt;/p&gt;
      
      &lt;h2&gt;Cheese It!&lt;/h2&gt;
      
      &lt;p&gt;A very early start (5.30am) saw us on the 7am (sorry 7.30am...) bus to Veraval which needed to be jump started and whose horn got stuck on after mass overuse so the driver had to disconnect it. Sitting down the front of the bus meant we got to ignore almost all the usual stares (the door was in the middle) - a nice change. Once in Veraval we went looking for the bus we'd been assured we could get to Visavadar, which turned out to actually be a bus to Junagh and then get a connection from there, an extra 96km. It's only 120km from Diu to Visavadar.&lt;/p&gt;
      
      &lt;p&gt;A hilariously roundabout negotiation for a rickshaw got us to the train station for 10 rupees saving us the trip in the pouring rain. We just about managed to purchase a ticket to Visavadar on a train that was leaving 3 hours later and headed for our platform. The bridge was really high and floored with tiles that were slick with rain, so so utterly dim cool with a giant bag and flip flops on. Even after being up close to 9 or 10 hours I still loved being on the train. Over half the stops had no visible buildings but people would be waiting around, sometimes to sell you things when you got off for a break or because it was a 'station'. At one stop there were monkeys outside, so being the ultimate tourist I leap from the train, camera in hand, and tried to get as close as possible to get a good picture. These monkeys were enjoying the food they were being given but apparently the white man getting closer than 3 feet is a faux pas....I got hissed and had teeth bared at me. It was rad. I could have totally taken that monkey....&lt;/p&gt;
    &lt;img src="http://feeds.feedburner.com/~r/ghickman/~4/UxCxEo-vCh0" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://ghickman.co.uk//2010/09/16/diu.html</feedburner:origLink></entry>
  <entry>
    <title>Phase Two, Ahmedabad</title>
    <link href="http://feedproxy.google.com/~r/ghickman/~3/ssitgWVds4k/phase-two-ahmedabad.html" />
    <updated>2010-08-01T00:00:00+01:00</updated>
    <id>tag:ghickman.co.uk,2010-08-01:/2010/08/01/phase-two-ahmedabad.html</id>
    <content type="html">
      &lt;p&gt;We'd pre-booked our flight from Delhi to Ahmedabad which added a nice respite from working out what to do. Delhi's domestic terminal was an experience in itself, at the doorway and right up until you pass through security there are heavily armed guards wherever you look. Since everyone stared at us wherever we went this shouldn't have been a problem in the airport but having guards with machine guns staring at me was not a pleasant experience.&lt;/p&gt;
      &lt;p&gt;They were pretty thorough with the basic search for both of us. At least Poppy got a private booth for her light petting. I feel like I got the raw deal here. India is far more relaxed about liquids on planes, we left our two litre bottle of water in one of the day bags when we went through security and they looked more bemused than anything, granted we tried to drink most of it before we chucked the bottle. The X-Ray man was pretty interested in my stash of gadgets, sending my bag and laptop through the machine a good 5 times before he'd had his fill. Past security there was a pretty big food court where I just couldn't resist a KFC and damn was it good. I even got mistaken for an American by a nice gentleman hailing from stateside who wondered if the burgers were 'as good as home?'. I put on my best British accent to reply 'bloody good grub ol' chap'. I got a chuckle from him at least.&lt;/p&gt;
      
      &lt;p&gt;Apart from a last minute change in the flight time, (it was postponed by 8 hours and went from being an hour to two and a half hours long) that I can't thank Ben enough for helping with, everything went quite smoothly. I'm still a complete child with planes and love the take off. Zoom zoom zoom! Apparently no electronic devices whatsoever are allowed to be used on smaller planes (I had the same experience on my internal flight in Vietnam where even my iPod Classic got me a telling off) and even my iPhone's flight mode wasn't allowed. Having been completely unprepared for this with no physical books in my bag (I was trying out eBooks at the time) I was at a complete loss for what to do, so I spent a good hour winding Poppy up. She'd had the forethought to bring real books at least...&lt;/p&gt;
      
      &lt;h2&gt;Arrival&lt;/h2&gt;
      
      &lt;p&gt;We didn't really have any specific plans for a place to stay but rather a short list of ones that would do. We ended up at Hotel Balwas around 10pm (thank you Indian culture for not closing anything until midnightish!) and found we'd made a good random pick from the list. Nice beds, working A/C and a toilet with no flush which confused my other half until I explained that was why we had a bucket and a tap.&lt;/p&gt;
      
      &lt;h2&gt;Force Recon&lt;/h2&gt;
      
      &lt;p&gt;Our hotel wasn't listed on my newly acquired bible (A Rough Guide to India that I'd say is a good five years old - not bad for 300 rupees) but with the help of the trusty iPhone and GPS I worked out that we were near Khas Bazaar roughly and at least knew which bit of Advance Road we were on. Our first trip out we found that Indians have drinks bars which do not in fact serve food to the starving George. They also house some really clever mosquitoes. The first bugger got me SIX times before I smeared him up my ankle. We moved on and eventually found some sort of food hall where we had Jeera rice which was pretty tasty but not a great meal for breakfast (scrambled eggs, weetos, meat in a sandwich or a cooked breakfast are about all I go in for).&lt;/p&gt;
      
      &lt;h2&gt;The Hunt for Red October&lt;/h2&gt;
      
      &lt;p&gt;I use Travellers Cheques when abroad for a number of reasons; they're guaranteed by American Express, have a tiny commission to buy/redeem, are insured by both American Express and the British Post Office (if you choose to buy them there - I'm not so sure about banks) and like any cheque can be cancelled. I've used them in the states like regular cheques in shops and all over South-East Asia they were excepted everywhere from massive Thai banks to a money exchange stall on the side of the road in Cambodia. I am a fan. I thought nothing of it when coming to India and promptly got my nice packet of cheques with the serial numbers, stashed copies of the serials in various mail boxes around the web and gave physical copies to the usual suspects. The old routine, or so I thought. Ahmedabad has a multitude of banks, most of which do not, in fact, change travellers cheques. Problem. We spent about 3 hours going on wild goose chases around the posher part of the city going from bank to bank on foot and in auto-rickshaws. There was a Western Union back over by the hotel but they wanted a minimum of £500 to be changed and that was our budget for the trip (each). Eventually we ended up at Thomas Cook which the book informed us was very reliable for changing Travellers Cheques and my feeling by this point was: They better bloody well had, i.e. fed up. We were in luck, not only would they change our cheques but they also had the A/C cranked down to Antarctic setting. At this point we thought it prudent to change pretty much all the money we would need until Mumbai, roughly 45,000 rupees or 1 inch of 500 rupee notes. One nervous auto-rickshaw back to the hotel and the cash (our spoils?) were split up and secreted away in various ingenious hiding places.&lt;/p&gt;
      
      &lt;p&gt;Ironically it turned out to be a lot easier to change money all across Diu. Lesson learnt: never doubt the cheques.&lt;/p&gt;
      
      &lt;h2&gt;Heat&lt;/h2&gt;
      
      &lt;p&gt;Having been to what has to have been at least 30 banks in one day there is one thing I can say with certainty about the banks of Ahmedabad: If you go on the rob to one, you &lt;em&gt;will&lt;/em&gt; be shot. Every single one we visited had a security guard with a 4 to 5ft shotgun (with optional second barrel). They were all very polite to customers and opened the door for you, some even directed you to the correct counter, etc but they are still holding a ruddy great gun. Add +1 to stress for the day.&lt;/p&gt;
      
      &lt;h2&gt;The Guide&lt;/h2&gt;
      
      &lt;p&gt;A couple of times we were approached by a nice enough guy offering us guided tours around the city including a free lunch. His english was very good and he showed us a book of testimonials from a variety of other travellers. I was pretty skeptical of him having seen the like in South-East Asia that didn't always turn out so nicely, but after taking us to an apparently good bus company to book our journey down to Diu he never asked for any money and genuinely seemed happy to help. It was quite a shock to realise this, it's not something I expect from people who act like touts, but it's a shame that he was just so annoying and he spent a lot of time touching us. Dim Cool.&lt;/p&gt;
      
      &lt;h2&gt;Exit Strategy and a Revelation&lt;/h2&gt;
      
      &lt;p&gt;As usual we grabbed an auto-rickshaw for the journey to the bus station. We were leaving from the office we booked at and not the main one in Ahmedabad so we left a little early to hedge our bets. We jumped out early on my prompt to find I'd not seen our bus place, but a shed like waiting room with a red sign....hey, there were coaches everywhere. While trying to get another auto-rickshaw to take us the rest of the way our driver started asking random people where to go and showing the address we had written up. It dawned on me, via some prompting from my more astute girlfriend, that he couldn't read. I thought back to all the other drivers who had done the same thing (the vast majority of them) and was shocked at how many probably couldn't read at all. India is a definitely a country of contrasts.&lt;/p&gt;
      
      &lt;p&gt;The bus pulled up and we jumped on. My first impression was: cool, they have a house door to separate the driver(s) from the back and we're getting an actual double sleeper, win! But more on that later. Tune in next week/month/day for Diu!&lt;/p&gt;
    &lt;img src="http://feeds.feedburner.com/~r/ghickman/~4/ssitgWVds4k" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://ghickman.co.uk//2010/08/01/phase-two-ahmedabad.html</feedburner:origLink></entry>
  <entry>
    <title>Delhi, the Experience</title>
    <link href="http://feedproxy.google.com/~r/ghickman/~3/FnCrYruEWM4/delhi-the-experience.html" />
    <updated>2010-07-25T00:00:00+01:00</updated>
    <id>tag:ghickman.co.uk,2010-07-25:/2010/07/25/delhi-the-experience.html</id>
    <content type="html">
      &lt;p&gt;Back at the beginning of the year while I was travelling around South-East Asia with friends my partner, who I'd had to leave at home, came up with the idea of visiting an orphanage in India that her family had ties to. Being quite taken with this travelling thing I thought it was a fantastic opportunity for her with the bonus of getting to teach some kids who haven't had the best luck. Later in my first trip I decided I'd like to go with her and we decided we'd make a mini trip of it and take in some more of what India has to offer. She drew up an itinerary, flights got booked, bags packed and off we trotted (with only one hiccup of almost not getting a visa in time, I probably should have thought of that one...).&lt;/p&gt;
      &lt;h1&gt;The Flight&lt;/h1&gt;
      
      &lt;p&gt;We flew out with BA, something I've never had the chance to do before and it is to date the best carrier I've ever flown with. The plane wasn't the newest but the service was very pleasant. However what I really enjoyed was the fully featured touch screen I had with access to a pretty wide range of films and TV. Bonus. I got a good three films in over the nine and a half hour flight and didn't even doze off - something very unheard of for me on long journeys. We had curries for food on the way there that were really quite nice for airplane food and at the end of the flight a kind of hot curry pasty which was incredibly tasty and filling!&lt;/p&gt;
      
      &lt;h1&gt;Our Arrival&lt;/h1&gt;
      
      &lt;p&gt;Delhi's International airport does not seem to have the facility for many of it's arrivals to disembark directly into the terminal. This was a shock. Not having to take the shuttle to the terminal, but heat. Oh god it was hot, and close. At least in Bangkok I'd had the opportunity to prepare myself for this, in Delhi I wasn't really paying attention and then suddenly it's eight thousand degree, two thousand percent humidity and I'm on a rickety set of steps. WHAT is going on is my body cried...&lt;/p&gt;
      
      &lt;p&gt;We'd had the foresight to book a hotel before flying, which was for the best as the flight landed at gone 11pm so we made the hotel by about 11.45, a little tired. The drive there was pretty interesting too. First of all we had to change money and get a taxi. The first one being simple as ever with travellers cheques, the second being a little more interesting. We didn't have a travel guide at the time (thinking we could use the internet to research what we needed on the fly - big mistake) so we had no idea what a decent price for the taxi should be. We got quoted 490 rupees the first place we went and took it. It was 11.20pm, I'd been up since 3.30am BST and hadn't really slept since...I just wanted to get to a bed, stat. I hand over a 500 rupee note just as the booth next to us charges some other westerners 400 rupees. Bugger, oh well - too tired to care. Luckily our booth didn't have change so I got a 100 rupee note back. Karma restored.&lt;/p&gt;
      
      &lt;h1&gt;First Experiences&lt;/h1&gt;
      
      &lt;p&gt;From the off we were spectacles to everyone in sight, even at the airport. We'd seen one other white couple since getting off the plane, but we'd expected this so it was just a bit weird rather than intimidating so far. The drive didn't take long into the city but it was evident that the drive didn't know where our hotel (Hotel Volga International) actually was, just the road it was on. A bit of searching and we found a 20 foot sign strapped to the side of a building that just about had a light on. Success, shower and a bed.&lt;/p&gt;
      
      &lt;p&gt;A shocking moment was having my first shower and realising it was the water making every break in my skin tingle and then sting within thirty seconds. Teeth were washed with drinking water from then on...&lt;/p&gt;
      
      &lt;h3&gt;For Sparta&lt;/h3&gt;
      
      &lt;p&gt;One pretty decent nights sleep later (A/C was a dream after the climate shock) we prepared to make our first foray onto the streets of Delhi.....at 1pm, jet lag is a bitch. We made it as far as the end of the alley and 50 yards up the road to a food stand that was past some building works. We got water and went back [read: made a hasty retreat] to the room. After building up some more courage and cooling down by draping ourselves over the beautiful A/C unit we prepared ourselves to find some food as water is pretty boring after a while.&lt;/p&gt;
      
      &lt;h3&gt;Once More Into the Breach Dear Friends&lt;/h3&gt;
      
      &lt;p&gt;We followed the same route as before and if anything got more stares this time, sunglasses helped no end in ignoring this. Experience has taught us that Indians will stare all the more if you stare back since you have 'caught their attention' but will look away abashed if you smile and nod/wave. I really wish I'd know this at the time! A short walk from the hotel and we ended up outside a locals dining hall. They were cooking food in huge vats, always a huge bonus in my opinion and in this case I couldn't have been more right. Poppy and I shared a portion of rice (possibly Jeera as it was flavoured) with a potato and chick pea curry. It was utterly sublime and is still my favourite dish of the trip (almost two weeks in).&lt;/p&gt;
      
      &lt;h3&gt;Behind Enemy Lines&lt;/h3&gt;
      
      &lt;p&gt;The Red Fort was on the top of our list of places to visit and we decided it would be clever to pack our bags after two nights at Hotel Volga and grab the nearest auto-rickshaw up to that end of the city to stay a night so that we could spend more time in Red Fort. There were two major problems with this: Red Fort is only open to Westerners between 7.30 and 8.30pm for a light show and there are no hotels that end of the city that we could find. It turns out the area around Connaught Place is the top destination for hotels unless you want to go really upmarket and is really Delhi's version of Bangkok's Khosan Road. Another auto-rickshaw back and we found Snow White Hotel after a gruelling hour of looking at hotels well outside of our budget. Internet is not big at most hotels either... Our night at Snow White was less than good with an A/C unit that sounded more like a diesel engine and tiny little bugs everywhere, oh and a mouse. Granted Volga had one of these but the room was nicer so I'll let it off. We found a nice upmarket restaurant nearby where had our second meat dish of the trip. I'm pretty sure my chicken wasn't cooked properly, but it was tasty!&lt;/p&gt;
      
      &lt;h3&gt;Third Times the Charm&lt;/h3&gt;
      
      &lt;p&gt;We went further afield from Snow White and discovered Main Bazaar Road where we found Hotel Vivek that boasted actual honest to god internet in the room. I jumped at the chance, but it turned out to be a dud. The Internet Man promised me a wire was broken which was why I couldn't get wireless in the room. A cursory glance at the structure of the building and what must have been a metre of steel laced concrete between my room and the far away Access Point told me otherwise. I even tried to use the lobby internet, got on the wireless with no trouble but found the internet to be broken to which I was told 'Apple is different software, try restarting. Then there was the rage blackout. Overall Hotel Vivek was pretty nice even with the water being off for most of the first day, however I tired of being told everything would be fixed in half an hour repeatedly (it was more like 6 hours).&lt;/p&gt;
      
      &lt;h3&gt;Random Jaunt&lt;/h3&gt;
      
      &lt;p&gt;While trying to visit Jantar Mantar we found it was closed for building work so the possible taut who had jumped on our auto-rickshaw took us round some Indian shopping Boutiques where we saw some fantastic clothing and material that was sadly, for the majority, for the majority out of our price range. Poppy picked up a lovely scarf and we found stacks of carpets, wall hangings and cushion covers that would have looked great at home. Driving around for a while in Delhi was pretty fun and I managed to get some good pictures of that help to illustrate the manic nature of driving there, especially the beat up look of every vehicle on the road. I would have loved to have tried it for myself but unfortunately we didn't find anywhere to rent cars (motorbikes might have been a bit too much...).&lt;/p&gt;
      
      &lt;h1&gt;Closing Thoughts&lt;/h1&gt;
      
      &lt;p&gt;Delhi is busy and so utterly dirty. Most of it seems to be under [de]construction too, but after some looking around this seems more to be because of the impending Commonwealth Games they are hosting. Indians seem to build in an utterly chaotic fashion but no doubt it is like their traffic system and has a beautiful pattern underneath as buildings do seem to get built. So often we'd see the side of a road demolished but nobody working on it or any workers in sight! The city in general is busy, dirty and completely full of life. It was a both a brilliant experience and a complete shock to the system that I would highly recommend to anyone.&lt;/p&gt;
    &lt;img src="http://feeds.feedburner.com/~r/ghickman/~4/FnCrYruEWM4" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://ghickman.co.uk//2010/07/25/delhi-the-experience.html</feedburner:origLink></entry>
  <entry>
    <title>A New Year, A New Blog</title>
    <link href="http://feedproxy.google.com/~r/ghickman/~3/bQUkczCUkbw/new-blog.html" />
    <updated>2010-07-04T00:00:00+01:00</updated>
    <id>tag:ghickman.co.uk,2010-07-04:/2010/07/04/new-blog.html</id>
    <content type="html">
      &lt;p&gt;One thing I've noticed about coders on the internet is how many of them rebuild their blogs almost as a matter of habit and unsurprisingly I'm no exception. I've build three blogs, I only really have three posts...says it all really doesn't it? So here is my new blog!&lt;/p&gt;
      
      &lt;p&gt;This one is built using the static site generator, &lt;a href="http://github.com/mojombo/jekyll"&gt;Jekyll&lt;/a&gt;, modified with some useful extras by my good friend &lt;a href="http://26smiles.com"&gt;RichGuk&lt;/a&gt;. A full list of the extras he added can be found on his &lt;a href="http://github.com/richguk/jekyll"&gt;Github page&lt;/a&gt;. The benefit of using Jekyll, for me, is the simplicity the system provides. I can create posts in markdown, haml or even plain HTML, let Jekyll convert it into an HTML page and view it locally using the built in server Jekyll provides. Since the whole thing is tracked in Git I can push new posts to the remote web-server where a hook is setup to run the Jekyll build command, thus automating the whole thing!&lt;/p&gt;
      
      
      &lt;div class="right photo"&gt;
          &lt;img src="http://farm1.static.flickr.com/2/3425464_068a1e6124_m_d.jpg" /&gt;
          &lt;p class="photo"&gt;
              &lt;a href="http://www.flickr.com/photos/johnseb/3425464/"&gt;JohnSeb&lt;/a&gt;
              &lt;img class="cc" src="/images/cc.png" width="16" height="16" title="Creative Commons Icon" alt="CC"&gt;
          &lt;/p&gt;
      &lt;/div&gt;
      
      
      &lt;p&gt;The whole thing is hosted using &lt;a href="http://nginx.org/"&gt;Nginx&lt;/a&gt; and &lt;a href="http://www.modrails.com/"&gt;Phusion Passenger&lt;/a&gt; which was pretty fun to play around with until I tried to set them up on my Debian web-server. A combination of outdated Ruby, Gems and being so new to the Ruby ecosystem meant the build took up most of a weekend, however now I have a nice setup with &lt;a href="http://www.rubyenterpriseedition.com/"&gt;Ruby Enterprise&lt;/a&gt; and the aforementioned technologies. It even prompted me to clean up my web-server a little which was really due for some TLC, last time I check it's uptime was closing on 800 days (pretty proud of that!) and it's got some really old projects on there...&lt;/p&gt;
      
      &lt;p&gt;One problem I came across while building the site was the lack of options for a contact form. After a bit of digging around I decided to dabble with some &lt;a href="http://www.sinatrarb.com/"&gt;Sinatra&lt;/a&gt; (it has to be the easiest Hello World I've ever built). It was pretty easy to combine the two, but I'll leave the explanation for a future post.&lt;/p&gt;
      
      &lt;p&gt;Hope you enjoy the new site, I certainly enjoyed building it!&lt;/p&gt;
    &lt;img src="http://feeds.feedburner.com/~r/ghickman/~4/bQUkczCUkbw" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://ghickman.co.uk//2010/07/04/new-blog.html</feedburner:origLink></entry>
  <entry>
    <title>Running PHP 5.2 and PHP 5.3 on OSX</title>
    <link href="http://feedproxy.google.com/~r/ghickman/~3/0qi8V9neTRg/running-php-5.2-and-php-5.3-on-osx.html" />
    <updated>2009-09-02T00:00:00+01:00</updated>
    <id>tag:ghickman.co.uk,2009-09-02:/2009/09/02/running-php-5.2-and-php-5.3-on-osx.html</id>
    <content type="html">
      &lt;p&gt;With the release of Snow Leopard Mac users have been provided with version 5.3 of PHP already installed and are one commented line away from running it with Apache. Upon installing Snow Leopard I thought "great! shiny new things!", then discovered all my projects down and out from all the shiny goodness. So I needed to get my PHP 5.2 working again. Back on Leopard I'd been using the Entropy PHP package created by Marc Liyange since it comes with all the extensions I needed. Now I didn't want to lose PHP 5.3 as I'd like to play around in it when I have some more spare time. So the ideal situation would be to have both installed and be able to switch between them with as little as an Apache restart.&lt;/p&gt;
      &lt;p&gt;My current situation is that I'm running PHP 5.2.9 with 5.3 disabled by commenting out the php5 line in httpd.conf. Now to switch back is the hard bit. So far I've not found a nice way to switch back, mainly because I haven't had the time. At the moment if I want to switch back I remove the Entropy package by deleting the folder and uncommenting the line in httpd.conf. In theory there has to be a link between Apache and the Entropy package to make my PHP run (magic?) which hopefully it is possible to disable. As soon as I get the time I'll work out a cleaner solution.&lt;/p&gt;
      
      &lt;p&gt;EDIT: Joel Moss (who prompted me to document this in the first place) came up with a &lt;a href="http://twitter.com/joelmoss/status/3714955305"&gt;solution&lt;/a&gt; by wrapping one of your PHP's in a FastCGI wrapper allowing a simple change to the httpd.conf file to switch between the two versions. However the solution proposed by &lt;a href="http://mark-story.com/posts/view/updating-to-php5-3-with-macports"&gt;Mark Story&lt;/a&gt; seems more up my alley (I'm lazy and running a script suits that trait far better!).&lt;/p&gt;
      
      &lt;p&gt;Now I just need the time to get round to actually setting one of these up...&lt;/p&gt;
    &lt;img src="http://feeds.feedburner.com/~r/ghickman/~4/0qi8V9neTRg" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://ghickman.co.uk//2009/09/02/running-php-5.2-and-php-5.3-on-osx.html</feedburner:origLink></entry>
  <entry>
    <title>Stacking Movie Files in XBox Media Center</title>
    <link href="http://feedproxy.google.com/~r/ghickman/~3/h8O1Mlq-zeQ/stacking-movie-files-in-xbox-media-center.html" />
    <updated>2009-08-06T00:00:00+01:00</updated>
    <id>tag:ghickman.co.uk,2009-08-06:/2009/08/06/stacking-movie-files-in-xbox-media-center.html</id>
    <content type="html">
      &lt;p&gt;I'm the first person to admit that I have some fairly obsessive habits when it comes to making things look nice and neat, more specifically in the media files department. So while playing around with getting my Films folder all neatly into XBox Media Centre (XBMC because I'm lazy and abbreviations FTW) when I found that my films in multiple files weren't stacking properly.&lt;/p&gt;
      &lt;h4&gt;What is Stacking and Why Should I Want This Ambrosia of the Gods?!&lt;/h4&gt;
      
      &lt;p&gt;For those of you unaware of this nifty little feature it lets you take those split film files you have, in formats such as Film (part 1).something and Film (part 2).something and turn them into Film.something with XBMC magic. In technical speak it literally stacks them on top of each other so you see one file instead of many based on the numbering.&lt;/p&gt;
      
      &lt;p&gt;Now, I prefer the format Film (1).something to all the others I've seen. I don't need to know it's a part or a disk, this is assumed by the simple action of just having the parenthesis (yes, it means brackets but I'll damned well sound fancy now I have a dictionary at my fingertips!). This of course led to some hacking of XBMC, which as a standard nerd I love doing because it involves hacking at something for ages to make the tiniest little change. This, as it turns out, is actually very easy. The folks over at the XBMC project let you fiddle with all sorts of things using XML files (a personal favourite of mine) to control various eccentricities of your media centre. They also document stuff, so I love them, big time. While perusing &lt;a href="http://wiki.xbmc.org/index.php?title=Advancedsettings.xml"&gt;here&lt;/a&gt; I found the &lt;code&gt;advancedsettings.xml&lt;/code&gt; file that basically lets you do everything, even the dishes in some lovely xml tags. The tag you'll want that lets you play with stacks within this file is the &lt;code&gt;&amp;lt;moviestacking&amp;gt;&lt;/code&gt; tag where you can place a regex filter. Below is my version for your viewing pleasure:&lt;/p&gt;
      
      &lt;div class="gist"&gt;                                      &lt;div class="gist-file"&gt;          &lt;div class="gist-data gist-syntax"&gt;                                                  &lt;div class="gist-highlight"&gt;&lt;pre&gt;&lt;span class=line id=LC1&gt;&lt;span class="nt"&gt;&amp;lt;advancedsettings&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;moviestacking&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;append&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC3&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;regexp&amp;gt;&lt;/span&gt;(.+)\\(([0-9])\\)()(\\.[^.]+)$&lt;span class="nt"&gt;&amp;lt;/regexp&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC4&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;/moviestacking&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=line id=LC5&gt;&lt;span class="nt"&gt;&amp;lt;/advancedsettings&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;                      &lt;/div&gt;          &lt;div class="gist-meta"&gt;            &lt;a href="https://gist.github.com/raw/1255782/2eb0a041153fb920616a958aa66456ad4842c617/gistfile1.xml" style="float:right;"&gt;view raw&lt;/a&gt;            &lt;a href="https://gist.github.com/1255782#file_gistfile1.xml" style="float:right;margin-right:10px;color:#666"&gt;gistfile1.xml&lt;/a&gt;            &lt;a href="https://gist.github.com/1255782"&gt;This Gist&lt;/a&gt; brought to you by &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt;.          &lt;/div&gt;        &lt;/div&gt;            &lt;/div&gt;
      
      
      &lt;p&gt;The append section means the rule is appended to the default XBMC rules and the advancedsettings tags are there because, well, it's the advanced settings file. Save the file in your userdata folder, restart XBMC and voila! you'll see the files that you've named in the format I (and &lt;a href="http://thetvdb.org"&gt;thetvdb.org&lt;/a&gt; which I use as the default library for &lt;a href="http://github.com/ghickman/tvrenamr"&gt;Tv Renamr&lt;/a&gt;) use will stack through what I can only gather is XBMC magic, or regex - which I'm reliably told involves ninjas anyway and they're practically magic. Enjoy!&lt;/p&gt;
    &lt;img src="http://feeds.feedburner.com/~r/ghickman/~4/h8O1Mlq-zeQ" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://ghickman.co.uk//2009/08/06/stacking-movie-files-in-xbox-media-center.html</feedburner:origLink></entry>
  <entry>
    <title>Tv Renamr - Finally</title>
    <link href="http://feedproxy.google.com/~r/ghickman/~3/rCaQD2FlZCQ/Tv-Renamr---Finally.html" />
    <updated>2009-08-03T00:00:00+01:00</updated>
    <id>tag:ghickman.co.uk,2009-08-03:/2009/08/03/Tv-Renamr---Finally.html</id>
    <content type="html">
      &lt;p&gt;For the last few years I've always wanted to create a program that renamed the TV files I had into the nice neat format that I seem to spend so much of my spare time doing manually. Well, on my birthday I decided to take the plunge, stop talking about it and get my arse in gear. On that day, 22 years after my mother labouriously gave birth to me Tv Renamr was created in what I have no doubt was a far less spectacular fashion than the miracle of child birth. I started off with a short script in Python with various bits taken de facto from the internet. It sort of worked, as long as your files were in the correct format to begin with, which was a pretty narrow groove for your files to be. Which of course mine weren't.&lt;/p&gt;
      
      &lt;p&gt;&lt;em&gt;Fast forward to a few months later and roughly the present day...&lt;/em&gt;&lt;/p&gt;
      &lt;p&gt;After the joy of final exams and the stress of moving back in with my parents and some random hacking away at my code I've ended up with a nicely object oriented Python API that takes a few formats and gives the user a variety of ways to rename TV files. I've even had a crash course in python testing, something which has recently proved invaluable to being able to dip in and out of the project as I please. The passing in of files and information is now pretty much complete, a user can choose the series name, the season number, the episode number (if you're doing a single file) and even specify a regex expression which is always useful if like me you want to make sure your Stargate SG-1 rips are perfect. I even have tests to back up my work, which in a personal project is a first for me, but damn is it awesome to see that growl popup with a green tick. It's like a giant thumbs up!&lt;/p&gt;
      
      &lt;p&gt;Next on the agenda is customising the output. The more important part of this is letting the user specify how to deal with characters that aren't supported by their file system. While Python already deals with this, I want to give the user the choice to specify what characters they want replaced and how. Then it's onto the output format, which I'm ignoring for now, because it sounds big and I haven't even got a test file ready for it yet &lt;em&gt;eep&lt;/em&gt;.&lt;/p&gt;
      
      &lt;p&gt;This project has taught me a few things about myself and coding along the way - coding stuff you're really interested in is hellishly fun (I've literally lost days to this project without even noticing) and doing it in a language you've barely tried before is a massive confidence boost to your skill level.&lt;/p&gt;
      
      &lt;p&gt;The project is of course hosted on my &lt;a href="http://github.com/ghickman/tvrenamr/tree/master"&gt;github page&lt;/a&gt; where you can download it or clone it to your neat little heart's content. If you find any bugs or problems, please add an issue on github, dm/@ me on &lt;a href="http://twitter.com/ghickman"&gt;twitter&lt;/a&gt; or email me on george [at] ghickman -dot- co -dot- uk.&lt;/p&gt;
    &lt;img src="http://feeds.feedburner.com/~r/ghickman/~4/rCaQD2FlZCQ" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://ghickman.co.uk//2009/08/03/Tv-Renamr---Finally.html</feedburner:origLink></entry>
</feed>

