<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Neil Ang (web-development)</title>
    <link>http://neilang.com</link>
    <description>Neil Ang Feed</description>
    <language>en-us</language>
    <generator>Symphony (build 1701)</generator>
    <item>
      <title>Generating a calendar using XSLT</title>
      <link>http://neilang.com/entries/generating-a-calendar-using-xslt/</link>
      <pubDate>Sun, 16 Nov 2008 07:43:00 GMT</pubDate>
      <guid>http://neilang.com/entries/generating-a-calendar-using-xslt/</guid>
      <description>&lt;p&gt;Recently I was tasked to build an interactive calendar in XSLT. I wanted the calendar to always start on a Sunday as well as have clean markup. I couldn't find any good examples on the web while I was building it, so I decided to post the base of my solution.&lt;/p&gt;

&lt;p&gt;
	&lt;img src="/workspace/upload/calendar.png" alt="Picture of final product" /&gt;
&lt;/p&gt;

&lt;p&gt;Insert the following variables and templates into your stylesheet:&lt;/p&gt;

&lt;code&gt;&amp;lt;xsl:variable name="DisplayDate" select="date:date()"/&amp;gt; &lt;br /&gt; &amp;lt;xsl:variable name="Year" select="date:year($DisplayDate)"/&amp;gt; &lt;br /&gt; &amp;lt;xsl:variable name="Month" select="date:month-in-year($DisplayDate)"/&amp;gt; &lt;br /&gt; &amp;lt;xsl:variable name="MonthName" select="date:month-name($DisplayDate)" /&amp;gt; &lt;br /&gt; &amp;lt;xsl:variable name="NumberOfDaysInMonth"&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;lt;xsl:call-template name="DaysInMonth"&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:with-param name="month" select="$Month" /&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:with-param name="year" select="$Year" /&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;lt;/xsl:call-template&amp;gt; &lt;br /&gt; &amp;lt;/xsl:variable&amp;gt; &lt;br /&gt; &amp;lt;xsl:variable name="FirstDayInWeekForMonth" select="date:day-in-week(date:date(concat($Year,'-', $Month, '-01')))" /&amp;gt; &lt;br /&gt; &amp;lt;xsl:variable name="WeeksInMonth"&amp;gt;&amp;lt;xsl:value-of select="($NumberOfDaysInMonth + $FirstDayInWeekForMonth - 1) div 7" /&amp;gt;&amp;lt;/xsl:variable&amp;gt; &lt;br /&gt; &lt;br /&gt; &amp;lt;xsl:template name="DaysInMonth"&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;lt;xsl:param name="month"&amp;gt;&amp;lt;xsl:value-of select="$Month" /&amp;gt;&amp;lt;/xsl:param&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;lt;xsl:param name="year"&amp;gt;&amp;lt;xsl:value-of select="$Year" /&amp;gt;&amp;lt;/xsl:param&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;lt;xsl:choose&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:when test="$month = 1 or $month = 3 or $month = 5 or $month = 7 or $month = 8 or $month = 10 or $month = 12"&amp;gt;31&amp;lt;/xsl:when&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:when test="$month=2"&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:choose&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:when test="$year mod 4 = 0"&amp;gt;29&amp;lt;/xsl:when&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:otherwise&amp;gt;28&amp;lt;/xsl:otherwise&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/xsl:choose&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/xsl:when&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:otherwise&amp;gt;30&amp;lt;/xsl:otherwise&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;lt;/xsl:choose&amp;gt; &lt;br /&gt; &amp;lt;/xsl:template&amp;gt; &lt;br /&gt; &lt;br /&gt; &amp;lt;xsl:template name="Calendar"&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;lt;table summary="Monthly calendar"&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;caption&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:value-of select="$MonthName" /&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:text&amp;gt; &amp;lt;/xsl:text&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:value-of select="$Year" /&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/caption&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;tr&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;th abbr="Sunday"&amp;gt;Sun&amp;lt;/th&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;th abbr="Monday"&amp;gt;Mon&amp;lt;/th&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;th abbr="Tuesday"&amp;gt;Tue&amp;lt;/th&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;th abbr="Wednesday"&amp;gt;Wed&amp;lt;/th&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;th abbr="Thursday"&amp;gt;Thu&amp;lt;/th&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;th abbr="Friday"&amp;gt;Fri&amp;lt;/th&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;th abbr="Saturday"&amp;gt;Sat&amp;lt;/th&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/tr&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:call-template name="CalendarWeek"/&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;lt;/table&amp;gt; &lt;br /&gt; &amp;lt;/xsl:template&amp;gt; &lt;br /&gt; &lt;br /&gt; &amp;lt;xsl:template name="CalendarWeek"&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;lt;xsl:param name="week"&amp;gt;1&amp;lt;/xsl:param&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;lt;xsl:param name="day"&amp;gt;1&amp;lt;/xsl:param&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;lt;tr&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:call-template name="CalendarDay"&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:with-param name="day" select="$day" /&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/xsl:call-template&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;lt;/tr&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;lt;xsl:if test="$WeeksInMonth &amp;amp;gt; $week"&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:call-template name="CalendarWeek"&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:with-param name="week" select="$week + 1" /&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:with-param name="day" select="$week * 7 - ($FirstDayInWeekForMonth - 2)" /&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/xsl:call-template&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;lt;/xsl:if&amp;gt; &lt;br /&gt; &amp;lt;/xsl:template&amp;gt; &lt;br /&gt; &lt;br /&gt; &amp;lt;xsl:template name="CalendarDay"&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;lt;xsl:param name="count"&amp;gt;1&amp;lt;/xsl:param&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;lt;xsl:param name="day" /&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;lt;xsl:choose&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:when test="($day = 1 and $count != $FirstDayInWeekForMonth) or $day &amp;amp;gt; $NumberOfDaysInMonth"&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;td class="empty"&amp;gt;&amp;lt;xsl:text disable-output-escaping="yes"&amp;gt;&amp;amp;amp;nbsp;&amp;lt;/xsl:text&amp;gt;&amp;lt;/td&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:if test="$count &amp;amp;lt; 7"&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:call-template name="CalendarDay"&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:with-param name="count" select="$count + 1" /&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:with-param name="day" select="$day" /&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/xsl:call-template&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/xsl:if&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/xsl:when&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:otherwise&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;td&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:value-of select="$day" /&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/td&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:if test="$count &amp;amp;lt; 7"&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:call-template name="CalendarDay"&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:with-param name="count" select="$count + 1" /&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;xsl:with-param name="day" select="$day + 1" /&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/xsl:call-template&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/xsl:if&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/xsl:otherwise&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;lt;/xsl:choose&amp;gt; &lt;br /&gt; &amp;lt;/xsl:template&amp;gt;&lt;/code&gt;

&lt;p&gt;For this code to work, you need to be using &lt;a href="http://exslt.org/"&gt;exslt&lt;/a&gt;.&lt;/p&gt;

&lt;code&gt;&amp;lt;xsl:stylesheet version="1.0" &lt;br /&gt; &amp;nbsp;&amp;nbsp;xmlns:xsl="http://www.w3.org/1999/XSL/Transform" &lt;br /&gt; &amp;nbsp;&amp;nbsp;xmlns:exslt="http://exslt.org/common" &lt;br /&gt; &amp;nbsp;&amp;nbsp;xmlns:date="http://exslt.org/dates-and-times"&amp;gt;&lt;/code&gt;

&lt;p&gt;Once you have added the templates you can call the calendar like this: &lt;/p&gt;

&lt;code&gt;&amp;lt;xsl:call-template name="Calendar" /&amp;gt;&lt;/code&gt;

&lt;p&gt;Finally add some CSS to the page so your calendar looks more presentable:&lt;/p&gt;

&lt;code&gt;&amp;lt;style type="text/css" media="screen"&amp;gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;table{ &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border:1px solid #CCC; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border-collapse: collapse; &lt;br /&gt; &amp;nbsp;&amp;nbsp;} &lt;br /&gt; &amp;nbsp;&amp;nbsp;caption{ &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-weight:bold; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-size:120%; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;margin-bottom:8px; &lt;br /&gt; &amp;nbsp;&amp;nbsp;} &lt;br /&gt; &amp;nbsp;&amp;nbsp; &lt;br /&gt; &amp;nbsp;&amp;nbsp;td,th{ &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;text-align:center; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;vertical-align:middle; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;width:36px; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;height:34px; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border:1px solid #CCC; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;padding:0; &lt;br /&gt; &amp;nbsp;&amp;nbsp;} &lt;br /&gt; &amp;nbsp;&amp;nbsp; &lt;br /&gt; &amp;nbsp;&amp;nbsp;th{ &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;height:inherit; &lt;br /&gt; &amp;nbsp;&amp;nbsp;} &lt;br /&gt; &amp;nbsp;&amp;nbsp; &lt;br /&gt; &amp;nbsp;&amp;nbsp;.empty{ &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background-color:#EEE; &lt;br /&gt; &amp;nbsp;&amp;nbsp;} &lt;br /&gt; &amp;lt;/style&amp;gt; &lt;br /&gt; &lt;br /&gt; &lt;/code&gt;

&lt;p&gt;This is only the base of the calendar I built, and you can expand this to make it browse-able. But I will leave that for another post. &lt;/p&gt;
					     &lt;p&gt;&lt;a title="What are you, chicken?!" href="http://neilang.com/entries/generating-a-calendar-using-xslt/#comment"&gt;Post a comment&lt;/a&gt; (I dare you!)&lt;/p&gt;
					   </description>
    </item>
    <item>
      <title>How to setup virtual hosts on Mac OS X 10.5 (Leopard)</title>
      <link>http://neilang.com/entries/how-to-setup-virtual-hosts-on-mac-os-x-105-leopar/</link>
      <pubDate>Sat, 20 Sep 2008 04:29:00 GMT</pubDate>
      <guid>http://neilang.com/entries/how-to-setup-virtual-hosts-on-mac-os-x-105-leopar/</guid>
      <description>&lt;p&gt;Whilst developing a new project it can be convenient to setup a virtual host on your local machine. For example, if I wanted to have a local development/demonstration version of a website I'm developing (e.g. &lt;a href="http://learnhowtojuggle.info"&gt;http://learnhowtojuggle.info&lt;/a&gt;), I could setup the following virtual host: &lt;a href="http://learnhowtojuggle.dev" rel="nofollow"&gt;http://learnhowtojuggle.dev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;N.B. Only follow this tutorial if you are comfortable with editing system configurations and are aware of the risks. If you have &lt;a href="http://macromates.com/"&gt;TextMate&lt;/a&gt; installed, you can click the file path links in these instructions to quickly open them on your local computer (&lt;a href="http://manual.macromates.com/en/using_textmate_from_terminal.html"&gt;More Information&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;1. Modify the virtual hosts configuration&lt;/h3&gt;

&lt;p&gt;Use terminal to find and modify your virtual hosts configuration file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mate &lt;a href="txmt://open/?url=file:///private/etc/apache2/extra/httpd-vhosts.conf" class="textmate"&gt;/private/etc/apache2/extra/httpd-vhosts.conf&lt;/a&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Append to this bottom of this file an entry for your virtual domain:&lt;/p&gt;

&lt;p&gt;
&lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt; &lt;br /&gt; ServerAdmin webmaster@learnhowtojuggle.dev &lt;br /&gt; DocumentRoot "/Users/neil/Sites/learnhowtojuggle" &lt;br /&gt; ServerName learnhowtojuggle.dev &lt;br /&gt; ServerAlias learnhowtojuggle.dev &lt;br /&gt; ErrorLog "/private/var/log/apache2/learnhowtojuggle.dev-error_log" &lt;br /&gt; &amp;lt;/VirtualHost&amp;gt;&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;Make sure the &lt;kbd&gt;DocumentRoot&lt;/kbd&gt; you enter actually exists. For convenience, I've placed mine in my Site folder. You can now save and close this file.&lt;/p&gt;

&lt;h3&gt;2. Check Apache knows about virtual hosts&lt;/h3&gt;

&lt;p&gt;Next we will need to modify the Apache configuration file to make sure it includes the virtual hosts file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mate &lt;a href="txmt://open/?url=file:///private/etc/apache2/httpd.conf&amp;amp;line=460" class="textmate"&gt;/private/etc/apache2/httpd.conf&lt;/a&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Locate the following line and remove the # sign (also known as an "octothorpe" ) from in front of it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Include /private/etc/apache2/extra/httpd-vhosts.conf&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Save and close this file as well.&lt;/p&gt;

&lt;h3&gt;3. Restart Apache&lt;/h3&gt;

&lt;p&gt;For any changes to take effect on the Apache server, you will need to restart it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo httpd -k restart&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;4. Update hosts file&lt;/h3&gt;

&lt;p&gt;Finally, the easiest way to let our browser know to use our local server when it get a request for our virtual host is to modify the hosts file. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;mate &lt;a href="txmt://open/?url=file:///private/etc/hosts" class="textmate"&gt;/private/etc/hosts&lt;/a&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Add the following entry:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;127.0.0.1	learnhowtojuggle.dev&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After you save and close this file, navigate to &lt;a href="http://learnhowtojuggle.dev" rel="nofollow"&gt;http://learnhowtojuggle.dev&lt;/a&gt; in your browser to see the newly created virtual host on your local machine. &lt;/p&gt;


&lt;h3&gt;Additional Configuration&lt;/h3&gt;

&lt;p&gt;Since I am serving my new virtual host out of my Sites folder, and I want to use my .htacess file for URL rewriting, I had to update the Apache configuration again to allow permission for this.&lt;/p&gt;

&lt;p&gt;The configuration for my Site folder was located at &lt;kbd&gt;/private/etc/apache2/users/neil.conf&lt;/kbd&gt; (yours will be different based on your system profile name). I then set my permissions to be pretty loose since it is only my local machine.&lt;/p&gt;

&lt;p&gt;Example configuration: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;Directory "/Users/neil/Sites/"&amp;gt; &lt;br /&gt; Options Indexes FollowSymLinks MultiViews &lt;br /&gt; AllowOverride All &lt;br /&gt; Order allow,deny &lt;br /&gt; Allow from all &lt;br /&gt; &amp;lt;/Directory&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After you update your directory permissions, you will need to restart apache again for these to changes to take effect.&lt;/p&gt;
					     &lt;p&gt;&lt;a title="What are you, chicken?!" href="http://neilang.com/entries/how-to-setup-virtual-hosts-on-mac-os-x-105-leopar/#comment"&gt;Post a comment&lt;/a&gt; (I dare you!)&lt;/p&gt;
					   </description>
    </item>
    <item>
      <title>Learn How To Juggle</title>
      <link>http://neilang.com/entries/learn-how-to-juggle/</link>
      <pubDate>Sat, 15 Mar 2008 23:11:00 GMT</pubDate>
      <guid>http://neilang.com/entries/learn-how-to-juggle/</guid>
      <description>&lt;p&gt;Last Thursday I was talking with &lt;a href="http://www.deanjrobinson.com/"&gt;Dean&lt;/a&gt; about ideas for new sites. Most of them were silly ideas and would never work, but there was one I felt I could accomplish successfully.&lt;/p&gt;
&lt;p&gt;So over the last couple of days I've been working on a new site that teaches visitors how to juggle. I'm happy to announce it is now live. There are some pages that I'm still writing, but the basics for learning how to juggle are there.&lt;/p&gt;

&lt;p&gt;Please check out my new site: &lt;a href="http://learnhowtojuggle.info/?utm_source=neilang&amp;amp;utm_medium=banner&amp;amp;utm_campaign=Self%2BPromotion"&gt;Learn How To Juggle&lt;/a&gt;, and leave a comment on this post of your thoughts.&lt;/p&gt;
					     &lt;p&gt;&lt;a title="What are you, chicken?!" href="http://neilang.com/entries/learn-how-to-juggle/#comment"&gt;Post a comment&lt;/a&gt; (I dare you!)&lt;/p&gt;
					   </description>
    </item>
    <item>
      <title>A better technique to stop spam?</title>
      <link>http://neilang.com/entries/a-better-technique-to-stop-spam/</link>
      <pubDate>Fri, 01 Feb 2008 21:52:34 GMT</pubDate>
      <guid>http://neilang.com/entries/a-better-technique-to-stop-spam/</guid>
      <description>&lt;p&gt;A couple of weeks ago I wrote an entry on how to &lt;a href="/entries/outsmarting-comment-spam/"&gt;outsmart comment spam&lt;/a&gt; with javascript. 
Although this is a good technique, it has a drawback - code maintenance. 
If there is a change to the mark up of the form, it is more time consuming to alter the javascript than the HTML. &lt;/p&gt;

&lt;p&gt;To overcome this problem and still out smart spam, I've been testing a new method which uses javascript to change the form action. In it's simplest form the javascript can look like this:&lt;/p&gt;

&lt;code&gt;&amp;lt;script type="text/javascript" charset="utf-8"&amp;gt; &lt;br /&gt;&amp;nbsp;function redirectForm(form){ &lt;br /&gt; &amp;nbsp;&amp;nbsp;form.action = ''; &lt;br /&gt; &amp;nbsp;&amp;nbsp;form.submit(); &lt;br /&gt;&amp;nbsp;} &lt;br /&gt; &amp;lt;/script&amp;gt; &lt;br /&gt; &lt;br /&gt; &amp;lt;form action="/no-javascript" onsubmit="redirectForm(this);" method="post" accept-charset="utf-8"&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;lt;p&amp;gt;&amp;lt;input type="text" name="test" /&amp;gt;&amp;lt;/p&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;lt;p&amp;gt;&amp;lt;input type="submit" value="Submit" /&amp;gt;&amp;lt;/p&amp;gt; &lt;br /&gt; &amp;lt;/form&amp;gt;&lt;/code&gt;

&lt;p&gt;&lt;small&gt;N.B. The default action for &lt;a href="http://21degrees.com.au/products/symphony/"&gt;Symphony&lt;/a&gt; forms is to submit to the same page, which is why the action is set to empty string.&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;If you use multiple forms that have different actions, you could expand the javascript to handle those as well:&lt;/p&gt;

&lt;code&gt;&amp;lt;script type="text/javascript" charset="utf-8"&amp;gt; &lt;br /&gt;&amp;nbsp;function redirectForm(form, action){ &lt;br /&gt; &amp;nbsp;&amp;nbsp;form.action = action; &lt;br /&gt; &amp;nbsp;&amp;nbsp;form.submit(); &lt;br /&gt; &amp;nbsp;} &lt;br /&gt; &amp;lt;/script&amp;gt; &lt;br /&gt; &lt;br /&gt; &amp;lt;form action="/no-javascript/" onsubmit="redirectForm(this, '');" method="post" accept-charset="utf-8"&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;lt;p&amp;gt;&amp;lt;input type="text" name="test" /&amp;gt;&amp;lt;/p&amp;gt; &lt;br /&gt;&amp;nbsp;&amp;lt;p&amp;gt;&amp;lt;input type="submit" value="Submit" /&amp;gt;&amp;lt;/p&amp;gt; &lt;br /&gt; &amp;lt;/form&amp;gt;&lt;/code&gt;

&lt;p&gt;This is just a start, there's more you can do to make this JS smarter (but I'll let you figure that out). So far this technique has worked great for me. Remember to setup a real page for the &lt;a href="/no-javascript/"&gt;fake submission url&lt;/a&gt;, so that authentic users of your site without JS enabled are alerted that there submission was unsuccessful.&lt;/p&gt;

&lt;p&gt;To get an idea on how much spam you've stopped, check your server logs to see for the number of requests to your &lt;a href="/no-javascript/"&gt;fake submission url&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Please leave a comment with your thoughts on this technique vs the &lt;a href="/entries/outsmarting-comment-spam/"&gt;previous one&lt;/a&gt;, or if you know of another solution to stop spam.&lt;/p&gt;
					     &lt;p&gt;&lt;a title="What are you, chicken?!" href="http://neilang.com/entries/a-better-technique-to-stop-spam/#comment"&gt;Post a comment&lt;/a&gt; (I dare you!)&lt;/p&gt;
					   </description>
    </item>
    <item>
      <title>Outsmarting comment spam</title>
      <link>http://neilang.com/entries/outsmarting-comment-spam/</link>
      <pubDate>Sun, 13 Jan 2008 08:27:00 GMT</pubDate>
      <guid>http://neilang.com/entries/outsmarting-comment-spam/</guid>
      <description>&lt;p&gt;It is often hard to find the right balance between stopping comment spam, and encouraging users to leave comments. For example, although captcha's are effective, I don't like asking my users to enter a (sometimes cryptic) code to leave a comment.&lt;/p&gt;
&lt;p&gt;I put a lot of effort into making sure comment spam doesn't make it on my web site. However, late 2007 I started receiving comment spam from a spam-bot who wasn't selling anything, or linking back to their site, it was just nonsense that didn't get caught by my anti-spam methods.&lt;/p&gt;

&lt;p&gt;To counter-act this annoying comment spam, I wrote a very simple piece of JavaScript that inserted the comment form dynamically. This meant that unless the spam-bot could interpret JavaScript, it wouldn't detect the embedded form on the page and attempt to spam it.&lt;/p&gt;

&lt;p&gt;Heres what the JS looks like:&lt;/p&gt;

&lt;code&gt;function insertCommentForm(){ &lt;br /&gt; &amp;nbsp;&amp;nbsp;var parent = document.getElementById('myCommentForm'); &lt;br /&gt; &lt;br /&gt; &amp;nbsp;&amp;nbsp;var form = document.createElement('form'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;form.setAttribute('action', ''); &lt;br /&gt; &amp;nbsp;&amp;nbsp;form.setAttribute('method', 'post'); &lt;br /&gt; &amp;nbsp;&amp;nbsp; &lt;br /&gt; &amp;nbsp;&amp;nbsp;var fieldset = document.createElement('fieldset'); &lt;br /&gt; &amp;nbsp;&amp;nbsp; &lt;br /&gt; &amp;nbsp;&amp;nbsp;// Input: Name &lt;br /&gt; &amp;nbsp;&amp;nbsp;var nameLabel = document.createElement('label'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;var nameText = document.createTextNode('Name '); &lt;br /&gt; &amp;nbsp;&amp;nbsp;var nameInput = document.createElement('input'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;nameInput.setAttribute('name', 'name'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;nameInput.setAttribute('value', document.getElementById('myComment-name').value); &lt;br /&gt; &amp;nbsp;&amp;nbsp;nameLabel.appendChild(nameText); &lt;br /&gt; &amp;nbsp;&amp;nbsp;nameLabel.appendChild(nameInput); &lt;br /&gt; &amp;nbsp;&amp;nbsp; &lt;br /&gt; &amp;nbsp;&amp;nbsp;//Input: Email &lt;br /&gt; &amp;nbsp;&amp;nbsp;var emailLabel = document.createElement('label'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;var emailText = document.createTextNode('Email '); &lt;br /&gt; &amp;nbsp;&amp;nbsp;var emailNote = document.createElement('small'); &lt;br /&gt;&amp;nbsp;&amp;nbsp;emailNote.innerHTML = 'Required but never displayed'; &lt;br /&gt; &amp;nbsp;&amp;nbsp;var emailInput = document.createElement('input'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;emailInput.setAttribute('name', 'email'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;emailInput.setAttribute('value', document.getElementById('myComment-email').value); &lt;br /&gt; &amp;nbsp;&amp;nbsp;emailLabel.appendChild(emailText); &lt;br /&gt; &amp;nbsp;&amp;nbsp;emailLabel.appendChild(emailNote); &lt;br /&gt; &amp;nbsp;&amp;nbsp;emailLabel.appendChild(emailInput); &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt; &amp;nbsp;&amp;nbsp;//Input: Website&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt; &amp;nbsp;&amp;nbsp;var websiteLabel = document.createElement('label'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;var websiteText = document.createTextNode('Website '); &lt;br /&gt; &amp;nbsp;&amp;nbsp;var websiteNote = document.createElement('small'); &lt;br /&gt;&amp;nbsp;&amp;nbsp;websiteNote.innerHTML = 'http://'; &lt;br /&gt; &amp;nbsp;&amp;nbsp;var websiteInput = document.createElement('input'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;websiteInput.setAttribute('name', 'website'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;websiteInput.setAttribute('value', document.getElementById('myComment-url').value); &lt;br /&gt; &amp;nbsp;&amp;nbsp;websiteLabel.appendChild(websiteText); &lt;br /&gt; &amp;nbsp;&amp;nbsp;websiteLabel.appendChild(websiteNote); &lt;br /&gt; &amp;nbsp;&amp;nbsp;websiteLabel.appendChild(websiteInput); &lt;br /&gt; &amp;nbsp;&amp;nbsp; &lt;br /&gt; &amp;nbsp;&amp;nbsp;//Input: Comment &lt;br /&gt; &amp;nbsp;&amp;nbsp;var commentLabel = document.createElement('label'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;var commentText = document.createTextNode('Comment '); &lt;br /&gt; &amp;nbsp;&amp;nbsp;var commentTextarea = document.createElement('textarea'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;commentTextarea.setAttribute('name', 'comment'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;commentTextarea.setAttribute('rows', '12'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;commentTextarea.setAttribute('cols', '24'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;commentLabel.appendChild(commentText); &lt;br /&gt; &amp;nbsp;&amp;nbsp;commentLabel.appendChild(commentTextarea); &lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt; &amp;nbsp;&amp;nbsp;//Hidden: Section&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt; &amp;nbsp;&amp;nbsp;var sectionHiddenInput = document.createElement('input'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;sectionHiddenInput.setAttribute('type', 'hidden'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;sectionHiddenInput.setAttribute('name', 'section'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;sectionHiddenInput.setAttribute('value', 'entries'); &lt;br /&gt; &amp;nbsp;&amp;nbsp; &lt;br /&gt; &amp;nbsp;&amp;nbsp;//Hidden: Remember &lt;br /&gt; &amp;nbsp;&amp;nbsp;var rememberHiddenInput = document.createElement('input'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;rememberHiddenInput.setAttribute('type', 'hidden'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;rememberHiddenInput.setAttribute('name', 'remember'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;rememberHiddenInput.setAttribute('value', 'on'); &lt;br /&gt; &amp;nbsp;&amp;nbsp; &lt;br /&gt; &amp;nbsp;&amp;nbsp;//Hidden: Entry Handle &lt;br /&gt; &amp;nbsp;&amp;nbsp;var rememberHiddenInput = document.createElement('input'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;rememberHiddenInput.setAttribute('type', 'hidden'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;rememberHiddenInput.setAttribute('name', 'entry-handle'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;rememberHiddenInput.setAttribute('value', document.getElementById('myComment-entry').value); &lt;br /&gt; &amp;nbsp;&amp;nbsp; &lt;br /&gt; &amp;nbsp;&amp;nbsp;//Hidden: Submit &lt;br /&gt; &amp;nbsp;&amp;nbsp;var submitInput = document.createElement('input'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;submitInput.setAttribute('type', 'submit'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;submitInput.setAttribute('id', 'submit'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;submitInput.setAttribute('value', 'Post Comment'); &lt;br /&gt; &amp;nbsp;&amp;nbsp;submitInput.setAttribute('name', 'action[comment]'); &lt;br /&gt; &amp;nbsp;&amp;nbsp; &lt;br /&gt; &amp;nbsp;&amp;nbsp;fieldset.appendChild(nameLabel); &lt;br /&gt; &amp;nbsp;&amp;nbsp;fieldset.appendChild(emailLabel); &lt;br /&gt; &amp;nbsp;&amp;nbsp;fieldset.appendChild(websiteLabel); &lt;br /&gt; &amp;nbsp;&amp;nbsp;fieldset.appendChild(commentLabel); &lt;br /&gt; &amp;nbsp;&amp;nbsp;fieldset.appendChild(sectionHiddenInput); &lt;br /&gt; &amp;nbsp;&amp;nbsp;fieldset.appendChild(rememberHiddenInput); &lt;br /&gt; &amp;nbsp;&amp;nbsp;fieldset.appendChild(submitInput); &lt;br /&gt; &amp;nbsp;&amp;nbsp; &lt;br /&gt; &amp;nbsp;&amp;nbsp;form.appendChild(fieldset); &lt;br /&gt; &amp;nbsp;&amp;nbsp; &lt;br /&gt; &amp;nbsp;&amp;nbsp;document.getElementById('myCommentWarning').style.display='none'; &lt;br /&gt; &amp;nbsp;&amp;nbsp; &lt;br /&gt; &amp;nbsp;&amp;nbsp;parent.appendChild(form); &lt;br /&gt; }&lt;/code&gt;

&lt;p&gt;Since using this JS I haven't received any comment spam. And until spam-bots evolve to read JavaScript, this is a simple and effective technique to reduce time spent dealing with spam.&lt;/p&gt;

&lt;p&gt;Also, if you use &lt;a href="http://21degrees.com.au/products/symphony/"&gt;Symphony&lt;/a&gt;, this JS will work with your comment forms too. &lt;a href="/about"&gt;Contact me&lt;/a&gt; if you would like the updates to the XSL you will need to make this work.&lt;/p&gt;
					     &lt;p&gt;&lt;a title="What are you, chicken?!" href="http://neilang.com/entries/outsmarting-comment-spam/#comment"&gt;Post a comment&lt;/a&gt; (I dare you!)&lt;/p&gt;
					   </description>
    </item>
    <item>
      <title>Exclude Your Images from Image Search Engines</title>
      <link>http://neilang.com/entries/exclude-your-images-from-image-search-engines/</link>
      <pubDate>Mon, 08 Oct 2007 10:35:28 GMT</pubDate>
      <guid>http://neilang.com/entries/exclude-your-images-from-image-search-engines/</guid>
      <description>&lt;p&gt;Google, Yahoo!, MSN and many other search engines, provide &lt;a href="http://images.google.com.au"&gt;image search services&lt;/a&gt;. If you're concerned about intellectual property theft or bandwidth leeches, you can ask these search engines not to index your images. This is a common practise and will not effect your ranking within normal text searches.&lt;/p&gt;

&lt;p&gt;Copy the following text into a text file called "robots.txt" and place it in the root directory of your website.&lt;/p&gt;

&lt;code&gt;User-agent: Googlebot-Image &lt;br /&gt; Disallow: / &lt;br /&gt; &lt;br /&gt; User-agent: MSNBot-Media &lt;br /&gt; Disallow: / &lt;br /&gt; &lt;br /&gt; User-agent: Yahoo-MMCrawler &lt;br /&gt; Disallow: / &lt;br /&gt; &lt;br /&gt; User-agent: vscooter &lt;br /&gt; Disallow: / &lt;br /&gt; &lt;br /&gt; User-agent: psbot &lt;br /&gt; Disallow: /&lt;/code&gt;

&lt;p&gt;More information: &lt;a href="http://www.robotstxt.org/wc/robots.html"&gt;The Web Robots Pages&lt;/a&gt;, &lt;a href="http://www.google.com/support/webmasters/bin/answer.py?answer=35308"&gt;Google Image Help&lt;/a&gt;.&lt;/p&gt;
					     &lt;p&gt;&lt;a title="What are you, chicken?!" href="http://neilang.com/entries/exclude-your-images-from-image-search-engines/#comment"&gt;Post a comment&lt;/a&gt; (I dare you!)&lt;/p&gt;
					   </description>
    </item>
    <item>
      <title>How to install the W3C Link Checker on Mac OS X</title>
      <link>http://neilang.com/entries/how-to-install-the-w3c-link-checker-on-mac-os-x/</link>
      <pubDate>Fri, 14 Sep 2007 11:59:19 GMT</pubDate>
      <guid>http://neilang.com/entries/how-to-install-the-w3c-link-checker-on-mac-os-x/</guid>
      <description>&lt;p&gt;The &lt;a href="http://validator.w3.org/checklink"&gt;W3C Link checker&lt;/a&gt; is a great online service for validating links. It is also freely available for download and use locally.&lt;/p&gt;

&lt;h3&gt;Advantages of a local link checking service&lt;/h3&gt;

&lt;ul&gt;
	&lt;li&gt;Intranet web site link validation&lt;/li&gt;
	&lt;li&gt;Faster validation for local sites&lt;/li&gt;
	&lt;li&gt;Increased recursive document limit&lt;/li&gt;
	&lt;li&gt;Command line link checker&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;How to install&lt;/h3&gt;

&lt;p&gt;The link checker requires these perl modules to run:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;CGI&lt;/li&gt;
	&lt;li&gt;Config::General&lt;/li&gt;
	&lt;li&gt;HTML::Parser&lt;/li&gt;
	&lt;li&gt;LWP&lt;/li&gt;
	&lt;li&gt;Term::ReadKey&lt;/li&gt;
	&lt;li&gt;Time::HiRes&lt;/li&gt;
	&lt;li&gt;URI&lt;/li&gt;
	&lt;li&gt;Test::Simple&lt;/li&gt;
	&lt;li&gt;File::Spec&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mac OS X (10.4) comes with most of the required perl modules, but these were a few missing ones I had to install: Config::General, Net::IP and Term::ReadKey. You will know which modules you are missing when you try to install the link checker.&lt;/p&gt;

&lt;p&gt;There are two options for installing the missing modules: the easy way through CPAN, or through manually downloading and building each module.&lt;/p&gt;

&lt;h4&gt;Installing missing modules through CPAN&lt;/h4&gt;

&lt;p&gt;Open a terminal window and enter:&lt;/p&gt;

&lt;p&gt;
&lt;code&gt;sudo perl -MCPAN -e 'install Config::General' &lt;br /&gt; sudo perl -MCPAN -e 'install Net::IP' &lt;br /&gt; sudo perl -MCPAN -e 'install Term::ReadKey'&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Simple, isn't it.&lt;/p&gt;

&lt;h4&gt;Installing missing modules manually&lt;/h4&gt;

&lt;p&gt;If you are on a private network or behind a proxy, you can manually install missing modules. Find, download and unpack the missing modules from &lt;a href="http://www.cpan.org/"&gt;CPAN&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Example installing &lt;a href="http://search.cpan.org/~tlinden/Config-General-2.33/General.pm"&gt;Config::General&lt;/a&gt;. Open Termianl and type:&lt;/p&gt;
&lt;p&gt;
&lt;code&gt;cd Desktop/Config-General-2.33/ &lt;br /&gt; perl Makefile.PL &lt;br /&gt; make &lt;br /&gt; make test &lt;br /&gt; sudo make install&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;Install the Link Checker&lt;/h3&gt;

&lt;p&gt;Download the latest copy of the &lt;a href="http://search.cpan.org/dist/W3C-LinkChecker/"&gt;W3C LinkChecker package&lt;/a&gt; from CPAN, and unpack it on your desktop.&lt;/p&gt;

&lt;p&gt;Change directory to the module directory and run the Makefile.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
cd Desktop/W3C-LinkChecker-4.3 &lt;br /&gt;
perl Makefile.PL
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If there are any missing modules you will prompted with a warning like this: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;
Warning: prerequisite Config::General 2.06 not found. &lt;br /&gt;
Warning: prerequisite Net::IP 0 not found. &lt;br /&gt;
Warning: prerequisite Term::ReadKey 2 not found. &lt;br /&gt;
Writing Makefile for W3C::LinkChecker
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you are missing any modules, go back and install them as demonstrated earlier. Once you have all the prerequisite modules installed you can continue:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
perl Makefile.PL &lt;br /&gt;
make &lt;br /&gt;
make test &lt;br /&gt;
sudo make install
&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;The link checker should now be installed, and ready to be used from the command line. Typing the following command in terminal should present the version:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;checklink --version&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For full instructions on how to use the command-line link checker, type:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;checklink --help&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;Installing the web interface&lt;/h3&gt;

&lt;p&gt;Mac OS X comes with an apache server built in. If you haven't yet turned on web sharing, do it now by selecting 'System Preferences' &amp;gt; 'Sharing' &amp;gt; and tick 'Personal Web Sharing'.&lt;/p&gt;

&lt;p&gt;You will need to copy the checklink file to the default cgi-bin dir and enable execute permission. In a new terminal window type:&lt;/p&gt;

&lt;p&gt;
&lt;code&gt;
cd /Library/WebServer/CGI-Executables &lt;br /&gt;
cp ~/Desktop/W3C-LinkChecker-4.3/bin/checklink . &lt;br /&gt;
chmod 755 checklink
&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;Done! In a browser navigate to: &lt;a href="http://localhost/cgi-bin/checklink"&gt;http://localhost/cgi-bin/checklink&lt;/a&gt;. Hopefully you will see a locally running copy of the link checker!&lt;/p&gt;

&lt;h3&gt;Troubleshooting&lt;/h3&gt;

&lt;ul&gt;
	&lt;li&gt;If you are experiencing server errors, check the server logs: /var/log/httpd/error_log &lt;/li&gt;
	&lt;li&gt;If you're server isn't even working, check the config: /etc/httpd/httpd.conf&lt;/li&gt;
&lt;/ul&gt;
					     &lt;p&gt;&lt;a title="What are you, chicken?!" href="http://neilang.com/entries/how-to-install-the-w3c-link-checker-on-mac-os-x/#comment"&gt;Post a comment&lt;/a&gt; (I dare you!)&lt;/p&gt;
					   </description>
    </item>
    <item>
      <title>8 Tips to combat Global Warming (for NERDS)</title>
      <link>http://neilang.com/entries/8-tips-to-combat-global-warming-for-nerds/</link>
      <pubDate>Sun, 18 Mar 2007 10:12:00 GMT</pubDate>
      <guid>http://neilang.com/entries/8-tips-to-combat-global-warming-for-nerds/</guid>
      <description>&lt;p&gt;As a computer nerd, I've been trying to think up ways I can help the environment and reduce the impact of global warming. If you have anymore tips that I haven't listed here, please leave a comment.&lt;/p&gt;
		
	&lt;p&gt;N.B. Although the following tips are some easy ways to reduce your carbon emissions, they are only a starting point. If you do some research and evaluate your lifestyle, you will notice other areas where you can reduce emissions.&lt;/p&gt;

	&lt;h3&gt;1. Use more black&lt;/h3&gt;

	&lt;p&gt;Last month, &lt;a href="http://www.treehugger.com"&gt;treehugger&lt;/a&gt; pointed out that if google used black, they would save &lt;a href="http://www.treehugger.com/files/2007/02/black_google_wo.php" &gt;750 Megawatt-Hours a Year&lt;/a&gt;. So if you can, design your next website or UI screen to use black as a dominant colour. Also set your wallpapers to black (heres one of my &lt;a href="http://interfacelift.com/wallpaper/details.php?id=227" &gt;favorites&lt;/a&gt;), change the background colour of your IDE, turn down the brightness of your monitor, and start utilising websites with a darker colour pallet (e.g. use &lt;a href="http://www.ninja.com/"&gt;ninja&lt;/a&gt; for searching). &lt;/p&gt;
		
	&lt;h3&gt;2. Switch off development servers&lt;/h3&gt;

	&lt;p&gt;If you're like me, you've setup your development computer to be an efficient resource. Which often results in servers being left on so you can access services 24/7. Although this produces a very productive work environment, it wastes a lot of electricity and is often overkill.&lt;/p&gt;
	
	&lt;p&gt;Try turning off your servers at night and on weekends (you could even set this up as a schedule task). If you think you can't live without it on, look into setting up &lt;a href="http://en.wikipedia.org/wiki/Wake_on_lan"&gt;wake on LAN&lt;/a&gt;.&lt;/p&gt;
	
	&lt;h3&gt;3. Use a laptop&lt;/h3&gt;
	
	&lt;p&gt;Laptop parts are designed to make efficient use of the available battery power and therefor use less electricity. So you &lt;strong&gt;can&lt;/strong&gt; use global warming to justify buying the more expensive laptop over the desktop PC.&lt;/p&gt;
	
	&lt;h3&gt;4. Do more on the Internet&lt;/h3&gt;

	&lt;p&gt;Why send a letter when you can email? Why get a receipt printed at a ATM when you can check your bank account status online? Doing more on the Internet will reduce the number of trees that get cut down for paper (a tree can absorb a ton of carbon over its lifetime). If you still own a printer, load it with recycled paper.&lt;/p&gt;
	
	&lt;h3&gt;5. Put a plant next to your desk.&lt;/h3&gt;
	
	&lt;p&gt;A house plant won't absorb as much carbon as a tree, but it will make your desk look fresher and help soak up some of those biohazardous gases floating around your work station.&lt;/p&gt;
	
	&lt;h3&gt;6. Switch off your router while you sleep&lt;/h3&gt;
	
	&lt;p&gt;If you're not online 24 hours a day, why keep your router on while you sleep? I've made it a habit to unplug my wireless router and external hard drive before going to bed and while I'm not at home.&lt;/p&gt;
	
	&lt;h3&gt;7. Turn the lights off&lt;/h3&gt;
	
	&lt;p&gt;Code in the dark. If this doesn't appeal to you, simply replace your lights with energy efficient fluorescent light bulbs (they use less power and last longer).&lt;/p&gt;
	
	&lt;h3&gt;8. Blog about Global Warming&lt;/h3&gt;
	
	&lt;p&gt;Nerds of the Internet unite and spread the word. Global warming is real and is happening now.&lt;/p&gt;
	

	
	&lt;h4&gt;More Information&lt;/h4&gt;
	&lt;ul&gt;
		&lt;li&gt;&lt;a href="http://www.google.com/search?q=global+warming"&gt;Google Search: Global Warming&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Global_warming"&gt;Wikipedia: Global warming&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://www.climatecrisis.net/" &gt;An Inconvenient Truth&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://www.worldviewofglobalwarming.org/"&gt;World View OF Global Warming&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;
					     &lt;p&gt;&lt;a title="What are you, chicken?!" href="http://neilang.com/entries/8-tips-to-combat-global-warming-for-nerds/#comment"&gt;Post a comment&lt;/a&gt; (I dare you!)&lt;/p&gt;
					   </description>
    </item>
    <item>
      <title>PHP: Explore your server through a PHP file browser</title>
      <link>http://neilang.com/entries/php-explore-your-server-through-a-php-file-browse/</link>
      <pubDate>Thu, 11 Jan 2007 10:09:00 GMT</pubDate>
      <guid>http://neilang.com/entries/php-explore-your-server-through-a-php-file-browse/</guid>
      <description>&lt;p&gt;In the past I've had to delete files from my server where the file permissions were set to apache and I could not override them because the host did not alllow terminal or shell access. So I quickly put together a PHP script that allowed me to navigate through the file system and unlink (or delete) files as the apache user. I haven't had to use the script for a while but I still think its pretty nifty to use when you want to explore a servers file system. &lt;/p&gt;

&lt;p&gt;In the code below I've stripped out the unlink code (as it can be dangerous to have a page like that on your server) and just made it into a file explorer. Copy the code into a page and give it a go. If you're like me and have set your localhost as your homepage you can use it to quickly access files you have been working on. If anyone is interested in the version that allows you to unlink files, just send me an email and I will post it on the site. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;


&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;lt;title&amp;gt;PHP File Browser&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;lt;style type="text/css"&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.error{ color:red; font-weight:bold; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;lt;/style&amp;gt;&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&amp;nbsp;&amp;nbsp;// Explore the files via a web interface. &amp;nbsp;&amp;nbsp;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;$script = basename(__FILE__); // the name of this script&lt;br /&gt;
&amp;nbsp;&amp;nbsp;$path = !empty($_REQUEST['path']) ? $_REQUEST['path'] : dirname(__FILE__); // the path the script should access&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;echo "&amp;lt;h1&amp;gt;Directory Browser&amp;lt;/h1&amp;gt;";&lt;br /&gt;
&amp;nbsp;&amp;nbsp;echo "&amp;lt;p&amp;gt;Browsing Location: {$path}&amp;lt;/p&amp;gt;";&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;$directories = array();&lt;br /&gt;
&amp;nbsp;&amp;nbsp;$files = array();&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;// Check we are focused on a dir&lt;br /&gt;
&amp;nbsp;&amp;nbsp;if (is_dir($path)) {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;chdir($path); // Focus on the dir&lt;br /&gt;
&amp;nbsp;&amp;nbsp;    if ($handle = opendir('.')) {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while (($item = readdir($handle)) !== false) {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Loop through current directory and divide files and directorys&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(is_dir($item)){&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;array_push($directories, realpath($item)); &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;array_push($files, ($item));&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;        }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;        closedir($handle);  // Close the directory handle&lt;br /&gt;
&amp;nbsp;&amp;nbsp;    }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo "&amp;lt;p class=\"error\"&amp;gt;Directory handle could not be obtained.&amp;lt;/p&amp;gt;";&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;else&lt;br /&gt;
&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo "&amp;lt;p class=\"error\"&amp;gt;Path is not a directory&amp;lt;/p&amp;gt;";&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;// There are now two arrays that contians the contents of the path. &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;// List the directories as browsable navigation&lt;br /&gt;
&amp;nbsp;&amp;nbsp;echo "&amp;lt;h2&amp;gt;Navigation&amp;lt;/h2&amp;gt;";&lt;br /&gt;
&amp;nbsp;&amp;nbsp;echo "&amp;lt;ul&amp;gt;";&lt;br /&gt;
&amp;nbsp;&amp;nbsp;foreach( $directories as $directory ){&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo ($directory != $path) ? "&amp;lt;li&amp;gt;&amp;lt;a href=\"{$script}?path={$directory}\"&amp;gt;{$directory}&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;" : "";&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;echo "&amp;lt;/ul&amp;gt;";&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;echo "&amp;lt;h2&amp;gt;Files&amp;lt;/h2&amp;gt;";&lt;br /&gt;
&amp;nbsp;&amp;nbsp;echo "&amp;lt;ul&amp;gt;";&lt;br /&gt;
&amp;nbsp;&amp;nbsp;foreach( $files as $file ){&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Comment the next line out if you wish see hidden files while browsing&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if(preg_match("/^\./", $file) || $file == $script): continue; endif; // This line will hide all invisible files. &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo '&amp;lt;li&amp;gt;&amp;lt;a href="' . basename($file) . '" target="_blank"&amp;gt;' . $file . '&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;';&lt;br /&gt;
&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;echo "&amp;lt;/ul&amp;gt;";&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;


&lt;/code&gt;&lt;/p&gt;
					     &lt;p&gt;&lt;a title="What are you, chicken?!" href="http://neilang.com/entries/php-explore-your-server-through-a-php-file-browse/#comment"&gt;Post a comment&lt;/a&gt; (I dare you!)&lt;/p&gt;
					   </description>
    </item>
    <item>
      <title>How to install Tomcat on Mac OS X</title>
      <link>http://neilang.com/entries/how-to-install-tomcat-on-mac-os-x/</link>
      <pubDate>Thu, 11 Jan 2007 10:09:00 GMT</pubDate>
      <guid>http://neilang.com/entries/how-to-install-tomcat-on-mac-os-x/</guid>
      <description>&lt;p&gt;A while back I wrote a post on the &lt;a href="http://www.ubuntuforums.org/"&gt;ubuntu forums&lt;/a&gt; on &lt;a href="http://www.ubuntuforums.org/showthread.php?t=44006" &gt;how to install Tomcat on ubuntu&lt;/a&gt;. It was very popular (if I do say myself) so I thought I would post the instructions on how to setup tomcat on Apple's OS X. These instructions work for 10.4 (Tiger) and 10.5 (Leopard).&lt;/p&gt;

&lt;h3&gt;Installing Tomcat&lt;/h3&gt;

&lt;ol&gt;


&lt;li&gt;Download the latest core binary distributions of tomcat from &lt;a href="http://tomcat.apache.org/"&gt;http://tomcat.apache.org/&lt;/a&gt; (do not download the windows service installer).&lt;/li&gt;



&lt;li&gt;Unzip the download and rename the folder from "apache-tomcat-x-x-xx" to something simple like "Tomcat". &lt;/li&gt;



&lt;li&gt;Move the folder to the root &lt;em&gt;/Library&lt;/em&gt; directory (or somewhere else convenient). Tomcat is installed. That's it!&lt;/li&gt;



&lt;li&gt;To start tomcat run startup.sh found in &lt;em&gt;/Library/Tomcat/bin&lt;/em&gt;. To stop tomcat run &lt;em&gt;shutdown.sh&lt;/em&gt; found in the same bin directory. After starting tomcat navigate to &lt;a href="http://localhost:8080"&gt;http://localhost:8080&lt;/a&gt; to see if the server is working.&lt;/li&gt;

&lt;/ol&gt;


&lt;h3&gt;Custom Tomcat Start/Stop Script&lt;/h3&gt;

&lt;p&gt;To make starting and stopping tomcat easier you can create a custom shell script to turn tomcat on and off through terminal. &lt;/p&gt;

&lt;p&gt;Open up your favorite text editor (mine is &lt;a href="http://macromates.com/" &gt;TextMate&lt;/a&gt;) and add the following code:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
case $1 in&lt;br /&gt;
&amp;nbsp;&amp;nbsp;start)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sh /Library/Tomcat/bin/startup.sh&lt;br /&gt;
&amp;nbsp;&amp;nbsp;;;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;stop)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sh /Library/Tomcat/bin/shutdown.sh&lt;br /&gt;
&amp;nbsp;&amp;nbsp;;;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;restart)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sh /Library/Tomcat/bin/shutdown.sh&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sh /Library/Tomcat/bin/startup.sh&lt;br /&gt;
&amp;nbsp;&amp;nbsp;;;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;*)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo "Usage: start|stop|restart"&lt;br /&gt;
&amp;nbsp;&amp;nbsp;;;&lt;br /&gt;
esac&lt;br /&gt;
&lt;br /&gt;
exit 0
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Save the file with the title "tomcat" (in lowercase and no extension). Place the file in a bin directory which is included in your terminal's path e.g. &lt;em&gt;/usr/bin&lt;/em&gt;. Now when you want to use tomcat, simply write "tomcat start" and "tomcat stop" in terminal.&lt;/p&gt;

&lt;p&gt;Leave a comment if you have any suggestions, troubleshooting or ideas.&lt;/p&gt;
					     &lt;p&gt;&lt;a title="What are you, chicken?!" href="http://neilang.com/entries/how-to-install-tomcat-on-mac-os-x/#comment"&gt;Post a comment&lt;/a&gt; (I dare you!)&lt;/p&gt;
					   </description>
    </item>
  </channel>
</rss>
