<?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>bylr.net</title>
	<atom:link href="http://bylr.net/3/feed/" rel="self" type="application/rss+xml" />
	<link>http://bylr.net/3</link>
	<description>&#34;you&#039;re at this website. i guarantee it.&#34; -dan byler</description>
	<lastBuildDate>Mon, 06 May 2013 21:20:48 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Bless you, OmniFocus (or, How I Learned to Stop Fidgeting and Quickly Rename Multiple Versions of the same Application)</title>
		<link>http://bylr.net/3/2013/05/bless-you-omnifocus-or-how-i-learned-to-stop-fidgeting-and-quickly-rename-multiple-versions-of-the-same-application/</link>
		<comments>http://bylr.net/3/2013/05/bless-you-omnifocus-or-how-i-learned-to-stop-fidgeting-and-quickly-rename-multiple-versions-of-the-same-application/#comments</comments>
		<pubDate>Mon, 06 May 2013 16:00:28 +0000</pubDate>
		<dc:creator>Dan Byler</dc:creator>
				<category><![CDATA[applescript]]></category>
		<category><![CDATA[OmniFocus]]></category>

		<guid isPermaLink="false">http://bylr.net/3/?p=335</guid>
		<description><![CDATA[The upcoming OmniFocus 2 refresh provides more than ample reason for excitement. Forecast view? Updated review mode? The giddy feeling of firing up this morning&#8217;s sneaky-peek build to find yet another shiny new release ready for your eager paws? Check, check, check. But unlike last time around1, OmniFocus 2 isn&#8217;t ready to take over my [...]]]></description>
				<content:encoded><![CDATA[<p>The upcoming OmniFocus 2 refresh provides more than ample reason for excitement. Forecast view? Updated review mode? The giddy feeling of firing up this morning&#8217;s sneaky-peek build to find yet another shiny new release ready for your eager paws? Check, check, check.</p>

<p>But unlike last time around<a name="13Apr301-a"></a><sup><a href="#13Apr301-b">1</a></sup>, OmniFocus 2 isn&#8217;t ready to take over my life yet, so for the moment I&#8217;m still usually working in OmniFocus 1. Every couple days I fire up OmniFocus 2 to kick the tires a little more and sometimes provide some (hopefully useful) feedback to the good folks at the Omni Group. (And yes, <a href="https://twitter.com/OmniFocus/status/329636742405689344">they&#8217;re listening</a>.)</p>

<p>Unfortunately, switching fluidly between the two versions becomes problematic when you bring third party tools into the mix. Case in point: AppleScripts that <code>tell application "OmniFocus"</code> expect that they&#8217;re working with an application called <em>OmniFocus</em>. So if OmniFocus 1 is called &#8220;OmniFocus 1&#8243; and OmniFocus 2 is called &#8220;OmniFocus&#8221;, your scripts will <em>always</em> invoke OmniFocus 2 until you rename the applications – even if you&#8217;re currently working in OmniFocus 1. That&#8217;s hardly ideal if you&#8217;re switching version with any regularity. And it was keeping me from using OmniFocus 2.</p>

<p>The solution? A script, of course! Here&#8217;s a script that automates the process of switching between primary versions of OmniFocus. This is what it does:</p>

<ol>
<li>Checks your applications folder for items matching the name OmniFocus* and asks you which version you&#8217;d like to bless<a name="13Apr302-a"></a><sup><a href="#13Apr302-b">2</a></sup> [See the end for a version that skips this]</li>
<li>Renames the blessed version to &#8220;OmniFocus.app&#8221;, and the other versions to &#8220;OmniFocus [version].app&#8221;</li>
<li>Launches the blessed version</li>
</ol>

<p>Here it is in action:</p>

<p><iframe src="http://player.vimeo.com/video/65313613" width="500" height="313" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe> </p><p><a href="http://vimeo.com/65313613">Bless OmniFocus demo</a></p>

<p>For those who enjoy reading detailed notes:</p>

<ul>
<li>If you choose the version that&#8217;s already blessed, that version will be activated and no renaming will occur.</li>
<li>If OmniFocus (or many OmniFoci) is running when a the script is ready to rename, the script will handle quitting and relaunching for you.</li>
<li>If you happen to have multiple copies that would have the same target name, only one will be renamed (i.e., files shouldn&#8217;t be randomly overwritten).</li>
<li>While I built this workflow for the purpose of OmniFocus testing, it could work just as easily with any other application: just change the application name at the beginning of the script. You can also change the applications folder.</li>
<li>If the script encounters an application without a version number in its metadata, it will be renamed according to its creation date.</li>
<li>If you use the <code>tell application "System Events" to choose from list</code> line, the dialog will appear at the front (rather than possibly being buried behind windows). However, in my experience, System Events can hang, so I endure the less convenient version in order to keep things running quickly.</li>
<li>&#8230;and of course, your user account needs to have the proper permissions to rename the files.</li>
</ul>

<p>I&#8217;ve been using this for about a month without issue, but of course use at your own risk and please let me know if you have any issues.</p>

<p><a href="https://gist.github.com/dbyler/5308392">Grab the script</a> here:</p>

<script src="https://gist.github.com/dbyler/5308392.js"></script>

<h4>p.s…</h4>

<p><a href="http://bettermess.com">Michael Schechter</a> wondered about a version that blesses a <em>specific</em> version, rather than prompting for user input. This could be useful if you want to…</p>

<ul>
<li>Set up a Hazel rule or timed Keyboard Maestro action to automatically switch versions</li>
<li>Keep two versions of the script for each version of the app to trigger by a launcher</li>
</ul>

<p>So if you&#8217;d prefer a &#8220;headless&#8221; version, <a href="https://gist.github.com/dbyler/5528131">try this one</a>.</p>

<hr />

<ol>
<li><a name="13Apr301-b"></a>OmniFocus 1 replaced Ethan Schoonover&#8217;s exceptionally clever but ultimately hackish OmniOutliner scripts, Kinkless GTD, so it wasn&#8217;t long before OmniFocus quickly surpassed kGTD&#8217;s utility. But OmniFocus 1 is now a very mature product, so it may be some time before OmniFocus 2 can fill its shoes.<a href="#13Apr301-a">&#8617;</a> </li>
<li><a name="13Apr302-b"></a>Blimey, why the blessing? The name comes from a system command to choose which operating system to run on startup. The OS that&#8217;s set to run is &#8220;blessed&#8221;, and you select it by running the <code>bless</code> command.<a href="#13Apr302-a">&#8617;</a></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://bylr.net/3/2013/05/bless-you-omnifocus-or-how-i-learned-to-stop-fidgeting-and-quickly-rename-multiple-versions-of-the-same-application/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Minimize distractions with Keyboard Maestro</title>
		<link>http://bylr.net/3/2012/04/minimize-distractions-with-keyboard-maestro/</link>
		<comments>http://bylr.net/3/2012/04/minimize-distractions-with-keyboard-maestro/#comments</comments>
		<pubDate>Tue, 01 May 2012 06:39:51 +0000</pubDate>
		<dc:creator>Dan Byler</dc:creator>
				<category><![CDATA[applescript]]></category>
		<category><![CDATA[productivity]]></category>
		<category><![CDATA[tools]]></category>

		<guid isPermaLink="false">http://bylr.net/3/?p=325</guid>
		<description><![CDATA[After Ryan Irelan posted about using Keyboard Maestro to block apps, I decided I could adapt the tip for a less cold-turkey approach to computer-enforced self control. So I&#8217;ve been using Ryan&#8217;s tip with one minor change: it uses the world&#8217;s simplest AppleScript to introduce a time limit for how long distracting apps can remain [...]]]></description>
				<content:encoded><![CDATA[<p>After Ryan Irelan posted about <a href="http://www.ryanirelan.com/articles/block-apps-keyboard-maestro/">using Keyboard Maestro to block apps</a>, I decided I could adapt the tip for a less cold-turkey approach to computer-enforced self control.</p>

<p>So I&#8217;ve been using Ryan&#8217;s tip with one minor change: it uses the world&#8217;s simplest AppleScript to introduce a time limit for how long distracting apps can remain open (or active). Just create a Keyboard Maestro macro like the following (<a href="http://bylr.net/files/misc/Quit%20NetNewsWire%20after%2010%20minutes.kmmacros.zip">or download this example</a>):</p>

<p><img style="display:block; margin-left:auto; margin-right:auto;" src="http://bylr.net/3/wp-content/uploads/2012/05/Hide-Twitter.png" alt="Hide Twitter" title="Hide Twitter.png" border="0" width="455" height="552" /></p>

<p>As you can see, this macro waits one minute (60 seconds) before hiding my Twitter client. Works like a charm: hiding the app doesn&#8217;t <em>force</em> me to leave Twitter; but reactivating the app becomes a conscious act of will that forces me to answer <a href="http://www.merlinmann.com/rightnow/">That Question</a>.</p>

<p>(I use a similar macro to quit my RSS reader after a more generous 10 minutes.)</p>
]]></content:encoded>
			<wfw:commentRss>http://bylr.net/3/2012/04/minimize-distractions-with-keyboard-maestro/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Amplifying human ability</title>
		<link>http://bylr.net/3/2011/12/amplifying-human-ability/</link>
		<comments>http://bylr.net/3/2011/12/amplifying-human-ability/#comments</comments>
		<pubDate>Tue, 13 Dec 2011 23:49:36 +0000</pubDate>
		<dc:creator>Dan Byler</dc:creator>
				<category><![CDATA[software]]></category>
		<category><![CDATA[tools]]></category>

		<guid isPermaLink="false">http://bylr.net/3/?p=322</guid>
		<description><![CDATA[Steve Jobs (1980): Scientific American I think it was did a study in the early 70&#8242;s on the efficiency of locomotion. What they did was for all different species of things on the planet &#8211; birds and cats dogs and fish and man and goats and stuff &#8211; they measured how much energy does it [...]]]></description>
				<content:encoded><![CDATA[<p>Steve Jobs (1980):</p>

<blockquote>
  <p>Scientific American I think it was did a study in the early 70&#8242;s on the efficiency of locomotion. What they did was for all different species of things on the planet &#8211; birds and cats dogs and fish and man and goats and stuff &#8211; they measured how much energy does it take for a goat to get from here to there&#8230; and they ranked them and published the list, and the condor won, it took the least amount of energy to get from here to there, and man didn&#8217;t do so well, came out with a rather unimpressive showing about a third of the way down the list.</p>
  
  <p>But fortunately, someone at Scientific American was insightful enough to test man with a bicycle, and man with a bicycle won—twice as good as the condor, all the way off the list. And what it showed was that man is a toolmaker, has the ability to make a tool to amplify the amount of inherent ability that he has.</p>
  
  <p>And that&#8217;s exactly what we&#8217;re doing here. We&#8217;re not making bicycles to be ridden between Palo Alto and San Francisco&#8230; but in general we&#8217;re making tools that amplify the human ability.</p>
  
  <p>(video on <a href="http://www.computerhistory.org/highlights/stevejobs/video/">computerhistory.org</a>)</p>
</blockquote>

<p>This is why I love technology.</p>
]]></content:encoded>
			<wfw:commentRss>http://bylr.net/3/2011/12/amplifying-human-ability/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>All OmniFocus AppleScripts updated to use new notification code</title>
		<link>http://bylr.net/3/2011/10/all-omnifocus-applescripts-updated-to-use-new-notification-code/</link>
		<comments>http://bylr.net/3/2011/10/all-omnifocus-applescripts-updated-to-use-new-notification-code/#comments</comments>
		<pubDate>Mon, 31 Oct 2011 09:07:01 +0000</pubDate>
		<dc:creator>Dan Byler</dc:creator>
				<category><![CDATA[applescript]]></category>
		<category><![CDATA[OmniFocus]]></category>

		<guid isPermaLink="false">http://bylr.net/3/?p=320</guid>
		<description><![CDATA[I&#8217;ve updated all the OmniFocus scripts to use new notification code, which can handle Growl 1.3, previous versions of Growl, and Growl-free systems. You can grab them individually on the Github repo or my download page. Or, just download them all in one go.]]></description>
				<content:encoded><![CDATA[<p>I&#8217;ve updated all the OmniFocus scripts to use new notification code, which can handle Growl 1.3, previous versions of Growl, and Growl-free systems.</p>

<p>You can grab them individually on the <a href="https://github.com/dbyler/omnifocus-scripts">Github repo</a> or <a href="http://bylr.net/files/omnifocus">my download page</a>. Or, just <a href="https://github.com/dbyler/omnifocus-scripts/zipball/master">download them all in one go.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://bylr.net/3/2011/10/all-omnifocus-applescripts-updated-to-use-new-notification-code/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AppleScript and Growl: a survey of possible solutions to the &#8220;Growl not installed&#8221; problem</title>
		<link>http://bylr.net/3/2011/09/applescript-and-growl/</link>
		<comments>http://bylr.net/3/2011/09/applescript-and-growl/#comments</comments>
		<pubDate>Wed, 07 Sep 2011 16:46:09 +0000</pubDate>
		<dc:creator>Dan Byler</dc:creator>
				<category><![CDATA[applescript]]></category>

		<guid isPermaLink="false">http://bylr.net/3/?p=305</guid>
		<description><![CDATA[10/31/11: Updated to work with Growl 1.3 (MAS version). TL;DR: If you want to use Growl notifications in your AppleScripts without causing problems for people who don&#8217;t have it installed, feel free to use this code. For anyone who writes AppleScripts that use Growl notifications, the problem is familiar: if a user doesn&#8217;t have Growl [...]]]></description>
				<content:encoded><![CDATA[<blockquote>
  <p>10/31/11: Updated to work with Growl 1.3 (MAS version).</p>
</blockquote>

<p><strong><em>TL;DR:</em></strong> <em>If you want to use Growl notifications in your AppleScripts without causing problems for people who don&#8217;t have it installed, feel free to use <a href="https://github.com/dbyler/misc-scripts/raw/master/Generic%20Growl%20Code.scpt">this code</a>.</em></p>

<p>For anyone who writes AppleScripts that use Growl notifications, the problem is familiar: if a user doesn&#8217;t have Growl installed, the script throws a fit when they try to run it. Specifically, at load time, the AppleScript interpreter looks for all the applications listed in the script to retrieve their scripting dictionaries, and if it can&#8217;t find any of the listed applications, it asks the user where to find it:</p>

<p><img style="display:block; margin-left:auto; margin-right:auto;" src="http://bylr.net/3/wp-content/uploads/2011/09/Where-is-GrowlHelperApp.png" alt="Where is GrowlHelperApp.png" title="Where is GrowlHelperApp.png" border="0" width="600" height="439" /></p>

<p>This can be frustrating for users who don&#8217;t have Growl installed: either they don&#8217;t know what Growl is (and therefore have no idea what to do in this situation), or they actively prefer not to have Growl on their system. In neither case do you want to force users to install Growl.</p>

<p>Although others have written about this issue—including a couple solutions that work—I still spent a lot of time and frustration trying to work through the issue and thought it might be helpful to post a survey of different methods that don&#8217;t work—and why.</p>

<h2>Method one (bad): Growl, straight-up</h2>

<p><strong>Pros:</strong> Elegant, simple, as Growl intended. <strong>Cons:</strong> Script chokes on Growl-free systems.</p>

<p>The simplest solution is to call Growl using the intended syntax, ignoring users who don&#8217;t have Growl installed. The code is straightforward and easy to understand:</p>

<div class="codesnip-container" ><div class="applescript codesnip" style="font-family:monospace;"><span class="kw3">property</span> growlAppName : <span class="st0">&quot;Dan&#8217;s Scripts&quot;</span><br />
<span class="kw3">property</span> allNotifications : <span class="br0">&#123;</span><span class="st0">&quot;General&quot;</span>, <span class="st0">&quot;Error&quot;</span><span class="br0">&#125;</span><br />
<span class="kw3">property</span> enabledNotifications : <span class="br0">&#123;</span><span class="st0">&quot;General&quot;</span>, <span class="st0">&quot;Error&quot;</span><span class="br0">&#125;</span><br />
<span class="kw3">property</span> iconApplication : <span class="st0">&quot;OmniFocus.app&quot;</span><br />
<br />
<span class="kw3">tell</span> <span class="kw1">application</span> <span class="st0">&quot;GrowlHelperApp&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; register <span class="kw2">as</span> <span class="kw1">application</span> growlAppName all notifications allNotifications default notifications enabledNotifications icon <span class="kw3">of</span> <span class="kw1">application</span> iconApplication<br />
&nbsp; &nbsp; &nbsp; &nbsp; notify <span class="kw3">with</span> <span class="kw1">name</span> <span class="st0">&quot;General&quot;</span> title <span class="st0">&quot;Note title&quot;</span> <span class="kw1">application</span> <span class="kw1">name</span> growlAppName description <span class="st0">&quot;Note description&quot;</span><br />
<span class="kw3">end</span> <span class="kw3">tell</span></div></div>

<p>But if the point of your script is to simplify a task, it&#8217;s not very helpful to publish something that won&#8217;t run for those who don&#8217;t happen to share your idea of a pleasant notification experience.</p>

<p>And you probably don&#8217;t want to maintain two versions of the same script.</p>

<h2>Interlude: Detecting Growl</h2>

<p>To support both Growl-enabled and Growl-free systems, you need to detect whether Growl is installed before deciding what to do. For that, best practice<a name="11Sep071-a"></a><sup><a href="#11Sep071-b">1</a></sup> seems to be to first check whether Growl is running:</p>

<div class="codesnip-container" ><div class="applescript codesnip" style="font-family:monospace;"><span class="kw3">tell</span> <span class="kw1">application</span> <span class="st0">&quot;System Events&quot;</span> <span class="kw3">to</span> <span class="kw3">set</span> GrowlRunning <span class="kw3">to</span> <span class="br0">&#40;</span><span class="kw1">count</span> <span class="kw3">of</span> <span class="br0">&#40;</span><span class="kw2">every</span> process <span class="kw2">where</span> creator type <span class="kw3">is</span> <span class="st0">&quot;GRRR&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> &gt; <span class="nu0">0</span></div></div>

<p>Then, if Growl isn&#8217;t running, check if it&#8217;s installed, try to launch it if so<a name="11Sep072-a"></a><sup><a href="#11Sep072-b">2</a></sup>, and run the alternative notification if not:</p>

<div class="codesnip-container" ><div class="applescript codesnip" style="font-family:monospace;"><span class="kw3">if</span> <span class="kw2">not</span> GrowlRunning <span class="kw3">then</span> <span class="co1">&#8211;if Growl isn&#8217;t running&#8230;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">set</span> GrowlPath <span class="kw3">to</span> <span class="st0">&quot;&quot;</span> <span class="co1">&#8211;check to see if Growl is installed&#8230;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">try</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">tell</span> <span class="kw1">application</span> <span class="st0">&quot;Finder&quot;</span> <span class="kw3">to</span> <span class="kw3">tell</span> <span class="br0">&#40;</span><span class="kw1">application</span> <span class="kw1">file</span> <span class="kw1">id</span> <span class="st0">&quot;GRRR&quot;</span><span class="br0">&#41;</span> <span class="kw3">to</span> <span class="kw3">set</span> strGrowlPath <span class="kw3">to</span> <span class="kw1">POSIX path</span> <span class="kw3">of</span> <span class="br0">&#40;</span>its container <span class="kw2">as</span> <span class="kw1">alias</span><span class="br0">&#41;</span> <span class="sy0">&amp;</span> <span class="kw1">name</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">end</span> <span class="kw3">try</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">if</span> GrowlPath <span class="kw3">is</span> <span class="kw2">not</span> <span class="st0">&quot;&quot;</span> <span class="kw3">then</span> <span class="co1">&#8211;&#8230;try to launch if so&#8230;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">do shell script</span> <span class="st0">&quot;open &quot;</span> <span class="sy0">&amp;</span> strGrowlPath <span class="sy0">&amp;</span> <span class="st0">&quot; &gt; /dev/null 2&gt;&amp;1 &amp;&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay 0.5<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">set</span> GrowlRunning <span class="kw3">to</span> <span class="kw3">my</span> IsGrowlRunning<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">end</span> <span class="kw3">if</span><br />
<span class="kw3">end</span> <span class="kw3">if</span><br />
<span class="kw3">if</span> GrowlRunning <span class="kw3">then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; NotifyWithGrowl<span class="br0">&#40;</span>alertName, alertTitle, alertText, useSticky<span class="br0">&#41;</span><br />
<span class="kw3">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; NotifyWithoutGrowl<span class="br0">&#40;</span>alertText<span class="br0">&#41;</span><br />
<span class="kw3">end</span> <span class="kw3">if</span></div></div>

<h2>Method two (bad): string encapsulation</h2>

<p><strong>Pros:</strong> Used to work; doesn&#8217;t choke on Growl-free systems. <strong>Cons:</strong> No longer works with Growl.</p>

<p>For a long while I used a very simple method that encapsulated Growl statements in a string variable, which prevents the interpreter from choking on systems that don&#8217;t have Growl installed:</p>

<div class="codesnip-container" ><div class="applescript codesnip" style="font-family:monospace;"><span class="kw3">tell</span> <span class="kw1">application</span> <span class="st0">&quot;Finder&quot;</span> <span class="kw3">to</span> <span class="kw3">tell</span> <span class="br0">&#40;</span><span class="kw1">application</span> <span class="kw1">file</span> <span class="kw1">id</span> <span class="st0">&quot;GRRR&quot;</span><span class="br0">&#41;</span> <span class="kw3">to</span> <span class="kw3">set</span> growlHelperAppName <span class="kw3">to</span> <span class="kw1">name</span><br />
<br />
<span class="kw3">tell</span> <span class="kw1">application</span> growlHelperAppName <span class="kw3">to</span> <span class="kw1">run</span> <span class="kw3">script</span> <span class="st0">&quot;register as application <span class="es0">\&quot;</span>&quot;</span> <span class="sy0">&amp;</span> growlAppName <span class="sy0">&amp;</span> <span class="st0">&quot;<span class="es0">\&quot;</span> all notifications {<span class="es0">\&quot;</span>General<span class="es0">\&quot;</span>, <span class="es0">\&quot;</span>Error<span class="es0">\&quot;</span>} &nbsp;default notifications {<span class="es0">\&quot;</span>General<span class="es0">\&quot;</span>, <span class="es0">\&quot;</span>Error<span class="es0">\&quot;</span>} icon of application <span class="es0">\&quot;</span>OmniFocus.app<span class="es0">\&quot;</span>&quot;</span><br />
<span class="kw3">tell</span> <span class="kw1">application</span> growlHelperAppName <span class="kw3">to</span> <span class="kw1">run</span> <span class="kw3">script</span> <span class="st0">&quot;notify with name <span class="es0">\&quot;</span>General<span class="es0">\&quot;</span> title <span class="es0">\&quot;</span>&quot;</span> <span class="sy0">&amp;</span> alertTitle <span class="sy0">&amp;</span> <span class="st0">&quot;<span class="es0">\&quot;</span> application name <span class="es0">\&quot;</span>&quot;</span> <span class="sy0">&amp;</span> growlAppName <span class="sy0">&amp;</span> <span class="st0">&quot;<span class="es0">\&quot;</span> description <span class="es0">\&quot;</span>&quot;</span> <span class="sy0">&amp;</span> alertText <span class="sy0">&amp;</span> <span class="st0">&quot;<span class="es0">\&quot;</span> icon of application <span class="es0">\&quot;</span>OmniFocus.app<span class="es0">\&quot;</span>&quot;</span></div></div>

<p>Unfortunately this method no longer works when Growl <em>is</em> installed:</p>

<p><img style="display:block; margin-left:auto; margin-right:auto;" src="http://bylr.net/3/wp-content/uploads/2011/09/Growl-Error.png" alt="Growl Error.png" title="Growl Error.png" border="0" width="600" height="521" /></p>

<p>So that&#8217;s out.</p>

<h2>Method three (bad): growlnotify</h2>

<p><strong>Pros:</strong> Elegant, doesn&#8217;t choke on Growl-free systems. <strong>Cons:</strong> Doesn&#8217;t work unless growlnotify is installed.</p>

<p>Another method is to use the <code>growlnotify</code> utility that ships with Growl Extras, and call it via a shell script:</p>

<div class="codesnip-container" ><div class="applescript codesnip" style="font-family:monospace;"><span class="kw1">do shell script</span> <span class="st0">&quot;/usr/local/bin/growlnotify OmniFocus &nbsp;-n &#8216;General&#8217; -m &#8216;My message&#8217;&quot;</span></div></div>

<p>But <code>growlnotify</code> isn&#8217;t part of the base Growl installation, so for Growl users who don&#8217;t have the tool installed, it won&#8217;t be obvious why the notification doesn&#8217;t work.</p>

<h2>Method four (good): osaScript</h2>

<p><strong>Pros:</strong> Works for Growl users, doesn&#8217;t choke on Growl-free systems, uses standard AppleScript syntax. <strong>Cons:</strong> Verbose and unsightly.</p>

<p>The first method I found that actually works in 2011, described by <a href="http://elasticthreads.tumblr.com/post/457996450/applescript-services-and-growl-issues">elasticthreads</a>, is to encapsulate the entire Growl-facing script as its own (perfectly quoted) string, and run that using the shell tool <code>osascript</code>:</p>

<div class="codesnip-container" ><div class="applescript codesnip" style="font-family:monospace;"><span class="kw3">set</span> osascript <span class="kw3">to</span> <span class="st0">&quot;property growlAppName : <span class="es0">\&quot;</span>Dan&#8217;s Scripts<span class="es0">\&quot;</span><br />
property allNotifications : {<span class="es0">\&quot;</span>General<span class="es0">\&quot;</span>, <span class="es0">\&quot;</span>Error<span class="es0">\&quot;</span>}<br />
property enabledNotifications : {<span class="es0">\&quot;</span>General<span class="es0">\&quot;</span>, <span class="es0">\&quot;</span>Error<span class="es0">\&quot;</span>}<br />
property iconApplication : <span class="es0">\&quot;</span>OmniFocus.app<span class="es0">\&quot;</span><br />
<br />
tell application <span class="es0">\&quot;</span>GrowlHelperApp<span class="es0">\&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; register as application growlAppName all notifications allNotifications default notifications enabledNotifications icon of application iconApplication<br />
&nbsp; &nbsp; &nbsp; &nbsp; notify with name <span class="es0">\&quot;</span>General<span class="es0">\&quot;</span> title <span class="es0">\&quot;</span>Note title<span class="es0">\&quot;</span> application name growlAppName description <span class="es0">\&quot;</span>Note description<span class="es0">\&quot;</span><br />
end tell<br />
&quot;</span><br />
<span class="kw3">set</span> shellScript <span class="kw3">to</span> <span class="st0">&quot;osascript -e &quot;</span> <span class="sy0">&amp;</span> <span class="kw1">quoted form</span> <span class="kw3">of</span> osascript <span class="sy0">&amp;</span> <span class="st0">&quot; &amp;&gt; /dev/null &amp;&quot;</span><br />
<br />
<span class="kw3">ignoring</span> <span class="kw1">application</span> responses<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">do shell script</span> shellScript<br />
<span class="kw3">end</span> <span class="kw3">ignoring</span></div></div>

<p>I didn&#8217;t want to hardcode the notification parameters, and with all the quoted stringiness, extracting them required writing a method for converting an AppleScript dictionary to string form. Here&#8217;s my complete version of this method:</p>

<div class="codesnip-container" ><div class="applescript codesnip" style="font-family:monospace;"><span class="kw3">property</span> growlAppName : <span class="st0">&quot;Dan&#8217;s Scripts&quot;</span><br />
<span class="kw3">property</span> allNotifications : <span class="br0">&#123;</span><span class="st0">&quot;General&quot;</span>, <span class="st0">&quot;Error&quot;</span><span class="br0">&#125;</span><br />
<span class="kw3">property</span> enabledNotifications : <span class="br0">&#123;</span><span class="st0">&quot;General&quot;</span>, <span class="st0">&quot;Error&quot;</span><span class="br0">&#125;</span><br />
<span class="kw3">property</span> iconApplication : <span class="st0">&quot;OmniFocus.app&quot;</span><br />
<br />
<span class="kw3">set</span> thisNotificationName <span class="kw3">to</span> <span class="st0">&quot;General&quot;</span><br />
<span class="kw3">set</span> thisNotificationTitle <span class="kw3">to</span> <span class="st0">&quot;Note title&quot;</span><br />
<span class="kw3">set</span> thisNotificationDescription <span class="kw3">to</span> <span class="st0">&quot;Note description&quot;</span><br />
<span class="kw3">tell</span> <span class="kw1">application</span> <span class="st0">&quot;Finder&quot;</span> <span class="kw3">to</span> <span class="kw3">tell</span> <span class="br0">&#40;</span><span class="kw1">application</span> <span class="kw1">file</span> <span class="kw1">id</span> <span class="st0">&quot;GRRR&quot;</span><span class="br0">&#41;</span> <span class="kw3">to</span> <span class="kw3">set</span> growlHelperAppName <span class="kw3">to</span> <span class="kw1">name</span><br />
<br />
<span class="kw3">on</span> dictToString<span class="br0">&#40;</span>dict<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">set</span> dictString <span class="kw3">to</span> <span class="st0">&quot;{&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">repeat</span> <span class="kw3">with</span> i <span class="kw3">in</span> dict<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">if</span> <span class="br0">&#40;</span>length <span class="kw3">of</span> dictString &gt; 1<span class="br0">&#41;</span> <span class="kw3">then</span> <span class="kw3">set</span> dictString <span class="kw3">to</span> dictString <span class="sy0">&amp;</span> <span class="st0">&quot;, &quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">set</span> dictString <span class="kw3">to</span> dictString <span class="sy0">&amp;</span> <span class="st0">&quot;<span class="es0">\&quot;</span>&quot;</span> <span class="sy0">&amp;</span> i <span class="sy0">&amp;</span> <span class="st0">&quot;<span class="es0">\&quot;</span>&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">end</span> <span class="kw3">repeat</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">set</span> dictString <span class="kw3">to</span> dictString <span class="sy0">&amp;</span> <span class="st0">&quot;}&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">return</span> dictString<br />
<span class="kw3">end</span> dictToString<br />
<br />
<span class="kw3">on</span> notifyWithGrowl<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">set</span> osascript <span class="kw3">to</span> <span class="st0">&quot;property growlAppName : <span class="es0">\&quot;</span>&quot;</span> <span class="sy0">&amp;</span> growlAppName <span class="sy0">&amp;</span> <span class="st0">&quot;<span class="es0">\&quot;</span><br />
property allNotifications : &quot;</span> <span class="sy0">&amp;</span> dictToString<span class="br0">&#40;</span>allNotifications<span class="br0">&#41;</span> <span class="sy0">&amp;</span> <span class="st0">&quot;<br />
property enabledNotifications : &quot;</span> <span class="sy0">&amp;</span> dictToString<span class="br0">&#40;</span>enabledNotifications<span class="br0">&#41;</span> <span class="sy0">&amp;</span> <span class="st0">&quot;<br />
property iconApplication : <span class="es0">\&quot;</span>&quot;</span> <span class="sy0">&amp;</span> iconApplication <span class="sy0">&amp;</span> <span class="st0">&quot;<span class="es0">\&quot;</span><br />
<br />
tell application <span class="es0">\&quot;</span>&quot;</span> <span class="sy0">&amp;</span> growlHelperAppName <span class="sy0">&amp;</span> <span class="st0">&quot;<span class="es0">\&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; register as application growlAppName all notifications allNotifications default notifications enabledNotifications icon of application iconApplication<br />
&nbsp; &nbsp; &nbsp; &nbsp; notify with name <span class="es0">\&quot;</span>&quot;</span> <span class="sy0">&amp;</span> thisNotificationName <span class="sy0">&amp;</span> <span class="st0">&quot;<span class="es0">\&quot;</span> title <span class="es0">\&quot;</span>&quot;</span> <span class="sy0">&amp;</span> thisNotificationTitle <span class="sy0">&amp;</span> <span class="st0">&quot;<span class="es0">\&quot;</span> application name growlAppName description <span class="es0">\&quot;</span>&quot;</span> <span class="sy0">&amp;</span> thisNotificationDescription <span class="sy0">&amp;</span> <span class="st0">&quot;<span class="es0">\&quot;</span><br />
end tell<br />
&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">set</span> shellScript <span class="kw3">to</span> <span class="st0">&quot;osascript -e &quot;</span> <span class="sy0">&amp;</span> <span class="kw1">quoted form</span> <span class="kw3">of</span> osascript <span class="sy0">&amp;</span> <span class="st0">&quot; &amp;&gt; /dev/null &amp;&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">ignoring</span> <span class="kw1">application</span> responses<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">do shell script</span> shellScript<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">end</span> <span class="kw3">ignoring</span><br />
<span class="kw3">end</span> notifyWithGrowl</div></div>

<p>This method doesn&#8217;t choke on Growl-free systems, uses standard (though obscured) AppleScript syntax, and works for the Growly. It&#8217;s quite a lot of code, though, and isn&#8217;t very pretty.</p>

<h2>Method five (good): AppleScript literal syntax</h2>

<p>Finally—hats off to <a href="http://www.shirt-pocket.com/blog/index.php/shadedgrey/2006/06/11/">Dave Nanian</a> for this method—AppleScript has an obscure <a href="http://www.manyetas.com/creed/AppleScriptEventSyntax.html">literal syntax</a> that can be used instead of standard syntax. In brief, literal syntax is a way of describing statements in guillemet-enclosed <code>events</code> and <code>classes</code>. This is what the above code looks like in literal syntax…</p>

<div class="codesnip-container" ><div class="applescript codesnip" style="font-family:monospace;"><span class="kw3">property</span> growlAppName : <span class="st0">&quot;Dan&#8217;s Scripts&quot;</span><br />
<span class="kw3">property</span> allNotifications : <span class="br0">&#123;</span><span class="st0">&quot;General&quot;</span>, <span class="st0">&quot;Error&quot;</span><span class="br0">&#125;</span><br />
<span class="kw3">property</span> enabledNotifications : <span class="br0">&#123;</span><span class="st0">&quot;General&quot;</span>, <span class="st0">&quot;Error&quot;</span><span class="br0">&#125;</span><br />
<span class="kw3">property</span> iconApplication : <span class="st0">&quot;OmniFocus.app&quot;</span><br />
<br />
<span class="kw3">tell</span> <span class="kw1">application</span> <span class="st0">&quot;Finder&quot;</span> <span class="kw3">to</span> <span class="kw3">tell</span> <span class="br0">&#40;</span><span class="kw1">application</span> <span class="kw1">file</span> <span class="kw1">id</span> <span class="st0">&quot;GRRR&quot;</span><span class="br0">&#41;</span> <span class="kw3">to</span> <span class="kw3">set</span> growlHelperAppName <span class="kw3">to</span> <span class="kw1">name</span><br />
<br />
<span class="kw3">on</span> notifyWithGrowl<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">tell</span> <span class="kw3">my</span> <span class="kw1">application</span> growlHelperAppName<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; «event register» <span class="kw3">given</span> «class appl»:growlAppName, «class anot»:allNotifications, «class dnot»:enabledNotifications, «class iapp»:iconApplication<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; «event notifygr» <span class="kw3">given</span> «class <span class="kw1">name</span>»:<span class="st0">&quot;General&quot;</span>, «class titl»:<span class="st0">&quot;Notes processed&quot;</span>, «class appl»:growlAppName, «class desc»:<span class="st0">&quot;strReport&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">end</span> <span class="kw3">tell</span><br />
<span class="kw3">end</span> notifyWithGrowl</div></div>

<p>N.B. While literal syntax doesn&#8217;t <em>require</em> encapsulating the app name in a string variable, you should do this for two reasons. First, if the application name is used, the interpreter will try to find GrowlHelperApp, thus choking on Growl-free systems. Also, Script Editor will try to convert the code to normal syntax, which you don&#8217;t want if you&#8217;ve gone to the trouble of crafting this version. Note also Nanian&#8217;s warning to use <code>tell my application</code>, not <code>tell application</code>.</p>

<p>This method won&#8217;t choke Growl-free systems as long as you don&#8217;t run the code; make sure you include a check to see if Growl is installed before running this code.</p>

<h2>All tedious things must come to an end</h2>

<p>Giving Apple the benefit of the doubt, I&#8217;ll make two assumptions:</p>

<ol>
<li><p>It&#8217;s generally important to have access to the scripting dictionaries of applications referenced in your script.</p></li>
<li><p>Growl is an edge case in that it&#8217;s simultaneously useful to include in a script but superfluous to the script&#8217;s execution.</p></li>
</ol>

<p>But it&#8217;s a problem that people spend so much time coming up with workarounds for such a seemingly straightforward problem. If you have any other methods for dealing with the &#8220;Growl not installed&#8221; scenario, I&#8217;d love to hear them.</p>

<p>You can download a paste-and-go version of the code (which includes both functioning methods) <a href="https://github.com/dbyler/misc-scripts/raw/master/Generic%20Growl%20Code.scpt">here</a>, or click <a href="applescript://com.apple.scripteditor?action=new&amp;script=property%20growlHelperAppName%20%3A%20%22%22%0Dproperty%20growlAppName%20%3A%20%22Dan%27s%20Scripts%22%0Dproperty%20allNotifications%20%3A%20%7B%22General%22%2C%20%22Error%22%7D%0Dproperty%20enabledNotifications%20%3A%20%7B%22General%22%2C%20%22Error%22%7D%0Dproperty%20iconApplication%20%3A%20%22OmniFocus.app%22%0D%0D%28%2A%20Begin%20notification%20code%20%2A%29%0Don%20notify%28alertName%2C%20alertTitle%2C%20alertText%29%0D%09--Call%20this%20to%20show%20a%20normal%20notification%0D%09my%20notifyMain%28alertName%2C%20alertTitle%2C%20alertText%2C%20false%29%0Dend%20notify%0D%0Don%20notifyWithSticky%28alertName%2C%20alertTitle%2C%20alertText%29%0D%09--Show%20a%20sticky%20Growl%20notification%0D%09my%20notifyMain%28alertName%2C%20alertTitle%2C%20alertText%2C%20true%29%0Dend%20notifyWithSticky%0D%0Don%20IsGrowlRunning%28%29%0D%09tell%20application%20%22System%20Events%22%20to%20set%20GrowlRunning%20to%20%28count%20of%20%28every%20process%20where%20creator%20type%20is%20%22GRRR%22%29%29%20%3E%200%0D%09return%20GrowlRunning%0Dend%20IsGrowlRunning%0D%0Don%20dictToString%28dict%29%20--needed%20to%20encapsulate%20dictionaries%20in%20osascript%0D%09set%20dictString%20to%20%22%7B%22%0D%09repeat%20with%20i%20in%20dict%0D%09%09if%20%28length%20of%20dictString%20%3E%201%29%20then%20set%20dictString%20to%20dictString%20%26%20%22%2C%20%22%0D%09%09set%20dictString%20to%20dictString%20%26%20%22%5C%22%22%20%26%20i%20%26%20%22%5C%22%22%0D%09end%20repeat%0D%09set%20dictString%20to%20dictString%20%26%20%22%7D%22%0D%09return%20dictString%0Dend%20dictToString%0D%0Don%20notifyWithGrowl%28growlHelperAppName%2C%20alertName%2C%20alertTitle%2C%20alertText%2C%20useSticky%29%0D%09tell%20my%20application%20growlHelperAppName%0D%09%09%C2%ABevent%20register%C2%BB%20given%20%C2%ABclass%20appl%C2%BB%3AgrowlAppName%2C%20%C2%ABclass%20anot%C2%BB%3AallNotifications%2C%20%C2%ABclass%20dnot%C2%BB%3AenabledNotifications%2C%20%C2%ABclass%20iapp%C2%BB%3AiconApplication%0D%09%09%C2%ABevent%20notifygr%C2%BB%20given%20%C2%ABclass%20name%C2%BB%3AalertName%2C%20%C2%ABclass%20titl%C2%BB%3AalertTitle%2C%20%C2%ABclass%20appl%C2%BB%3AgrowlAppName%2C%20%C2%ABclass%20desc%C2%BB%3AalertText%0D%09end%20tell%0Dend%20notifyWithGrowl%0D%0Don%20NotifyWithoutGrowl%28alertText%29%0D%09tell%20application%20%22OmniFocus%22%20to%20display%20dialog%20alertText%20with%20icon%201%20buttons%20%7B%22OK%22%7D%20default%20button%20%22OK%22%0Dend%20NotifyWithoutGrowl%0D%0Don%20notifyMain%28alertName%2C%20alertTitle%2C%20alertText%2C%20useSticky%29%0D%09set%20GrowlRunning%20to%20my%20IsGrowlRunning%28%29%20--check%20if%20Growl%20is%20running...%0D%09if%20not%20GrowlRunning%20then%20--if%20Growl%20isn%27t%20running...%0D%09%09set%20GrowlPath%20to%20%22%22%20--check%20to%20see%20if%20Growl%20is%20installed...%0D%09%09try%0D%09%09%09tell%20application%20%22Finder%22%20to%20tell%20%28application%20file%20id%20%22GRRR%22%29%20to%20set%20strGrowlPath%20to%20POSIX%20path%20of%20%28its%20container%20as%20alias%29%20%26%20name%0D%09%09end%20try%0D%09%09if%20GrowlPath%20is%20not%20%22%22%20then%20--...try%20to%20launch%20if%20so...%0D%09%09%09do%20shell%20script%20%22open%20%22%20%26%20strGrowlPath%20%26%20%22%20%3E%20%2Fdev%2Fnull%202%3E%261%20%26%22%0D%09%09%09delay%200.5%0D%09%09%09set%20GrowlRunning%20to%20my%20IsGrowlRunning%28%29%0D%09%09end%20if%0D%09end%20if%0D%09if%20GrowlRunning%20then%0D%09%09tell%20application%20%22Finder%22%20to%20tell%20%28application%20file%20id%20%22GRRR%22%29%20to%20set%20growlHelperAppName%20to%20name%0D%09%09notifyWithGrowl%28growlHelperAppName%2C%20alertName%2C%20alertTitle%2C%20alertText%2C%20useSticky%29%0D%09else%0D%09%09NotifyWithoutGrowl%28alertText%29%0D%09end%20if%0Dend%20notifyMain%0D%28%2A%20end%20notification%20code%20%2A%29%0D">here</a> to open it in your script editor of choice<a name="11Sep073-a"></a><sup><a href="#11Sep073-b">3</a></sup>.</p>

<p>&nbsp;
&nbsp;</p>

<hr />

<ol>
<li><p><a name="11Sep071-b"></a>Much of this is gleaned from discussion and examples posted at the OmniGroup and DEVONtechnologies forums. I think the current version is most similar to one from Rob Trew.<a href="#11Sep071-a">&#8617;</a> </p></li>
<li><p><a name="11Sep072-b"></a>In theory, you should be able to proceed without explicitly seeing if Growl is running/trying to launch if not, because calling <code>tell application "x"</code> will cause it to launch if it&#8217;s not already running. However, there was a time that Growl would crash frequently (I once measured one Growl crash every 7-8 activations), so checking for a successful launch was one way to ensure consistent behavior. Growl has gotten very stable, so this shouldn&#8217;t be a problem, but it&#8217;s cheap and fast to run the check so I keep it in.<a href="#11Sep072-a">&#8617;</a> </p></li>
<li><p><a name="11Sep073-b"></a>Hat tip to Don Southard&#8217;s handy <a href="http://www.dirtdon.com/?p=1212">AppleScript-encoding service</a>, which created the &#8220;open&#8221; link. <a href="#11Sep073-a">&#8617;</a> </p></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://bylr.net/3/2011/09/applescript-and-growl/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Airfoil volume scripts</title>
		<link>http://bylr.net/3/2011/07/airfoil-volume-scripts/</link>
		<comments>http://bylr.net/3/2011/07/airfoil-volume-scripts/#comments</comments>
		<pubDate>Tue, 12 Jul 2011 22:16:20 +0000</pubDate>
		<dc:creator>Dan Byler</dc:creator>
				<category><![CDATA[applescript]]></category>
		<category><![CDATA[airfoil]]></category>
		<category><![CDATA[music]]></category>

		<guid isPermaLink="false">http://bylr.net/3/?p=291</guid>
		<description><![CDATA[Here&#8217;s a quick &#38; dirty script to change the volume of all attached Airfoil speakers. Rather than incrementing by a set amount, this uses a multiplier to keep the perceived change constant. It&#8217;s nicer on the ears, and gives you more nuanced control when the stereo is set to a higher volume. property volume_multiplier : [...]]]></description>
				<content:encoded><![CDATA[<p>Here&#8217;s a quick &amp; dirty script to change the volume of all attached <a href="http://www.rogueamoeba.com/airfoil/">Airfoil</a> speakers. Rather than incrementing by a set amount, this uses a multiplier to keep the <em>perceived</em> change constant. It&#8217;s nicer on the ears, and gives you more nuanced control when the stereo is set to a higher volume.</p>

<pre><code>property volume_multiplier : 0.8

tell application "Airfoil"
    set all_speakers to (get every speaker)
    repeat with this_speaker in all_speakers
        set curr_volume to get volume of this_speaker
        set (volume of this_speaker) to (curr_volume * volume_multiplier)
        if (volume of this_speaker) is 0 then set (volume of this_speaker) to 0.1
    end repeat
end tell
</code></pre>

<p>I keep two copies of this script (&#8220;Airfoil Volume Down&#8221; and &#8220;Airfoil Volume Up&#8221;) bound to ⇧F10 and ⇧F11, respectively, to match the volume keys on my keyboard.</p>

<p>If I ever update them, I&#8217;ll do so over on <a href="https://github.com/dbyler/misc-scripts">Github</a>.</p>

<p>Download: <a href="https://raw.github.com/dbyler/misc-scripts/master/Airfoil%20Volume%20Down.scpt">Airfoil Volume Down</a> and <a href="https://raw.github.com/dbyler/misc-scripts/master/Airfoil%20Volume%20Up.scpt">Airfoil Volume Up</a></p>
]]></content:encoded>
			<wfw:commentRss>http://bylr.net/3/2011/07/airfoil-volume-scripts/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>All OmniFocus scripts updated for a &#8220;Start-based&#8221; workflow</title>
		<link>http://bylr.net/3/2011/07/all-omnifocus-scripts-updated-for-a-start-based-workflow/</link>
		<comments>http://bylr.net/3/2011/07/all-omnifocus-scripts-updated-for-a-start-based-workflow/#comments</comments>
		<pubDate>Mon, 11 Jul 2011 17:36:04 +0000</pubDate>
		<dc:creator>Dan Byler</dc:creator>
				<category><![CDATA[applescript]]></category>
		<category><![CDATA[OmniFocus]]></category>
		<category><![CDATA[productivity]]></category>

		<guid isPermaLink="false">http://bylr.net/3/?p=287</guid>
		<description><![CDATA[Like many OmniFocus users, I used to plan my days using Due dates. Planning to pick up supplies a the hardware store today? Set Due Date==Today. Need to call a friend back to catch up? Set Due Date==Today. This behavior makes sense, on one level level: just sort everything by Due date and you can [...]]]></description>
				<content:encoded><![CDATA[<p>Like many OmniFocus users, I used to plan my days using Due dates. Planning to pick up supplies a the hardware store today? Set Due Date==Today. Need to call a friend back to catch up? Set Due Date==Today. </p>

<p>This behavior makes sense, on one level level: just sort everything by Due date and you can see when things are planned. But every time a date isn&#8217;t met, it has to be pushed back, creating the need for <a href="http://bylr.net/3/2009/02/omnifocus-snooze-script/">most</a> of <a href="http://bylr.net/3/2008/02/omnifocus-defer-script/">my</a> <a href="http://bylr.net/3/2010/01/today-and-tomorrow-omnifocus-scripts/">date-related</a> <a href="http://bylr.net/3/2010/06/omnifocus-script-schedule-selected-items-for-this-weekend/">scripts</a>. </p>

<p><strong>Worse, indiscriminate use of Due dates dilutes their value and undermines any task-planning system.</strong></p>

<p>Need to pay a credit card bill today? It&#8217;s lost in the mess of other things that are artificially &#8220;due&#8221; today, and that red Due badge is no longer a respected indication that something <em>needs to happen today</em>.<a name="11Jul111-a"></a><sup><a href="#11Jul111-b">1</a></sup> </p>

<p>But there&#8217;s a better way.<a name="11Jul112-a"></a><sup><a href="#11Jul112-b">2</a></sup>  Just use Start Dates to plan what you <em>think you should do</em>, and reserve Due Dates for things that <em>actually have to get done</em>. (To keep this straight, I use a &#8220;Due&#8221; perspective to show what&#8217;s actually due, and a &#8220;Do&#8221; perspective to show what I&#8217;m planning to do.<a name="11Jul113-a"></a><sup><a href="#11Jul113-b">3</a></sup>)</p>

<p>The benefits of this approach are enormous. Things that actually need to happen don&#8217;t get lost in the shuffle, and (using <a href="http://bylr.net/3/2011/07/plan-your-day-better-with-omnifocus-time-estimates/">time estimates</a>) you can work with more realistic expectations of what can/should happen in a a day.</p>

<p>But switching to this workflow also required re-tooling my scripts, many of which focused on Due dates.</p>

<p>So, as of today, <strong>all my OmniFocus scripts default to a Start-based workflow.</strong> Here are some of the major changes:</p>

<ul>
<li><p><a href="http://bylr.net/3/2010/01/today-and-tomorrow-omnifocus-scripts/">Today</a>, <a href="http://bylr.net/3/2010/01/today-and-tomorrow-omnifocus-scripts/">Tomorrow</a>, and <a href="http://bylr.net/3/2010/06/omnifocus-script-schedule-selected-items-for-this-weekend/">This Weekend</a> all set the <em>Start date</em> of selected tasks by default.</p></li>
<li><p>In addition to pushing back due dates of tasks, <a href="http://bylr.net/3/2008/02/omnifocus-defer-script/">Defer</a> now has the option to act on un-timed tasks by pushing their start date back by the given number of days. (This option is on by default.)</p></li>
<li><p>All scripts now work when launched from the OmniFocus toolbar. </p></li>
<li><p>Scripts no longer fail when an OmniFocus grouping header is selected.</p></li>
<li><p>All scripts reorganized for performance and clarity.</p></li>
</ul>

<p>You can continue these scripts with a Due-based workflow, of course: this is a matter of changing a single setting in each script.<a name="11Jul114-a"></a><sup><a href="#11Jul114-b">4</a></sup> But if you&#8217;re successful with a Due-based workflow, you have much more discipline than me.</p>

<p>Download the lot of them <a href="https://github.com/dbyler/omnifocus-scripts/zipball/master">here</a>. (And as always, let me know if you have any problems with them.)</p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<hr />

<ol>
<li><p><a name="11Jul111-b"></a>Lest anyone complain of the cost of OmniFocus: I&#8217;m sure I&#8217;ve paid more money to my credit card company in day-of-due-date payment penalties than I have to the OmniGroup. <a href="#11Jul111-a">&#8617;</a> </p></li>
<li><p><a name="11Jul112-b"></a>Thanks to David Sparks and Benjamin Brooks for the insights that led to this realization. I mentioned this in a little more detail <a href="http://bylr.net/3/2011/07/plan-your-day-better-with-omnifocus-time-estimates/">here</a>. <a href="#11Jul112-a">&#8617;</a> </p></li>
<li><p><a name="11Jul113-b"></a>Here are the settings for my Do perspective: <br /><br /><img style="display:block; margin-left:auto; margin-right:auto;" src="http://bylr.net/3/wp-content/uploads/2011/07/Do-Perspective.jpg" alt="Do Perspective.jpg" title="Do Perspective.jpg" border="0" width="529" height="408" /><br />&#8230; and here are the settings for my &#8220;Due&#8221; perspective: <br /><br /><img style="display:block; margin-left:auto; margin-right:auto;" src="http://bylr.net/3/wp-content/uploads/2011/07/Due-Perspective.jpg" alt="Due Perspective.jpg" title="Due Perspective.jpg" border="0" width="530" height="413" /><br /> Both live in my toolbar for easy access.<a href="#11Jul113-a">&#8617;</a> </p></li>
<li><p><a name="11Jul114-b"></a>For example, in the Defer script, there is a line: &#8220;property snoozeUnscheduledItems : true. Simply open the script in AppleScript Editor and change &#8220;true&#8221; to &#8220;false&#8221; to switch this setting. If you have any problems, feel free to email me. <a href="#11Jul114-a">&#8617;</a> </p></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://bylr.net/3/2011/07/all-omnifocus-scripts-updated-for-a-start-based-workflow/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Plan your day better with OmniFocus time estimates</title>
		<link>http://bylr.net/3/2011/07/plan-your-day-better-with-omnifocus-time-estimates/</link>
		<comments>http://bylr.net/3/2011/07/plan-your-day-better-with-omnifocus-time-estimates/#comments</comments>
		<pubDate>Wed, 06 Jul 2011 20:07:05 +0000</pubDate>
		<dc:creator>Dan Byler</dc:creator>
				<category><![CDATA[OmniFocus]]></category>
		<category><![CDATA[productivity]]></category>

		<guid isPermaLink="false">http://bylr.net/3/?p=269</guid>
		<description><![CDATA[Confession: I usually fail to accomplish what I plan for a day. When the morning begins, big plans are in place&#8230; but at the end of the day, a pile of undone tasks lingers in my OmniFocus &#8220;Do&#8221; perspective.1 More often than not, they just get snoozed for the next day&#8217;s action list. And the [...]]]></description>
				<content:encoded><![CDATA[<p><img style="display:block; margin-left:auto; margin-right:auto;" src="http://bylr.net/3/wp-content/uploads/2011/07/Overbooked1.png" alt="Overbooked.png" title="Overbooked.png" border="0" width="444" height="135" /></p>

<p>Confession: I usually fail to accomplish what I plan for a day. When the morning begins, big plans are in place&#8230; but at the end of the day, a pile of undone tasks lingers in my OmniFocus &#8220;Do&#8221; perspective.<a name="a1"></a><sup><a href="#fn1">1</a></sup> More often than not, they just get snoozed for the next day&#8217;s action list.</p>

<p>And the process repeats. </p>

<p>It&#8217;s demoralizing to watch the Pile of Do grow, and I often feel out of control when looking at what seems like a reasonable list of things to accomplish in a day&#8217;s time. Clearly, good intentions need to be tempered by reasonable expectations.</p>

<p>Enter time estimates. Over the years I&#8217;ve been using OmniFocus, I&#8217;ve never really used its ability to assign a time estimate to projects and tasks. It seemed like a lot of effort for very little benefit: all OmniFocus really does with time estimates is sort/filter.<a name="a2"></a><sup><a href="#fn2">2</a></sup></p>

<p>But <em>time</em> is a critical dimension of doing: without time, there is no action. It should follow that time estimates are just as important.</p>

<p>So here is my new morning routine:</p>

<ol>
<li><p>Collect all actions I <em>want</em> to do today by assigning them a Start Date of today.</p></li>
<li><p>In &#8220;Do&#8221; perspective, assign time estimates to each item.</p></li>
<li><p>Check the total time of the day&#8217;s planned items; remove lowest priority items until my list is doable. (Use the <a href="/3/2011/07/omnifocus-script-get-total-time-of-selected-items/">Total time</a> and <a href="/3/2009/02/omnifocus-snooze-script/">Snooze</a> scripts to make this step easier.) </p></li>
</ol>

<p>This routine has several immediate benefits:</p>

<ol>
<li><p><strong>Assigning estimates forces you to clarify next actions.</strong> In cases where it was difficult to assign a time estimate, I realized I hadn&#8217;t clarified the next action well enough. Poorly defined next action → inaction.</p></li>
<li><p><strong>Using estimates helps clarify what is feasible for the day.</strong> This morning, my first pass included almost 14 hours&#8217; worth of work. Without time estimates, I wouldn&#8217;t have known how feasible this plan was.</p></li>
<li><p><strong>You can start right now.</strong> No need to assign estimates to everything in your OmniFocus database; just estimate what you&#8217;re looking at for <em>today</em>.</p></li>
</ol>

<p>Having seen how simple this process is, I&#8217;m shocked I didn&#8217;t do this years ago.</p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<hr />

<ol>
<li><p><a name="fn1"></a>I keep two perspectives side-by-side in my toolbar: &#8220;Due&#8221; and &#8220;Do&#8221;. <strong>Due</strong> shows tasks sorted by due date; these are items that really truly have to get done by the given date. <strong>Do</strong> shows tasks sorted by <em>start date</em>; these are the items that I plan to do on a given day. This gives me the benefit of some planning flexibility without the problems that come from recklessly using due dates. For more on this method, see <a href="http://www.macsparky.com/blog/2008/12/8/omnifocus-tips-the-omniscient-start-date.html">this David Sparks post</a>, which inspired me to use it. <a href="#a1">&#8617;</a></p></li>
<li><p><a name="fn2"></a>While OmniFocus doesn&#8217;t do much with estimates out of the box, there are some scripts that can do things like starting timers to keep you on task. See <a href="http://forums.omnigroup.com/showthread.php?t=16267&amp;highlight=timer">this discussion thread</a> for more info. <a href="#a2">&#8617;</a></p></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://bylr.net/3/2011/07/plan-your-day-better-with-omnifocus-time-estimates/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>OmniFocus script: Get total time of selected items</title>
		<link>http://bylr.net/3/2011/07/omnifocus-script-get-total-time-of-selected-items/</link>
		<comments>http://bylr.net/3/2011/07/omnifocus-script-get-total-time-of-selected-items/#comments</comments>
		<pubDate>Wed, 06 Jul 2011 20:03:33 +0000</pubDate>
		<dc:creator>Dan Byler</dc:creator>
				<category><![CDATA[applescript]]></category>
		<category><![CDATA[OmniFocus]]></category>
		<category><![CDATA[productivity]]></category>
		<category><![CDATA[script]]></category>

		<guid isPermaLink="false">http://bylr.net/3/?p=267</guid>
		<description><![CDATA[Update: If you downloaded the script before 18 July 2011, there was a bug that could cause an additional hour to be added to the time. That issue is fixed in the current version. Here&#8217;s a script to sum the total time of selected items in OmniFocus. Just select some items, fire it off and [...]]]></description>
				<content:encoded><![CDATA[<p><strong>Update: If you downloaded the script before 18 July 2011, there was a bug that could cause an additional hour to be added to the time. That issue is fixed in the current version.</strong></p>

<p><img style="display:block; margin-left:auto; margin-right:auto;" src="http://bylr.net/3/wp-content/uploads/2011/07/Total-Time.png" alt="Total Time.png" title="Total Time.png" border="0" width="300" height="61" /></p>

<p>Here&#8217;s a script to sum the total time of selected items in OmniFocus. Just select some items, fire it off and see how overcommitted you are.</p>

<p><a href="/files/omnifocus/Total%20Time.zip">Download it here.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://bylr.net/3/2011/07/omnifocus-script-get-total-time-of-selected-items/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Greasing-song of the escalator</title>
		<link>http://bylr.net/3/2011/06/greasing-song-of-the-escalator/</link>
		<comments>http://bylr.net/3/2011/06/greasing-song-of-the-escalator/#comments</comments>
		<pubDate>Sat, 25 Jun 2011 16:48:16 +0000</pubDate>
		<dc:creator>Dan Byler</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[misc]]></category>
		<category><![CDATA[sound]]></category>
		<category><![CDATA[travel]]></category>

		<guid isPermaLink="false">http://bylr.net/3/?p=264</guid>
		<description><![CDATA[The West Falls Church Metro station provides an unusual aural experience to D.C.-area commuters. As I entered the station last week, I thought I heard, in the following order: A pre-novice saxophonist assaulting commuters&#8217; ears with noise A highly skilled saxophonist assaulting commuters&#8217; ears with extended techniques Whale-song None of these guesses was correct, as [...]]]></description>
				<content:encoded><![CDATA[<p>The West Falls Church Metro station provides an unusual aural experience to D.C.-area commuters. As I entered the station last week, I thought I heard, in the following order:</p>

<ol>
<li>A pre-novice saxophonist assaulting commuters&#8217; ears with noise</li>
<li>A highly skilled saxophonist assaulting commuters&#8217; ears with extended techniques</li>
<li>Whale-song</li>
</ol>

<p>None of these guesses was correct, as it turns out. As I pulled out my phone to record the scene, it occurred to me that what sounded like the pained vocalizations of a large animal or aspiring musician might be neither.</p>

<p>It was the greasing-song of the downward escalator. Put another way: the escalator was groaning in need of maintenance.</p>

<p>After my train arrived, I inspected the recording to see if it followed any pattern. As the following image shows, it was distinctly periodic—and I had been able to catch almost three full cycles before my train arrived:</p>

<p><img style="display:block; margin-left:auto; margin-right:auto;" src="http://bylr.net/3/wp-content/uploads/2011/06/WFC-Escalator.png" alt="WFC Escalator.png" title="WFC Escalator.png" border="0" width="573" height="174" /></p>

<p>What&#8217;s more, the cycles are almost exactly 88.5 seconds long. D.C. locals will recognize this as the broadcast frequency of WAMU, American University&#8217;s radio station. Which leaves open the question: does the greasing-song represent a breakdown in maintenance, or is it a planned student art installation?</p>

<p>Listen here:</p>

<p><object height="81" width="100%"> <param name="movie" value="http://player.soundcloud.com/player.swf?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F17807467"/> <param name="allowscriptaccess" value="always"/> <embed allowscriptaccess="always" height="81" src="http://player.soundcloud.com/player.swf?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F17807467" type="application/x-shockwave-flash" width="100%"/> </object>  <span><a href="http://soundcloud.com/dbyler/greasing-song">Greasing-song</a> by <a href="http://soundcloud.com/dbyler">dbyler</a></span> </p>
]]></content:encoded>
			<wfw:commentRss>http://bylr.net/3/2011/06/greasing-song-of-the-escalator/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Archive messages with a single keystroke in Mail.app</title>
		<link>http://bylr.net/3/2011/03/archive-messages-with-a-single-keystroke-in-mail-app/</link>
		<comments>http://bylr.net/3/2011/03/archive-messages-with-a-single-keystroke-in-mail-app/#comments</comments>
		<pubDate>Mon, 21 Mar 2011 00:56:07 +0000</pubDate>
		<dc:creator>Dan Byler</dc:creator>
				<category><![CDATA[applescript]]></category>
		<category><![CDATA[productivity]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[mail]]></category>

		<guid isPermaLink="false">http://bylr.net/3/?p=253</guid>
		<description><![CDATA[Aug 2011 Lion update: the script works but is quite slow in Lion (it&#8217;s zippy in Snow Leopard). I&#8217;m looking for a workaround, but this appears to be a Mail.app bug. TL;DR version: Archive Mail messages with a single keystroke: Download this script and Fastscripts (free for up to 10 hotkeys) Move the script to [...]]]></description>
				<content:encoded><![CDATA[<blockquote>
  <p><em>Aug 2011 Lion update: the script works but is quite slow in Lion (it&#8217;s zippy in Snow Leopard). I&#8217;m looking for a workaround, but this appears to be a Mail.app bug.</em></p>
</blockquote>

<p><strong>TL;DR version:</strong> Archive Mail messages with a single keystroke:</p>

<ol>
<li>Download <a href="http://bylr.net/files/misc/Archive%20Selected%20Messages.scpt">this script</a> and <a href="http://www.red-sweater.com/fastscripts/">Fastscripts</a> (free for up to 10 hotkeys)</li>
<li>Move the script to ~/Library/Scripts/Applications/Mail/</li>
<li>Set your hotkey in Fastscripts (Using a letter key is possible but not recommended. Try another character like `\/=- or an F-Key.)</li>
</ol>

<p>The script will then move selected message(s) to a folder named &#8220;Archive&#8221;.</p>

<p><strong>More information:</strong></p>

<p>Existing shortcuts to file messages in Mail.app get you down to two or three keystrokes, but that just isn&#8217;t good enough for someone who has tasted the sweet, sweet bliss of single-keystroke archiving in Postbox or Gmail.</p>

<p>In my original reply to <a href="http://superuser.com/questions/179627/any-way-to-file-an-email-with-a-single-keystroke-in-mail-app">this superuser thread</a>, I suggested using an AppleScript to move selected messages to an archive, and triggering the script using a single-key shortcut using Fastscripts. That script is simple and straightforward, but it has a major shortcoming: it leaves you hanging with no next message selected, so you have to manually select your next message. Not ideal.</p>

<p>My new script archives messages with a bit more smarts. Here&#8217;s what it does:</p>

<ul>
<li><p>If a mailbox is in the foreground, the script moves selected messages to the folder named &#8220;Archive&#8221; and selects the next available message. Boom.</p></li>
<li><p>But you don&#8217;t want to accidentally archive messages whenever you hit your archive key. If the frontmost window isn&#8217;t a mailbox, the script will ignore the archiving functions and (optionally) type some text wherever you are. This is useful if you use a single key to trigger the script; without this function, you would never be able to type that key into a mail message because it&#8217;s intercepted by FastScripts before getting to the Compose window.</p></li>
</ul>

<p>For interested scripters, here were some challenges:</p>

<ul>
<li><p><strong>Select next message:</strong> The solutions I found online select the next message by sequential Message ID, which usually means that it only works if your mailbox is sorted by Date Received. Using <em>visible messages</em> gets messages in the order in which they&#8217;re displayed. Watch out, though: if message threading is turned on, the top-level thread item is not selectable. See my workaround in the script.</p></li>
<li><p><strong>Enter the keystroke that was captured:</strong> Merely telling System Events type the character that triggered the script will trigger the script again, resulting in a virtual infinite loop. I used a paste routine to work around this.</p></li>
</ul>

<p>That&#8217;s it&#8230; happy archiving!</p>

<p><em>22 Mar 2011 update: fixed bug that caused selection to be lost when only the topmost message in a mailbox is selected.</em></p>

<p><a href="http://bylr.net/files/misc/Archive%20Selected%20Messages.scpt"><img style="display:block; margin-left:auto; margin-right:auto;" src="http://bylr.net/3/wp-content/uploads/2011/03/applescripticon.gif" alt="applescripticon.gif" title="applescripticon.gif" border="0" width="60" height="49" />
<center>Download: Archive Selected Messages</center></a></p>
]]></content:encoded>
			<wfw:commentRss>http://bylr.net/3/2011/03/archive-messages-with-a-single-keystroke-in-mail-app/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Tools of the Trade: Learning Objective-C from Scratch</title>
		<link>http://bylr.net/3/2011/02/tools-of-the-trade-learning-objective-c-from-scratch/</link>
		<comments>http://bylr.net/3/2011/02/tools-of-the-trade-learning-objective-c-from-scratch/#comments</comments>
		<pubDate>Tue, 01 Mar 2011 03:23:20 +0000</pubDate>
		<dc:creator>Dan Byler</dc:creator>
				<category><![CDATA[tools]]></category>
		<category><![CDATA[development]]></category>

		<guid isPermaLink="false">http://bylr.net/3/?p=250</guid>
		<description><![CDATA[Learning a new language is never a simple task, but the process itself shouldn&#8217;t be difficult. For my Master&#8217;s final project, I&#8217;m teaching myself Objective-C. (More on our decision to go native here.) For those facing a similar task, here are some tools I&#8217;m using using to facilitate this process. Learning Materials I researched several [...]]]></description>
				<content:encoded><![CDATA[<p>Learning a new language is never a simple task, but the process itself shouldn&#8217;t be difficult. For my Master&#8217;s final project, I&#8217;m teaching myself Objective-C. (More on our decision to go native <a href="http://bit.ly/f52Nyx">here</a>.) For those facing a similar task, here are some tools I&#8217;m using using to facilitate this process.</p>

<h2>Learning Materials</h2>

<p>I researched several learning resources that had been recommended on Quora, including Big Nerd Ranch&#8217;s <em>iPhone Programming</em> and Craig Hockenberry&#8217;s <em>iPhone App Development: The Missing Manual</em>.</p>

<p>In the end, I decided to &#8220;take&#8221; the Stanford iPhone Application Development course, which is available in its entirety on iTunes U. (Note that iTunes U has both the <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewPodcast?id=384233222">2009</a> and <a href="http://itunes.apple.com/itunes-u/iphone-application-development/id384233225">2010</a> courses. I chose the 2010 version because a) it&#8217;s geared for a newer iOS SDK, and b) all the supporting materials are still (as of Spring 2011) available on Stanford&#8217;s <a href="http://www.stanford.edu/class/cs193p/">course website</a>.</p>

<p>iTunes handles the lecture downloads, but I watch them with QuickTime Player for two reasons: it uses less screen real estate, and you can speed up playback by option-clicking the fast-forward button. A text editor is ideal for notes (particularly one that handles Obj-C syntax highlighting), and it&#8217;s always handy to keep the lecture slides open as well. Here&#8217;s my typical &#8220;class time&#8221; screen:</p>

<p><img style="display:block; margin-left:auto; margin-right:auto;" src="http://bylr.net/3/wp-content/uploads/2011/02/Screen-shot-2011-02-27-at-10.29.51-PM.png" alt="Screen shot 2011-02-27 at 10.29.51 PM.png" title="Screen shot 2011-02-27 at 10.29.51 PM.png" border="0" width="600" height="375" /></p>

<p><strong>Helpful shortcuts:</strong></p>

<ul>
<li>Setting up the screen like this is a snap with <a href="http://www.mizage.com/divvy/">Divvy</a>. I set up shortcuts to move windows to each half or quadrant of the screen, so they can fly to any position with a keyboard shortcut. Priceless.</li>
<li>A series of quick-and-dirty AppleScripts—which can be quickly invoked with <a href="http://www.red-sweater.com/fastscripts/">FastScripts</a>—makes it easy to work the lecture files. Scripts I use (<a href="https://github.com/dbyler/misc-scripts">available on Github</a>) include:

<ul>
<li>launch the current iTunes file in QuickTime Player (or vice-versa), retaining the current playback spot</li>
<li>jump to an arbitrary playback position in QuickTime Player (especially helpful if I&#8217;ve been watching a video on my iPhone)</li>
<li>jump backwards or forwards in QuickTime Player</li>
</ul></li>
</ul>

<h2>Notekeeping</h2>

<p>Right now I keep two types of notes: course notes and error notes.</p>

<p><strong>Course notes</strong>—general notes from the lectures or books—go in a single text file that&#8217;s easily searchable. I type or copy most of the lecture slides into this document because it&#8217;s easier to have it all in one place.</p>

<p><strong>Error notes</strong>, which detail all the build errors I get in Xcode, live in Notational Velocity (tagged with &#8220;ObjC&#8221; and &#8220;Error&#8221;). Each error note contains the following sections:</p>

<ul>
<li>Error message</li>
<li>Context (anything that might help)</li>
<li>My code (specific code throwing the error, and which file)</li>
<li>Problem explanation (interpretation of what went wrong)</li>
<li>Solution (fixed code)</li>
</ul>

<p>These error notes are a personal history of the mistakes I&#8217;ve made. My expectation is that this practice will have value both now and in the future, but as the good folks at Field Notes say, &#8220;I&#8217;m not writing it down to remember it later, I&#8217;m writing it down to remember it now.&#8221; The more I can internalize beginner&#8217;s mistakes, the less likely I&#8217;ll be to repeat them.</p>

<p>My only complaint w/r/t using Notational Velocity for this purpose is that it doesn&#8217;t have syntax highlighting. A relatively minor inconvenience, but I&#8217;m hopeful that a future NValt build might include this.</p>

<p><strong>Helpful shortcut:</strong> I use a <a href="http://smilesoftware.com/TextExpander/">TextExpander</a> shortcut to pre-fill each error note before I start adding data. It simply adds each section&#8217;s header—something that might not seem that important, but it saves a little time and helps me be consistent in this practice.</p>

<h2>Troubleshooting</h2>

<p><a href="http://stackoverflow.com">Stack Overflow</a> is an indispensable Web site for programming questions/answers. I should probably get better at perusing Xcode documentation, but often it&#8217;s faster to search Stack Overflow. (I&#8217;ve noticed that most of my problems are answered in Stack Overflow questions with no upvotes, meaning that they&#8217;re beginner errors. I&#8217;ll know I&#8217;ve arrived when I graduate to more popular questions!)</p>

<p><strong>Helpful shortcut:</strong> Searching Stack Overflow is nearly instantaneous using a <a href="http://www.obdev.at/products/launchbar/">LaunchBar</a> <a href="http://www.obdev.at/resources/launchbar/help/SearchTemplates.html">search template</a> set to search StackOverflow with the [Objective C] tag pre-filled. Once it&#8217;s set up, ⌘[space] → &#8220;so&#8221; → [query] gets it done <em>pronto</em>.</p>
]]></content:encoded>
			<wfw:commentRss>http://bylr.net/3/2011/02/tools-of-the-trade-learning-objective-c-from-scratch/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Zenburn theme for OmniFocus</title>
		<link>http://bylr.net/3/2011/01/zenburn-theme-for-omnifocus/</link>
		<comments>http://bylr.net/3/2011/01/zenburn-theme-for-omnifocus/#comments</comments>
		<pubDate>Sun, 02 Jan 2011 09:37:52 +0000</pubDate>
		<dc:creator>Dan Byler</dc:creator>
				<category><![CDATA[OmniFocus]]></category>

		<guid isPermaLink="false">http://bylr.net/3/?p=241</guid>
		<description><![CDATA[Here&#8217;s a draft Zenburn-based theme for OmniFocus. Due to some limitations of the theming engine, some of the status indicators (repeating, flagged, etc.) are displayed as grey-on-grey and are therefore somewhat difficult to read. Otherwise it&#8217;s quite usable. Download it here.]]></description>
				<content:encoded><![CDATA[<p>Here&#8217;s a draft Zenburn-based theme for OmniFocus. Due to some limitations of the theming engine, some of the status indicators (repeating, flagged, etc.) are displayed as grey-on-grey and are therefore somewhat difficult to read. Otherwise it&#8217;s quite usable. <a href="http://bylr.net/files/omnifocus/ZenBurn.zip">Download it here.</a></p>

<p><img style="display:block; margin-left:auto; margin-right:auto;" src="http://bylr.net/3/wp-content/uploads/2011/01/Zenburn.png" alt="Zenburn.png" title="Zenburn.png" border="0" width="600" height="312" /></p>
]]></content:encoded>
			<wfw:commentRss>http://bylr.net/3/2011/01/zenburn-theme-for-omnifocus/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Stata bundle for TextMate</title>
		<link>http://bylr.net/3/2010/10/stata-bundle-for-textmate/</link>
		<comments>http://bylr.net/3/2010/10/stata-bundle-for-textmate/#comments</comments>
		<pubDate>Tue, 12 Oct 2010 20:38:48 +0000</pubDate>
		<dc:creator>Dan Byler</dc:creator>
				<category><![CDATA[software]]></category>
		<category><![CDATA[tools]]></category>
		<category><![CDATA[textmate]]></category>

		<guid isPermaLink="false">http://bylr.net/3/?p=221</guid>
		<description><![CDATA[Rumor has it that there&#8217;s an extant Stata bundle for TextMate. The original package link is a dead, but Gabriel Rossman was kind enough to send me a copy of his installed bundle. With thanks to the author, Timothy Beatty, here&#8217;s the original bundle: Stata bundle (original) For those wanting a little extra functionality, George [...]]]></description>
				<content:encoded><![CDATA[<p><a href="http://www.maconomics.net/?p=44">Rumor</a> has it that there&#8217;s an extant Stata bundle for TextMate. The <a href="http://www-users.york.ac.uk/~tb526/Stata.tmbundle.zip">original package</a> link is a dead, but <a href="http://codeandculture.wordpress.com/2009/12/01/r-and-textmate/">Gabriel Rossman</a> was kind enough to send me a copy of his installed bundle.</p>

<p>With thanks to the author, Timothy Beatty, here&#8217;s the original bundle:</p>

<p><a href="http://bylr.net/3/wp-content/uploads/2010/10/Stata.tmbundle.zip"><img src="http://bylr.net/3/wp-content/uploads/2010/10/logo_bundle.png" alt="Download Stata Bundle" title="Download Stata Bundle" width="50" height="51" class="aligncenter size-full wp-image-222" /><center>Stata bundle (original)</center></a></p>

<p>For those wanting a little extra functionality, George MacKerron <a href="http://blog.mackerron.com/2010/02/stata-textmate-tab-completion/">described a method</a> to add tab-completion for Stata variables. I&#8217;ve added his code to this version of the Stata bundle. (N.B. If your Stata application is not named &#8220;Stata&#8221;, you&#8217;ll need to make one small change. Open TextMate&#8217;s Bundle Editor; then, in the Stata bundle&#8217;s Complete Variable command, change the &#8220;appname&#8221; variable in line 6 to reflect your app&#8217;s true name, e.g. &#8220;StataMP&#8221;.)</p>

<p><a href="http://bylr.net/3/wp-content/uploads/2010/10/Stata-tab.tmbundle.zip"><img src="http://bylr.net/3/wp-content/uploads/2010/10/logo_bundle.png" alt="Download Stata Bundle with tab-completion" title="Download Stata Bundle with Tab-Completion" width="50" height="51" class="aligncenter size-full wp-image-222" /><center>Stata bundle (with tab-completion)</center></a></p>

<p><b>Update:</b> I&#8217;ve learned that two forward slashes can also be used in Stata for comments, including inline comments. To properly highlight this in Textmate, open the Bundle Editor > Stata > Stata. At the end of this file is the &#8216;comment.line.star.stata&#8217;. Change the match line to this:</p>

<div class="codesnip-container" >match = &#8216;((^|\s)\*|//).*$&#8217;;</div>

<p>(N.B. As Sean points out below, make sure the single-quotes are straight, not curly, when you paste this line. Otherwise TextMate will throw an error.)</p>
]]></content:encoded>
			<wfw:commentRss>http://bylr.net/3/2010/10/stata-bundle-for-textmate/feed/</wfw:commentRss>
		<slash:comments>33</slash:comments>
		</item>
		<item>
		<title>Billion Day</title>
		<link>http://bylr.net/3/2010/09/billion-day/</link>
		<comments>http://bylr.net/3/2010/09/billion-day/#comments</comments>
		<pubDate>Mon, 27 Sep 2010 04:46:29 +0000</pubDate>
		<dc:creator>Dan Byler</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[date]]></category>
		<category><![CDATA[holiday]]></category>
		<category><![CDATA[number]]></category>

		<guid isPermaLink="false">http://bylr.net/3/?p=219</guid>
		<description><![CDATA[While studying in Oxford seven years ago—most likely in a fit of procrastination—I determined that the word billion can be spelled on a telephone keypad with the number 245-5466. As it turns out, 2455466 was also the Julian date of a certain September day in [the then-distant future year] 2010. I put a reminder in [...]]]></description>
				<content:encoded><![CDATA[<p>While studying in Oxford seven years ago—most likely in a fit of procrastination—I determined that the word <em>billion</em> can be spelled on a telephone keypad with the number 245-5466. As it turns out, 2455466 was also the <a href="http://en.wikipedia.org/wiki/Julian_day">Julian date</a> of a certain September day in [the then-distant future year] 2010. I put a reminder in my Palm V and forgot about it. Thanks to an electronic calendar that doesn&#8217;t forget, I was just reminded&#8230;</p>

<p><em>That day is today.</em></p>

<p>Happy Billion Day, everyone!</p>

<p>(One could discount this event by pointing out it&#8217;s only the coincidence of a) Julius Caesar&#8217;s arbitrary selection of the calendar&#8217;s start date, as well as b) the arbitrary—though now <a href="http://en.wikipedia.org/wiki/E.161">standardized</a>—mapping of Latin letters to the 10-digit keypad. I suppose we could also cite the rise of the decimal numeral system in this celebration as well; who knows what <em>billion</em> would map to on a hexadecimal phone keypad, or if we&#8217;d even care since 1,000,000,000 is much less elegant as 3B9ACA00 in hex. Then again, many of our declared holidays aren&#8217;t much less arbitrary.)</p>
]]></content:encoded>
			<wfw:commentRss>http://bylr.net/3/2010/09/billion-day/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk: basic
Page Caching using disk: enhanced
Database Caching using disk: basic
Object Caching 842/995 objects using disk: basic

 Served from: bylr.net @ 2013-05-18 14:54:44 by W3 Total Cache -->