<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Nine More Minutes</title>
	<atom:link href="http://www.ninemoreminutes.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ninemoreminutes.com</link>
	<description>Software Design and Consulting</description>
	<lastBuildDate>Sat, 08 Oct 2011 19:57:06 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Triangle MLS Tech Fair</title>
		<link>http://www.ninemoreminutes.com/2010/03/triangle-mls-tech-fair/</link>
		<comments>http://www.ninemoreminutes.com/2010/03/triangle-mls-tech-fair/#comments</comments>
		<pubDate>Tue, 09 Mar 2010 20:29:55 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://www.ninemoreminutes.com/?p=235</guid>
		<description><![CDATA[Nine More Minutes will be attending the Triangle MLS Tech Fair as an exhibitor this Thursday, March 11, in Cary, NC.  The tech fair runs from 9:00am to 4:00pm at 111 Realtors Way, Cary, NC. We&#8217;d love it if you could stop by our booth (either #23 or #22 depending on the diagram you&#8217;re looking [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.tmlstechfair.com/"><img class="size-medium wp-image-237 alignright" title="Triangle MLS Tech Fair" src="http://www.ninemoreminutes.com/wp-content/uploads/2010/03/tmlstechfair-267x300.png" alt="" width="160" height="180" /></a>Nine More Minutes will be attending the <a href="http://www.tmlstechfair.com/">Triangle MLS Tech Fair</a> as an exhibitor this Thursday, March 11, in Cary, NC.  The tech fair runs from 9:00am to 4:00pm at <a href="http://maps.google.com/maps?f=q&amp;source=s_q&amp;hl=en&amp;geocode=&amp;q=111+Realtors+Way,+Cary,+NC+(Triangle+MLS+Tech+Fair)&amp;sll=35.830762,-78.773874&amp;sspn=0.011186,0.021114&amp;ie=UTF8&amp;hq=&amp;hnear=111+Realtors+Way,+Cary,+Wake,+North+Carolina+27513&amp;t=h&amp;z=16">111 Realtors Way, Cary, NC</a>.</p>
<p>We&#8217;d love it if you could stop by our booth (either #23 or #22 depending on the diagram you&#8217;re looking at) and say &#8220;hi&#8221;.  We have plenty of candy and pens to give away, and would be happy to discuss how our software development and IT consulting services could benefit your small business!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ninemoreminutes.com/2010/03/triangle-mls-tech-fair/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Good Morning From PyCon</title>
		<link>http://www.ninemoreminutes.com/2010/02/good-morning-from-pycon/</link>
		<comments>http://www.ninemoreminutes.com/2010/02/good-morning-from-pycon/#comments</comments>
		<pubDate>Fri, 19 Feb 2010 14:54:32 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[pycon]]></category>

		<guid isPermaLink="false">http://www.ninemoreminutes.com/?p=201</guid>
		<description><![CDATA[I have made the journey to the mecca of nerdery, at least my kind of nerds. Nerds who write Python. I&#8217;m at PyCon 2010 Atlanta. The morning begins with Guido&#8217;s keynote, answering questions posted via Twitter: #python. More to come&#8230;]]></description>
			<content:encoded><![CDATA[<p>I have made the journey to the mecca of nerdery, at least my kind of nerds.  Nerds who write Python.  I&#8217;m at <a href="http://us.pycon.org/">PyCon 2010 Atlanta</a>.</p>
<p>The morning begins with Guido&#8217;s keynote, answering questions posted via Twitter: <a href="http://twitter.com/#search?q=%23pycon">#python</a>.</p>
<p>More to come&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ninemoreminutes.com/2010/02/good-morning-from-pycon/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google Maps with Python and KML</title>
		<link>http://www.ninemoreminutes.com/2009/12/google-maps-with-python-and-kml/</link>
		<comments>http://www.ninemoreminutes.com/2009/12/google-maps-with-python-and-kml/#comments</comments>
		<pubDate>Fri, 18 Dec 2009 01:02:48 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[TriZPUG]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://www.ninemoreminutes.com/?p=181</guid>
		<description><![CDATA[Here&#8217;s a little guide on how to make a &#8220;custom&#8221; Google Map using Python to generate KML.  It&#8217;s a simple way to display your own placemarks on a Google Map or generate a file that can be imported into Google Earth.  And it uses only modules available in the Python standard library, so there are [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a little guide on how to make a &#8220;custom&#8221; Google Map using Python to generate KML.  It&#8217;s a simple way to display your own placemarks on a Google Map or generate a file that can be imported into Google Earth.  And it uses only modules available in the Python standard library, so there are no additional dependencies other than Python itself.<span id="more-181"></span></p>
<h3>Importing Addresses</h3>
<p>I started this project with an Excel spreadsheet someone had sent me, and of course immediately saved it to CSV so I could read in from Python.  I&#8217;ve changed the names and addresses below to protect the innocent, indemnify the guilty, and remove any traces linking me to the incident.  Instead, I&#8217;ll just list my favorite places to find sweet tea along with delicious chicken and biscuits.</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">name,address,city,state,zip,phone,county
Apex - Williams Street,1581 East Williams Street,Apex,NC,27539,919-362-6796,Wake
Apex - Laura Village Drive,1209 Laura Village Drive,Apex,NC,27502,919-362-1416,Wake
Durham - Garrett Road,4600 Garrett Road,Durham,NC,27701,919-489-5942,Durham
Durham - Guess Road,2801 Guess Road,Durham,NC,27705,919-477-2362,Durham
Durham - Hillsboro Road,3558 Hillsboro Road,Durham,NC,27705,919-383-6797,Durham
Durham - Miami Boulevard,1712 Miami Boulevard,Durham,NC,27703,919-596-4330,Durham
Durham - South Miami Boulevard,5425 South Miami Boulevard,Durham,NC,27703,919-941-5620,Durham
Durham - Roxboro Road,4521 Roxboro Road,Durham,NC,27702,919-471-0581,
Fuquay Varina,1400 N. Main Street,Fuquay Varina,NC,27526,919-557-0749,Wake
Garner - Jones Sausage Road,3920 Jones Sausage Road,Garner,NC,27529,919-662-1621,Wake
Garner - NC 42 East,5497 NC 42 East,Garner,NC,27529,919-773-9116,Wake
...</pre>
<p>Using the <a href="http://docs.python.org/library/csv.html">csv</a> module in the Python standard library, it&#8217;s a piece of <span style="text-decoration: line-through;">fried chicken</span> cake to read in the CSV and return a dictionary for each row.  In my situation, I had a spreadsheet with some missing values, so I filtered the rows to only include the ones with complete addresses.</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">import csv

def read_addresses(filename):
    """Retrieve addresses from the given CSV filename."""
    required_fields = set(['name', 'address', 'city', 'zip'])
    reader = csv.DictReader(file(filename, 'rU'))
    for row in reader:
        if not all(row.get(f, '').strip() for f in required_fields):
            continue
        yield row</pre>
<p>And then a little code to just use the first argument to the script as the filename.</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">import sys

if __name__ == '__main__':
    for address in read_addresses(sys.argv[1]):
        print address</pre>
<h3>Geocoding</h3>
<p>Now, we need to use the <a href="http://code.google.com/apis/maps/documentation/geocoding/index.html">Google Maps API</a> to geocode our addresses and return the latitude and longitude in <a href="http://code.google.com/apis/maps/documentation/geocoding/index.html#CSV">CSV</a> format.</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">import urllib
import urlparse

def geocode(address):
    """Geocode the given address, updating the standardized address, latitude,
    and longitude."""
    qs = dict(q=address['address_string'], key=GMAPS_API_KEY, sensor='true',
              output='csv')
    qs = urllib.urlencode(qs)
    url = urlparse.urlunsplit(('http', 'maps.google.com', '/maps/geo', qs, ''))
    f = urllib.urlopen(url)
    result = list(csv.DictReader(f, ('status', 'accurary', 'latitude', 'longitude')))[0]
    if int(result['status']) != 200:
        raise RuntimeError, 'could not geocode address %s (%s)' % \
                            (address, result['status'])
    address['latitude'] = result['latitude']
    address['longitude'] = result['longitude']</pre>
<p>To iterate over the addresses and format them for geocoding, we use the following code:</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">for address in read_addresses(sys.argv[1]):
    address['address_string'] = \
            '%(address)s, %(city)s, %(state)s %(zip)s' % address
    geocode(address)</pre>
<h3>Geocoding to Make Google Happy</h3>
<p>The geocoding works, well almost.  It seems to start out fine, then ends up returning quite a few errors as it goes along.  When we look at the <a href="http://code.google.com/apis/maps/documentation/geocoding/index.html#StatusCodes">status code</a> returned, it&#8217;s a 620 &#8211; G_GEO_TOO_MANY_QUERIES.  So we just add a sleep to the geocode function and it makes it through all the addresses, albeit a little more slowly now.</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">import time

def geocode(address):
    ...
    time.sleep(1.0)</pre>
<h3>Generating KML</h3>
<p>Now than we have addresses with their corresponding coordinates, we can start to create a <a href="http://code.google.com/apis/kml/documentation/">KML</a> document with our placemarks.</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">import xml.dom.minidom

def create_document(title, description=''):
    """Create the overall KML document."""
    doc = xml.dom.minidom.Document()
    kml = doc.createElement('kml')
    kml.setAttribute('xmlns', 'http://www.opengis.net/kml/2.2')
    doc.appendChild(kml)
    document = doc.createElement('Document')
    kml.appendChild(document)
    docName = doc.createElement('name')
    document.appendChild(docName)
    docName_text = doc.createTextNode(title)
    docName.appendChild(docName_text)
    docDesc = doc.createElement('description')
    document.appendChild(docDesc)
    docDesc_text = doc.createTextNode(description)
    docDesc.appendChild(docDesc_text)
    return doc</pre>
<p>And to use this method to create a basic document, we call it with our title and description parameters.  The second line gets the Document element of the overall KML doc; this is the element to which we&#8217;ll append other child elements.</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">    kml_doc = create_document('RDU Bojangle\'s',
                              'Sweet Tea, Chicken and Biscuits')
    document = kml_doc.documentElement.getElementsByTagName('Document')[0]</pre>
<p>Now we need a way to create a placemark using the address information we&#8217;ve obtained from geocoding.  We put the phone number in the description, if there is one available.</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">def create_placemark(address):
    """Generate the KML Placemark for a given address."""
    doc = xml.dom.minidom.Document()
    pm = doc.createElement("Placemark")
    doc.appendChild(pm)
    name = doc.createElement("name")
    pm.appendChild(name)
    name_text = doc.createTextNode('%(name)s' % address)
    name.appendChild(name_text)
    desc = doc.createElement("description")
    pm.appendChild(desc)
    desc_text = doc.createTextNode(address.get('phone', ''))
    desc.appendChild(desc_text)
    pt = doc.createElement("Point")
    pm.appendChild(pt)
    coords = doc.createElement("coordinates")
    pt.appendChild(coords)
    coords_text = doc.createTextNode('%(longitude)s,%(latitude)s,0' % address)
    coords.appendChild(coords_text)
    return doc</pre>
<p>To use this method to build our KML document from the list of addresses, we add the following code:</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">        placemark = create_placemark(address)
        document.appendChild(placemark.documentElement)</pre>
<p>And finally, we need a way to print the whole document to stdout:</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">print kml_doc.toprettyxml(indent="  ", encoding='UTF-8')</pre>
<h3>Generating KML to Make Google Happy</h3>
<p>If we upload this file to a web server, and point to its URL from Google Maps, we have a problem.  It doesn&#8217;t work.  Apparently Google doesn&#8217;t like the default pretty formatting of our KML, in particular the nodes containing only text, because of the extra newlines inserted before and after the text.  We can either turn off pretty printing, which I&#8217;d rather not do since it makes the output hard to read, or apply this little monkey patch to fix the problem:</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">class Element(xml.dom.minidom.Element):

    def writexml(self, writer, indent="", addindent="", newl=""):
        # indent = current indentation
        # addindent = indentation to add to higher levels
        # newl = newline string
        writer.write(indent+"&lt;" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()

        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            xml.dom.minidom._write_data(writer, attrs[a_name].value)
            writer.write("\"")
        if self.childNodes:
            newl2 = newl
            if len(self.childNodes) == 1 and \
                self.childNodes[0].nodeType == xml.dom.minidom.Node.TEXT_NODE:
                indent, addindent, newl = "", "", ""
            writer.write("&gt;%s"%(newl))
            for node in self.childNodes:
                node.writexml(writer,indent+addindent,addindent,newl)
            writer.write("%s%s" % (indent,self.tagName,newl2))
        else:
            writer.write("/&gt;%s"%(newl))

# Monkey patch Element class to use our subclass instead.
xml.dom.minidom.Element = Element</pre>
<h3>Changing Placemark Styles</h3>
<p>KML files also support the notion of styles, which allow you to customize the appearance of your placemarks.  For this example, I&#8217;ll just use different colored icons provided by Google to correspond to the county in which the address is located (based on the &#8220;county&#8221; column in my CSV file).  The code below is used to generate the style elements for the KML document:</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">def create_style(style_id, icon_href):
    """Create a new style for different placemark icons."""
    doc = xml.dom.minidom.Document()
    style = doc.createElement('Style')
    style.setAttribute('id', style_id)
    doc.appendChild(style)
    icon_style = doc.createElement('IconStyle')
    style.appendChild(icon_style)
    icon = doc.createElement('Icon')
    icon_style.appendChild(icon)
    href = doc.createElement('href')
    icon.appendChild(href)
    href_text = doc.createTextNode(icon_href)
    href.appendChild(href_text)
    return doc</pre>
<p>In our main function, we use this code to create three different styles:</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">    style_doc = create_style('Wake', \
        'http://maps.google.com/mapfiles/kml/paddle/red-blank.png')
    document.appendChild(style_doc.documentElement)
    style_doc = create_style('Durham', \
        'http://maps.google.com/mapfiles/kml/paddle/blu-blank.png')
    document.appendChild(style_doc.documentElement)
    style_doc = create_style('Orange', \
        'http://maps.google.com/mapfiles/kml/paddle/wht-blank.png')
    document.appendChild(style_doc.documentElement)</pre>
<p>Now, we add this code to our create_placemark method in order to associate the placemark with a style based on the &#8220;county&#8221; field:</p>
<pre style="background: #e0e0e0; color: #000040; overflow: scroll;">    if address.get('county', ''):
        style_url = doc.createElement("styleUrl")
        pm.appendChild(style_url)
        style_url_text = doc.createTextNode('#%(county)s' % address)
        style_url.appendChild(style_url_text)</pre>
<p>And now there is a different colored icon associated with the addresses, based on county.</p>
<h3>Putting It All Together</h3>
<p>I&#8217;ve attached the final script combining all of the snippets above (minus my Google Maps API key).</p>
<p><a href="http://www.ninemoreminutes.com/wp-content/uploads/2009/12/makemaps.py_.txt">makemaps.py</a></p>
<p>(updated 2011/01/12: added a version with a BSD license) <a href="http://www.ninemoreminutes.com/wp-content/uploads/2011/01/makemaps20110112_py.txt">makemaps20110112.py</a></p>
<p>To view the custom placemarks in your browser, you need to make the KML file available on the web, and enter its URL into the search field in Google Maps.  You can also generate a URL with a query string such as the following:</p>
<pre>http://maps.google.com/?q=&lt;kml-url&gt;</pre>
<p>Or view the results of my sample data:</p>
<p><a href="http://maps.google.com/?q=http://www.ninemoreminutes.com/bojomap.kml">http://maps.google.com/?q=http://www.ninemoreminutes.com/bojomap.kml</a></p>
<h3>And Then?</h3>
<p>It would be relatively simple to include this code in a web app to read addresses from a database and generate a KML file on the fly.  For use in any Python web framework you choose.</p>
<h3>And Then?</h3>
<p>No more &#8220;and then&#8221;.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ninemoreminutes.com/2009/12/google-maps-with-python-and-kml/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Happy Birthday, David!</title>
		<link>http://www.ninemoreminutes.com/2009/12/happy-birthday-david/</link>
		<comments>http://www.ninemoreminutes.com/2009/12/happy-birthday-david/#comments</comments>
		<pubDate>Thu, 17 Dec 2009 21:30:53 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[IT]]></category>
		<category><![CDATA[Networking]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://www.ninemoreminutes.com/?p=172</guid>
		<description><![CDATA[I&#8217;d like to wish a happy (30th) birthday to my good friend and now employee David Horton! He&#8217;s been helping me out on occasion since May with some IT work, and he&#8217;s been diving into some WordPress customizations and even a little Python code recently. As you can see, I&#8217;d found him wandering around on [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.ninemoreminutes.com/wp-content/uploads/2009/12/10933_102239773132287_100000387935775_55406_418322_n-2.jpg"><img class="alignleft size-full wp-image-178" style="margin-right: 10px;" title="David the Fisherman / PHP Programmer" src="http://www.ninemoreminutes.com/wp-content/uploads/2009/12/10933_102239773132287_100000387935775_55406_418322_n-2.jpg" alt="David the Fisherman / PHP Programmer" width="173" height="180" /></a>I&#8217;d like to wish a happy (30th) birthday to my good friend and now employee David Horton!</p>
<p>He&#8217;s been helping me out on occasion since May with some IT work, and he&#8217;s been diving into some WordPress customizations and even a little Python code recently.</p>
<p>As you can see, I&#8217;d found him wandering around on a riverbank, trying to catch fish by hand, and to my surprise he&#8217;s much better suited for sitting in front of a computer writing PHP code.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ninemoreminutes.com/2009/12/happy-birthday-david/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>My &#8220;Typical&#8221; Work Day</title>
		<link>http://www.ninemoreminutes.com/2009/07/my-typical-work-day/</link>
		<comments>http://www.ninemoreminutes.com/2009/07/my-typical-work-day/#comments</comments>
		<pubDate>Thu, 23 Jul 2009 06:59:52 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[meeting]]></category>
		<category><![CDATA[paul graham]]></category>
		<category><![CDATA[schedule]]></category>

		<guid isPermaLink="false">http://www.ninemoreminutes.com/?p=143</guid>
		<description><![CDATA[I really can&#8217;t say it any better than Paul Graham himself, so I&#8217;ll just refer you to to his most recent essay as a starting point. Go read it. Do it. Now with that in mind, here&#8217;s how my days usually go, or at least here&#8217;s how I&#8217;d like them to go, barring any major [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.ninemoreminutes.com/wp-content/uploads/2009/07/p1000119.jpg"><img class="alignleft size-thumbnail wp-image-144" style="margin-right: 10px;" title="The Durham Office" src="http://www.ninemoreminutes.com/wp-content/uploads/2009/07/p1000119-150x112.jpg" alt="The Durham Office" width="150" height="112" /></a>I really can&#8217;t say it any better than <a title="Paul Graham" href="http://paulgraham.com/">Paul Graham</a> himself, so I&#8217;ll just refer you to to his <a title="Maker's Schedule, Manager's Schedule" href="http://paulgraham.com/makersschedule.html">most recent essay</a> as a starting point. Go read it. Do it.</p>
<p>Now with that in mind, here&#8217;s how my days usually go, or at least here&#8217;s how I&#8217;d like them to go, barring any major distractions or interruptions.</p>
<p><span id="more-143"></span></p>
<p>I usually wake up somewhere between 10 am and noon. I rarely set an alarm, because I know I&#8217;ll just turn it off and sleep even longer if I do. About half the time, I&#8217;m usually woken up by a phone call or text message that finally kicks me out of dreamland.</p>
<p>I usually reply to emails, return phone calls and catch up on some tech news first thing. If I have lunch plans, I&#8217;ll head out for that &#8220;speculative meeting&#8221; as the essay describes it. Sometimes I&#8217;ll even attempt to do something resembling physical activity, in hopes of getting into a shape slightly more defined than my current shape.</p>
<p>I spend a few more hours in the afternoon on both personal and work errands &#8212; responding to additional emails, IMs, phone calls, and other busy work. I even find it to be a good time to buy groceries, go to the bank, even do some yard work or housework. I tend to avoid getting myself sucked into coding until everyone else is finished with their work day.</p>
<p>And then, somewhere around 4-5 pm, the fun begins. I can finally dig in for a 5-6 hour stretch of work with relatively few interruptions. I&#8217;ll break for dinner and even a short nap around 9-10 pm, and I&#8217;m usually back at it by 11. I&#8217;ll put in another shift until 4-6 am, or until my eyes can&#8217;t stay open any longer.</p>
<p>Sure, this kind of schedule may kill my social life, but since it doesn&#8217;t bother me to go a few days without much human interaction, it may not be so much of a problem. And if any of you who know me find me avoiding you in the evenings, now you know why. The end of the day for you is when I&#8217;m just getting started. If I lose that focus and motivation early on, it tends to throw me off for the rest of the night.</p>
<p>And now back to the grind. I have at least 3 more hours left to go.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ninemoreminutes.com/2009/07/my-typical-work-day/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Scripting Software Updates</title>
		<link>http://www.ninemoreminutes.com/2009/06/scripting-software-updates/</link>
		<comments>http://www.ninemoreminutes.com/2009/06/scripting-software-updates/#comments</comments>
		<pubDate>Tue, 16 Jun 2009 19:59:40 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Embedded]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[updates]]></category>

		<guid isPermaLink="false">http://www.ninemoreminutes.com/?p=141</guid>
		<description><![CDATA[I wrote a shell script that can periodically check a URL for updates. It can download and run another script to apply those updates, potentially overwriting the first script if the update mechanism needs to change.  I needed  a way to install the update script initially, so I wrote a Python script to read and [...]]]></description>
			<content:encoded><![CDATA[<p>I wrote a <a href="http://www.gnu.org/software/bash/">shell script</a> that can periodically check a <a href="http://en.wikipedia.org/wiki/Uniform_Resource_Locator">URL</a> for updates. It can download and run another script to apply those updates, potentially overwriting the first script if the update mechanism needs to change.  I needed  a way to install the update script initially, so I wrote a <a href="http://www.python.org/">Python</a> script to read and <a href="http://en.wikipedia.org/wiki/Escape_character">escape</a> each line of the update script, then generate an install script which can write the update script if it is not installed.  Following me so far?  Good.</p>
<p><span id="more-141"></span>So this update script is on an <a href="http://en.wikipedia.org/wiki/Embedded_Linux">embedded Linux</a> device and can be completely wiped away if the user does a factory reset or firmware update from the manufacturer.  If they do that, my enhancements to the device and my upgrade script are gone, making the device useless for the particular application.  Fortunately, the manufacturer gives me a way to store a one-line setting in an area of flash that doesn&#8217;t get erased.  And even better, the default firmware will read and <a href="http://en.wikipedia.org/wiki/Eval">evaluate</a> this one line setting in the shell on startup.  <a href="http://www.a-ha.com/">AHA</a>!</p>
<p>The aforementioned <a href="http://www.python.org/">Python</a> script also takes the install script, packs it into one line, escapes everything again, and creates a <a href="http://en.wikipedia.org/wiki/Installation_(computer_programs)">bootstrap</a> script, whose sole purpose is to write the one setting that gets read on startup, that runs the install script, which creates the update script, which periodically checks for updates to the whole thing.</p>
<p>And now my head hurts.  But it works!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ninemoreminutes.com/2009/06/scripting-software-updates/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>All Your Media Are Belong To Us</title>
		<link>http://www.ninemoreminutes.com/2009/01/all-your-media-are-belong-to-us/</link>
		<comments>http://www.ninemoreminutes.com/2009/01/all-your-media-are-belong-to-us/#comments</comments>
		<pubDate>Sat, 17 Jan 2009 22:45:33 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Multimedia]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[boxee]]></category>
		<category><![CDATA[media]]></category>

		<guid isPermaLink="false">http://www.ninemoreminutes.com/?p=130</guid>
		<description><![CDATA[At least that&#8217;s the way it seems when you look at most attempts to bring the media you want to watch and listen to into your living room. Nearly every company wants to be your sole provider of entertainment and lock you into the content they have available. However, the power of the Internet and [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.ninemoreminutes.com/wp-content/uploads/2009/01/img_0516.jpg"><img class="alignleft size-thumbnail wp-image-131" style="margin-right: 10px;" title="Boxee" src="http://www.ninemoreminutes.com/wp-content/uploads/2009/01/img_0516-150x150.jpg" alt="Boxee" width="150" height="150" /></a>At least that&#8217;s the way it seems when you look at most attempts to bring the media you want to watch and listen to into your living room. Nearly every company wants to be your sole provider of entertainment and <a title="Digital Rights Management" href="http://www.eff.org/issues/drm" target="_blank">lock you in</a>to the content they have available. However, the power of the Internet and the innovations of a few small businesses are in a position to continue to change we ways in which we consume our entertainment.</p>
<p>I think <a title="boxee: the open, connected social media center for mac os x and linux" href="http://www.boxee.tv/" target="_blank">Boxee</a> will be one company to keep an eye on in next couple of months, as their user base increases and they transition from an alpha version of the software into a full version of the product. Adding Windows support, as well as finding a business model to support the ongoing development, will be key.</p>
<p>As <a title="Boxee, Used to View Web on TV, Generates Buzz" href="http://www.nytimes.com/2009/01/17/technology/internet/17video.html?ref=technology" target="_blank">this NY Times article</a> mentions today, <a title="boxee: the open, connected social media center for mac os x and linux" href="http://www.boxee.tv" target="_blank">Boxee</a> is currently developed by a small team, and is building a passionate group of fans already. The open source and social networking aspects of the product will help it to grow from the bottom up, as well as continue to support new streaming content and hardware devices as they become available. While the <a title="boxee on Apple TV" href="http://blog.boxee.tv/2008/10/01/xbmcboxee-on-apple-tv/" target="_blank">Apple TV</a> seems to be the most common platform to hack and install <a title="boxee: the open, connected social media center for mac os x and linux" href="http://www.boxee.tv" target="_blank">Boxee</a>, the <a title="Playstation 3" href="http://www.us.playstation.com/PS3" target="_blank">Sony PS3</a> or even <a title="Roku Netflix Player" href="http://www.roku.com/netflixplayer/" target="_blank">Roku&#8217;s Netflix box</a> would also be good candidates.</p>
<p>In trying it on my <a title="MacBook Pro" href="http://www.apple.com/macbookpro/" target="_blank">MacBook Pro</a>, I&#8217;ve found the interface to be very slick, and mostly intuitive to use with the <a title="Apple Remote" href="http://en.wikipedia.org/wiki/Apple_Remote" target="_blank">6-button Apple remote</a>. It lacks the minimal, clean look of <a title="Front Row" href="http://en.wikipedia.org/wiki/Front_Row_(software)" target="_blank">Apple&#8217;s Front Row</a>, but the flexibility and available content make up for it in an instant. I do wish they had support for PowerPC-based Macs, so I could leave it running on my trusty <a title="PowerMac G5" href="http://www.apple.com/support/powermac/" target="_blank">dual G5</a> and take advantage of it on my <a title="Apple Cinema Displays" href="http://support.apple.com/kb/SP79" target="_blank">23&#8243; Cinema Display</a> in my home office.</p>
<p>All that being said, I&#8217;m a huge fan. I&#8217;ll be following <a title="boxee: the open, connected social media center for mac os x and linux" href="http://www.boxee.tv" target="_blank">Boxee</a> closely to see where they go, recommending it to all my friends, and wishing the company the best as they aim to shake up the industry just a little. It&#8217;s time that my media belonged to me, or at least put me in more control of when and where and how I can watch it.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ninemoreminutes.com/2009/01/all-your-media-are-belong-to-us/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Customizing the Default WordPress Theme</title>
		<link>http://www.ninemoreminutes.com/2008/12/customizing-the-default-wordpress-theme/</link>
		<comments>http://www.ninemoreminutes.com/2008/12/customizing-the-default-wordpress-theme/#comments</comments>
		<pubDate>Sun, 14 Dec 2008 23:00:53 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[kubrick]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[theme]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www.ninemoreminutes.com/?p=14</guid>
		<description><![CDATA[To get the new Nine More Minutes site going, I&#8217;d considered various options, trying to find the simplest one that would give me a way of displaying a few pages about the company and the work I do. I&#8217;d looked at doing a simple static site (in strict XHTML, of course) or even using Python + Django [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.ninemoreminutes.com/wp-content/uploads/2008/12/wp29mm.gif"><img class="alignleft size-full wp-image-100" style="margin-right: 10px" title="WP to 9MM" src="http://www.ninemoreminutes.com/wp-content/uploads/2008/12/wp29mm.gif" alt="WP to 9MM" width="197" height="158" /></a>To get the new <a title="Nine More Minutes" href="http://www.ninemoreminutes.com/" target="_self">Nine More Minutes</a> site going, I&#8217;d considered various options, trying to find the simplest one that would give me a way of displaying a few pages about the company and the work I do. I&#8217;d looked at doing a simple static site (in strict <a title="XHTML" href="http://www.w3.org/TR/xhtml1/" target="_blank">XHTML</a>, of course) or even using <a title="Python Programming Language" href="http://www.python.org/" target="_blank">Python</a> + <a title="Django" href="http://www.djangoproject.com/" target="_blank">Django</a> to build a database-driven web site to display, well, plain old pages.  </p>
<p>In spite of my general disdain towards <a title="PHP: Hypertext Processor" href="http://www.php.net/" target="_blank">PHP</a>, I realized that <a title="WordPress: Blog Tool and Publishing Platform" href="http://www.wordpress.org" target="_blank">WordPress</a> was exactly what I was looking for, and it would <a title="The Virtues of a Programmer" href="http://www.hhhh.org/wiml/virtues.html" target="_blank">save me from having to write much code</a>. Of course, it would also give me an excuse to write some posts and keep the site updated on a regular basis. But first, I needed to make a theme using my existing 9MM logo and colors.</p>
<p>I started by reading various articles on the topic, most of them describing the files required in the theme directory and how to build a theme from scratch. <a title="Building Custom WordPress Theme" href="http://www.webdesignerwall.com/tutorials/building-custom-wordpress-theme/" target="_blank">This one</a> is a really good guide, if you&#8217;re into that sort of thing. Taking the even <span style="text-decoration: line-through;">lazier</span> simpler route, I just copied the <strong>default</strong> theme folder and renamed it to <strong>9mm</strong>, and started hacking away there&#8230;<span id="more-14"></span></p>
<h3>The Code</h3>
<p>Of course just copying the theme to a new directory isn&#8217;t enough. Not that I expected it to be, but worth a shot. For the files in the <strong>default</strong> (<a title="Kubrick" href="http://binarybonsai.com/kubrick/" target="_blank">Kubrick</a>) theme, I&#8217;ve listed the changes that were required to make them into the <strong>9mm</strong> theme.</p>
<ul style="text-align: left;">
<li><strong>functions.php</strong> &#8211; <a title="PHP: Hypertext Preprocessor" href="http://www.php.net/" target="_blank">PHP</a> wasn&#8217;t happy to have functions in both the <strong>default</strong> and <strong>9mm</strong> themes with the same names. I renamed all of the kubrick* functions to ninemore* instead. I didn&#8217;t notice this same problem with other themes I&#8217;ve customized since, so it may have been related to my version of <a title="PHP: Hypertext Preprocessor" href="http://www.php.net/" target="_blank">PHP</a> or <a title="WordPress: Blog Tool and Publishing Platform" href="http://www.wordpress.org" target="_blank">WordPress</a> at the time.</li>
<li><strong>header.php</strong> &#8211; Since my header graphic would contain the blog title and caption, I didn&#8217;t need to display this text dynamically. I instead made the entire header div into a link to the blog homepage. I also modified the #page style to remove the kubrick prefix from the image file names.</li>
<li><strong>screenshot.png</strong> &#8211; I recreated this file from a screenshot of my new theme.</li>
<li><strong>style.css</strong> &#8211; I first modified the content block at the beginning of the file to reflect my new theme name and additional information.  Then I changed the colors and images for my new theme.  I also removed the extra margin around the body tag and #page div, and updated the #headerimg div height to match my own header image file dimensions.</li>
<li><strong>images/audio.jpg</strong> &#8211; I removed this file from my theme.</li>
<li><strong>images/header-img.php</strong> &#8211; Since I had no need to make a dynamically-configurable header background image, I removed this file from my theme.</li>
<li><strong>images/kubrickbg-ltr.jpg</strong> &#8211; This file would be replaced with bg-ltr.png.</li>
<li><strong>images/kubrickbg-rtl.jpg</strong> - This file would be replaced with bg-rtl.png.</li>
<li><strong>images/kubrickbgcolor.jpg</strong> - This file would be replaced with bgcolor.png.</li>
<li><strong>images/kubrickbgwide.jpg</strong> - This file would be replaced with bgwide.png.</li>
<li><strong>images/kubrickfooter.jpg</strong> - This file would be replaced with footer.png.</li>
<li><strong>images/kubrickheader.jpg</strong> - This file would be replaced with header.png.</li>
</ul>
<p>The following files required no changes:</p>
<ul>
<li><strong>404.php</strong></li>
<li><strong>archive.php</strong></li>
<li><strong>archives.php</strong></li>
<li><strong>comments-popup.php</strong></li>
<li><strong>comments.php</strong></li>
<li><strong>footer.php</strong></li>
<li><strong>image.php</strong></li>
<li><strong>index.php</strong></li>
<li><strong>links.php</strong></li>
<li><strong>page.php</strong></li>
<li><strong>rtl.css</strong></li>
<li><strong>search.php</strong></li>
<li><strong>searchform.php</strong></li>
<li><strong>sidebar.php</strong></li>
<li><strong>single.php</strong></li>
</ul>
<h3>The Design</h3>
<p>Now it was time to fire up <a title="Adobe Photoshop" href="http://www.adobe.com/products/photoshop/" target="_blank">Photoshop</a> and mock up the layout of the site, basically starting from the business card design I&#8217;d done back in April. I really liked the logo, font, colors and background image on that one, so why change it?</p>
<p><a href="http://www.ninemoreminutes.com/wp-content/uploads/2008/12/preview.jpg"><img class="alignnone size-full wp-image-53" title="Business Card" src="http://www.ninemoreminutes.com/wp-content/uploads/2008/12/preview.jpg" alt="Business Card" width="259" height="152" /></a></p>
<p>I created the mockup image below to match the dimensions of the <strong>default</strong> theme, but instead using my own logo, font, colors and background. It&#8217;s all saved with layers, using various blending options for the borders, glow and shadows, making it pretty simple to tweak if needed.</p>
<p><a href="http://www.ninemoreminutes.com/wp-content/uploads/2008/12/9mmpsd.png"><img class="alignnone size-full wp-image-98" title="9MM Mockup with Slices" src="http://www.ninemoreminutes.com/wp-content/uploads/2008/12/9mmpsd.png" alt="9MM Mockup with Slices" width="473" height="320" /></a></p>
<p>As you can also see, I sliced the mockup image into six slices, and named them to match the images files expected by the theme.  By doing it this way, I could simply do a &#8220;Save for Web&#8221; (using <a title="PNG (Portable Network Graphics)" href="http://libpng.org/pub/png/" target="_blank">PNG</a> format) into my theme folder, and have <a title="Adobe Photoshop" href="http://www.adobe.com/products/photoshop/" target="_blank">Photoshop</a> save my six image files with the right names.  From top to bottom, the six layers are named as follows:</p>
<ol>
<li>header</li>
<li>bgwide</li>
<li>bg-ltr</li>
<li>bg-rtl</li>
<li>footer</li>
<li>bgcolor</li>
</ol>
<h3>The Conclusion</h3>
<p>And that&#8217;s all it took to make this custom <a title="WordPress: Blog Tool and Publishing Platform" href="http://www.wordpress.org" target="_blank">WordPress</a> theme.  Since the original <a title="Kubrick" href="http://binarybonsai.com/kubrick/" target="_blank">Kubrick</a> theme is licensed under the <a title="GPL" href="http://www.opensource.org/licenses/gpl-license.php" target="_blank">GPL</a>, I also have to release my theme under the same license.  Since I&#8217;m not actually redistributing it or selling it, and you&#8217;re only viewing the output of it in your browser, I don&#8217;t <em>have</em> to make it available.  But I will anyways (minus my original <a title="Adobe Photoshop" href="http://www.adobe.com/products/photoshop/" target="_blank">Photoshop</a> file), since it would already be possible to grab the images and style sheet from this server.  Enjoy!</p>
<p><a href="http://www.ninemoreminutes.com/wp-content/uploads/2008/12/9mm.zip">9mm WordPress Theme (9mm.zip)</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ninemoreminutes.com/2008/12/customizing-the-default-wordpress-theme/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Is It That Time Already, Again?</title>
		<link>http://www.ninemoreminutes.com/2008/12/is-it-that-time-already-again/</link>
		<comments>http://www.ninemoreminutes.com/2008/12/is-it-that-time-already-again/#comments</comments>
		<pubDate>Sun, 14 Dec 2008 01:33:59 +0000</pubDate>
		<dc:creator>chris</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://www.ninemoreminutes.com/?p=41</guid>
		<description><![CDATA[  No, it&#8217;s not that time of year when I teach my cat new computer tricks. In this one, from over a year ago, she&#8217;s learning how to update Internet Explorer on a new install of Windows XP, running in a VM, of course. She&#8217;s since lost interest in operating systems, and moved on to [...]]]></description>
			<content:encoded><![CDATA[<p> </p>
<p><a href="http://www.ninemoreminutes.com/wp-content/uploads/2008/12/hpim0431.jpg"><img class="alignleft size-thumbnail wp-image-69" style="margin-right: 10px" title="Bandit, The Computer Cat" src="http://www.ninemoreminutes.com/wp-content/uploads/2008/12/hpim0431-150x150.jpg" alt="Bandit, The Computer Cat" width="150" height="150" /></a>No, it&#8217;s not that time of year when I teach my cat new computer tricks. In this one, from over a year ago, she&#8217;s learning how to update <a title="Internet Explorer" href="http://www.microsoft.com/windows/internet-explorer/" target="_blank">Internet Explorer</a> on a new install of <a title="Windows XP" href="http://www.microsoft.com/windows/windows-xp/" target="_blank">Windows XP</a>, running in a <a title="Yeah, this was actually running under Virtual PC on my dual G5 box" href="http://en.wikipedia.org/wiki/Microsoft_Virtual_PC" target="_blank">VM</a>, of course. She&#8217;s since lost interest in operating systems, and moved on to more exciting hobbies, like destroying my Christmas tree.</p>
<p>It&#8217;s actually that time of year when my nocturnal productivity is at its best. The extra darkness and coldness just make me want to stay inside, and I end up on the computer most of the night. Instead of becoming lazy and turning into a couch potato, I&#8217;ve decided to work on some of my side and personal projects.</p>
<p>So here it is, the first post on the new <a title="Nine More Minutes, Inc." href="http://www.ninemoreminutes.com" target="_self">ninemoreminutes.com</a>! I&#8217;ve customized the default <a title="WordPress: Blog Tool and Publishing Platform" href="http://wordpress.org/" target="_blank">WordPress</a> theme and turned this site into a blog and a few other pages of information about my little one-man company. This blog will be a place to write some technical articles related to the kinds of work I&#8217;m doing. Stay tuned!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ninemoreminutes.com/2008/12/is-it-that-time-already-again/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

