<?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>ptone</title>
	<atom:link href="http://ptone.com/dablog/feed/" rel="self" type="application/rss+xml" />
	<link>http://ptone.com/dablog</link>
	<description>Hodgepodge of thoughts, technical notes, and random observations</description>
	<lastBuildDate>Sat, 04 Jun 2011 14:42:35 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.5</generator>
		<item>
		<title>Broker Django do-gooders</title>
		<link>http://ptone.com/dablog/2011/02/broker-django-do-gooders/</link>
		<comments>http://ptone.com/dablog/2011/02/broker-django-do-gooders/#comments</comments>
		<pubDate>Mon, 28 Feb 2011 19:47:00 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Random Observation]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/?p=162</guid>
		<description><![CDATA[The Problems Small and growing charities have many operational and communications needs that would be well served with custom Django apps. At the same time there are many budding developers who are looking for real projects, not contrived tutorials to learn with. There are also a number of busy experienced developers who still have a [...]]]></description>
			<content:encoded><![CDATA[<div class="document">


<div class="section" id="the-problems">
<h2>The Problems</h2>
<p>Small and growing charities have many operational and communications needs that would be well served with custom Django apps.  At the same time there are many budding developers who are looking for real projects, not contrived tutorials to learn with.  There are also a number of busy experienced developers who still have a bit a spare time and have a strong moral core.</p>
</div>
<div class="section" id="a-possible-solution">
<h2>A Possible solution</h2>
<p>A site that connects worthy organizations with willing developers.
Charities/Groups put together proposals about what they need &#8211; clarity counts.
They must provide a contact/liason.</p>
<p>Developers can register, but their contact info is not shared with charities.  This is developer centric.</p>
<p>Everything must be open source (is license type specified?)
Can stipulate that some form of credit banner for project be placed on final
result such a credit would list this project (the broker project) and hosting
co, and would link to a project page listing all contributors</p>
<p>Provide github organization repo page utilyze issue tracker and read-the-docs what other collaboration tools could be used? a donated basecamp?  could leverage donated deployment options (with advertising credit)</p>
<dl class="docutils">
<dt>Roles of people helping out:</dt>
<dd><ul class="first last simple">
<li>developer python/django</li>
<li>front end designer</li>
<li>mentor</li>
<li>project manager</li>
</ul>
</dd>
</dl>
<p>Can look at the GSOC mentor model</p>
<p>Could have developers and community members vote for most worthy</p>
<p>Could have sprints for charities
How to verify groups/501c3 (can search IRS pub 78)</p>
<p>Limit this to smaller groups initially, based on cashflows? # employees?
Initially limit this to US Domestic agencies (even if they have international
projects)</p>
</div>
<div class="section" id="the-challenges">
<h2>The Challenges</h2>
<p>Would there be anything approaching equilibrium in supply and demand &#8211; or would the demand swamp the process?  Could filters/voting systems fix this?</p>
<p>How to ensure that organizations that CAN afford to hire developrs do, and not take advantage.</p>
<p>How to ensure that code quality is reasonable?
How to follow up with improvements, changes, and training?</p>
</div>
</div>

<p><a href="https://convore.com/django-community/bringing-together-django-devs-and-charities/"><h4>Discuss Here</h4></a></p>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2011/02/broker-django-do-gooders/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MIDI to DMX light chases</title>
		<link>http://ptone.com/dablog/2010/11/midi-to-dmx-light-chases/</link>
		<comments>http://ptone.com/dablog/2010/11/midi-to-dmx-light-chases/#comments</comments>
		<pubDate>Thu, 04 Nov 2010 07:14:38 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Random Observation]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2010/11/midi-to-dmx-light-chases/</guid>
		<description><![CDATA[As a follow on the previous post &#8211; I wanted to demonstrate how the individual lights (with all their own features) can not only be grouped into a simple synchronized group &#8211; but they can be added into a &#8220;sequence&#8221; container which will operate a chase. This also shows the type of interactive control provided [...]]]></description>
			<content:encoded><![CDATA[<p>As a follow on the previous post &#8211; I wanted to demonstrate how the individual lights (with all their own features) can not only be grouped into a simple synchronized group &#8211; but they can be added into a &#8220;sequence&#8221; container which will operate a chase.  This also shows the type of interactive control provided by MIDI hardware.</p>

<p><span id="more-160"></span>
Here is a video demonstrating some of the features, remember the lights on screen are just simple proxy lights for demo purposes.  The main output is realtime DMX &#8211; which is an already working feature, I just don&#8217;t have it hooked up to light gear yet.</p>

<p><object width="480" height="385"><param name="movie" value="http://www.youtube.com/v/deP9JoYJLpw?fs=1&amp;hl=en_US"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/deP9JoYJLpw?fs=1&amp;hl=en_US" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"></embed></object></p>

<p>Here is the code listing that created the demo sequence elements:</p>

<div class="highlight" ><pre><span style="color: #60a0b0; font-style: italic">#!/usr/bin/env python</span>
<span style="color: #60a0b0; font-style: italic"># encoding: utf-8</span>

<span style="color: #007020; font-weight: bold">from</span> <span style="color: #0e84b5; font-weight: bold">midi_reader</span> <span style="color: #007020; font-weight: bold">import</span> MidiDispatcher
<span style="color: #007020; font-weight: bold">import</span> <span style="color: #0e84b5; font-weight: bold">time</span>
<span style="color: #007020; font-weight: bold">from</span> <span style="color: #0e84b5; font-weight: bold">lights</span> <span style="color: #007020; font-weight: bold">import</span> <span style="color: #666666">*</span>
<span style="color: #007020; font-weight: bold">import</span> <span style="color: #0e84b5; font-weight: bold">sys</span>


<span style="color: #60a0b0; font-style: italic"># create a light show - manages the updating of all lights</span>
show <span style="color: #666666">=</span> LightShow()

light_seqA <span style="color: #666666">=</span> LightSequence()
light_seqB <span style="color: #666666">=</span> LightSequence()
light_seqC <span style="color: #666666">=</span> LightSequence()
light_seqD <span style="color: #666666">=</span> LightSequence()


<span style="color: #60a0b0; font-style: italic"># create our 8 lights and add them to each sequence and the show</span>
<span style="color: #007020; font-weight: bold">for</span> i <span style="color: #007020; font-weight: bold">in</span> <span style="color: #007020">range</span>(<span style="color: #40a070">1</span>,<span style="color: #40a070">9</span>):
    l <span style="color: #666666">=</span> LightUnit(channels<span style="color: #666666">=</span>[i])
    l<span style="color: #666666">.</span>release <span style="color: #666666">=</span> <span style="color: #666666">.</span><span style="color: #40a070">3</span>
    show<span style="color: #666666">.</span>lights<span style="color: #666666">.</span>append(l)
    light_seqA<span style="color: #666666">.</span>elements<span style="color: #666666">.</span>append(SequenceElement(l))
    light_seqB<span style="color: #666666">.</span>elements<span style="color: #666666">.</span>append(SequenceElement(l))
    light_seqC<span style="color: #666666">.</span>elements<span style="color: #666666">.</span>append(SequenceElement(l))
    light_seqD<span style="color: #666666">.</span>elements<span style="color: #666666">.</span>append(SequenceElement(l))

<span style="color: #60a0b0; font-style: italic"># add the sequences themselves to the show</span>
show<span style="color: #666666">.</span>lights<span style="color: #666666">.</span>append(light_seqA)
show<span style="color: #666666">.</span>lights<span style="color: #666666">.</span>append(light_seqB)
show<span style="color: #666666">.</span>lights<span style="color: #666666">.</span>append(light_seqC)
show<span style="color: #666666">.</span>lights<span style="color: #666666">.</span>append(light_seqD)


<span style="color: #60a0b0; font-style: italic"># set up the midi communication thread</span>
dispatcher <span style="color: #666666">=</span> MidiDispatcher(<span style="color: #40a070">0</span>)

light_seqA<span style="color: #666666">.</span>speed_control <span style="color: #666666">=</span> <span style="color: #666666">.</span><span style="color: #40a070">01</span>
light_seqA<span style="color: #666666">.</span>duration <span style="color: #666666">=</span> <span style="color: #40a070">0</span>
light_seqA<span style="color: #666666">.</span>on_off_trigger <span style="color: #666666">=</span> <span style="color: #4070a0">&quot;reverse&quot;</span>
<span style="color: #60a0b0; font-style: italic"># set_message is a way of mapping a message to an attribute</span>
light_seqA<span style="color: #666666">.</span>set_message((<span style="color: #40a070">176</span>, <span style="color: #40a070">14</span>),[<span style="color: #4070a0">&#39;speed_control&#39;</span>])
light_seqA<span style="color: #666666">.</span>max_speed <span style="color: #666666">=</span> <span style="color: #666666">.</span><span style="color: #40a070">5</span>

light_seqB<span style="color: #666666">.</span>speed_control <span style="color: #666666">=</span> <span style="color: #666666">.</span><span style="color: #40a070">01</span>
light_seqB<span style="color: #666666">.</span>duration <span style="color: #666666">=</span> <span style="color: #40a070">0</span>
light_seqB<span style="color: #666666">.</span>on_off_trigger <span style="color: #666666">=</span> <span style="color: #4070a0">&quot;sequence&quot;</span>


light_seqC<span style="color: #666666">.</span>speed_control <span style="color: #666666">=</span> <span style="color: #666666">.</span><span style="color: #40a070">3</span>
light_seqC<span style="color: #666666">.</span>duration <span style="color: #666666">=</span> <span style="color: #666666">-</span><span style="color: #40a070">1</span>
light_seqC<span style="color: #666666">.</span>max_speed <span style="color: #666666">=</span> <span style="color: #666666">.</span><span style="color: #40a070">5</span>
light_seqC<span style="color: #666666">.</span>max_duration <span style="color: #666666">=</span> <span style="color: #666666">.</span><span style="color: #40a070">5</span>
light_seqC<span style="color: #666666">.</span>set_message((<span style="color: #40a070">176</span>, <span style="color: #40a070">15</span>),[<span style="color: #4070a0">&#39;speed_control&#39;</span>])
light_seqC<span style="color: #666666">.</span>set_message((<span style="color: #40a070">176</span>, <span style="color: #40a070">16</span>),[<span style="color: #4070a0">&#39;duration_control&#39;</span>])



light_seqD<span style="color: #666666">.</span>elements<span style="color: #666666">.</span>reverse()
light_seqD<span style="color: #666666">.</span>speed_control <span style="color: #666666">=</span> <span style="color: #666666">.</span><span style="color: #40a070">3</span>
light_seqD<span style="color: #666666">.</span>duration <span style="color: #666666">=</span> <span style="color: #666666">-</span><span style="color: #40a070">1</span>

dispatcher<span style="color: #666666">.</span>add_observer((<span style="color: #40a070">144</span>, <span style="color: #40a070">42</span>), light_seqA)
dispatcher<span style="color: #666666">.</span>add_observer((<span style="color: #40a070">176</span>, <span style="color: #40a070">14</span>), light_seqA)
dispatcher<span style="color: #666666">.</span>add_observer((<span style="color: #40a070">176</span>, <span style="color: #40a070">15</span>), light_seqC)
dispatcher<span style="color: #666666">.</span>add_observer((<span style="color: #40a070">176</span>, <span style="color: #40a070">16</span>), light_seqC)
dispatcher<span style="color: #666666">.</span>add_observer((<span style="color: #40a070">144</span>, <span style="color: #40a070">44</span>), light_seqB)
dispatcher<span style="color: #666666">.</span>add_observer((<span style="color: #40a070">144</span>, <span style="color: #40a070">54</span>), light_seqC)
dispatcher<span style="color: #666666">.</span>add_observer((<span style="color: #40a070">144</span>, <span style="color: #40a070">49</span>), light_seqD)



<span style="color: #60a0b0; font-style: italic"># startup the midi communication</span>
dispatcher<span style="color: #666666">.</span>start()

<span style="color: #60a0b0; font-style: italic"># this defaults to true for certain equipment</span>
show<span style="color: #666666">.</span>dmx_keep_alive <span style="color: #666666">=</span> <span style="color: #007020">False</span>
<span style="color: #60a0b0; font-style: italic"># run the show</span>
<span style="color: #007020; font-weight: bold">try</span>:
    show<span style="color: #666666">.</span>run_live()
<span style="color: #007020; font-weight: bold">except</span> <span style="color: #007020">KeyboardInterrupt</span>:
    <span style="color: #60a0b0; font-style: italic"># cleanup</span>
    dispatcher<span style="color: #666666">.</span>stop()
    sys<span style="color: #666666">.</span>exit(<span style="color: #40a070">0</span>)
</pre></div>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2010/11/midi-to-dmx-light-chases/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>An object oriented approach to light show sequencing</title>
		<link>http://ptone.com/dablog/2010/11/an-object-oriented-approach-to-light-show-sequencing/</link>
		<comments>http://ptone.com/dablog/2010/11/an-object-oriented-approach-to-light-show-sequencing/#comments</comments>
		<pubDate>Tue, 02 Nov 2010 21:13:32 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Random Observation]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2010/11/an-object-oriented-approach-to-light-show-sequencing/</guid>
		<description><![CDATA[There is a large hobbiest community out there of people putting together light shows synchronized to music. These are mostly around xmas string lights during the holidays. The lights are controlled via a hardware board that takes signals from a computer and operates multiple dimmers to control the brightness of the lights. These dimmers range [...]]]></description>
			<content:encoded><![CDATA[<p>There is a large hobbiest community out there of people putting together light shows synchronized to music.  These are mostly around xmas string lights during the holidays.</p>

<p>The lights are controlled via a hardware board that takes signals from a computer and operates multiple dimmers to control the brightness of the lights.  These dimmers range in the number of channels, but can be connected together to add more channel capacity.  It is not unusual to have hundreds of channels in a residential size show.</p>

<p>The sequencing of these dimmer channels is generally done with software that divides the show into a set of time chunks represented as columns, with each channel being a row &#8211; resulting in a grid.  To sequence a show, a light intensity level needs to be set for each chunk of time, usually many per second, for many channels.  This grid can be huge and time consuming to fill, and doesn&#8217;t seem an intuitive canvas to experiment with creativity in response to the music.  I thought there should be a better way.</p>

<p><span id="more-156"></span>
I&#8217;m not alone.  The problem with the grid and a hope for a better way are well outlined in this piece called &#8220;<a href="http://www.planetchristmas.com/magazine/Spring2010/index.htm#/18/">The Death of the Grid</a>&#8220;, which I did not discover till after I started down this path.</p>

<p>Other approaches that try to abstract away the grid is in development software called <a href="http://diylightanimation.com/index.php?topic=3290.0">Prancer</a>, and commercial software LightShow Pro which takes an interesting approach of using video images mapped to a light layout called <a href="http://vimeo.com/11969010">layer transitions</a>.</p>

<p>Being on a Mac and a Python programmer, I wanted to look at coming up with an easy way to create expressive sequences on my gear without too much work.</p>

<p>Now there is an existing protocol for capturing musical expressiveness via computer and that is the MIDI protocol which was designed to capture the act of playing a musical instrument into a digital signal.  I felt like this was a good input protocol to adopt, as there is lots of hardware out there to support it, and it was built to capture an expressive range of actions.  This would need to be converted into DMX &#8211; which is the protocol that controls the lights (there are other lighting protocols, but DMX seems to be the main non-proprietary standard, and the smartest to work with).</p>

<p>Now each protocol has its own features, and they are not a perfect match &#8211; but they are good enough.  Midi has 16 channels, each with 127 notes, and a whole mess of controller channels (see <a href="http://www.midi.org/techspecs/midimessages.php">here</a>) with a message data value range of 0-127.  DMX consists of a universe of 512 channels, with values of 0-255.</p>

<p>What I wanted to write was something that abstracts the channels of DMX involved in a set of lights, creating light objects (which may consist of one or more physical light sets), and allow these to be controlled expressively through MIDI.</p>

<p><img src="http://ptone.com/dablog/wp-content/uploads/2010/11/program_structure.png" alt="Program Structure" /></p>

<p>Now I&#8217;m not the first to consider the combination of midi and dmx &#8211; the most comprehensive review is <a href="http://www.innovateshowcontrols.com/support/downloads/midi-dmx.pdf">this paper</a> (but also see (<a href="http://response-box.com/gear/decabox-midi-to-dmx-bridge/">1</a>,<a href="http://www.anyma.ch/2007/research/udmx-midi-interface-10/">2</a>,<a href="http://www.chromakinetics.com/DMX/miniStageConsoleMac.html">3</a>, and I&#8217;m sure others).  I felt there was still a lot of room of putting a higher level of abstraction between the basics of MIDI notes to DMX channels.</p>

<p>Here are two quick screen captures showing the start of this project in action (if you have quicktime, you can just copy the URLs and open them directly in quicktime player)</p>

<p>The first shows just the basics of a simple light setup:</p>

<p><a href="http://www.ptone.com/lights_demo/single%20light.mov">A single light</a></p>

<p>The second shows the addition of a couple more lights, and a couple methods of creating simple groups</p>

<p><a href="http://www.ptone.com/lights_demo/three%20lights.mov">Three Lights</a></p>

<p>Here is more information about the <a href="http://en.wikiaudio.org/ADSR_envelope">A.ttack D.ecay S.ustain R.elease envelope</a></p>

<p>The remaining features I have implemented or planned are:</p>

<ul>
<li>combining lights or light groups into a &#8220;sequence&#8221; (not to be confused with a show sequence &#8211; more of a chase sequence).  These sequences have parameters like duration and speed, loop patterns etc.</li>
<li>Calculating RGB values for Hue, and blending between them over time or space.</li>
<li>Adding physics tween motion &#8211; such as acceleration, bounce, or elastic to sequence groups.</li>
</ul>

<p>The idea will be to record multiple &#8220;live sessions&#8221; and then merge them.  The complexity may prevent the realtime processing of the midi-track into DMX &#8211; and so a MIDI file would be compiled against a show setup to produce either a vixen sequence, or some other similar DMX &#8220;player file&#8221; (really just binary data of chunks of 512byte DMX data).</p>

<p>This will eventually all be open sourced.  I&#8217;m not planning on any GUI at the moment, I hope to come up with a clean API that actually makes it pretty easy to write out the scripts.</p>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2010/11/an-object-oriented-approach-to-light-show-sequencing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="http://www.ptone.com/lights_demo/single%20light.mov" length="48974641" type="video/quicktime" />
<enclosure url="http://www.ptone.com/lights_demo/three%20lights.mov" length="37214717" type="video/quicktime" />
		</item>
		<item>
		<title>Easy Django choices done right</title>
		<link>http://ptone.com/dablog/2010/05/easy-django-choices-done-right/</link>
		<comments>http://ptone.com/dablog/2010/05/easy-django-choices-done-right/#comments</comments>
		<pubDate>Mon, 10 May 2010 18:26:48 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Random Observation]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2010/05/easy-django-choices-done-right/</guid>
		<description><![CDATA[In a old, but still relevant post James Bennet argues for a way of handling the choice tuples used by Django. One of the reasons I haven&#8217;t always followed that advice was that it was just a lot of extra mundane keystrokes, and I&#8217;m lazy. It was well suited for a quick Python hack, and [...]]]></description>
			<content:encoded><![CDATA[<p>In a <a href="http://www.b-list.org/weblog/2007/nov/02/handle-choices-right-way/">old, but still relevant post</a> James Bennet argues for a way of handling the choice tuples used by Django.  One of the reasons I haven&#8217;t always followed that advice was that it was just a lot of extra mundane keystrokes, and I&#8217;m lazy.  It was well suited for a quick Python hack, and I now use the script below as a TextMate bundle so that I can just type in a list and have it converted to &#8220;the right way&#8221;.</p>

<p><span id="more-152"></span>
Here is the snippet:</p>

<pre><code>#!/usr/bin/env python
# encoding: utf-8


import os
import re
from sys import stdout, stdin, exit

display_list = stdin.read()
explicit = 1


def sanitize_enum(s):
    # @@ plenty to improve here
    s = s.upper().strip(' ()')
    s = re.sub('^[-\d ]+','',s)
    s = re.sub('[./() \-]', "_",s)
    while re.search('__',s):
        s = s.replace('__','_')
    return s

def format_choice(t):
    return "    ( %s, '%s' )," % t


choices = []
i = 1

for choice in display_list.split('\n'):
    if choice:
        if explicit:
            sanitized = sanitize_enum(choice)
            print "%s = %s" % (sanitized,i)
            choices.append((sanitized,choice.strip()))
        else:
            choices.append((i,choice.strip()))
        i+=1

print "choices = ("
for c in choices:
    print format_choice(c)
print "    )"
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2010/05/easy-django-choices-done-right/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Turning a Mac Lab into a disc burning machine</title>
		<link>http://ptone.com/dablog/2010/03/turning-a-mac-lab-into-a-disc-burning-machine/</link>
		<comments>http://ptone.com/dablog/2010/03/turning-a-mac-lab-into-a-disc-burning-machine/#comments</comments>
		<pubDate>Fri, 12 Mar 2010 18:54:36 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Random Observation]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2010/03/turning-a-mac-lab-into-a-disc-burning-machine/</guid>
		<description><![CDATA[Have a lab of Macs &#8211; need to burn a bunch of CD or DVDs? Harness those monkeys! No one part of this solution is all that earth shattering, but it is a simple clever combination of steps. So you have a bunch of Macs in a lab &#8211; you have Network accounts and server [...]]]></description>
			<content:encoded><![CDATA[<p>Have a lab of Macs &#8211; need to burn a bunch of CD or DVDs?  Harness those monkeys!</p>

<p><span id="more-147"></span>
No one part of this solution is all that earth shattering, but it is a simple clever combination of steps.</p>

<p>So you have a bunch of Macs in a lab &#8211; you have Network accounts and server based home folders working, and a fast network.  Here are the steps to turn that lab into a fast burn factory for optical disks.</p>

<ul>
<li><p>First, create a network home folder user, I call mine burn.</p></li>
<li><p>Set a few settings for that user, such as to ignore blank media when inserted.</p></li>
<li><p>Create your master .img .dmg or .cdr lets call it &#8216;burnme.img&#8217;, on any machine and then copy it to the Desktop of the burn user.</p></li>
<li><p>Create a burn.command file on the Desktop whose contents is:</p></li>
</ul>

<p>burn.command (make executable):</p>

<pre><code>#!/bin/bash
hdiutil burn ~/Desktop/burnme.img
</code></pre>

<p>Now you can execute two sets of commands through ARD.  The first will log a set of machines in as the burn user (you need to enable assistive devices in UniAccess prefs for this to work):</p>

<pre><code>osascript -e 'tell application "System Events" to keystroke "burn"'; \
osascript -e 'tell application "System Events" to keystroke tab'; \
osascript -e 'tell application "System Events" to delay 0.5'; \
osascript -e 'tell application "System Events" to keystroke "burn"'; \
osascript -e 'tell application "System Events" to delay 0.5'; \
osascript -e 'tell application "System Events" to keystroke return'
</code></pre>

<p>The next ARD UNIX command is a simple command to execute the burning:</p>

<pre><code>open ~/Desktop/burn.command
</code></pre>

<p>Using the combo of the open command with a command file will give you the visual feedback on each machine, as well as return from the ARD task immediately.</p>

<p>The hdiutil command will even wait for media to be inserted if you execute the above before a blank disc is inserted.</p>

<p>I believe hdiutil also uses buffer under-run protection so even if you hit a network bottleneck &#8211; you shouldn&#8217;t end up with coasters.  On a gigabit connection I&#8217;ve done up to 13 machines at the same time no problem.</p>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2010/03/turning-a-mac-lab-into-a-disc-burning-machine/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Bash completion for diskutil (and others&#8230;)</title>
		<link>http://ptone.com/dablog/2010/03/bash-completion-for-diskutil-and-others/</link>
		<comments>http://ptone.com/dablog/2010/03/bash-completion-for-diskutil-and-others/#comments</comments>
		<pubDate>Fri, 12 Mar 2010 17:58:25 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Random Observation]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2010/03/bash-completion-for-diskutil-and-others/</guid>
		<description><![CDATA[A few of the tools I use have spent some time working up bash completing. django-admin and virtualenvwrapper to name two. As a Mac sysadmin I use a number of CLI tools for stuff, and was interested in working up some bash completion for these. I picked diskutil for starters as its one I use [...]]]></description>
			<content:encoded><![CDATA[<p>A few of the tools I use have spent some time working up bash completing.  django-admin and virtualenvwrapper to name two.  As a Mac sysadmin I use a number of CLI tools for stuff, and was interested in working up some bash completion for these.</p>

<p><span id="more-142"></span>
I picked diskutil for starters as its one I use with some regularity on my personal machine (mainly for force unmounting stubborn volumes) as well it has a pretty basic verb set.  Other candidates to apply this two would be hdiutil, severadmin, dscl &#8211; I&#8217;m sure there are a bunch.  It would be interesting to work these up into a single package someday if the effort can ever be marshalled.</p>

<p>I borrowed the approach used in Django of having the completion choices be determined by a python script as it is much more pleasant (for me) to put together any logic or algorithms in Python vs Bash.  The same approach could be used with Ruby, Perl, etc.</p>

<p>You can find the project <a href="http://bitbucket.org/ptone/diskutil_completion/">here</a></p>

<p>Click below to watch a micro screencast:
<a href="http://ptone.com/misc/diskutilcomplete/"><img src="http://ptone.com/dablog/wp-content/uploads/2010/03/diskutilcomplete_poster.jpg"></a></p>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2010/03/bash-completion-for-diskutil-and-others/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Integrating a paper based stage in a digital workflow with Django and QR code</title>
		<link>http://ptone.com/dablog/2010/03/integrating-a-paper-based-stage-in-a-digital-workflow-with-django-and-qr-code/</link>
		<comments>http://ptone.com/dablog/2010/03/integrating-a-paper-based-stage-in-a-digital-workflow-with-django-and-qr-code/#comments</comments>
		<pubDate>Tue, 09 Mar 2010 00:41:50 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Random Observation]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2010/03/integrating-a-paper-based-stage-in-a-digital-workflow-with-django-and-qr-code/</guid>
		<description><![CDATA[There are several procedural things at work that still involve a signature, or hand written note on a piece of paper. This reality has made it hard to digitize these practices. While much of the process could be replace with a web app, with plenty of benefits. The reality is that because the paper step [...]]]></description>
			<content:encoded><![CDATA[<p>There are several procedural things at work that still involve a signature, or hand written note on a piece of paper.  This reality has made it hard to digitize these practices.  While much of the process could be replace with a web app, with plenty of benefits.  The reality is that because the paper step is required, the process would become disjointed.  One way to reconcile the paper with the digital record, is to scan in the signed document and attach it to the digital record.  However this doesn&#8217;t pass my &#8220;ugh&#8221; test in that even with ajax, manually attaching scanned documents to the correct record is still a tedious process.  That is where qrcode comes in.</p>

<p><span id="more-140"></span>
<a href="http://en.wikipedia.org/wiki/QRcode">QR Code</a> is a 2 dimensional matrix code invented in Japan that has qualities of easy machine recognition.  The idea is that if the paper document is printed with a qrcode, then a computer could later do the work of attaching the scan back to the record. So the qrcode becomes the bridge between the digital and paper steps of the process.  The item could even switch between the two multiple times (ie to get multiple signatures in different locations).</p>

<p>I put together a quick django proof of concept that illustrates all the steps.</p>

<p>Briefly:</p>

<ul>
<li>a Django view prints a item-document with a generated qrcode in a corner of the page</li>
<li>an item has a filefield to store a scanned document</li>
<li>a cron script that loads up the Django environment looks through the scanned documents, decodes the qrcode, and matches them up with the django object</li>
</ul>

<p>The qrencoding is done with google charts (no hassle of a cached image), and the decode is done with <a href="http://pyqrcode.sourceforge.net/">pyqrcode</a>.  Note that the pyqrcode project doesn&#8217;t have an egg for 10.6, but I put one together <a href="http://ptone.com/temp/qrcode-0.2.1-py2.6-macosx-10.6-universal.egg.gz">here</a>.  A little ghostscript love can be used to convert PDF for the decoding step.</p>

<p>Many workplaces now have copiers with built in scanners that can scan a pile of documents with ease, making the effort to attach documents back to the object from where they came pretty easy.  There are also iPhone and phone apps that will open the embedded URL, which could be used to pull up a &#8220;quick action&#8221; list for the item.  I haven&#8217;t seen anything like that for iSight cameras &#8211; which is too bad.</p>

<p>So if you are interested in the proof of concept (it is bare bones, but does cover all the core steps you can grab it <a href="http://ptone.com/temp/qrcode-experiment.tgz">here</a> (if you don&#8217;t know python/django &#8211; you&#8217;re going to be a bit lost if you download it &#8211; sorry).  There is one hardcoded path in the link.py script which is what you run to do the importing (ie called from cron).  Now I just have to see if I can find time to actually get some apps that use this written.</p>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2010/03/integrating-a-paper-based-stage-in-a-digital-workflow-with-django-and-qr-code/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Kevin Nails it</title>
		<link>http://ptone.com/dablog/2010/02/kevin-nails-it/</link>
		<comments>http://ptone.com/dablog/2010/02/kevin-nails-it/#comments</comments>
		<pubDate>Mon, 15 Feb 2010 19:49:01 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Random Observation]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2010/02/kevin-nails-it/</guid>
		<description><![CDATA[The Django Advent site is proving to be some great writing. The recent piece by Kevin Fricovsky hits the nail on the head in so many ways. Basically he is highlighting some areas for growth when it comes to the process of combining, in an efficient way, multiple reusable Django apps. He covers the following [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://djangoadvent.com/">Django Advent</a> site is proving to be some great writing.  The <a href="http://djangoadvent.com/1.2/everything-i-hate-about-mingus/">recent piece</a> by <a href="http://blog.montylounge.com/">Kevin Fricovsky</a> hits the nail on the head in so many ways.</p>

<p><span id="more-139"></span>
Basically he is highlighting some areas for growth when it comes to the process of combining, in an efficient way, multiple reusable Django apps.</p>

<p>He covers the following areas:</p>

<ul>
<li>settings</li>
<li>static media</li>
<li>upload paths</li>
<li>Migrations</li>
<li>cache keys</li>
<li>translation</li>
</ul>

<p>Basically &#8211; every one of those except the last two is a pain point that I&#8217;ve experienced relatively early in my Django life.</p>

<p>The Django community has a strong bent towards caution and letting &#8220;convention&#8221; pick the best in class.  While this works in some cases (ie I think it has happened with South for migrations) it is often slow to be recognized or slow to happen.</p>

<p>Basically &#8211; South is the way to go for migrations and it&#8217;s time to give the author the support that comes from it being the blessed version.  If not then there is the risk that he will burn out, and South will wither, and then we have to begin the process all over again (I know thats not likely &#8211; but it is a risk)</p>

<p>For other areas &#8211; waiting for a &#8220;cohesive&#8221; convention is a waste of time, because there are multiple, equally good, ways of doing something, and the problem is not that one is better, just that there exists frustrating variety in the context of predictable combination and reuse.</p>

<p>Take upload paths &#8211; it would really take nothing to namespace the upload zone as Kevin is suggesting.  This is not a convention that will organically come from the community easily, and should just be something that Django core dictates.  There is a reason why Python likes the BDFL tag &#8211; because we know that it&#8217;s often best in the end to just have certain things dictated.</p>

<p>Same with static media &#8211; Django already basically does this with templates, it seems like it makes sense to extend and expand on that approach for static media.</p>

<p>I don&#8217;t know much about cache keys and translation &#8211; but given how strongly I agree with everything else in the article, the suggestions should probably be strongly considered.</p>

<p>Like the whos down in whoville, just wanted to add one more &#8220;we are here, we are here&#8221;</p>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2010/02/kevin-nails-it/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>a little tip on color</title>
		<link>http://ptone.com/dablog/2010/02/a-little-tip-on-color/</link>
		<comments>http://ptone.com/dablog/2010/02/a-little-tip-on-color/#comments</comments>
		<pubDate>Thu, 11 Feb 2010 16:48:12 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Random Observation]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2010/02/a-little-tip-on-color/</guid>
		<description><![CDATA[Not much to say other than I&#8217;ve been using this for a while and want to pass it on. This post has a great tool for randomizing terminal colors. If you have a lot of terminal windows open &#8211; this can make expose very handy (I don&#8217;t really use tabs). I have this bound to [...]]]></description>
			<content:encoded><![CDATA[<p>Not much to say other than I&#8217;ve been using this for a while and want to pass it on.</p>

<p>This <a href="http://www.red-sweater.com/blog/220/random-color-terminal">post</a> has a great tool for randomizing terminal colors.</p>

<p>If you have a lot of terminal windows open &#8211; this can make expose very handy (I don&#8217;t really use tabs).</p>

<p>I have this bound to CMD-Shift-C</p>

<div style="width:90%;">
<a href="http://ptone.com/dablog/wp-content/uploads/2010/02/expose.png"><img style="width:90%;" src="http://ptone.com/dablog/wp-content/uploads/2010/02/expose.png" width=500></a>
</div>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2010/02/a-little-tip-on-color/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python,Multiprocessing,Hyperthreading, and image resizing</title>
		<link>http://ptone.com/dablog/2010/01/pythonmultiprocessinghyperthreading-and-image-resizing/</link>
		<comments>http://ptone.com/dablog/2010/01/pythonmultiprocessinghyperthreading-and-image-resizing/#comments</comments>
		<pubDate>Wed, 13 Jan 2010 22:18:33 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Random Observation]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2010/01/pythonmultiprocessinghyperthreading-and-image-resizing/</guid>
		<description><![CDATA[I have the occasional need to resize a set of images. I used to use Photoshop batch actions, then I used some droplets, and recently I&#8217;ve been using a simple python script with PIL (Python Image Library) We recently got an 8 core Mac Pro, and I wanted to see if I could take more [...]]]></description>
			<content:encoded><![CDATA[<p>I have the occasional need to resize a set of images.  I used to use Photoshop batch actions, then I used some droplets, and recently I&#8217;ve been using a simple python script with PIL (Python Image Library)</p>

<p>We recently got an 8 core Mac Pro, and I wanted to see if I could take more advantage of all those cores when resizing images.</p>

<p><span id="more-134"></span>
One of the things that confused me when I first opened activity monitor, is that it had 16 processors listed.  A little digging turns up that this relates to Intel&#8217;s Hyperthreading technology, where they present the OS twice the cores and hand some extra concurrency on the chip.  There is some debate out there as to whether or not it makes a difference.</p>

<p>It&#8217;s frustrating to have all that power and watch a CPU utilization tool look like this:</p>

<p><img src="http://ptone.com/dablog/wp-content/uploads/2010/01/single.png" alt="Single" /></p>

<p>But that is what you get when a tool is not written to be parallel across processing units.  Much is made over Python&#8217;s limit to threading and the GIL, however it seems that multiple threads never take as much advantage of multicore horsepower as do multiple processes.</p>

<p>Thanks to Python&#8217;s <a href="http://docs.python.org/library/multiprocessing.html">multiprocessing library</a> it was very easy to create a worker <a href="http://docs.python.org/library/multiprocessing.html#module-multiprocessing.pool">pool</a> to handle the resizing.  The results are impressive.  The test task was to resize a folder of 350 jpeg files by 50% and save them to a folder.</p>

<p><img src="http://ptone.com/dablog/wp-content/uploads/2010/01/performance.png" alt="Performance" /></p>

<p>This shows you the performance gain by doing the image resizing in parallel.  It goes from a 6 minute task to a 30 second task.</p>

<p>What is interesting is that even though there are only 8 true cores, there is a 40% increase in speed using all 16 virtual cores, but almost no advantage in going any higher than that.  I&#8217;d say hyperthreading makes a difference in this case.</p>

<p>Now this is more like it:</p>

<p><img src="http://ptone.com/dablog/wp-content/uploads/2010/01/maxed.png" alt="Maxed" /></p>

<p>A couple assorted notes:</p>

<p>With 8 workers, there is a roughly 10% increase in performance seen when turning off hyperthreading (via processor prefpane from dev-tools).  It may be that the overhead of managing threads that aren&#8217;t doing much for you detracts from the overall performance?? Not sure.</p>

<p>Photoshop batch automate on the same task takes about 6 minutes, which seems to refute Adobe&#8217;s <a href="http://blogs.adobe.com/jnack/2006/12/photoshop_and_multicore.html">implication</a> that muliprocessing doesn&#8217;t often gain you much.</p>

<p>There is one gotcha however, and that is that there does seem to be some sort of memory leak with the multiprocessing module.  With just one worker in the pool, you can see a steadily increasing memory use that isn&#8217;t present in the same PIL code that isn&#8217;t run through the multiprocessing module.  This is probably a manifestation of <a href="http://bugs.python.org/issue6653">this bug</a></p>

<p>Finally, the script that I used to do the tests is available <a href="http://gist.github.com/276618">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2010/01/pythonmultiprocessinghyperthreading-and-image-resizing/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Pretty view of hg diff</title>
		<link>http://ptone.com/dablog/2009/11/pretty-view-of-hg-diff/</link>
		<comments>http://ptone.com/dablog/2009/11/pretty-view-of-hg-diff/#comments</comments>
		<pubDate>Fri, 20 Nov 2009 22:21:55 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Random Observation]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2009/11/pretty-view-of-hg-diff/</guid>
		<description><![CDATA[Been using hg, and like to use hg diff to help me make better commit notes &#8211; but been spoiled by bitbuckets HTML view of diffs So here is a quick script that I keep on my path for viewing hg diff, formated with pygments &#8211; I&#8217;m sure it would be very easy to adopt [...]]]></description>
			<content:encoded><![CDATA[<p>Been using hg, and like to use hg diff to help me make better commit notes &#8211; but been spoiled by bitbuckets HTML view of diffs</p>

<p>So here is a quick script that I keep on my path for viewing hg diff, formated with pygments &#8211; I&#8217;m sure it would be very easy to adopt this to git.</p>

<p><a href="http://gist.github.com/239803">here is the gist</a></p>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2009/11/pretty-view-of-hg-diff/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Setting up pinax on Dreamhost Private Server</title>
		<link>http://ptone.com/dablog/2009/10/setting-up-pinax-on-dreamhost-private-server/</link>
		<comments>http://ptone.com/dablog/2009/10/setting-up-pinax-on-dreamhost-private-server/#comments</comments>
		<pubDate>Thu, 29 Oct 2009 22:29:07 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[django pinax]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2009/10/setting-up-pinax-on-dreamhost-private-server/</guid>
		<description><![CDATA[using apache, mysql, mod_wsgi, and virtualenv Dreamhost provides free hosting to nonprofits, and for now they seem to have thrown in a virtual private server. This is hard not to take advantage of, and I&#8217;m hoping that the VPS is better performing than the shared hosting &#8211; but my concern is that they all share [...]]]></description>
			<content:encoded><![CDATA[<p>using apache, mysql, mod_wsgi, and virtualenv</p>

<p>Dreamhost provides free hosting to nonprofits, and for now they seem to have thrown in a virtual private server.  This is hard not to take advantage of, and I&#8217;m hoping that the VPS is better performing than the shared hosting &#8211; but my concern is that they all share the same mysql servers.  So here is how I got pinax up and running in its comfy and modern Python web stack.</p>

<p><span id="more-127"></span>
At first I tried to go the route of custom install of python2.6 &#8211; but got bogged down trying to get either passenger<em>wsgi or mod</em>wsgi to work properly &#8211; they both seemed to have fatal dead ends in the end.</p>

<p>The first thing you need to do is associate a domain with your PS and set it up as a directory of a user.</p>

<p>so that you have a user and directory like /home/django_user/example.com/</p>

<p>In the Dreamhost panel private server section &#8220;Web Server Configuration&#8221; uncheck &#8220;DreamHost Managed:&#8221;.  This will prevent any accidental changes you make in the panel from undoing the customizations you need to make to the apache config.</p>

<p>Next you need to create an admin user in the Dreamhost control panel for your PS, lets say django<em>admin, this probably should be a different user than is set up for the domain.  This user will just be configuring system level software, namely set the python version to use, install the mysql bindings, PIL, and mod</em>wsgi packages.</p>

<p>login as the admin user and then:</p>

<pre><code>mkdir src

# This is to set python 2.5 as the default - if you don't care you can skip this step - but I'm assuming this is done
cd /usr/bin/
sudo rm python
sudo ln -s python2.5 python


cd ~/src
# note that this is specific for 2.5 - use the right egg for your python version
wget http://pypi.python.org/packages/2.5/s/setuptools/setuptools-0.6c11-py2.5.egg#md5=64c94f3bf7a72a13ec83e0b24f2749b2
sudo sh setuptools-0.6c11-py2.5.egg
</code></pre>

<p>You next need to download the MySQL-python tarball from http://sourceforge.net/projects/mysql-python/ as there is no easy way to fetch it from the command line.  FTP it to your src/ directory of the admin user then:</p>

<pre><code>tar xvzf MySQL-python-1.2.3c1.tar.gz
cd MySQL-python-1.2.3c1
sudo python setup.py install

cd ..
wget http://effbot.org/media/downloads/Imaging-1.1.6.tar.gz
tar xvzf Imaging-1.1.6.tar.gz
cd Imaging-1.1.6
python setup.py build --force
sudo python setup.py install
python selftest.py
</code></pre>

<p>You should see: 57 tests passed. Next:</p>

<pre><code>sudo easy_install pip
sudo pip install virtualenv
# virtualenvwrapper is primarily useful if you are going to do 
# dev work or host many projects - I don't assume you fetch this
sudo pip install virtualenvwrapper

cd ~/src
wget http://modwsgi.googlecode.com/files/mod_wsgi-3.0c5.tar.gz
tar xvzf mod_wsgi-3.0c5.tar.gz 

./configure --with-apxs=/usr/local/dh/apache2/template/sbin/apxs --with-python=/usr/bin/python
make
sudo make install

# note that your private server ID replaces the 99999, 
# sub your favorite editor of choice (vi,emacs etc)

sudo pico /usr/local/dh/apache2/apache2-ps99999/etc/httpd.conf
</code></pre>

<p>find the section on modules and add: </p>

<pre><code>LoadModule wsgi_module /dh/apache2/template/lib/modules/mod_wsgi.so
</code></pre>

<p>Now your base python environment is configured, don&#8217;t log out of this user &#8211; as we will need to make more changes to the httpd.conf file later.  Instead open up another terminal session and login as your django_user</p>

<p>The first thing we need to do is create some folders we will use later</p>

<pre><code>mkdir src envs projects wsgi-scripts
</code></pre>

<p>Then we will grab pinax, install it, and activate the virtualenv</p>

<pre><code>cd ~/src
wget http://downloads.pinaxproject.com/Pinax-0.7.1-bundle.tar.gz
tar xvzf Pinax-0.7.1-bundle.tar.gz
python Pinax-0.7.1-bundle/scripts/pinax-boot.py ~/envs/pinax_test/
cd ~
source envs/pinax_test/bin/activate

#optional - update django to current release version
pip install -U django
</code></pre>

<p>Now we will create a basic pinax project</p>

<pre><code>pinax-admin clone_project basic_project projects/basictest
cd projects/basictest/
</code></pre>

<p>Before you continue, go back to the Dreamhost panel and create a mysql database for your project &#8211; note the name and password, and the host name.</p>

<p>Edit the settings.py in your basictest project to use these database settings</p>

<p>Now lets see if we can get pinax up and running:</p>

<pre><code>chmod +x manage.py 
./manage.py syncdb
./manage.py runserver 0.0.0.0:8000
</code></pre>

<p>You should now be able to go to http://example.com:8000 and see the pinax welcome screen, ctrl-C to stop the dev server.</p>

<p>To get pinax working with mod_wsgi you need two parts, a wsgi script, and changes to the apache configuration</p>

<p>create a file called pinax_basictest.wsgi in your wsgi-scripts folder.  Its contents should look like (cobbled from wsgi docs and pinax deployment sample wsgi file):</p>

<pre><code>import os
import sys
import site
sys.stdout = sys.stderr

# not needed in all environments - but is in others
os.environ['PYTHON_EGG_CACHE'] = '/tmp'

# this forces the virtualenv site-packages to be higher priority than system site-packages
site.addsitedir('/home/django_user/envs/pinax_test/lib/python2.5/site-packages')

sys.path.insert(0,'/home/django_user/projects/')

from django.conf import settings
os.environ['DJANGO_SETTINGS_MODULE'] = 'basictest.settings'

sys.path.insert(0, os.path.join(settings.PINAX_ROOT, "apps"))
sys.path.insert(0, os.path.join(settings.PROJECT_ROOT, "apps"))


import django.core.handlers.wsgi

application = django.core.handlers.wsgi.WSGIHandler()


# uncomment below to do a sanity check on the wsgi setup

# def test_wsgi(environ, start_response):
#     status = '200 OK'
#     output = 'Hello World! wsgi py \n' + sys.version + '\n' + '\n'.join(sys.path)
# 
#     response_headers = [('Content-type', 'text/plain'),
#                         ('Content-Length', str(len(output)))]
#     start_response(status, response_headers)
# 
#     return [output]
# 
# application = test_wsgi
</code></pre>

<p>Next you need to switch back to your admin user terminal (you didn&#8217;t close it right?) and edit your httpd.conf file again</p>

<pre><code>sudo pico /usr/local/dh/apache2/apache2-ps99999/etc/httpd.conf
</code></pre>

<p>go to the very end of the file, and before the last closing /virtualhost tag (so inside the virtualhost) add the following</p>

<pre><code># wsgi
&lt;Directory /home/django_user/wsgi-scripts&gt;
Order allow,deny
Allow from all
&lt;/Directory&gt;


# absolute path
WSGIScriptAlias / /home/django_user/wsgi-scripts/pinax_basictest.wsgi 

&lt;Directory "/home/django_user/projects/basictest/media"&gt;
    Allow from all
    Order allow,deny
&lt;/Directory&gt;


&lt;Directory "/home/django_user/envs/pinax_test/lib/python2.5/site-packages/django/contrib/admin/media"&gt;
    Allow from all
    Order allow,deny
&lt;/Directory&gt;

Alias "/media/" "/home/django_user/projects/basictest/media/"

# note some use hyphen - others _
Alias "/admin_media/" "/home/django_user/envs/pinax_test/lib/python2.5/site-packages/django/contrib/admin/media/"
</code></pre>

<p>Finally, still while in the admin user terminal  &#8211; restart apache (remember to change for your private server id):</p>

<pre><code>sudo /etc/init.d/httpd2 restart apache2-ps999999
</code></pre>

<p>Now you should be able to go to http://example.com and see the pinax welcome screen</p>

<p>If you get a 500 error:</p>

<ul>
<li>look in your apache error log which will be at /home/django_user/logs/example.com/http/error.log</li>
<li>uncomment the sanity check in the wsgi script to see if you can get basic hello world working, along with some info about what python environment is being used by wsgi</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2009/10/setting-up-pinax-on-dreamhost-private-server/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Restricting login to account based on IP address</title>
		<link>http://ptone.com/dablog/2009/10/restricting-login-to-account-based-on-ip-address/</link>
		<comments>http://ptone.com/dablog/2009/10/restricting-login-to-account-based-on-ip-address/#comments</comments>
		<pubDate>Wed, 28 Oct 2009 16:31:38 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[osx]]></category>
		<category><![CDATA[sys-admin]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2009/10/restricting-login-to-account-based-on-ip-address/</guid>
		<description><![CDATA[At work we needed to have a standard local account that would work off campus, but not on campus. Here was my solution. First I check for the user and create it if it doesn&#8217;t exist #!bash user_exists=`dscl . -read /Users/remote GeneratedUID &#124; grep -c GeneratedUID` if [ $user_exists -ne 1 ]; then echo "creating [...]]]></description>
			<content:encoded><![CDATA[<p>At work we needed to have a standard local account that would work off campus, but not on campus. Here was my solution.</p>

<p><span id="more-97"></span>
First I check for the user and create it if it doesn&#8217;t exist</p>

<pre><code>#!bash
user_exists=`dscl . -read /Users/remote GeneratedUID | grep -c GeneratedUID`
if [ $user_exists -ne 1 ]; then
    echo "creating remote user"
    sudo dscl . -create /Users/remote
    dscl . -create /Users/remote UserShell /bin/bash
    sudo dscl . -create /Users/remote RealName "remote"
    dscl . -create /Users/remote UniqueID 509
    dscl . -create /Users/remote PrimaryGroupID 1000
    dscl . -create /Users/remote NFSHomeDirectory /Local/Users/remote
    dscl . -passwd /Users/remote remote
fi
</code></pre>

<p>because these are fully managed machines, I know what UIDs are available.  (For a method that checks for available UID I&#8217;ve posted a script from Andrew Mortensen below)</p>

<p>The next part of the script will check if the user is logged in as &#8220;remote&#8221; and on campus using a regular expression (our two subnets are 10.5.5.X and 10.6.6.X).  You could also check a router, DHCP server, or internal DNS as other approaches.  If they are on campus I use a display utility called BigHonkingText to throw up a message and then kill the loginwindow.</p>

<pre><code>#!bash
user="$1"

if [ "$user" == "remote" ]; then
    IP=`ifconfig | grep "inet " | grep -v 127.0.0.1 | awk 'NR&gt;1{exit};{ print $2 }'`
    echo $IP
    if [[ "$IP" =~ 10.[5,6].[5,6].[0-9]* ]]; then
        echo "on campus"
    /usr/local/bin/BigHonkingText "account not allowed on campus"
    killall loginwindow
        # reboot
    fi
fi
</code></pre>

<p>Here is the script from Andrew Mortensen:</p>

<pre><code>#!bash
#! /bin/sh

# create a template user

export PATH=/bin:/usr/bin:/sbin:/usr/sbin

# arbitrary uid
N_UID=501

# arbitrary gid
N_GID=501

# user name
N_USERNAME="$1"

# home
N_HOME="/var/${N_USERNAME}"

# system default user home template
SYSHOMETEMPLATE="/System/Library/User Template/English.lproj"

# make sure the uid and gid are available
while [ true ]; do
    user="`dscl . -search /users UniqueID ${N_UID} 2&gt;/dev/null`"

    if [ -z "${user}" ]; then
    break
    fi

    N_UID=$((${N_UID} + 1));
done

while [ true ]; do
    group=`dscl . -search /groups PrimaryGroupID ${N_GID} 2&gt;/dev/null`

    if [ -z "${group}" ]; then
    break
    fi

    N_GID=$((${N_GID} + 1));
done

# create user
dscl . &lt;&lt;EOF
create "/users/${N_USERNAME}"
create "/users/${N_USERNAME}" AppleMetaNodeLocation /Local/Default
create "/users/${N_USERNAME}" GeneratedUID `uuidgen`
create "/users/${N_USERNAME}" UniqueID ${N_UID}
create "/users/${N_USERNAME}" PrimaryGroupID ${N_GID}
create "/users/${N_USERNAME}" Password "*"
create "/users/${N_USERNAME}" RecordName ${N_USERNAME}
create "/users/${N_USERNAME}" RecordType dsRecTypeNative:users
create "/users/${N_USERNAME}" NFSHomeDirectory ${N_HOME}
create "/users/${N_USERNAME}" RealName "Template User"
create "/users/${N_USERNAME}" UserShell /bin/bash
EOF
if [ $? -ne 0 ]; then
    logger -is Creation of ${N_USERNAME} failed.

    # destroy account
    dscl . -delete "/users/${N_USERNAME}" 2&gt;/dev/null
    exit 2
fi

# create group
dscl . &lt;&lt;EOF
create "/groups/${N_USERNAME}"
create "/groups/${N_USERNAME}" AppleMetaNodeLocation /Local/Default
create "/groups/${N_USERNAME}" GeneratedUID `uuidgen`
create "/groups/${N_USERNAME}" PrimaryGroupID ${N_GID}
create "/groups/${N_USERNAME}" RecordName ${N_USERNAME}
create "/groups/${N_USERNAME}" RecordType dsRecTypeNative:groups
create "/groups/${N_USERNAME}" Password "*"
create "/groups/${N_USERNAME}" GroupMembership ${N_USERNAME}
EOF
if [ $? -ne 0 ]; then
    logger -is Creation of ${N_USERNAME} failed.

    # destroy account
    dscl . -delete "/users/${N_USERNAME}" 2&gt;/dev/null
    dscl . -delete "/groups/${N_USERNAME}" 2&gt;/dev/null
    exit 2
fi

# make home directory
mkdir -m 0700 -p ${N_HOME}
ditto --rsrc "${SYSHOMETEMPLATE}" "${N_HOME}"

if [ $? -ne 0 ]; then
    logger -is Creation of ${N_USERNAME} failed.

    # destroy account
    dscl . -delete "/users/${N_USERNAME}" 2&gt;/dev/null
    dscl . -delete "/groups/${N_USERNAME}" 2&gt;/dev/null
    exit 2
fi

chown -R ${N_USERNAME}:${N_USERNAME} ${N_HOME}

logger -i Creation of template user ${N_USERNAME} succeeded.

exit 0
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2009/10/restricting-login-to-account-based-on-ip-address/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Installing MySQL Python bindings on OS X Leopard server</title>
		<link>http://ptone.com/dablog/2009/10/installing-mysql-python-bindings-on-os-x-leopard-server/</link>
		<comments>http://ptone.com/dablog/2009/10/installing-mysql-python-bindings-on-os-x-leopard-server/#comments</comments>
		<pubDate>Thu, 22 Oct 2009 16:56:11 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Random Observation]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2009/10/installing-mysql-python-bindings-on-os-x-leopard-server/</guid>
		<description><![CDATA[Installing the mysql-python package on Leopard is relatively easy if you&#8217;ve installed MySQL from the mysql.org distribution &#8211; but installing on Leopard Server is a bit more problematic. The crux of the issue is that the version of MySQL that comes with Leopard Server does not include the header and library files needed for linking [...]]]></description>
			<content:encoded><![CDATA[<p>Installing the mysql-python package on Leopard is relatively easy if you&#8217;ve installed MySQL from the mysql.org distribution &#8211; but installing on Leopard Server is a bit more problematic.</p>

<p><span id="more-96"></span>
The crux of the issue is that the version of MySQL that comes with Leopard Server does not include the header and library files needed for linking external libraries with.  This applies to 10.5, but a similar process should work with 10.6.</p>

<p>If you attempt to build the MySQLdb python module you&#8217;ll get errors like:</p>

<pre><code>building '_mysql' extension
gcc -fno-strict-aliasing -Wno-long-double -no-cpp-precomp -mno-fused-madd -fno-common -dynamic -DNDEBUG -g -Os -Wall -Wstrict-prototypes -DMACOSX -I/usr/include/ffi -DENABLE_DTRACE -arch i386 -arch ppc -pipe -Dversion_info=(1,2,3,'gamma',1) -D__version__=1.2.3c1 -I/usr/include -I/System/Library/Frameworks/Python.framework/Versions/2.5/include/python2.5 -c _mysql.c -o build/temp.macosx-10.5-i386-2.5/_mysql.o -fno-omit-frame-pointer -pipe -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DIGNORE_SIGHUP_SIGQUIT
_mysql.c:36:23: error: my_config.h: No such file or directory
_mysql.c:36:23: error: my_config.h: No such file or directory
_mysql.c:38:19: error: mysql.h: No such file or directory
_mysql.c:38:19: error: mysql.h: No such file or directory
</code></pre>

<p>Apple has a <a href="technote">http://support.apple.com/kb/TA25017</a> on the issue &#8211; and the solution is to download these separately.  You can also just install a different version of mysql &#8211; but for a variety of reasons, I wanted to continue to run the installed version.</p>

<p>So here are the commands that will build you a working mysql python binding:</p>

<p>(assumes you have dev tools installed)</p>

<p>grab the binding library source:</p>

<p>http://sourceforge.net/projects/mysql-python/files/</p>

<pre><code>mv path/to/MySQL-python-1.2.3c1.tar.gz /tmp
cd /tmp
tar xvzf MySQL-python-1.2.3c1.tar.gz
curl -O http://www.opensource.apple.com/other/MySQL-43.binaries.tar.gz
tar xzvf MySQL-43.binaries.tar.gz
tar xvzf MySQL-43.binaries/MySQL-43.root.tar.gz
cd usr
sudo ditto usr/include/ /usr/include/
sudo ditto usr/lib/ /usr/lib/
cd /tmp/MySQL-python-1.2.3c1
ARCHFLAGS='-arch i386 -arch x86_64'
export ARCHFLAGS
# edit site.cfg to point to point to /usr/bin/mysql_config
python setup.py build
sudo python setup.py install
</code></pre>

<p>To verify this worked &#8211; fire up a python console and &#8216;import MySQLdb&#8217;</p>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2009/10/installing-mysql-python-bindings-on-os-x-leopard-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Local editing of remote files</title>
		<link>http://ptone.com/dablog/2009/10/local-editing-of-remote-files/</link>
		<comments>http://ptone.com/dablog/2009/10/local-editing-of-remote-files/#comments</comments>
		<pubDate>Thu, 15 Oct 2009 23:05:35 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Random Observation]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2009/10/local-editing-of-remote-files/</guid>
		<description><![CDATA[So found this buried under some dust. I had forgotten that I had ever set this up, but in adding some stuff to a .bash_profile on an older server found some code that I&#8217;ve spruced up bit for this post that lets you locally edit a remote file initiated via command in a remote SSH [...]]]></description>
			<content:encoded><![CDATA[<p>So found this buried under some dust.  I had forgotten that I had ever set this up, but in adding some stuff to a .bash_profile on an older server found some code that I&#8217;ve spruced up bit for this post that lets you locally edit a remote file initiated via command in a remote SSH session.</p>

<p><span id="more-94"></span>
I&#8217;ve been mostly using transmit/SFTP to do editing of remote files with my local editor of choice (TextMate).  Before I switched to TextMate I was using TextWrangler.  The problem with using Transmit (or any FTP client) for editing is that if you are already where you need to be in a SSH session &#8211; you have to navigate to that same location in the FTP client before opening the file for local editing.</p>

<p>One feature TextWrangler has that TextMate does not is the ability to open files from a SFTP URL and save them back remotely when you do CMD-S.</p>

<p>So putting the following in the .bash_profile on the server will let you execute &#8220;redit somefile&#8221; which will cause a reverse ssh command to be sent you telling TextWrangler to open the file.</p>

<p>Some prereqs:</p>

<ul>
<li>You have to have key based SSH auth working in BOTH directions</li>
<li>You have to have the TextWrangler CLI tool (edit) installed</li>
<li>Since there is a good chance that the local user you are logged in as is different than the one you are shelling into as, you have to hard code that &#8211; so unless your name is preston &#8211; you will have to change that.</li>
</ul>

<p>`</p>

<pre><code>SSH_CLIENT_ADDRESS=`echo $SSH_CONNECTION | cut -f1 -d" "`
export SSH_CLIENT_ADDRESS

SSH_HOST_ADDRESS=`echo $SSH_CONNECTION | cut -f3 -d" "`
export SSH_HOST_ADDRESS

ME=`whoami`

function redit() {
    ssh preston@$SSH_CLIENT_ADDRESS edit \"sftp://$ME@$SSH_HOST_ADDRESS/$PWD/"$@"\"
}
</code></pre>

<p>`</p>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2009/10/local-editing-of-remote-files/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

