<?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>Brett Terpstraapplescript page  - Brett Terpstra</title>
	<atom:link href="http://brettterpstra.com/tag/applescript/feed/" rel="self" type="application/rss+xml" />
	<link>http://brettterpstra.com</link>
	<description>Elegant solutions to complex problems.</description>
	<lastBuildDate>Tue, 22 May 2012 02:49:10 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>Desktop countdown timer with GeekTool and AppleScript</title>
		<link>http://brettterpstra.com/desktop-countdown-timer-with-geektool-and-applescript/</link>
		<comments>http://brettterpstra.com/desktop-countdown-timer-with-geektool-and-applescript/#comments</comments>
		<pubDate>Sun, 15 Apr 2012 22:50:43 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[applescript]]></category>
		<category><![CDATA[geeklet]]></category>
		<category><![CDATA[geektool]]></category>
		<category><![CDATA[productivity]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=3930</guid>
		<description><![CDATA[<p>I just realized today, quite belatedly, that you can control GeekTool on your Mac with AppleScript. I just wanted to play around with it a bit, so I threw together a countdown timer. This could be done much more elegantly, I’m sure; I just wanted to see what I could pull off quickly. The script takes an argument ending in&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/desktop-countdown-timer-with-geektool-and-applescript/">Desktop countdown timer with GeekTool and AppleScript</a></p>]]></description>
			<content:encoded><![CDATA[<p><img style=' display: block; margin-right: auto; margin-left: auto;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2012/04/DoSomethingInteresting.jpg?9d7bd4" alt="" title="DoSomethingInteresting" width="650" height="209" class="aligncenter size-full wp-image-3931" /></p>

<p>I just realized today, quite belatedly, that you can control <a href="http://itunes.apple.com/us/app/geektool/id456877552?mt=12">GeekTool</a> on your Mac with AppleScript. I just wanted to play around with it a bit, so I threw together a countdown timer. This could be done much more elegantly, I’m sure; I just wanted to see what I could pull off quickly.</p>

<p>The script takes an argument ending in an integer (interpreted as minutes), or a colon-separated hour/minutes argument. The last argument is always the time from <em>now</em>. For example <code>Pick up the kids 1:30</code> would set a timer for an hour and 30 minutes from now. <code>Feed the fish 10</code> would set a timer to go off in 10 minutes.</p>

<p>The script calculates the target time and then runs a loop every second to update a GeekTool shell geeklet with the countdown timer. Yes, you could probably do this more efficiently by making use of the Geeklet’s interval property, but… meh, I don’t have an excuse. I kind of thought of that after writing the script. It’s Sunday, lay off.</p>

<p>If you want to play with it, you need to have GeekTool installed and running. Create a Shell Geeklet by dragging the shell icon to your desktop from the GeekTool window. In the properties for the geeklet, name it “GeekTimer” and leave the timeout and refresh values at zero. Size it so that it’s the full width of your screen, set the paragraph justification to centered, pick a font/color and make it as large as you want.</p>

<p><span id="more-3930"></span></p>

<p>Now, save the AppleScript below as a file called <code>geektooltimer</code> somewhere on your drive. Wherever you put it, you’ll need to adjust any commands that call it to match your own path.</p>

<h3>The AppleScript</h3>

<pre><code>#!/usr/bin/osascript

on padNum(_num)
    if _num &lt; 10 then set _num to "0" &amp; _num
    return _num
end padNum

on run argv
    set message to item 1 of argv

    tell application "GeekTool Helper" to set command of shell geeklet named "GeekTimer" to "echo"

    set {astid, AppleScript's text item delimiters} to {AppleScript's text item delimiters, " "}
    set _task to text items 1 thru ((count of text items of message) - 1) of message as string
    set _min to last item of text items of message
    if (offset of ":" in _min) &gt; 0 then
        set AppleScript's text item delimiters to ":"
        set _min to (item 1 of text items of _min) * 60 + (item 2 of text items of _min)
    end if
    set AppleScript's text item delimiters to astid

    set _date to current date
    set _target to (_date + (_min * 60))
    repeat
        set timeLeft to (_target - (current date))
        set minLeft to round timeLeft / 60 rounding down
        if minLeft &gt; 60 then
            set minLeft to (round minLeft / 60 rounding down) &amp; ":" &amp; padNum(minLeft mod 60)
        else
            set minLeft to padNum(minLeft)
        end if
        set secLeft to padNum(timeLeft mod 60)
        tell application "GeekTool Helper"
            set command of shell geeklet named "GeekTimer" to "echo \"" &amp; _task &amp; " in " &amp; minLeft &amp; ":" &amp; secLeft &amp; "\""

            if (current date) ≥ _target then
                do shell script "/usr/bin/afplay /System/Library/Sounds/Glass.aiff"
                set command of shell geeklet named "GeekTimer" to "echo \"Time to " &amp; _task &amp; "\""
                return "Time to " &amp; _task
            end if
        end tell
        delay 1
    end repeat
end run
</code></pre>

<p>Note that the hashbang at the beginning will let you make it executable and call it without <code>osascript</code>, but I used <code>osascript</code> in the methods below just to be safe.</p>

<p>When the timer is up, it will use <code>afplay</code> to ring a bell and set the final text of the Geeklet to your reminder title. I’m pretty sure <code>afplay</code> is included in a standard install, but if you run into issues just remove that line or substitute your own alert method.</p>

<h3>As a Bash function</h3>

<p>I’m mostly calling this script from the command line. I added a function to <code>~/.bash_profile</code> that looks like this:</p>

<pre><code>## GeekTool Timer
# `gtt Pick up the kids 1:30` sets a timer for 1 hour and 30 minutes
# `gtt Feed the fish 10` will set a timer for 10 minutes
# Running `gtt` with no arguments will clear the running timer and exit
gtt() {
    # if a timer is running, kill it
    pid=$(ps ax | grep -E "osascript .*/geektooltimer" | grep -v grep | awk '{print $1}')
    [[ $pid ]] &amp;&amp; kill $pid
    # Clear any existing text
    /usr/bin/osascript -e 'tell application "GeekTool Helper" to set command of shell geeklet named "GeekTimer" to "echo"'
    # if there are arguments, run the script with them. 
    if [[ $# -gt 0 ]]; then
        /usr/bin/osascript ~/scripts/geektooltimer "$*" 2&gt;&amp;1 &amp;
    fi
}
</code></pre>

<p>Drop that into your <code>~/.bash_profile</code> and run <code>source ~/.bash_profile</code>. Now, in combination with the previous AppleScript, you have a <code>gtt</code> command for setting timers on your desktop from Terminal. Be sure to modify the path in the last command (the one that calls <code>geektooltimer</code>) to match the location of the AppleScript you created.</p>

<p>The function first checks to see if a timer is already running, and if so, kills it. Then it clears any text currently in the “GeekTimer” Geeklet, and then runs the AppleScript and passes all command line arguments as one quoted string. The <code>geektoolreminder</code> script handles parsing out the last number and turns the preceding text into the reminder title. Running just <code>gtt</code> without any arguments will clear the current timer.</p>

<p>There’s not a lot of error checking involved, so incorrect parameters will throw errors on the command line. Feel free to spiff it up.</p>

<h3>As a Launchbar (or Alfred or whatever) action</h3>

<p>You can also call the script from <a href="http://www.obdev.at/products/launchbar/index.html">Launchbar</a> by creating an action like:</p>

<pre><code>on handle_string(message)
    do shell script "/Users/ttscoff/scripts/geektooltimer '" &amp; message &amp; "' &amp;"
end handle_string
</code></pre>

<p>Name the action “GeekTool Reminder” (save it in ~/Library/Application Support/Launchbar/Actions/GeekTool Reminder.scpt). You’ll call it up by popping up Launchbar and typing “GTR” or similar, then pressing space. Enter the text of the reminder and end it with a minute or hour:minute designation. Minor catch: execute it with Option-Return to run it in the background, otherwise Launchbar will freeze until the timer is up.</p>

<p>In Alfred you can probably make a straight shell script that runs in the background automatically, so it would be more in line with the Bash function above than with the Launchbar AppleScript method.</p>

<hr />

<p>What I’m hoping is that this example will get a ball rolling, and someone will see a little bit more exciting potential in it than I came up with on a lazy Sunday. Got a cool AppleScript (or even an idea) for GeekTool? I’d love to hear about it!</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/geeklet-1-minute-average-cpu-load/' rel='bookmark' title='Geeklet: 1-minute average CPU load'>Geeklet: 1-minute average CPU load</a></li>
<li><a href='http://brettterpstra.com/imagemagick-and-geektool-or-nerdtool/' rel='bookmark' title='ImageMagick and GeekTool (or NerdTool)'>ImageMagick and GeekTool (or NerdTool)</a></li>
<li><a href='http://brettterpstra.com/geeklets-weather-and-forecast/' rel='bookmark' title='Geeklets: weather and forecast'>Geeklets: weather and forecast</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/desktop-countdown-timer-with-geektool-and-applescript/">Desktop countdown timer with GeekTool and AppleScript</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/desktop-countdown-timer-with-geektool-and-applescript/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Log TaskPaper archives to Day One</title>
		<link>http://brettterpstra.com/log-taskpaper-archives-to-day-one/</link>
		<comments>http://brettterpstra.com/log-taskpaper-archives-to-day-one/#comments</comments>
		<pubDate>Fri, 24 Feb 2012 01:38:34 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[applescript]]></category>
		<category><![CDATA[dayone]]></category>
		<category><![CDATA[logging]]></category>
		<category><![CDATA[productivity]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=3701</guid>
		<description><![CDATA[<p>I wrote a while back about some Day One geekery, and shared the git wrapper I set up for bagging some of my larger commit messages to Day One entries automatically. Then Rob went and asked me if I could do something similar with TaskPaper, logging archived tasks to Day One on the fly. Had to try it. I built&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/log-taskpaper-archives-to-day-one/">Log TaskPaper archives to Day One</a></p>]]></description>
			<content:encoded><![CDATA[<p><img style=' display: block; margin-right: auto; margin-left: auto;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2012/02/day_one_plus_taskpaper.jpg?9d7bd4" alt="Day One plus TaskPaper" height="220" width="640" class="aligncenter" ></p>

<p>I wrote a while back about some <a href="http://brettterpstra.com/logging-with-day-one-geek-style/">Day One geekery</a>, and shared the git wrapper I set up for bagging some of my larger commit messages to Day One entries automatically. Then <a href="https://twitter.com/#!/ruminatr">Rob</a> went and asked me if I could <a href="http://twitter.com/ruminatr/status/172192725758771200">do something similar</a> with <a href="http://www.hogbaysoftware.com/products/taskpaper">TaskPaper</a>, logging archived tasks to <a href="http://dayoneapp.com/">Day One</a> on the fly. Had to try it.</p>

<p>I built the script using the newer query syntax, and I find it a little more stable than the old project-by-project parsing method (nice work, Jesse). To use it, you just need a TaskPaper document with at least one project and an “Archive:” section, and Day One with the <a href="http://dayoneapp.com/faq/#commandlineinterface">CLI tool installed</a>.</p>

<ul>
<li>Using the frontmost document in TaskPaper, it grabs all the @done tasks<sup id="fnref:done"><a href="#fn:done" rel="footnote">1</a></sup> (with or without a date) that aren’t already in the “Archive” project for processing. </li>
<li>It goes through a few of my common “in-process” tags (@na, @priority, @waiting) and removes them if they exist on a @done task (they’re meaningless after completion). </li>
<li>Then it looks to see if there’s a @project tag, and if not, it adds one for the project the task was in when it was archived (I think this is default TaskPaper behavior…). </li>
<li>The full text content of each task (complete with Markdown-style list delimiter and all of the project/date tags you’d want in a log entry) is added to a string. </li>
<li>Each @done task is then moved to the “Archive” project. </li>
<li>The name of the parent file and the list of all the tasks you just archived are sent as a single entry to Day One using the <code>dayone</code> CLI tool.</li>
</ul>

<p><span id="more-3701"></span></p>

<p>I’m not certain that the end results of using this are superior to logging commit messages. With commit messages I’m talking about what I just did and noting any issues; just being more verbose in general. This technique is a really convenient way to log, though, if you’re already a TaskPaper (and Day One) user, and works perfectly as a supplement to other logging methods.</p>

<p>As you archive your tasks, they get dropped into a calendar view in ready-to-display Markdown format. It’s faster and prettier than to trying to maintain and sort archives of finished tasks in TaskPaper. Given that this is pretty much automatic in my current workflow, I’m just going to let both logging systems churn for a while and see if one or the other isn’t pulling its weight.</p>

<p>The script is thoroughly commented. Probably unnecessarily so for such a short task (I’m pretty sure there’s more comment than code in there). See below for brief installation instructions, and <a href="applescript://com.apple.scripteditor?action=new&amp;script=set%20archivedTasks%20to%20%22%22%0Atell%20application%20%22TaskPaper%22%0A%09tell%20front%20document%0A%09%09--%20don't%20care%20which%20file%20your%20log%20entry%20came%20from?%0A%09%09--%20comment%20the%20next%20line%20out%0A%09%09set%20archivedTasks%20to%20%22%23%23%20%22%20&amp;%20name%20&amp;%20return%0A%09%09repeat%20with%20_task%20in%20search%20with%20query%20%22project%20!=%20Archive%20and%20@done%22%0A%09%09%09if%20entry%20type%20of%20_task%20is%20not%20project%20type%20then%0A%09%09%09%09--%20remove%20common%20tags%20that%20won't%20matter%20after%20archiving%0A%09%09%09%09repeat%20with%20_tag%20in%20%7B%22na%22,%20%22next%22,%20%22priority%22,%20%22waiting%22%7D%0A%09%09%09%09%09if%20exists%20(tag%20named%20_tag%20of%20_task)%20then%20delete%20tag%20named%20_tag%20of%20_task%0A%09%09%09%09end%20repeat%0A%09%09%09%09--%20if%20there's%20no%20project%20tag%20on%20the%20task,%20%0A%09%09%09%09--%20add%20the%20task's%20current%20project%20as%20a%20tag%0A%09%09%09%09if%20not%20(exists%20(tag%20named%20%22project%22%20of%20_task))%20then%0A%09%09%09%09%09tell%20_task%20to%20make%20tag%20with%20properties%20%7Bname:%22project%22,%20value:(name%20of%20containing%20project%20of%20_task%20as%20rich%20text)%7D%0A%09%09%09%09end%20if%0A%09%09%09%09--%20append%20the%20full%20text%20of%20the%20entry,%20including%20tags,%20to%20our%20log%0A%09%09%09%09set%20archivedTasks%20to%20archivedTasks%20&amp;%20(text%20line%20of%20_task)%0A%09%09%09%09--%20archive%20it%0A%09%09%09%09move%20entry%20id%20(id%20of%20_task)%20to%20beginning%20of%20entries%20of%20project%20%22Archive%22%0A%09%09%09end%20if%0A%09%09end%20repeat%0A%09end%20tell%0Aend%20tell%0A--%20send%20the%20accumulated%20results%20to%20Day%20One%20via%20the%20command%20line%20tool%0A--%20http://dayoneapp.com/faq/%23commandlineinterface%0A--%20You'll%20need%20to%20run%20%60ln%20-s%20%22/Applications/Day%20One/Day%20One.app/Contents/MacOS/dayone%22%20/usr/local/bin/dayone%60%20to%20have%20it%20accessible%20at%20this%20path%0Ado%20shell%20script%20%22echo%20%22%20&amp;%20(quoted%20form%20of%20archivedTasks)%20&amp;%20%22%7Ctr%20-d%20%5C%22%5C%5Ct%5C%22%7C/usr/local/bin/dayone%20new%22">click here to open it directly in AppleScript Editor</a>.</p>


<div class="wp_syntax"><div class="code"><pre class="applescript"><span class="kw3">set</span> archivedTasks <span class="kw3">to</span> <span class="st0">&quot;&quot;</span>
<span class="kw3">tell</span> <span class="kw1">application</span> <span class="st0">&quot;TaskPaper&quot;</span>
	<span class="kw3">tell</span> <span class="kw2">front</span> <span class="kw1">document</span>
		<span class="co1">-- don't care which file your log entry came from?</span>
		<span class="co1">-- comment the next line out</span>
		<span class="kw3">set</span> archivedTasks <span class="kw3">to</span> <span class="st0">&quot;## &quot;</span> <span class="sy0">&amp;</span> <span class="kw1">name</span> <span class="sy0">&amp;</span> <span class="kw3">return</span>
		<span class="kw3">repeat</span> <span class="kw3">with</span> _task <span class="kw3">in</span> search <span class="kw3">with</span> query <span class="st0">&quot;project != Archive and @done&quot;</span>
			<span class="kw3">if</span> entry type <span class="kw3">of</span> _task <span class="kw3">is</span> <span class="kw2">not</span> project type <span class="kw3">then</span>
				<span class="co1">-- remove common tags that won't matter after archiving</span>
				<span class="kw3">repeat</span> <span class="kw3">with</span> _tag <span class="kw3">in</span> <span class="br0">&#123;</span><span class="st0">&quot;na&quot;</span>, <span class="st0">&quot;next&quot;</span>, <span class="st0">&quot;priority&quot;</span>, <span class="st0">&quot;waiting&quot;</span><span class="br0">&#125;</span>
					<span class="kw3">if</span> <span class="kw1">exists</span> <span class="br0">&#40;</span>tag <span class="kw2">named</span> _tag <span class="kw3">of</span> _task<span class="br0">&#41;</span> <span class="kw3">then</span> <span class="kw1">delete</span> tag <span class="kw2">named</span> _tag <span class="kw3">of</span> _task
				<span class="kw3">end</span> <span class="kw3">repeat</span>
				<span class="co1">-- if there's no project tag on the task, </span>
				<span class="co1">-- add the task's current project as a tag</span>
				<span class="kw3">if</span> <span class="kw2">not</span> <span class="br0">&#40;</span><span class="kw1">exists</span> <span class="br0">&#40;</span>tag <span class="kw2">named</span> <span class="st0">&quot;project&quot;</span> <span class="kw3">of</span> _task<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw3">then</span>
					<span class="kw3">tell</span> _task <span class="kw3">to</span> <span class="kw1">make</span> tag <span class="kw3">with</span> <span class="kw1">properties</span> <span class="br0">&#123;</span><span class="kw1">name</span>:<span class="st0">&quot;project&quot;</span>, value:<span class="br0">&#40;</span><span class="kw1">name</span> <span class="kw3">of</span> containing project <span class="kw3">of</span> _task <span class="kw2">as</span> rich <span class="kw1">text</span><span class="br0">&#41;</span><span class="br0">&#125;</span>
				<span class="kw3">end</span> <span class="kw3">if</span>
				<span class="co1">-- append the full text of the entry, including tags, to our log</span>
				<span class="kw3">set</span> archivedTasks <span class="kw3">to</span> archivedTasks <span class="sy0">&amp;</span> <span class="br0">&#40;</span><span class="kw1">text</span> line <span class="kw3">of</span> _task<span class="br0">&#41;</span>
				<span class="co1">-- archive it</span>
				<span class="kw1">move</span> entry <span class="kw1">id</span> <span class="br0">&#40;</span><span class="kw1">id</span> <span class="kw3">of</span> _task<span class="br0">&#41;</span> <span class="kw3">to</span> <span class="kw2">beginning</span> <span class="kw3">of</span> entries <span class="kw3">of</span> project <span class="st0">&quot;Archive&quot;</span>
			<span class="kw3">end</span> <span class="kw3">if</span>
		<span class="kw3">end</span> <span class="kw3">repeat</span>
	<span class="kw3">end</span> <span class="kw3">tell</span>
<span class="kw3">end</span> <span class="kw3">tell</span>
<span class="co1">-- send the accumulated results to Day One via the command line tool</span>
<span class="co1">-- http://dayoneapp.com/faq/#commandlineinterface</span>
<span class="co1">-- You'll need to run `ln -s &quot;/Applications/Day One/Day One.app/Contents/MacOS/dayone&quot; /usr/local/bin/dayone` to have it accessible at this path</span>
<span class="kw1">do shell script</span> <span class="st0">&quot;echo &quot;</span> <span class="sy0">&amp;</span> <span class="br0">&#40;</span><span class="kw1">quoted form</span> <span class="kw3">of</span> archivedTasks<span class="br0">&#41;</span> <span class="sy0">&amp;</span> <span class="st0">&quot;|tr -d <span class="es0">\&quot;</span><span class="es0">\\</span>t<span class="es0">\&quot;</span>|/usr/local/bin/dayone new&quot;</span></pre></div></div>


<p>Just copy the script into AppleScript Editor (or click the handy <a href="applescript://com.apple.scripteditor?action=new&amp;script=set%20archivedTasks%20to%20%22%22%0Atell%20application%20%22TaskPaper%22%0A%09tell%20front%20document%0A%09%09--%20don't%20care%20which%20file%20your%20log%20entry%20came%20from?%0A%09%09--%20comment%20the%20next%20line%20out%0A%09%09set%20archivedTasks%20to%20%22%23%23%20%22%20&amp;%20name%20&amp;%20return%0A%09%09repeat%20with%20_task%20in%20search%20with%20query%20%22project%20!=%20Archive%20and%20@done%22%0A%09%09%09if%20entry%20type%20of%20_task%20is%20not%20project%20type%20then%0A%09%09%09%09--%20remove%20common%20tags%20that%20won't%20matter%20after%20archiving%0A%09%09%09%09repeat%20with%20_tag%20in%20%7B%22na%22,%20%22next%22,%20%22priority%22,%20%22waiting%22%7D%0A%09%09%09%09%09if%20exists%20(tag%20named%20_tag%20of%20_task)%20then%20delete%20tag%20named%20_tag%20of%20_task%0A%09%09%09%09end%20repeat%0A%09%09%09%09--%20if%20there's%20no%20project%20tag%20on%20the%20task,%20%0A%09%09%09%09--%20add%20the%20task's%20current%20project%20as%20a%20tag%0A%09%09%09%09if%20not%20(exists%20(tag%20named%20%22project%22%20of%20_task))%20then%0A%09%09%09%09%09tell%20_task%20to%20make%20tag%20with%20properties%20%7Bname:%22project%22,%20value:(name%20of%20containing%20project%20of%20_task%20as%20rich%20text)%7D%0A%09%09%09%09end%20if%0A%09%09%09%09--%20append%20the%20full%20text%20of%20the%20entry,%20including%20tags,%20to%20our%20log%0A%09%09%09%09set%20archivedTasks%20to%20archivedTasks%20&amp;%20(text%20line%20of%20_task)%0A%09%09%09%09--%20archive%20it%0A%09%09%09%09move%20entry%20id%20(id%20of%20_task)%20to%20beginning%20of%20entries%20of%20project%20%22Archive%22%0A%09%09%09end%20if%0A%09%09end%20repeat%0A%09end%20tell%0Aend%20tell%0A--%20send%20the%20accumulated%20results%20to%20Day%20One%20via%20the%20command%20line%20tool%0A--%20http://dayoneapp.com/faq/%23commandlineinterface%0A--%20You'll%20need%20to%20run%20%60ln%20-s%20%22/Applications/Day%20One/Day%20One.app/Contents/MacOS/dayone%22%20/usr/local/bin/dayone%60%20to%20have%20it%20accessible%20at%20this%20path%0Ado%20shell%20script%20%22echo%20%22%20&amp;%20(quoted%20form%20of%20archivedTasks)%20&amp;%20%22%7Ctr%20-d%20%5C%22%5C%5Ct%5C%22%7C/usr/local/bin/dayone%20new%22">link</a>) and save it as a compiled script in <code>~/Library/Scripts/Applications/TaskPaper</code> (creating the folder if it’s not there). If you have the AppleScript menubar item enabled in AppleScript Editor preferences, you’ll be able to access the script from within TaskPaper. It’s really only convenient if you have a hotkey, though. Keyboard Maestro, FastScripts, Launchbar, System Preferences… whatever your poison, just make it easy.</p>

<p>Again, you’ll need to have the <code>dayone</code> CLI tool linked to <code>/usr/local/bin/dayone</code> (or modify the path in the script). If you have Day One installed in the standard /Applications directory, just run this in Terminal:</p>

<pre><code>ln -s "/Applications/Day One/Day One.app/Contents/MacOS/dayone" /usr/local/bin/dayone
</code></pre>

<p>Thanks for the idea, Rob!</p>

<div class="footnotes">
<hr />
<ol>

<li id="fn:done">
<p>⌘D, but you knew that. <a href="#fnref:done" rev="footnote">↩</a></p>
</li>

</ol>
</div>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/automating-taskpaper-to-day-one-logs/' rel='bookmark' title='Automating TaskPaper to Day One logs'>Automating TaskPaper to Day One logs</a></li>
<li><a href='http://brettterpstra.com/a-few-scripts-for-taskpaper-users/' rel='bookmark' title='A few scripts for TaskPaper users'>A few scripts for TaskPaper users</a></li>
<li><a href='http://brettterpstra.com/totally-taskpaper/' rel='bookmark' title='Totally TaskPaper'>Totally TaskPaper</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/log-taskpaper-archives-to-day-one/">Log TaskPaper archives to Day One</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/log-taskpaper-archives-to-day-one/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Connecting nvALT and Address Book</title>
		<link>http://brettterpstra.com/connecting-nvalt-and-address-book/</link>
		<comments>http://brettterpstra.com/connecting-nvalt-and-address-book/#comments</comments>
		<pubDate>Fri, 03 Feb 2012 03:11:46 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[applescript]]></category>
		<category><![CDATA[nvalt]]></category>
		<category><![CDATA[osx]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=3615</guid>
		<description><![CDATA[<p>Here’s a quick, simple AppleScript to help you hook Notational Velocity/nvALT into Address Book. I sometimes want to attach a note or list of links to an entry in my address book, but I don’t like using the notes field. I tend to keep all of my notes1 in nvALT, and I prefer not to scatter them too far. All&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/connecting-nvalt-and-address-book/">Connecting nvALT and Address Book</a></p>]]></description>
			<content:encoded><![CDATA[<p><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2012/02/Johnny-Appleseed.jpg?9d7bd4" alt="" title="Johnny Appleseed" width="300" height="199" class="alignright size-full wp-image-3616" />Here’s a quick, simple AppleScript to help you hook <a href="http://notational.net/">Notational Velocity</a>/<a href="http://brettterpstra.com/project/nvalt/">nvALT</a> into Address Book. I sometimes want to attach a note or list of links to an entry in my address book, but I don’t like using the notes field. I tend to keep <em>all</em> of my notes<sup id="fnref:diff"><a href="#fn:diff" rel="footnote">1</a></sup> in nvALT, and I prefer not to scatter them too far. All I needed was a way to quickly create and link an nvALT note to each address…</p>

<p>As of recent versions, Notational Velocity and nvALT have a URL handler for nv:// (or nvalt://). Using the <code>/find/</code> parameter allows you to initiate a search in NV from a link, e.g. <code>nv://find/abnote%3AJohnny Appleseed</code>. If you use a unique prefix and full name, you can pinpoint a single note without having to create a file or locate the note’s ID. The first time you click the link, it will open a search in NV, and pressing Return will create the note and begin editing. Once the note is there, it will locate it instantly the next time you click the link.</p>

<p>I’m using the prefix “abnote:” on my notes. This AppleScript will create the URL entry automatically from the selected entries’ first and last names, and you can edit the prefix in the script to be anything you like. Just save it as “Add NV Note.scpt” in <code>~/Library/Scripts/Applications/Address Book</code> and it will show up in your script menu<sup id="fnref:menu"><a href="#fn:menu" rel="footnote">2</a></sup> when you’re in Address Book. You can run it on a bunch of entries (it’s not optimized to run on an entire large address book, though), or one at a time as you need it.</p>

<p>I wrote this on Lion. I honestly have no idea if it works on anything earlier. It might<sup id="fnref:might"><a href="#fn:might" rel="footnote">3</a></sup>.</p>

<h2>The script</h2>


<div class="wp_syntax"><div class="code"><pre class="applescript"><span class="kw3">tell</span> <span class="kw1">application</span> <span class="st0">&quot;Address Book&quot;</span>
	<span class="kw3">set</span> thePeople <span class="kw3">to</span> <span class="kw2">the</span> <span class="kw1">selection</span>
	<span class="kw3">repeat</span> <span class="kw3">with</span> thisPerson <span class="kw3">in</span> thePeople
		<span class="kw3">set</span> theName <span class="kw3">to</span> <span class="kw1">name</span> <span class="kw3">of</span> thisPerson <span class="kw2">as</span> <span class="kw1">string</span>
		<span class="kw1">make</span> <span class="kw1">new</span> url at <span class="kw3">end</span> <span class="kw3">of</span> urls <span class="kw3">of</span> thisPerson <span class="kw3">with</span> <span class="kw1">properties</span> <span class="br0">&#123;</span>label:<span class="st0">&quot;NV Note&quot;</span>, value:<span class="st0">&quot;nv://find/abnote%3A&quot;</span> <span class="sy0">&amp;</span> theName<span class="br0">&#125;</span>
	<span class="kw3">end</span> <span class="kw3">repeat</span>
	<span class="kw1">save</span>
<span class="kw3">end</span> <span class="kw3">tell</span></pre></div></div>


<div class="footnotes">
<hr />
<ol>

<li id="fn:diff">
<p>Notes, for me, are different from <a href="http://brettterpstra.com/logging-with-day-one-geek-style/">log entries</a>. I actually <em>like</em> keeping those separate most of the time. <a href="#fnref:diff" rev="footnote">↩</a></p>
</li>

<li id="fn:menu">
<p>Enabled in AppleScript Editor, Preferences-&gt;General-&gt;Show Script menu in menubar. Or better, use <a href="http://www.red-sweater.com/fastscripts/">FastScripts</a>. <a href="#fnref:menu" rev="footnote">↩</a></p>
</li>

<li id="fn:might">
<p>It might not. <a href="#fnref:might" rev="footnote">↩</a></p>
</li>

</ol>
</div>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/address-book-search-and-skype-from-the-command-line/' rel='bookmark' title='Address Book search and Skype from the command line'>Address Book search and Skype from the command line</a></li>
<li><a href='http://brettterpstra.com/nvalt-2-1-in-the-wild/' rel='bookmark' title='nvALT 2.1 in the wild'>nvALT 2.1 in the wild</a></li>
<li><a href='http://brettterpstra.com/nvalt-1-0-8-progress/' rel='bookmark' title='nvALT 1.0.8 progress'>nvALT 1.0.8 progress</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/connecting-nvalt-and-address-book/">Connecting nvALT and Address Book</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/connecting-nvalt-and-address-book/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Automating random giveaways, v1.0</title>
		<link>http://brettterpstra.com/automating-random-giveaways-v1-0/</link>
		<comments>http://brettterpstra.com/automating-random-giveaways-v1-0/#comments</comments>
		<pubDate>Sat, 01 Oct 2011 17:15:13 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[applescript]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[scripting]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=2879</guid>
		<description><![CDATA[<p>To pick the winners for the Yoink and Listary giveaways, I wrote an AppleScript to make the process completely random and as painless as possible for me. I still have plans for making a similar WordPress plugin, but that’s still in the planning stages. For now, this is working quite well and I thought I’d share it. I doubt many&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/automating-random-giveaways-v1-0/">Automating random giveaways, v1.0</a></p>]]></description>
			<content:encoded><![CDATA[<p><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2011/10/winduprobot.jpg?9d7bd4" alt="windup robot" title="windup robot" width="200" height="334" class="alignright size-full wp-image-2880" />To pick the winners for the Yoink and Listary giveaways, I wrote an AppleScript to make the process completely random and as painless as possible for me. I still have plans for making a similar WordPress plugin, but that’s still in the planning stages. For now, this is working quite well and I thought I’d share it. I doubt many people have the exact same setup and requirements, but the basic structure might be helpful for other projects.</p>

<p>It’s designed to work with promo code giveaways. So far, that’s what my giveaways have been. If I end up running a giveaway with a different registration method, I’ll extend the script and post an update for anyone interested.</p>

<p>This method currently has two requirements/limitations based on my own needs and setup. First, it only works with Mail.app for collecting entries and sending notifications. Second,  the regular expressions it uses to find the entrants name, email and IP address are based on the standard WordPress comment notification emails. The basic idea here could easily be applied to other AppleScript-able email applications and modified to parse any format, but I’ll leave that up to intrepid readers for now.</p>

<p><span id="more-2879"></span></p>

<h3>How it works</h3>

<p>First, I do a search for the subject line in Mail. All of the comment notifications that WordPress sends me for the post have the same subject line, so that gathers them all very quickly. All that matters is that I can select them all before running the script.</p>

<p>Next, I run the AppleScript. It begins by asking me for the giveaway app’s name and requests my list of promo codes. Then the script pulls the names and the message content from each selected email, passing the information to a Ruby script which scans the content for the actual email address (necessary because the actual sender on the email is always my WordPress address) and entrant’s name/handle and IP. The list of results are then passed to a second Ruby script along with the promo codes. This script checks for duplicates in the emails and IPs, picks enough random numbers (range 0 — number of entrants) to match each code provided (recursive function to avoid duplicate numbers). The Ruby script then opens a new message in Mail.app for each winner, and populates it with recipient, subject, congratulatory message (including code) and signature. It also adds the mailto: link with all of this info to an HTML file on the Desktop for reference.</p>

<p>It needs some improvements, especially in the mail creation routine. It currently uses the <code>mailto</code> AppleScript command, but really should create the outgoing message step by step, which would ultimately allow for complete automation at some point. For the time being I still want to be able to confirm the winners and message content anyway; I’ll automate more when I have full trust in it.</p>

<h4>The AppleScript</h4>


<div class="wp_syntax"><div class="code"><pre class="applescript"><span class="coMULTI">(* 
PickWinners by Brett Terpstra, 2011, freely distributed
Picks random winners from selected WordPress comment notification emails in Mail.app
Checks for duplicate emails and IP addresses
On run, requests Application title and a newline-separated list of promo codes
Picks winners from list for each promo code and opens ready-to-send notification emails in Mail.app
Saves list of winners in HTML file with mailto links (including message and promo code)
*)</span>
&nbsp;
<span class="kw3">set</span> pickWinnerScript <span class="kw3">to</span> <span class="br0">&#40;</span><span class="kw1">path to</span> <span class="kw1">me</span><span class="br0">&#41;</span> <span class="sy0">&amp;</span> <span class="st0">&quot;Contents:Resources:Scripts:pickwinners.rb&quot;</span> <span class="kw2">as</span> <span class="kw1">string</span>
<span class="kw3">set</span> extractEmailScript <span class="kw3">to</span> <span class="br0">&#40;</span><span class="kw1">path to</span> <span class="kw1">me</span><span class="br0">&#41;</span> <span class="sy0">&amp;</span> <span class="st0">&quot;Contents:Resources:Scripts:extractemail.rb&quot;</span> <span class="kw2">as</span> <span class="kw1">string</span>
<span class="kw3">property</span> winners : <span class="st0">&quot;&quot;</span>
<span class="kw3">set</span> _res <span class="kw3">to</span> <span class="kw1">display dialog</span> <span class="st0">&quot;Application name?&quot;</span> <span class="kw1">default answer</span> <span class="st0">&quot;&quot;</span>
<span class="kw3">set</span> appname <span class="kw3">to</span> <span class="kw1">text</span> returned <span class="kw3">of</span> _res
<span class="kw3">set</span> _res <span class="kw3">to</span> <span class="kw1">display dialog</span> <span class="st0">&quot;Enter promo codes&quot;</span> <span class="kw1">default answer</span> <span class="st0">&quot;Paste codes, one per line&quot;</span>
<span class="kw3">set</span> codes <span class="kw3">to</span> <span class="kw1">text</span> returned <span class="kw3">of</span> _res
&nbsp;
<span class="kw3">tell</span> <span class="kw1">application</span> <span class="st0">&quot;Mail&quot;</span>
	<span class="kw3">set</span> _sel <span class="kw3">to</span> <span class="kw2">the</span> <span class="kw1">selection</span>
	<span class="kw3">set</span> entries <span class="kw3">to</span> <span class="br0">&#123;</span><span class="br0">&#125;</span>
&nbsp;
	<span class="kw3">repeat</span> <span class="kw3">with</span> _msg <span class="kw3">in</span> _sel
		<span class="kw3">set</span> nameAndEmail <span class="kw3">to</span> <span class="kw1">do shell script</span> <span class="st0">&quot;<span class="es0">\&quot;</span>&quot;</span> <span class="sy0">&amp;</span> <span class="br0">&#40;</span><span class="kw1">POSIX path</span> <span class="kw3">of</span> extractEmailScript<span class="br0">&#41;</span> <span class="sy0">&amp;</span> <span class="st0">&quot;<span class="es0">\&quot;</span> <span class="es0">\&quot;</span>&quot;</span> <span class="sy0">&amp;</span> <span class="kw1">content</span> <span class="kw3">of</span> _msg <span class="sy0">&amp;</span> <span class="st0">&quot;<span class="es0">\&quot;</span>&quot;</span>
		<span class="kw3">set</span> <span class="kw3">end</span> <span class="kw3">of</span> entries <span class="kw3">to</span> nameAndEmail
	<span class="kw3">end</span> <span class="kw3">repeat</span>
&nbsp;
	<span class="kw3">set</span> <span class="br0">&#123;</span>astid, AppleScript<span class="co2">'</span>s <span class="kw1">text</span> <span class="kw1">item</span> <span class="kw1">delimiters</span><span class="br0">&#125;</span> <span class="kw3">to</span> <span class="br0">&#123;</span>AppleScript<span class="co2">'</span>s <span class="kw1">text</span> <span class="kw1">item</span> <span class="kw1">delimiters</span>, <span class="st0">&quot;
&quot;</span><span class="br0">&#125;</span>
	<span class="kw3">set</span> emails <span class="kw3">to</span> entries <span class="kw2">as</span> <span class="kw1">string</span>
	<span class="kw3">set</span> AppleScript<span class="co2">'</span>s <span class="kw1">text</span> <span class="kw1">item</span> <span class="kw1">delimiters</span> <span class="kw3">to</span> astid
&nbsp;
	<span class="kw3">set</span> winners <span class="kw3">to</span> <span class="kw1">do shell script</span> <span class="st0">&quot;<span class="es0">\&quot;</span>&quot;</span> <span class="sy0">&amp;</span> <span class="br0">&#40;</span><span class="kw1">POSIX path</span> <span class="kw3">of</span> pickWinnerScript<span class="br0">&#41;</span> <span class="sy0">&amp;</span> <span class="st0">&quot;<span class="es0">\&quot;</span>  <span class="es0">\&quot;</span>&quot;</span> <span class="sy0">&amp;</span> appname <span class="sy0">&amp;</span> <span class="st0">&quot;<span class="es0">\&quot;</span> <span class="es0">\&quot;</span>&quot;</span> <span class="sy0">&amp;</span> codes <span class="sy0">&amp;</span> <span class="st0">&quot;<span class="es0">\&quot;</span> <span class="es0">\&quot;</span>&quot;</span> <span class="sy0">&amp;</span> emails <span class="sy0">&amp;</span> <span class="st0">&quot;<span class="es0">\&quot;</span>&quot;</span>
<span class="kw3">end</span> <span class="kw3">tell</span>
&nbsp;
<span class="kw3">if</span> winners <span class="kw3">is</span> <span class="st0">&quot;error&quot;</span> <span class="kw3">then</span>
	<span class="kw1">display dialog</span> <span class="st0">&quot;There was an error generating winners&quot;</span>
<span class="kw3">else</span>
	<span class="kw3">set</span> _btn <span class="kw3">to</span> <span class="kw1">display dialog</span> <span class="st0">&quot;Winners written to &quot;</span> <span class="sy0">&amp;</span> winners <span class="kw1">buttons</span> <span class="br0">&#123;</span><span class="st0">&quot;OK&quot;</span>, <span class="st0">&quot;Open in Safari&quot;</span><span class="br0">&#125;</span>
	<span class="kw3">if</span> button returned <span class="kw3">of</span> _btn <span class="kw3">is</span> <span class="st0">&quot;Open in Safari&quot;</span> <span class="kw3">then</span>
		<span class="kw3">tell</span> <span class="kw1">application</span> <span class="st0">&quot;Safari&quot;</span> <span class="kw3">to</span> <span class="kw1">open</span> <span class="br0">&#40;</span><span class="kw1">POSIX file</span> winners<span class="br0">&#41;</span> <span class="kw2">as</span> <span class="kw1">alias</span>
	<span class="kw3">end</span> <span class="kw3">if</span>
<span class="kw3">end</span> <span class="kw3">if</span></pre></div></div>


<h4>extractemail.rb</h4>


<div class="wp_syntax"><div class="code"><pre class="ruby"><span class="co1">#!/usr/bin/env ruby</span>
&nbsp;
input = ARGV.<span class="me1">join</span><span class="br0">&#40;</span><span class="st0">&quot; &quot;</span><span class="br0">&#41;</span>
emailmatch = input.<span class="me1">match</span><span class="br0">&#40;</span><span class="sy0">/</span>E<span class="sy0">-</span>mail : <span class="br0">&#40;</span>.<span class="sy0">*</span><span class="br0">&#41;</span><span class="sy0">/</span><span class="br0">&#41;</span>
namematch = input.<span class="me1">match</span><span class="br0">&#40;</span><span class="sy0">/</span>Author : <span class="br0">&#40;</span>.<span class="sy0">*</span>?<span class="br0">&#41;</span> \<span class="br0">&#40;</span>IP: <span class="br0">&#40;</span>.<span class="sy0">*</span>?<span class="br0">&#41;</span>\<span class="br0">&#41;</span><span class="sy0">/</span><span class="br0">&#41;</span>
&nbsp;
<span class="kw3">print</span> <span class="st0">&quot;#{namematch[1].strip} &lt;#{emailmatch[1].strip}&gt; (#{namematch[2].strip})&quot;</span></pre></div></div>


<h4>pickwinners.rb</h4>


<div class="wp_syntax"><div class="code"><pre class="ruby"><span class="co1">#!/usr/bin/env ruby</span>
<span class="kw3">require</span> <span class="st0">'ftools'</span>
&nbsp;
appname = ARGV<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span>
ARGV.<span class="me1">shift</span>
codes = ARGV<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span>.<span class="kw3">split</span>
count = codes.<span class="me1">length</span>
ARGV.<span class="me1">shift</span>
input = ARGV<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span>.<span class="kw3">split</span><span class="br0">&#40;</span><span class="st0">&quot;<span class="es0">\n</span>&quot;</span><span class="br0">&#41;</span>.<span class="me1">uniq</span>
&nbsp;
norepeat_email = <span class="br0">&#91;</span><span class="br0">&#93;</span>
norepeat_IP = <span class="br0">&#91;</span><span class="br0">&#93;</span>
entries = <span class="br0">&#91;</span><span class="br0">&#93;</span>
&nbsp;
input.<span class="me1">each</span> <span class="br0">&#123;</span><span class="sy0">|</span>entry<span class="sy0">|</span>
  name,email,ip = entry.<span class="me1">scan</span><span class="br0">&#40;</span><span class="sy0">/</span>^<span class="br0">&#40;</span>.<span class="sy0">*</span>?<span class="br0">&#41;</span> <span class="sy0">*&lt;</span><span class="br0">&#40;</span><span class="br0">&#91;</span>^ <span class="br0">&#93;</span><span class="sy0">+</span><span class="br0">&#41;</span><span class="sy0">&gt;</span> \<span class="br0">&#40;</span><span class="br0">&#40;</span>.<span class="sy0">*</span>?<span class="br0">&#41;</span>\<span class="br0">&#41;</span><span class="sy0">/</span><span class="br0">&#41;</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span>
  <span class="kw1">unless</span> <span class="br0">&#40;</span>norepeat_email.<span class="kw1">include</span>?<span class="br0">&#40;</span>email<span class="br0">&#41;</span> <span class="sy0">||</span> norepeat_IP.<span class="kw1">include</span>?<span class="br0">&#40;</span>ip<span class="br0">&#41;</span><span class="br0">&#41;</span>
    norepeat_email.<span class="me1">push</span><span class="br0">&#40;</span>email<span class="br0">&#41;</span>
    norepeat_IP.<span class="me1">push</span><span class="br0">&#40;</span>ip<span class="br0">&#41;</span>
    entries <span class="sy0">&lt;&lt;</span> <span class="br0">&#123;</span> <span class="st0">'name'</span> <span class="sy0">=&gt;</span> name, <span class="st0">'email'</span> <span class="sy0">=&gt;</span> email <span class="br0">&#125;</span>
  <span class="kw1">end</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw1">def</span> pick_number<span class="br0">&#40;</span>max,numbers<span class="br0">&#41;</span>
  num = <span class="kw3">rand</span><span class="br0">&#40;</span>max<span class="br0">&#41;</span>
  <span class="kw1">if</span> numbers.<span class="kw1">include</span>? num
    pick_number<span class="br0">&#40;</span>max,numbers<span class="br0">&#41;</span>
  <span class="kw1">else</span>
    <span class="kw2">return</span> num
  <span class="kw1">end</span>
<span class="kw1">end</span>
&nbsp;
randoms = <span class="br0">&#91;</span><span class="br0">&#93;</span>
count.<span class="me1">times</span> <span class="kw1">do</span>
  randoms.<span class="me1">push</span><span class="br0">&#40;</span>pick_number<span class="br0">&#40;</span>entries.<span class="me1">length</span>,randoms<span class="br0">&#41;</span><span class="br0">&#41;</span>
<span class="kw1">end</span>
&nbsp;
winners = <span class="br0">&#91;</span><span class="br0">&#93;</span>
randoms.<span class="me1">each_with_index</span> <span class="br0">&#123;</span><span class="sy0">|</span>winner,i<span class="sy0">|</span>
  entry = entries<span class="br0">&#91;</span>winner<span class="br0">&#93;</span>
  name = entry<span class="br0">&#91;</span><span class="st0">'name'</span><span class="br0">&#93;</span>
  email = entry<span class="br0">&#91;</span><span class="st0">'email'</span><span class="br0">&#93;</span>
  mailto = <span class="sy0">%</span>Q<span class="br0">&#123;</span>mailto:<span class="co1">#{email}?subject=Congratulations #{name}, you won!&amp;body=Here is your promo code for #{appname}: #{codes[i]}%0A%0AThanks for reading!%0A%0A-Brett}</span>
  link = <span class="sy0">%</span>Q<span class="br0">&#123;</span><span class="sy0">&lt;</span>li<span class="sy0">&gt;&lt;</span>a href=<span class="st0">&quot;#{mailto}&quot;</span><span class="sy0">&gt;</span><span class="co1">#{name} &lt;#{email}&gt;&lt;/a&gt;&lt;/li&gt;}</span>
  winners.<span class="me1">push</span><span class="br0">&#40;</span>link<span class="br0">&#41;</span>
  <span class="sy0">%</span>x<span class="br0">&#123;</span>echo <span class="st0">'tell application &quot;Mail&quot; to mailto &quot;#{mailto.gsub(/'</span><span class="sy0">/</span>,<span class="st0">&quot;<span class="es0">\'</span>&quot;</span><span class="br0">&#41;</span><span class="br0">&#125;</span><span class="st0">&quot;'|osascript}
}
&nbsp;
if winners.length == count
  output = &quot;</span><span class="sy0">&lt;</span>ul<span class="sy0">&gt;</span><span class="st0">&quot;
  output += winners.join(&quot;</span>\n<span class="st0">&quot;)
  output += &quot;</span><span class="sy0">&lt;/</span>ul<span class="sy0">&gt;</span><span class="st0">&quot;
&nbsp;
  outfile = File.new(File.expand_path(&quot;</span>~<span class="sy0">/</span>Desktop<span class="sy0">/</span><span class="co1">#{appname}Winners.html&quot;),'w+')</span>
  outfile.<span class="kw3">puts</span> output
  outfile.<span class="me1">close</span>
  <span class="kw3">puts</span> <span class="kw4">File</span>.<span class="me1">expand_path</span><span class="br0">&#40;</span><span class="st0">&quot;~/Desktop/#{appname}Winners.html&quot;</span><span class="br0">&#41;</span>
<span class="kw1">else</span>
  <span class="kw3">puts</span> <span class="st0">&quot;error&quot;</span>
<span class="kw1">end</span></pre></div></div>


<p>It’s not the most elegant solution, but it does the job of ensuring randomness and handling the nitty gritty parts of running a contest.</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/listary-giveaway-get-yours/' rel='bookmark' title='Listary giveaway, get yours!'>Listary giveaway, get yours!</a></li>
<li><a href='http://brettterpstra.com/five-yoink-promo-codes-up-for-grabs/' rel='bookmark' title='Five Yoink promo codes up for grabs!'>Five Yoink promo codes up for grabs!</a></li>
<li><a href='http://brettterpstra.com/ios-giveaway-writeup/' rel='bookmark' title='iOS App Giveaway: WriteUp'>iOS App Giveaway: WriteUp</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/automating-random-giveaways-v1-0/">Automating random giveaways, v1.0</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/automating-random-giveaways-v1-0/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Duplicating Safari browsing sessions between Macs</title>
		<link>http://brettterpstra.com/duplicating-safari-browsing-sessions-between-macs/</link>
		<comments>http://brettterpstra.com/duplicating-safari-browsing-sessions-between-macs/#comments</comments>
		<pubDate>Tue, 03 May 2011 22:30:09 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[applescript]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[safari]]></category>
		<category><![CDATA[scripting]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=2302</guid>
		<description><![CDATA[<p>Hey, you’re just in time for another “stupid trick of the day” script. I have good reason for this one, and it only took me about 8 minutes to set up. It will take me longer to write about it than it’s probably worth, but it might be of use to anyone in a similar situation. Here’s the scenario: I&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/duplicating-safari-browsing-sessions-between-macs/">Duplicating Safari browsing sessions between Macs</a></p>]]></description>
			<content:encoded><![CDATA[<p>Hey, you’re just in time for another “stupid trick of the day” script. I have good reason for this one, and it only took me about 8 minutes to set up. It will take me longer to write about it than it’s probably worth, but it might be of use to anyone in a similar situation. Here’s the scenario:</p>

<p>I bought a MacBook Air recently. I have never been this happy with an Apple hardware purchase before. Not to gush, but I’ve bought and loved a lot of Macs and this one takes the cake. I’m doing more and more of my everyday work and writing on it, but I still like to sit down at the dual-monitor setup of my Mac Pro fairly regularly. When I do that, the Air becomes an auxiliary machine and I offload most of my chat and social apps to it. The annoying side of this setup is that I end up with Safari tabs piling up on both Macs, and half of them really make more sense on the other machine.</p>

<p><span id="more-2302"></span></p>

<p>I wrote a pair of scripts that execute over SSH to pull in all of the browser tabs from the front window of Safari on the other Mac into new tabs on the one calling the script. They’re designed to run on Macs on the same network, though they’d work remotely if you could think of a reason to do it. I run it in both directions, and call it with a simple <code>do shell script</code> AppleScript in <code>~/Library/Scripts/Applications/Safari</code> so it’s in my menubar when I’m browsing.</p>

<p>Just a few prerequisites:</p>

<ol>
<li>You need keyless ssh set up between the two (or more) Macs. If you want a two-way sync, you need keys in both directions. <a href="http://www.rootsilver.com/2007/10/keyless-ssh-sshkeygen-setup-an">This article has everything you need</a>.</li>
<li>To keep things simple, set up a <code>~/.ssh/config</code> file on each machine you want to pull tabs to. Create the file if you don’t have one, or add this at the bottom of an existing one, modifying it for your setup:</li>
</ol>

<pre><code>
host air
  HostName computername.local
  User remoteusername
</code></pre>

<p>Now you can just install the scripts, edit one line on each and start pulling tabs back and forth between computers.</p>

<h3>remotetabs.rb</h3>

<p>This goes on the machine you want to pull <em>from</em>. If you’re going both directions, you’ll want both scripts on both machines. Easy enough, right? Save this one as <code>remotetabs.rb</code> in <code>~/scripts/</code> and run <code>chmod a+x ~/scripts/remotetabs.rb</code>. Note that it doesn’t attempt to do any error reporting, it just fails silently or times out if there’s a problem. You’ll know something went wrong, you just won’t know what. It’s mysterious, enjoy it.</p>

<p>Because I often run <a href="http://www.webkit.org/">Webkit</a>, and because Webkit demands that it be addressed separately from Safari, there’s a quick check in here to see which one is running at the time.</p>

<pre><code>
#!/usr/bin/ruby

def app_running?(app)
  not `ps ax|grep -i "#{app}.app"|grep -v grep`.empty?
end

def webkit_running?
  return false if `ps ax|grep -i "Safari.app"|grep -v grep`.empty?
  not `ps ax|grep -i "/Applications/Webkit.app"|grep -v grep`.empty?
end

if app_running?("Safari")
  browser = webkit_running? ? "Webkit" : "Safari"
  urllist = %x{osascript <<-APPLESCRIPT
               tell application "#{browser}"
               set _tabs to every tab of window 1
               set _urls to {}
               repeat with _tab in _tabs
               set end of _urls to URL of _tab
               end repeat
               set {astid, AppleScript's text item delimiters} to {AppleScript's text item delimiters, " "}
               set output to _urls as text
               set AppleScript's text item delimiters to astid
               return output
               end tell
               APPLESCRIPT }.chomp
  puts urllist
end
</code></pre>

<h3>getremotetabs.rb</h3>

<p>This goes on the machine that's doing the "pulling." Save it as <code>getremotetabs.rb</code> in <code>~/scripts/</code> and run <code>chmod a+x ~/scripts/getremotetabs.rb</code>. You need to edit the <code>remote_host</code> variable in this script on each machine to match the hostname you set up in your <code>~/.ssh/config</code> file for the 'other' Mac.</p>

<pre><code>
#!/usr/bin/ruby
# retrieves a list of urls from the front Safari window running on a remote machine

remote_host = 'air' # as set up in ~/.ssh/config with nick and keyless login

%x{ssh #{remote_host} ~/scripts/remotetabs.rb}.chomp.split(' ').each { |url|
  %x{osascript -e 'tell application "Safari" to open location "#{url}"'}
}
</code></pre>

<p>That's it. You can save an AppleScript with <code>do shell script "/Users/username/scripts/getremotetabs.rb"</code> anywhere you want to, or just call the script from the command line. Also, stop making fun of my <abbr title="Obsessive Scripting Disorder">OSD</abbr>. I mean it.</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/saving-safari-browsing-sessions-to-evernote/' rel='bookmark' title='Saving Safari browsing sessions to Evernote'>Saving Safari browsing sessions to Evernote</a></li>
<li><a href='http://brettterpstra.com/save-safari-tabs-to-instapaper/' rel='bookmark' title='Save Safari tabs to Instapaper'>Save Safari tabs to Instapaper</a></li>
<li><a href='http://brettterpstra.com/geeklet-1-minute-average-cpu-load/' rel='bookmark' title='Geeklet: 1-minute average CPU load'>Geeklet: 1-minute average CPU load</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/duplicating-safari-browsing-sessions-between-macs/">Duplicating Safari browsing sessions between Macs</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/duplicating-safari-browsing-sessions-between-macs/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>LaunchBar actions for url encoding and decoding</title>
		<link>http://brettterpstra.com/launchbar-actions-for-url-encoding-and-decoding/</link>
		<comments>http://brettterpstra.com/launchbar-actions-for-url-encoding-and-decoding/#comments</comments>
		<pubDate>Fri, 04 Feb 2011 13:40:52 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[applescript]]></category>
		<category><![CDATA[experiments]]></category>
		<category><![CDATA[launchbar]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=1767</guid>
		<description><![CDATA[<p>I usually get up an hour or two before I start my work day and “play.” Playtime usually results in half-finished scripts and deleted git branches, but sometimes I do something simple and useful (to me). Wednesday was Bash fun, and here’s this morning’s project: LaunchBar actions to url encode and decode strings1. If you run them outside of LaunchBar,&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/launchbar-actions-for-url-encoding-and-decoding/">LaunchBar actions for url encoding and decoding</a></p>]]></description>
			<content:encoded><![CDATA[<p>I usually get up an hour or two before I start my work day and “play.” Playtime usually results in half-finished scripts and deleted git branches, but sometimes I do something simple and useful (to me). Wednesday was <a href="http://brettterpstra.com/quick-calculations-in-bash/">Bash fun</a>, and here’s this morning’s project: <a href="http://www.obdev.at/products/launchbar/index.html">LaunchBar</a> actions to url encode and decode strings<sup id="fnref:fn1"><a href="#fn:fn1" rel="footnote">1</a></sup>. If you run them outside of LaunchBar, they’ll encode/decode your clipboard, replacing what’s in your clipboard with the result, so they have multiple applications. These have probably been done before, but my quick DuckDuckGo search didn’t yield any immediate results.</p>

<p>I find it especially useful to be able to quickly encode and decode urls and strings when I’m testing online APIs out, but there are many times when I find I need this. I usually use a shell function or the very handy <a href="http://www.apple.com/downloads/dashboard/developer/hashwidget.html">Hash Widget</a> for Dashboard, but as a LaunchBar user, this is faster.</p>

<p><span id="more-1767"></span></p>

<p>To use with LaunchBar, open the script in your Script Editor (instant-open links provided) and save it to <code>~/Library/Application Support/LaunchBar/Actions</code>, creating the folder if it doesn’t already exist. Then, assuming you have Actions enabled in your indexing preferences, you can just type “urle” to get the action, then hit space to enter or paste the text to encode/decode. Alternatively, you can paste first or use Instant Send on a selection, then hit Tab and select the encode or decode action. To use elsewhere, such as in <a href="http://www.red-sweater.com/fastscripts/">FastScripts</a>, just save them as scripts in your <code>~/Library/Scripts</code> folder. Using them outside of LaunchBar won’t be interactive; they will encode or decode your clipboard in place.</p>

<p><strong>Side note:</strong> I decided to do the encoding/decoding in pure AppleScript, using functions I’ve mentioned previously from <a href="http://harvey.nu/">http://harvey.nu/</a>. You can encode faster with Perl using a shell call, if you prefer. In a shell script for encoding, you’d use <code>echo "string to encode"|perl -pe's/([^-_.~A-Za-z0-9])/sprintf("%%%02X", ord("$1"))/seg'</code>. In AppleScript, that would look like <code>set _res to do shell script "echo \"" &amp; ASTextVar &amp; "\"|perl -pe's/([^-_.~A-Za-z0-9])/sprintf(\"%%%02X\", ord(\"$1\"))/seg'"</code>, where ASTextVar is your string to encode.</p>

<p>The LaunchBar actions copy the resulting text to the clipboard, but you may prefer to have it passed back to LaunchBar for subsequent processing. There are commented lines in the scripts for doing so, just comment out the last line in the handle_string function and uncomment the line above it.</p>

<p>Here are the scripts/actions:</p>

<h2>URL Encode</h2>

<p>Open this script in your AppleScript editor: <a href="applescript://com.apple.scripteditor?action=new&amp;script=on%20handle_string(lbText)%0A%09set%20_res%20to%20urlencode(lbText)%0A%09--%20to%20return%20the%20result%20to%20launchbar%20instead%20of%20copying%20it%20substitute%0A%09--%20the%20next%20line%20for%20the%20line%20after%20it%20(set%20the%20clipboard%20to%20_res)%0A%09--%20open%20location%20%22x-launchbar:select?string=%22%20&amp;%20urlencode(_res)%0A%09set%20the%20clipboard%20to%20_res%0Aend%20handle_string%0A%0Aon%20run%0A%09set%20the%20clipboard%20to%20urlencode(the%20clipboard%20as%20text)%0Aend%20run%0A%0Aon%20urlencode(theText)%20--%20http://harvey.nu/applescript_url_encode_routine.html%0A%09set%20theTextEnc%20to%20%22%22%0A%09repeat%20with%20eachChar%20in%20characters%20of%20theText%0A%09%09set%20useChar%20to%20eachChar%0A%09%09set%20eachCharNum%20to%20ASCII%20number%20of%20eachChar%0A%09%09if%20eachCharNum%20=%2032%20then%0A%09%09%09set%20useChar%20to%20%22+%22%0A%09%09else%20if%20(eachCharNum%20%E2%89%A0%2042)%20and%20(eachCharNum%20%E2%89%A0%2095)%20and%20(eachCharNum%20%3C%2045%20or%20eachCharNum%20%3E%2046)%20and%20(eachCharNum%20%3C%2048%20or%20eachCharNum%20%3E%2057)%20and%20(eachCharNum%20%3C%2065%20or%20eachCharNum%20%3E%2090)%20and%20(eachCharNum%20%3C%2097%20or%20eachCharNum%20%3E%20122)%20then%0A%09%09%09set%20firstDig%20to%20round%20(eachCharNum%20/%2016)%20rounding%20down%0A%09%09%09set%20secondDig%20to%20eachCharNum%20mod%2016%0A%09%09%09if%20firstDig%20%3E%209%20then%0A%09%09%09%09set%20aNum%20to%20firstDig%20+%2055%0A%09%09%09%09set%20firstDig%20to%20ASCII%20character%20aNum%0A%09%09%09end%20if%0A%09%09%09if%20secondDig%20%3E%209%20then%0A%09%09%09%09set%20aNum%20to%20secondDig%20+%2055%0A%09%09%09%09set%20secondDig%20to%20ASCII%20character%20aNum%0A%09%09%09end%20if%0A%09%09%09set%20numHex%20to%20(%22%25%22%20&amp;%20(firstDig%20as%20string)%20&amp;%20(secondDig%20as%20string))%20as%20string%0A%09%09%09set%20useChar%20to%20numHex%0A%09%09end%20if%0A%09%09set%20theTextEnc%20to%20theTextEnc%20&amp;%20useChar%20as%20string%0A%09end%20repeat%0A%09return%20theTextEnc%0Aend%20urlencode">URLEncode.applescript</a></p>


<div class="wp_syntax"><div class="code"><pre class="applescript"><span class="kw3">on</span> handle_string<span class="br0">&#40;</span>lbText<span class="br0">&#41;</span>
	<span class="kw3">set</span> _res <span class="kw3">to</span> urlencode<span class="br0">&#40;</span>lbText<span class="br0">&#41;</span>
	<span class="co1">-- to return the result to launchbar instead of copying it substitute</span>
	<span class="co1">-- the next line for the line after it (set the clipboard to _res)</span>
	<span class="co1">-- open location &quot;x-launchbar:select?string=&quot; &amp; urlencode(_res)</span>
	<span class="kw1">set <span class="kw2">the</span> clipboard to</span> _res
<span class="kw3">end</span> handle_string
&nbsp;
<span class="kw3">on</span> <span class="kw1">run</span>
	<span class="kw1">set <span class="kw2">the</span> clipboard to</span> urlencode<span class="br0">&#40;</span><span class="kw1">the clipboard</span> <span class="kw2">as</span> <span class="kw1">text</span><span class="br0">&#41;</span>
<span class="kw3">end</span> <span class="kw1">run</span>
&nbsp;
<span class="kw3">on</span> urlencode<span class="br0">&#40;</span>theText<span class="br0">&#41;</span> <span class="co1">-- http://harvey.nu/applescript_url_encode_routine.html</span>
	<span class="kw3">set</span> theTextEnc <span class="kw3">to</span> <span class="st0">&quot;&quot;</span>
	<span class="kw3">repeat</span> <span class="kw3">with</span> eachChar <span class="kw3">in</span> characters <span class="kw3">of</span> theText
		<span class="kw3">set</span> useChar <span class="kw3">to</span> eachChar
		<span class="kw3">set</span> eachCharNum <span class="kw3">to</span> ASCII <span class="kw1">number</span> <span class="kw3">of</span> eachChar
		<span class="kw3">if</span> eachCharNum <span class="sy0">=</span> <span class="nu0">32</span> <span class="kw3">then</span>
			<span class="kw3">set</span> useChar <span class="kw3">to</span> <span class="st0">&quot;+&quot;</span>
		<span class="kw3">else</span> <span class="kw3">if</span> <span class="br0">&#40;</span>eachCharNum <span class="sy0">&amp;</span>ne; <span class="nu0">42</span><span class="br0">&#41;</span> <span class="kw2">and</span> <span class="br0">&#40;</span>eachCharNum <span class="sy0">&amp;</span>ne; <span class="nu0">95</span><span class="br0">&#41;</span> <span class="kw2">and</span> <span class="br0">&#40;</span>eachCharNum <span class="sy0">&lt;</span> <span class="nu0">45</span> <span class="kw2">or</span> eachCharNum &gt; <span class="nu0">46</span><span class="br0">&#41;</span> <span class="kw2">and</span> <span class="br0">&#40;</span>eachCharNum <span class="sy0">&lt;</span> <span class="nu0">48</span> <span class="kw2">or</span> eachCharNum &gt; <span class="nu0">57</span><span class="br0">&#41;</span> <span class="kw2">and</span> <span class="br0">&#40;</span>eachCharNum <span class="sy0">&lt;</span> <span class="nu0">65</span> <span class="kw2">or</span> eachCharNum &gt; <span class="nu0">90</span><span class="br0">&#41;</span> <span class="kw2">and</span> <span class="br0">&#40;</span>eachCharNum <span class="sy0">&lt;</span> <span class="nu0">97</span> <span class="kw2">or</span> eachCharNum &gt; <span class="nu0">122</span><span class="br0">&#41;</span> <span class="kw3">then</span>
			<span class="kw3">set</span> firstDig <span class="kw3">to</span> round <span class="br0">&#40;</span>eachCharNum <span class="sy0">/</span> <span class="nu0">16</span><span class="br0">&#41;</span> rounding down
			<span class="kw3">set</span> secondDig <span class="kw3">to</span> eachCharNum <span class="kw2">mod</span> <span class="nu0">16</span>
			<span class="kw3">if</span> firstDig &gt; <span class="nu0">9</span> <span class="kw3">then</span>
				<span class="kw3">set</span> aNum <span class="kw3">to</span> firstDig <span class="sy0">+</span> <span class="nu0">55</span>
				<span class="kw3">set</span> firstDig <span class="kw3">to</span> ASCII character aNum
			<span class="kw3">end</span> <span class="kw3">if</span>
			<span class="kw3">if</span> secondDig &gt; <span class="nu0">9</span> <span class="kw3">then</span>
				<span class="kw3">set</span> aNum <span class="kw3">to</span> secondDig <span class="sy0">+</span> <span class="nu0">55</span>
				<span class="kw3">set</span> secondDig <span class="kw3">to</span> ASCII character aNum
			<span class="kw3">end</span> <span class="kw3">if</span>
			<span class="kw3">set</span> numHex <span class="kw3">to</span> <span class="br0">&#40;</span><span class="st0">&quot;%&quot;</span> <span class="sy0">&amp;</span> <span class="br0">&#40;</span>firstDig <span class="kw2">as</span> <span class="kw1">string</span><span class="br0">&#41;</span> <span class="sy0">&amp;</span> <span class="br0">&#40;</span>secondDig <span class="kw2">as</span> <span class="kw1">string</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw2">as</span> <span class="kw1">string</span>
			<span class="kw3">set</span> useChar <span class="kw3">to</span> numHex
		<span class="kw3">end</span> <span class="kw3">if</span>
		<span class="kw3">set</span> theTextEnc <span class="kw3">to</span> theTextEnc <span class="sy0">&amp;</span> useChar <span class="kw2">as</span> <span class="kw1">string</span>
	<span class="kw3">end</span> <span class="kw3">repeat</span>
	<span class="kw3">return</span> theTextEnc
<span class="kw3">end</span> urlencode</pre></div></div>


<h2>URL Decode</h2>

<p>Open this script in your AppleScript editor: <a href="applescript://com.apple.scripteditor?action=new&amp;script=on%20handle_string(lbText)%0A%09set%20_res%20to%20urldecode(lbText)%0A%09--%20to%20return%20the%20result%20to%20launchbar%20instead%20of%20copying%20it%20substitute%0A%09--%20the%20next%20line%20for%20the%20line%20after%20it%20(set%20the%20clipboard%20to%20_res)%0A%09--%20open%20location%20%22x-launchbar:select?string=%22&amp;urldecode(_res)%0A%09set%20the%20clipboard%20to%20_res%0Aend%20handle_string%0A%0Aon%20run%0A%09set%20the%20clipboard%20to%20urldecode(the%20clipboard%20as%20text)%0Aend%20run%0A%0Aon%20urldecode(theText)%20--%20http://harvey.nu/applescript_url_decode_routine.html%0A%09set%20sDst%20to%20%22%22%0A%09set%20sHex%20to%20%220123456789ABCDEF%22%0A%09set%20i%20to%201%0A%09repeat%20while%20i%20%E2%89%A4%20length%20of%20theText%0A%09%09set%20c%20to%20character%20i%20of%20theText%0A%09%09if%20c%20=%20%22+%22%20then%0A%09%09%09set%20sDst%20to%20sDst%20&amp;%20%22%20%22%0A%09%09else%20if%20c%20=%20%22%25%22%20then%0A%09%09%09if%20i%20%3E%20((length%20of%20theText)%20-%202)%20then%0A%09%09%09%09display%20dialog%20(%22Invalid%20URL%20Encoded%20string%20-%20missing%20hex%20char%22)%20buttons%20%7B%22Crap...%22%7D%20with%20icon%20stop%0A%09%09%09%09return%20%22%22%0A%09%09%09end%20if%0A%09%09%09set%20iCVal1%20to%20(offset%20of%20(character%20(i%20+%201)%20of%20theText)%20in%20sHex)%20-%201%0A%09%09%09set%20iCVal2%20to%20(offset%20of%20(character%20(i%20+%202)%20of%20theText)%20in%20sHex)%20-%201%0A%09%09%09if%20iCVal1%20=%20-1%20or%20iCVal2%20=%20-1%20then%0A%09%09%09%09display%20dialog%20(%22Invalid%20URL%20Encoded%20string%20-%20not%202%20hex%20chars%20after%20%25%20sign%22)%20buttons%20%7B%22Crap...%22%7D%20with%20icon%20stop%0A%09%09%09%09return%20%22%22%0A%09%09%09end%20if%0A%09%09%09set%20sDst%20to%20sDst%20&amp;%20(ASCII%20character%20(iCVal1%20*%2016%20+%20iCVal2))%0A%09%09%09set%20i%20to%20i%20+%202%0A%09%09else%0A%09%09%09set%20sDst%20to%20sDst%20&amp;%20c%0A%09%09end%20if%0A%09%09set%20i%20to%20i%20+%201%0A%09end%20repeat%0A%09return%20sDst%0Aend%20urldecode">URLDecode.applescript</a></p>


<div class="wp_syntax"><div class="code"><pre class="applescript"><span class="kw3">on</span> handle_string<span class="br0">&#40;</span>lbText<span class="br0">&#41;</span>
	<span class="kw3">set</span> _res <span class="kw3">to</span> urldecode<span class="br0">&#40;</span>lbText<span class="br0">&#41;</span>
	<span class="co1">-- to return the result to launchbar instead of copying it substitute</span>
	<span class="co1">-- the next line for the line after it (set the clipboard to _res)</span>
	<span class="co1">-- open location &quot;x-launchbar:select?string=&quot;&amp;urldecode(_res)</span>
	<span class="kw1">set <span class="kw2">the</span> clipboard to</span> _res
<span class="kw3">end</span> handle_string
&nbsp;
<span class="kw3">on</span> <span class="kw1">run</span>
	<span class="kw1">set <span class="kw2">the</span> clipboard to</span> urldecode<span class="br0">&#40;</span><span class="kw1">the clipboard</span> <span class="kw2">as</span> <span class="kw1">text</span><span class="br0">&#41;</span>
<span class="kw3">end</span> <span class="kw1">run</span>
&nbsp;
<span class="kw3">on</span> urldecode<span class="br0">&#40;</span>theText<span class="br0">&#41;</span> <span class="co1">-- http://harvey.nu/applescript_url_decode_routine.html</span>
	<span class="kw3">set</span> sDst <span class="kw3">to</span> <span class="st0">&quot;&quot;</span>
	<span class="kw3">set</span> sHex <span class="kw3">to</span> <span class="st0">&quot;0123456789ABCDEF&quot;</span>
	<span class="kw3">set</span> i <span class="kw3">to</span> <span class="nu0">1</span>
	<span class="kw3">repeat</span> <span class="kw3">while</span> i <span class="sy0">&amp;</span>le; length <span class="kw3">of</span> theText
		<span class="kw3">set</span> c <span class="kw3">to</span> character i <span class="kw3">of</span> theText
		<span class="kw3">if</span> c <span class="sy0">=</span> <span class="st0">&quot;+&quot;</span> <span class="kw3">then</span>
			<span class="kw3">set</span> sDst <span class="kw3">to</span> sDst <span class="sy0">&amp;</span> <span class="st0">&quot; &quot;</span>
		<span class="kw3">else</span> <span class="kw3">if</span> c <span class="sy0">=</span> <span class="st0">&quot;%&quot;</span> <span class="kw3">then</span>
			<span class="kw3">if</span> i &gt; <span class="br0">&#40;</span><span class="br0">&#40;</span>length <span class="kw3">of</span> theText<span class="br0">&#41;</span> <span class="sy0">-</span> <span class="nu0">2</span><span class="br0">&#41;</span> <span class="kw3">then</span>
				<span class="kw1">display dialog</span> <span class="br0">&#40;</span><span class="st0">&quot;Invalid URL Encoded string - missing hex char&quot;</span><span class="br0">&#41;</span> <span class="kw1">buttons</span> <span class="br0">&#123;</span><span class="st0">&quot;Crap...&quot;</span><span class="br0">&#125;</span> <span class="kw3">with</span> icon stop
				<span class="kw3">return</span> <span class="st0">&quot;&quot;</span>
			<span class="kw3">end</span> <span class="kw3">if</span>
			<span class="kw3">set</span> iCVal1 <span class="kw3">to</span> <span class="br0">&#40;</span><span class="kw1">offset of</span> <span class="br0">&#40;</span>character <span class="br0">&#40;</span>i <span class="sy0">+</span> <span class="nu0">1</span><span class="br0">&#41;</span> <span class="kw3">of</span> theText<span class="br0">&#41;</span> <span class="kw3">in</span> sHex<span class="br0">&#41;</span> <span class="sy0">-</span> <span class="nu0">1</span>
			<span class="kw3">set</span> iCVal2 <span class="kw3">to</span> <span class="br0">&#40;</span><span class="kw1">offset of</span> <span class="br0">&#40;</span>character <span class="br0">&#40;</span>i <span class="sy0">+</span> <span class="nu0">2</span><span class="br0">&#41;</span> <span class="kw3">of</span> theText<span class="br0">&#41;</span> <span class="kw3">in</span> sHex<span class="br0">&#41;</span> <span class="sy0">-</span> <span class="nu0">1</span>
			<span class="kw3">if</span> iCVal1 <span class="sy0">=</span> <span class="sy0">-</span><span class="nu0">1</span> <span class="kw2">or</span> iCVal2 <span class="sy0">=</span> <span class="sy0">-</span><span class="nu0">1</span> <span class="kw3">then</span>
				<span class="kw1">display dialog</span> <span class="br0">&#40;</span><span class="st0">&quot;Invalid URL Encoded string - not 2 hex chars after % sign&quot;</span><span class="br0">&#41;</span> <span class="kw1">buttons</span> <span class="br0">&#123;</span><span class="st0">&quot;Crap...&quot;</span><span class="br0">&#125;</span> <span class="kw3">with</span> icon stop
				<span class="kw3">return</span> <span class="st0">&quot;&quot;</span>
			<span class="kw3">end</span> <span class="kw3">if</span>
			<span class="kw3">set</span> sDst <span class="kw3">to</span> sDst <span class="sy0">&amp;</span> <span class="br0">&#40;</span>ASCII character <span class="br0">&#40;</span>iCVal1 <span class="sy0">*</span> <span class="nu0">16</span> <span class="sy0">+</span> iCVal2<span class="br0">&#41;</span><span class="br0">&#41;</span>
			<span class="kw3">set</span> i <span class="kw3">to</span> i <span class="sy0">+</span> <span class="nu0">2</span>
		<span class="kw3">else</span>
			<span class="kw3">set</span> sDst <span class="kw3">to</span> sDst <span class="sy0">&amp;</span> c
		<span class="kw3">end</span> <span class="kw3">if</span>
		<span class="kw3">set</span> i <span class="kw3">to</span> i <span class="sy0">+</span> <span class="nu0">1</span>
	<span class="kw3">end</span> <span class="kw3">repeat</span>
	<span class="kw3">return</span> sDst
<span class="kw3">end</span> urldecode</pre></div></div>


<div class="footnotes">
<hr />
<ol>

<li id="fn:fn1">
<p>People may love <a href="http://www.alfredapp.com/">Alfred</a>, but this is another example of why I will probably always prefer LaunchBar. Extensibility. Also, QuickSilver is dead, just give up. <a href="#fnref:fn1" rev="footnote">↩</a></p>
</li>

</ol>
</div>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/save-safari-tabs-to-instapaper/' rel='bookmark' title='Save Safari tabs to Instapaper'>Save Safari tabs to Instapaper</a></li>
<li><a href='http://brettterpstra.com/is-your-url-too-short-try-our-system-free/' rel='bookmark' title='Is your URL too short? Try our system, free!'>Is your URL too short? Try our system, free!</a></li>
<li><a href='http://brettterpstra.com/textmate-drag-command-for-base64-encoding-images/' rel='bookmark' title='TextMate drag command for Base64 encoding images'>TextMate drag command for Base64 encoding images</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/launchbar-actions-for-url-encoding-and-decoding/">LaunchBar actions for url encoding and decoding</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/launchbar-actions-for-url-encoding-and-decoding/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Quick Tip: Multi-browser hotkey with Choosy</title>
		<link>http://brettterpstra.com/quick-tip-multi-browser-hotkey-with-choosy/</link>
		<comments>http://brettterpstra.com/quick-tip-multi-browser-hotkey-with-choosy/#comments</comments>
		<pubDate>Sun, 23 Jan 2011 18:17:00 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[applescript]]></category>
		<category><![CDATA[browsers]]></category>
		<category><![CDATA[choosy]]></category>
		<category><![CDATA[experiments]]></category>
		<category><![CDATA[quicktip]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=1661</guid>
		<description><![CDATA[<p>Riffing on my AppleScript to toggle an app between foreground and hidden, and inspired by Daniel Jalkut’s script to toggle multiple Twitter apps, I wanted a way to do something similar with web browsers. I already have a great tool for intelligently detecting which browser I want to use: Choosy. Choosy lets me set up “rules” and define behaviors which&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/quick-tip-multi-browser-hotkey-with-choosy/">Quick Tip: Multi-browser hotkey with Choosy</a></p>]]></description>
			<content:encoded><![CDATA[<p><img style="display:block; margin:0 auto;" src="http://cdn2.brettterpstra.com/wp-content/uploads/2011/01/ChoosyBar.jpg?9d7bd4" alt="ChoosyBar.jpg" border="0" width="600" height="157" /></p>

<p>Riffing on my AppleScript to <a href="http://brettterpstra.com/quick-tip-applescript-application-toggle/">toggle an app between foreground and hidden</a>, and inspired by Daniel Jalkut’s <a href="http://www.red-sweater.com/blog/1646/toggle-twitter">script to toggle multiple Twitter apps</a>, I wanted a way to do something similar with web browsers. I already have a great tool for intelligently detecting which browser I want to use: <a href="http://www.choosyosx.com/">Choosy</a>.</p>

<p>Choosy lets me set up “rules” and define behaviors which select the best option from my list of browsers, using the full list, just running browsers, or more specific lists based on source and type of the url I’m opening. I just needed to get it onto a hotkey.</p>

<p>Choosy, fortunately, has a url-handler for running different behaviors, which is detailed on the <a href="http://www.choosyosx.com/api">Choosy API page</a>. All you need to do is run this AppleScript in your favorite hotkey-triggered script-launching app:</p>


<div class="wp_syntax"><div class="code"><pre class="applescript"><span class="kw1">open</span> location <span class="st0">&quot;x-choosy://open//&quot;</span></pre></div></div>


<p><a href="http://cdn2.brettterpstra.com/wp-content/uploads/2011/01/ChoosyPrefPane.jpg?9d7bd4"><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2011/01/ChoosyPrefPane-300x232.jpg?9d7bd4" alt="Choosy Preference Pane" title="Choosy Pref Pane" width="300" height="232" class="alignright size-medium wp-image-1662" /></a>That will trigger the Choosy popup HUD, which can be navigated by keyboard or mouse, where your full list of browsers shows up in your preferred order. Now, you’re hotkey will do exactly what the settings in Choosy tell it to do. You can have it automatically pick your favorite browser if none are running, or offer you a choice of preferred or all browsers. Personally, if no browser is running, I like the choice of all browsers. I also tell Choosy to automatically pick the running browser with the highest preference level in my settings if more than one are running.</p>

<p>This method works well for all the browsers I’ve tested, but has the annoying side effect of always opening a new tab in Chrome/Chromium. It’s not a big deal to me, but might be a deal breaker if Chrome is your primary browser.</p>

<p>I’m inspired to write a quick tool which takes a list of application names from AppleScript, pops up a Choosy-style HUD and returns the selected app name back to the script. A very simple <a href="http://cocoadialog.sourceforge.net/">CocoaDialog</a> kind of thing, but better looking in this specific use case. It would make it possible to do this kind of trick with any type of app, and is basically Daniel’s script on steroids. It’s on my long list of projects to play with, we’ll see what happens.</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/livereload-addendum/' rel='bookmark' title='LiveReload addendum'>LiveReload addendum</a></li>
<li><a href='http://brettterpstra.com/quick-tip-extracting-mac-app-store-reviews-as-text/' rel='bookmark' title='Quick Tip: Extracting Mac App Store reviews as text'>Quick Tip: Extracting Mac App Store reviews as text</a></li>
<li><a href='http://brettterpstra.com/watch-for-file-changes-and-refresh-your-browser-automatically/' rel='bookmark' title='Watch for file changes and refresh your browser automatically'>Watch for file changes and refresh your browser automatically</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/quick-tip-multi-browser-hotkey-with-choosy/">Quick Tip: Multi-browser hotkey with Choosy</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/quick-tip-multi-browser-hotkey-with-choosy/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Quick tip: AppleScript application toggle</title>
		<link>http://brettterpstra.com/quick-tip-applescript-application-toggle/</link>
		<comments>http://brettterpstra.com/quick-tip-applescript-application-toggle/#comments</comments>
		<pubDate>Sat, 22 Jan 2011 15:54:46 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[applescript]]></category>
		<category><![CDATA[quicktip]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=1641</guid>
		<description><![CDATA[<p>From my hat full of stupid Mac tricks: I use a lesser-known (and very old) program called Spark for defining most of the keyboard shortcuts on my system. I have a shortcut for every one of my most regularly-used applications, plus shortcuts for various AppleScripts, shell scripts, system functions, etc. I know there are more recent applications which do the&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/quick-tip-applescript-application-toggle/">Quick tip: AppleScript application toggle</a></p>]]></description>
			<content:encoded><![CDATA[<p><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2011/01/tophatmagic.jpg?9d7bd4" alt="Tophat and wand" title="tophatmagic" width="232" height="228" class="alignright size-full wp-image-1647" /></p>

<p>From my hat full of stupid Mac tricks:</p>

<p>I use a lesser-known (and very old) program called <a href="http://www.shadowlab.org/Software/spark.php">Spark</a> for defining most of the keyboard shortcuts on my system. I have a shortcut for every one of my most regularly-used applications, plus shortcuts for various AppleScripts, shell scripts, system functions, etc. I know there are more recent applications which do the same thing, but I’ve had everything set up in Spark for ages and it still works a treat. Seriously, if you want an application launcher, it’s worth checking out (and free). However, you can use this tip in any app which lets you assign a hotkey to an AppleScript (<a href="http://www.red-sweater.com/fastscripts/">FastScripts</a>, <a href="http://www.boastr.de/">BetterTouchTool</a>).</p>

<p>So, anyway, I’ve grown to like applications which have a system-wide hotkey that toggles them between foreground and hidden. It makes a lot of sense for certain applications which you check and then move on from. Sparrow, Twitter, etc. I wanted that functionality in more apps, so I run this as the AppleScript in Spark, replacing the app name with whatever I want to toggle.</p>


<div class="wp_syntax"><div class="code"><pre class="applescript"><span class="kw3">set</span> appName <span class="kw3">to</span> <span class="st0">&quot;Mail&quot;</span>
&nbsp;
<span class="kw3">set</span> appID <span class="kw3">to</span> bundle identifier <span class="kw3">of</span> <span class="br0">&#40;</span><span class="kw1">info for</span> <span class="br0">&#40;</span><span class="kw1">path to</span> <span class="kw1">application</span> appName<span class="br0">&#41;</span><span class="br0">&#41;</span>
<span class="kw3">tell</span> <span class="kw1">application</span> <span class="st0">&quot;System Events&quot;</span>
	<span class="kw3">if</span> <span class="kw2">not</span> <span class="br0">&#40;</span><span class="kw1">exists</span> process appName<span class="br0">&#41;</span> <span class="kw3">then</span>
		<span class="kw3">tell</span> <span class="kw1">application</span> appID <span class="kw3">to</span> <span class="kw1">activate</span>
	<span class="kw3">else</span>
		<span class="kw3">if</span> frontmost <span class="kw3">of</span> process appName <span class="kw3">then</span>
			<span class="kw3">set</span> visible <span class="kw3">of</span> process appName <span class="kw3">to</span> <span class="kw1">false</span>
		<span class="kw3">else</span>
			<span class="kw3">set</span> frontmost <span class="kw3">of</span> process appName <span class="kw3">to</span> <span class="kw1">true</span>
		<span class="kw3">end</span> <span class="kw3">if</span>
	<span class="kw3">end</span> <span class="kw3">if</span>
<span class="kw3">end</span> <span class="kw3">tell</span></pre></div></div>


<p><del datetime="2011-01-22T18:30:55+00:00">Sorry about the <code>do shell script</code> for launching the app. I’m really lazy about replacing more than one instance of a variable, and “tell application appName” doesn’t work, even with various “using terms from” attempts. Know how to fix that? Let me know.</del> Thanks to D Curtis and Zettt in the comments, I’ve put together a more elegant script. It does the same thing without shelling out, and the syntax is cleaned up. Thanks guys!</p>

<p><strong>One more update:</strong> after some testing, it looks like D Curtis’ first script below is much faster for some reason (I’m assuming that getting the “bundle identifier of (info for (path to application appName))” takes some extra resources). I recommend going with this one instead, but I’m leaving both up for reference:</p>


<div class="wp_syntax"><div class="code"><pre class="applescript"><span class="kw3">set</span> appName <span class="kw3">to</span> <span class="st0">&quot;Mail&quot;</span>
<span class="kw3">set</span> startIt <span class="kw3">to</span> <span class="kw1">false</span>
<span class="kw3">tell</span> <span class="kw1">application</span> <span class="st0">&quot;System Events&quot;</span>
	<span class="kw3">if</span> <span class="kw2">not</span> <span class="br0">&#40;</span><span class="kw1">exists</span> process appName<span class="br0">&#41;</span> <span class="kw3">then</span>
		<span class="kw3">set</span> startIt <span class="kw3">to</span> <span class="kw1">true</span>
	<span class="kw3">else</span> <span class="kw3">if</span> frontmost <span class="kw3">of</span> process appName <span class="kw3">then</span>
		<span class="kw3">set</span> visible <span class="kw3">of</span> process appName <span class="kw3">to</span> <span class="kw1">false</span>
	<span class="kw3">else</span>
		<span class="kw3">set</span> frontmost <span class="kw3">of</span> process appName <span class="kw3">to</span> <span class="kw1">true</span>
	<span class="kw3">end</span> <span class="kw3">if</span>
<span class="kw3">end</span> <span class="kw3">tell</span>
<span class="kw3">if</span> startIt <span class="kw3">then</span>
	<span class="kw3">tell</span> <span class="kw1">application</span> appName <span class="kw3">to</span> <span class="kw1">activate</span>
<span class="kw3">end</span> <span class="kw3">if</span></pre></div></div>

<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/quick-tip-quickly-clear-stuck-growl-notifications/' rel='bookmark' title='Quick Tip: Quickly clear stuck Growl notifications'>Quick Tip: Quickly clear stuck Growl notifications</a></li>
<li><a href='http://brettterpstra.com/automating-random-giveaways-v1-0/' rel='bookmark' title='Automating random giveaways, v1.0'>Automating random giveaways, v1.0</a></li>
<li><a href='http://brettterpstra.com/textmate-keybinding-tip/' rel='bookmark' title='A quick TextMate KeyBindings tip'>A quick TextMate KeyBindings tip</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/quick-tip-applescript-application-toggle/">Quick tip: AppleScript application toggle</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/quick-tip-applescript-application-toggle/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Answer Skype with a hotkey</title>
		<link>http://brettterpstra.com/answer-skype-with-a-hotkey/</link>
		<comments>http://brettterpstra.com/answer-skype-with-a-hotkey/#comments</comments>
		<pubDate>Sun, 03 Oct 2010 05:54:10 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[applescript]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[skype]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=1063</guid>
		<description><![CDATA[<p>If you use Skype and happen to be as clumsy as I am, you may have run into this at some point: you see a call come in, you fumble for your headset, you go back to your mouse, find the cursor on your big screen and then try to click the “Answer” button on the call window… only to&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/answer-skype-with-a-hotkey/">Answer Skype with a hotkey</a></p>]]></description>
			<content:encoded><![CDATA[<p><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2010/10/applescriptskypeicons.jpg?9d7bd4" alt="applescriptskypeicons.jpg" border="0" width="198" height="183" class="alignright" />If you use <a href="http://www.skype.com/">Skype</a> and happen to be as clumsy as I am, you may have run into this at some point: you see a call come in, you fumble for your headset, you go back to your mouse, find the cursor on your big screen and then try to click the “Answer” button on the call window… only to miss the call because you took too long. I solved this for myself a while back, and thought I’d share my solution.</p>

<p>It’s a fairly simple AppleScript that requires nothing but Skype. It will make good use of <a href="http://growl.info/">Growl</a> if you have it installed, but it’s only needed for visual feedback; the script will function fine without it. I use <a href="http://www.shadowlab.org/Software/spark.php">Spark</a> to trigger it, but you can use any kind of launcher that can run AppleScripts. If Spark isn’t your cup of tea, definitely check out <a href="http://www.red-sweater.com/fastscripts/">FastScripts</a>. Ultimately, you just need to assign the following script to a hotkey…<span id="more-1063"></span></p>

<h3>The script</h3>


<div class="wp_syntax"><div class="code"><pre class="applescript"><span class="kw3">global</span> _proc
<span class="kw3">global</span> use_growl
&nbsp;
<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> _proc <span class="kw3">to</span> <span class="kw1">name</span> <span class="kw3">of</span> processes <span class="kw2">as</span> <span class="kw1">list</span>
<span class="kw3">if</span> _proc <span class="kw2">contains</span> <span class="st0">&quot;GrowlHelperApp&quot;</span> <span class="kw3">then</span>
	<span class="kw3">set</span> use_growl <span class="kw3">to</span> <span class="kw1">true</span>
	<span class="kw3">my</span> growlRegister<span class="br0">&#40;</span><span class="br0">&#41;</span>
<span class="kw3">else</span>
	<span class="kw3">set</span> use_growl <span class="kw3">to</span> <span class="kw1">false</span>
<span class="kw3">end</span> <span class="kw3">if</span>
&nbsp;
<span class="kw3">if</span> _proc <span class="kw2">contains</span> <span class="st0">&quot;Skype&quot;</span> <span class="kw3">then</span>
	<span class="kw3">tell</span> <span class="kw1">application</span> <span class="st0">&quot;Skype&quot;</span>
		<span class="kw3">set</span> calls <span class="kw3">to</span> send command <span class="st0">&quot;SEARCH ACTIVECALLS&quot;</span> <span class="kw3">script</span> <span class="kw1">name</span> <span class="st0">&quot;AnsweringScript&quot;</span>
		<span class="kw3">set</span> callID <span class="kw3">to</span> <span class="kw2">last</span> word <span class="kw3">of</span> calls
		<span class="kw3">if</span> callID <span class="kw3">is</span> <span class="kw2">not</span> <span class="st0">&quot;CALLS&quot;</span> <span class="kw3">then</span>
			<span class="kw3">set</span> status <span class="kw3">to</span> send command <span class="st0">&quot;GET CALL &quot;</span> <span class="sy0">&amp;</span> callID <span class="sy0">&amp;</span> <span class="st0">&quot; STATUS&quot;</span> <span class="kw3">script</span> <span class="kw1">name</span> <span class="st0">&quot;AnsweringScript&quot;</span>
			<span class="kw3">if</span> <span class="kw2">last</span> word <span class="kw3">of</span> status <span class="kw3">is</span> <span class="st0">&quot;RINGING&quot;</span> <span class="kw3">then</span>
				send command <span class="st0">&quot;ALTER CALL &quot;</span> <span class="sy0">&amp;</span> callID <span class="sy0">&amp;</span> <span class="st0">&quot; ANSWER&quot;</span> <span class="kw3">script</span> <span class="kw1">name</span> <span class="st0">&quot;AnsweringScript&quot;</span>
				<span class="kw3">my</span> growlNotify<span class="br0">&#40;</span><span class="st0">&quot;SkypeAnswer&quot;</span>, <span class="st0">&quot;Answering call&quot;</span><span class="br0">&#41;</span>
				<span class="kw3">return</span>
			<span class="kw3">else</span>
				send command <span class="st0">&quot;ALTER CALL &quot;</span> <span class="sy0">&amp;</span> callID <span class="sy0">&amp;</span> <span class="st0">&quot; HANGUP&quot;</span> <span class="kw3">script</span> <span class="kw1">name</span> <span class="st0">&quot;AnsweringScript&quot;</span>
				<span class="kw3">my</span> growlNotify<span class="br0">&#40;</span><span class="st0">&quot;SkypeAnswer&quot;</span>, <span class="st0">&quot;Hanging up&quot;</span><span class="br0">&#41;</span>
			<span class="kw3">end</span> <span class="kw3">if</span>
		<span class="kw3">else</span>
			<span class="kw3">my</span> growlNotify<span class="br0">&#40;</span><span class="st0">&quot;SkypeAnswer&quot;</span>, <span class="st0">&quot;No call found to answer or hang up&quot;</span><span class="br0">&#41;</span>
		<span class="kw3">end</span> <span class="kw3">if</span>
	<span class="kw3">end</span> <span class="kw3">tell</span>
<span class="kw3">else</span>
	<span class="kw3">my</span> growlNotify<span class="br0">&#40;</span><span class="st0">&quot;SkypeAnswer&quot;</span>, <span class="st0">&quot;Skype not detected&quot;</span><span class="br0">&#41;</span>
<span class="kw3">end</span> <span class="kw3">if</span>
&nbsp;
using terms <span class="kw3">from</span> <span class="kw1">application</span> <span class="st0">&quot;GrowlHelperApp&quot;</span>
	<span class="kw3">on</span> growlRegister<span class="br0">&#40;</span><span class="br0">&#41;</span>
		<span class="kw3">tell</span> <span class="kw1">application</span> <span class="st0">&quot;GrowlHelperApp&quot;</span>
			register <span class="kw2">as</span> <span class="kw1">application</span> <span class="st0">&quot;SkypeAnswer&quot;</span> all notifications <span class="br0">&#123;</span><span class="st0">&quot;Alert&quot;</span><span class="br0">&#125;</span> default notifications <span class="br0">&#123;</span><span class="st0">&quot;Alert&quot;</span><span class="br0">&#125;</span> icon <span class="kw3">of</span> <span class="kw1">application</span> <span class="st0">&quot;Skype.app&quot;</span>
		<span class="kw3">end</span> <span class="kw3">tell</span>
	<span class="kw3">end</span> growlRegister
&nbsp;
	<span class="kw3">on</span> growlNotify<span class="br0">&#40;</span>grrTitle, grrDescription<span class="br0">&#41;</span>
		<span class="kw3">if</span> use_growl <span class="kw3">is</span> <span class="kw1">true</span> <span class="kw3">then</span>
			<span class="kw3">tell</span> <span class="kw1">application</span> <span class="st0">&quot;GrowlHelperApp&quot;</span>
				notify <span class="kw3">with</span> <span class="kw1">name</span> <span class="st0">&quot;Alert&quot;</span> title grrTitle description grrDescription <span class="kw1">application</span> <span class="kw1">name</span> <span class="st0">&quot;SkypeAnswer&quot;</span>
			<span class="kw3">end</span> <span class="kw3">tell</span>
		<span class="kw3">end</span> <span class="kw3">if</span>
	<span class="kw3">end</span> growlNotify
<span class="kw3">end</span> using terms <span class="kw3">from</span></pre></div></div>


<p><a href="applescript://com.apple.scripteditor?action=new&amp;script=global%20_proc%0Aglobal%20use_growl%0A%0Atell%20application%20%22System%20Events%22%20to%20set%20_proc%20to%20name%20of%20processes%20as%20list%0Aif%20_proc%20contains%20%22GrowlHelperApp%22%20then%0A%09set%20use_growl%20to%20true%0A%09my%20growlRegister%28%29%0Aelse%0A%09set%20use_growl%20to%20false%0Aend%20if%0A%0Aif%20_proc%20contains%20%22Skype%22%20then%0A%09tell%20application%20%22Skype%22%0A%09%09set%20calls%20to%20send%20command%20%22SEARCH%20ACTIVECALLS%22%20script%20name%20%22AnsweringScript%22%0A%09%09set%20callID%20to%20last%20word%20of%20calls%0A%09%09if%20callID%20is%20not%20%22CALLS%22%20then%0A%09%09%09set%20status%20to%20send%20command%20%22GET%20CALL%20%22%20%26%20callID%20%26%20%22%20STATUS%22%20script%20name%20%22AnsweringScript%22%0A%09%09%09if%20last%20word%20of%20status%20is%20%22RINGING%22%20then%0A%09%09%09%09send%20command%20%22ALTER%20CALL%20%22%20%26%20callID%20%26%20%22%20ANSWER%22%20script%20name%20%22AnsweringScript%22%0A%09%09%09%09my%20growlNotify%28%22SkypeAnswer%22%2C%20%22Answering%20call%22%29%0A%09%09%09%09return%0A%09%09%09else%0A%09%09%09%09send%20command%20%22ALTER%20CALL%20%22%20%26%20callID%20%26%20%22%20HANGUP%22%20script%20name%20%22AnsweringScript%22%0A%09%09%09%09my%20growlNotify%28%22SkypeAnswer%22%2C%20%22Hanging%20up%22%29%0A%09%09%09end%20if%0A%09%09else%0A%09%09%09my%20growlNotify%28%22SkypeAnswer%22%2C%20%22No%20call%20found%20to%20answer%20or%20hang%20up%22%29%0A%09%09end%20if%0A%09end%20tell%0Aelse%0A%09my%20growlNotify%28%22SkypeAnswer%22%2C%20%22Skype%20not%20detected%22%29%0Aend%20if%0A%0Ausing%20terms%20from%20application%20%22GrowlHelperApp%22%0A%09on%20growlRegister%28%29%0A%09%09tell%20application%20%22GrowlHelperApp%22%0A%09%09%09register%20as%20application%20%22SkypeAnswer%22%20all%20notifications%20%7B%22Alert%22%7D%20default%20notifications%20%7B%22Alert%22%7D%20icon%20of%20application%20%22Skype%2Eapp%22%0A%09%09end%20tell%0A%09end%20growlRegister%0A%09%0A%09on%20growlNotify%28grrTitle%2C%20grrDescription%29%0A%09%09if%20use_growl%20is%20true%20then%0A%09%09%09tell%20application%20%22GrowlHelperApp%22%0A%09%09%09%09notify%20with%20name%20%22Alert%22%20title%20grrTitle%20description%20grrDescription%20application%20name%20%22SkypeAnswer%22%0A%09%09%09end%20tell%0A%09%09end%20if%0A%09end%20growlNotify%0Aend%20using%20terms%20from">Open this script in your Script Editor</a></p>

<p>In an app like Spark, I can just paste the source into a new command and assign a hotkey. If you’re running a launcher that needs file input, just open the source in your AppleScript Editor and save it as an .scpt file, then point to that.</p>

<p>The script basically looks at current calls in Skype, and if a call is ringing or in progress, it takes the appropriate action (answers if it’s ringing, hangs up if it’s in progress). If no calls are happening, it will just exit (with a little whimper via Growl). Put it on an easy-to-hit keyboard shortcut and you’ll be able to grab your headset and answer a call faster than, well… faster than I’ve ever managed to without it.</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/address-book-search-and-skype-from-the-command-line/' rel='bookmark' title='Address Book search and Skype from the command line'>Address Book search and Skype from the command line</a></li>
<li><a href='http://brettterpstra.com/geeklet-top-ram-processes/' rel='bookmark' title='Geeklet: Top RAM Processes'>Geeklet: Top RAM Processes</a></li>
<li><a href='http://brettterpstra.com/duplicating-safari-browsing-sessions-between-macs/' rel='bookmark' title='Duplicating Safari browsing sessions between Macs'>Duplicating Safari browsing sessions between Macs</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/answer-skype-with-a-hotkey/">Answer Skype with a hotkey</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/answer-skype-with-a-hotkey/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>HomeControl: Local Mac control for iPhone</title>
		<link>http://brettterpstra.com/homecontrol-local-mac-control-for-iphone/</link>
		<comments>http://brettterpstra.com/homecontrol-local-mac-control-for-iphone/#comments</comments>
		<pubDate>Sun, 03 Oct 2010 02:31:37 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[Featured]]></category>
		<category><![CDATA[applescript]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[scripting]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=1041</guid>
		<description><![CDATA[<p>I put together this little web app today as a proof of concept (that got a little out of hand). It basically provides a full interface for volume control, application starting and stopping and many iTunes functions, including volume and EQ. All features provide interface feedback and update you with current info from your Mac.</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/homecontrol-local-mac-control-for-iphone/">HomeControl: Local Mac control for iPhone</a></p>]]></description>
			<content:encoded><![CDATA[<p><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2010/10/homecontrolpostimage.jpg?9d7bd4" alt="" title="homecontrolpostimage" width="300" height="264" class="alignright size-full wp-image-1047" />I tried out <a href="http://dashdingo.org/post/1075781336/mute-mac-osx-from-iphone">a tip</a> recently for controlling a Mac via Mobile Safari on your iPhone, and it got me thinking, which is often dangerous. I put together this little web app today as a proof of concept (that got a little out of hand). It basically provides a full interface for volume control, application starting and stopping and many iTunes functions, including volume and EQ. All features provide interface feedback and update you with current info from your Mac.</p>

<h3>Video preview</h3>

<p>httpv://www.youtube.com/watch?v=KTcISVU4Nf4</p>

<p><a href="http://www.youtube.com/watch?v=KTcISVU4Nf4&amp;fmt=21">YouTube Link…</a></p>

<p><span id="more-1041"></span></p>

<h3>Setting up your web server</h3>

<p>To run it, you need to run your local web server as your own user. This is, of course, a major security risk and completely inadvisable if your local web server is open to outsiders in any way. Mine’s not, so I didn’t put too much time into figuring out a more secure way to do this. If you have any clues in that area, let me know and I’ll post them.</p>

<p>To run your local web server as a different user, you need to edit <code>/etc/apache2/httpd.conf</code>. You’ll need to edit it as root, so use sudo to launch your text editor of choice (e.g. <code>sudo vi /etc/apache2/httpd.conf</code>). If you, like me, just use TextMate’s <code>mate</code> command, you’ll be prompted for a password when you save.</p>

<p>Locate the lines:</p>

<pre><code>User _www
Group _www
</code></pre>

<p>Change them to:</p>

<pre><code>User yourusername
Group staff
</code></pre>

<p>You’ll also need to enable PHP, if you haven’t already. If you haven’t, locate the line that starts with:</p>

<pre><code>#LoadModule php5_module
</code></pre>

<p>Just remove the hashmark at the beginning (#) to turn PHP on.</p>

<p>Now, at the command line, type <code>sudo apachectl graceful</code> to restart the server under the new user. If everything is in place, you’ll be able to run HomeControl without a hitch now. Turn on Web Sharing in System Preferences &gt; Sharing to keep the web server running through reboots and logouts.</p>

<h3>Installing HomeControl</h3>

<p>Just download the zip file at the end of this post and unzip it into your <code>~/Sites</code> folder. If you prefer to have it elsewhere, or have a custom folder set up for Apache, it will run just fine in any folder, as long as you can access it from a web browser on the local network.</p>

<p>Next, point your web browser to the folder. If you put the ‘homecontrol’ folder directly in <code>~/Sites</code>, you should be able to reach it at the url <code>http://computer_name.local/~Username/homecontrol</code>. You need to know the name of the computer it’s on (set in System Preferences &gt; Sharing, at the top), and your username on that system, substituting each in the appropriate place in the url.</p>

<p>Once you’ve loaded the page and tested it out, use the “+” icon at the bottom of Mobile Safari’s web browser to add an icon to your home screen which will take you directly there in the future, and will run the app full-screen.</p>

<h3>Customizing HomeControl</h3>

<p>Since I know not everybody who wants to try this out is going to be ready to hack into the jQuery and PHP, I made quite a few bits of the app modifiable with simple HTML edits. If you’re comfortable with that, you can change the list of applications and add iTunes features quite easily.</p>

<h4>Application launcher</h4>

<ul>
<li>Locate the div with the id “apps”</li>
<li>Find the unordered list (<code>&lt;ul&gt;</code>) inside of it</li>
<li>Edit or copy and edit existing lines by changing only the name of the application in the first span</li>
<li>Use the exact displayed name of the application you want to control, and HomeControl will pass it to the PHP exec function</li>
</ul>

<h4>iTunes functions</h4>

<ul>
<li>Locate the div with the id “itunes”</li>
<li>Find the unordered list inside of it with the id “itunescmd”</li>
<li>Add new features by copying an existing line and changing the rel attribute and the text of the link

<ul>
<li>The rel attribute passes the actual iTunes AppleScript command, which will be appended to a ‘<code>tell application "iTunes" to</code>’ line and passed to osascript</li>
<li>The text of the link is the title which will appear in the menu</li>
</ul></li>
</ul>

<h4>iTunes EQ Presets</h4>

<ul>
<li>Locate the div with the id “ituneseq”</li>
<li>Find the unordered list inside of it</li>
<li>Edit the text of the links in the list with the exact title of the preset you want to control</li>
<li>Add or remove list items as desired</li>
</ul>

<h4>Startup screen and icon</h4>

<ul>
<li>Edit <code>homecontrolicon.png</code> in the <code>homecontrol</code> folder to customize the app’s icon on the homescreen.</li>
<li>Edit <code>hc_startup.png</code> in the <code>homecontrol</code> folder to customize the startup screen.</li>
<li>If you’ve installed the web app, delete the icon and reinstall from Mobile Safari to see the new images.</li>
</ul>

<h4>Advanced customization</h4>

<p>If you’re handy with the jQuery, the PHP and the HTML, you can do a lot with the examples in the code. It’s very much a proof-of-concept, and intended to be a jumping point for more experimentation, so have at it.</p>

<p>The app currently uses the <a href="http://www.jqtouch.com/">jQTouch</a> library, but mostly for the CSS. It has very few dependencies on the API, so it should be a relatively trivial matter to switch to a different library. It does rely quite heavily on jQuery, though.</p>

<p>The main PHP/osascript calls are in <code>functions.php</code>. All functions are called using jQuery’s $.get function, which makes Ajax calls to the <code>functions.php</code> file in the background and receives updates on completion.</p>

<p>Have fun, hopefully my horrible waste of time will be someone else’s inspiration…</p>

<p><div id="attachment_1045" class="wp-caption alignleft" style="width: 160px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; float: left;"><a href="http://cdn2.brettterpstra.com/wp-content/uploads/2010/10/homecontrolhomescreen.jpg?9d7bd4"><img src="http://cdn2.brettterpstra.com/wp-content/uploads/2010/10/homecontrolhomescreen-150x150.jpg?9d7bd4" alt="Screenshot of HomeControl Main Screen" title="HomeControl Main Screen" width="150" height="150" class="size-thumbnail wp-image-1045" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text"> Main Screen</p></div>
<div id="attachment_1042" class="wp-caption alignleft" style="width: 160px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; float: left;"><a href="http://cdn2.brettterpstra.com/wp-content/uploads/2010/10/homecontrolapplications.jpg?9d7bd4"><img src="http://cdn2.brettterpstra.com/wp-content/uploads/2010/10/homecontrolapplications-150x150.jpg?9d7bd4" alt="Screenshot of HomeControl Applications Screen" title="HomeControl Applications Screen" width="150" height="150" class="size-thumbnail wp-image-1042" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">Applications Screen</p></div>
<div id="attachment_1046" class="wp-caption alignleft" style="width: 160px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; float: left;"><a href="http://cdn2.brettterpstra.com/wp-content/uploads/2010/10/homecontrolitunes.jpg?9d7bd4"><img src="http://cdn2.brettterpstra.com/wp-content/uploads/2010/10/homecontrolitunes-150x150.jpg?9d7bd4" alt="Screenshot of HomeControl iTunes controls" title="HomeControl iTunes controls" width="150" height="150" class="size-thumbnail wp-image-1046" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">iTunes controls</p></div></p>

<h3>Download</h3>

<div class="download_desc"><p class="download-icon"><a href="http://brettterpstra.com/downloads/homecontrol.0.10.zip?9d7bd4" title="Download HomeControl (1392)"><img src="http://cdn2.brettterpstra.com/wp-content/uploads/downloads/thumbnails/2010/10/homecontrolicon.png?9d7bd4" alt="download image for HomeControl" width="64" /></a><br /><a href="http://brettterpstra.com/downloads/homecontrol.0.10.zip?9d7bd4" title="Download HomeControl (1392)" class="download-button">Download</a></p><p class="desc"><a href="http://brettterpstra.com/downloads/homecontrol.0.10.zip?9d7bd4" title="Download HomeControl (1392)">HomeControl</a> — A web app—designed to run on a local server and be accessed over the local network—which provides control over volume, iTunes features and application launching. This is a skeleton for further experimentation. <a href="http://brettterpstra.com/homecontrol-local-mac-control-for-iphone">More Info</a></p></div>


<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/promptdown-for-ios-mobile-markdown-teleprompter/' rel='bookmark' title='PromptDown for iOS: Mobile Markdown Teleprompter'>PromptDown for iOS: Mobile Markdown Teleprompter</a></li>
<li><a href='http://brettterpstra.com/the-mac-and-ios-mind-mapping-app-extravaganza/' rel='bookmark' title='The Mac and iOS mind mapping app extravaganza'>The Mac and iOS mind mapping app extravaganza</a></li>
<li><a href='http://brettterpstra.com/promptdown-markdown-teleprompter/' rel='bookmark' title='Look, I made you a Markdown teleprompter'>Look, I made you a Markdown teleprompter</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/homecontrol-local-mac-control-for-iphone/">HomeControl: Local Mac control for iPhone</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/homecontrol-local-mac-control-for-iphone/feed/</wfw:commentRss>
		<slash:comments>41</slash:comments>
		</item>
		<item>
		<title>Clear sticky Growl notifications with a keyboard shortcut</title>
		<link>http://brettterpstra.com/clear-sticky-growl-notifications-with-a-keyboard-shortcut/</link>
		<comments>http://brettterpstra.com/clear-sticky-growl-notifications-with-a-keyboard-shortcut/#comments</comments>
		<pubDate>Sat, 25 Sep 2010 21:05:35 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[applescript]]></category>
		<category><![CDATA[growl]]></category>
		<category><![CDATA[keyboard]]></category>
		<category><![CDATA[os x]]></category>
		<category><![CDATA[scripting]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=1022</guid>
		<description><![CDATA[<p>I ran into a question yesterday that didn’t seem to have an obvious answer: how can I clear a stack of sticky Growl notifications using only the keyboard. It’s not been any secret that I’m a fan of keyboard shortcuts, as indicated by the extensive keyboard support I’ve added to Instapaper Beyond. So I decided to make an interim solution&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/clear-sticky-growl-notifications-with-a-keyboard-shortcut/">Clear sticky Growl notifications with a keyboard shortcut</a></p>]]></description>
			<content:encoded><![CDATA[<p><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2010/09/GrowlHelperApp.jpg?9d7bd4" alt="GrowlHelperApp.jpg" border="0" width="312" height="88" class="alignright" />I ran into a question yesterday that didn’t seem to have an obvious answer: how can I clear a stack of sticky <a href="http://growl.info/">Growl</a> notifications using only the keyboard. It’s not been any secret that I’m a fan of keyboard shortcuts, as indicated by the extensive keyboard support I’ve added to <a href="http://brettterpstra.com/instapaperbeyond/">Instapaper Beyond</a>. So I decided to make an interim solution until a specific feature for this is added, either to the Growl preferences or via AppleScript support.</p>

<p>For the record, I’m fully aware of the Option-Click shortcut to make all current notifications disappear, but thanks to all of the Twitter responses to that effect nonetheless. I really wanted a pure keyboard solution to handle this (I’m <a href="http://code.google.com/p/growl/issues/detail?id=11">not alone</a>). Usually, at least with apps that adhere to the Growl suggestion regarding stickiness, you only get sticky notifications when something goes wrong, and then you usually get more than one. I just wanted to be able to “poof” them away quickly and tend to whatever was causing them. I’m weird, I know.</p>

<p>After a lot of toying around, I decided to just go with a brute force method: quit the helper application and start it back up. It does the trick, and if you use AppleScript to handle the process, you can keep the bridge alive and experience no interruption in your Growl service. If you call the <a href="http://brettterpstra.com/tag/applescript/">AppleScript</a> with <a href="http://www.red-sweater.com/fastscripts/">FastScripts</a>, a launcher like <a href="http://www.shadowlab.org/Software/spark.php">Spark</a> or even <a href="http://code.google.com/p/blacktree-alchemy/">QuickSilver</a> or <a href="http://www.obdev.at/products/launchbar/index.html">LaunchBar</a>, you can cause all sticky notifications to disappear with a keystroke of your choice.</p>

<p>Here’s the script:</p>

<div markdown=0>
<pre><code>
tell application "GrowlHelperApp" to quit
delay 1
tell application "GrowlHelperApp" to activate
</code></pre>
</div>

<p>I found the 1 second delay necessary to let the process close out before trying to launch it again. If you run into issues with Growl not responding after running this script, you might try increasing that delay by a second or two. I also played around with using kill (grep/awk for the PID, kill the process, etc.), but the whole system stays much more stable this way.</p>

<p>There, my contribution to the keyboard-obsessed minority of OS X users.</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/quick-tip-quickly-clear-stuck-growl-notifications/' rel='bookmark' title='Quick Tip: Quickly clear stuck Growl notifications'>Quick Tip: Quickly clear stuck Growl notifications</a></li>
<li><a href='http://brettterpstra.com/quick-tip-applescript-application-toggle/' rel='bookmark' title='Quick tip: AppleScript application toggle'>Quick tip: AppleScript application toggle</a></li>
<li><a href='http://brettterpstra.com/answer-skype-with-a-hotkey/' rel='bookmark' title='Answer Skype with a hotkey'>Answer Skype with a hotkey</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/clear-sticky-growl-notifications-with-a-keyboard-shortcut/">Clear sticky Growl notifications with a keyboard shortcut</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/clear-sticky-growl-notifications-with-a-keyboard-shortcut/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Taskpaper Date Scripts</title>
		<link>http://brettterpstra.com/taskpaper-date-scripts/</link>
		<comments>http://brettterpstra.com/taskpaper-date-scripts/#comments</comments>
		<pubDate>Fri, 10 Sep 2010 07:36:39 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[applescript]]></category>
		<category><![CDATA[date]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[TaskPaper]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=940</guid>
		<description><![CDATA[<p>4 quick scripts for TaskPaper users tonight, specifically for handling dates quickly. If you’ve used my other TaskPaper scripts, you know you can use natural language to set start and due dates, and then convert them with the Expand Dates script. These scripts allow you to assign shortcut keys to increment and decrement start and due dates. Just add them&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/taskpaper-date-scripts/">Taskpaper Date Scripts</a></p>]]></description>
			<content:encoded><![CDATA[<p><a href="http://cdn2.brettterpstra.com/wp-content/uploads/2010/09/TaskpaperDates.jpg?9d7bd4"><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2010/09/TaskpaperDates-300x77.jpg?9d7bd4" alt="" title="TaskpaperDates" width="300" height="77" class="alignright size-medium wp-image-942" /></a>4 quick scripts for TaskPaper users tonight, specifically for handling dates quickly. If you’ve used my <a href="http://brettterpstra.com/a-few-scripts-for-taskpaper-users/">other TaskPaper scripts</a>, you know you can use natural language to set start and due dates, and then convert them with the Expand Dates script. These scripts allow you to assign shortcut keys to increment and decrement start and due dates.</p>

<p><a href="http://cdn2.brettterpstra.com/wp-content/uploads/2010/09/KeyboardPrefsNewShortcut.jpg?9d7bd4"><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2010/09/KeyboardPrefsNewShortcut-150x150.jpg?9d7bd4" alt="" title="KeyboardPrefsNewShortcut" width="150" height="150" class="noshadow alignright size-thumbnail wp-image-941" /></a>Just add them to your TaskPaper Scripts folder (pull down the script menu and choose Open Scripts Folder). Then, assign them keyboard shortcuts using the Keyboard Preferences pane of System Preferences.</p>

<p>Put your cursor on a line with a task and run them. If there is no matching tag (@start or @due), one will be added for the current date. Once there’s a tag there, it will go forward and backwards days, depending on which script you’re running. Enjoy!</p>

<div class="download_desc"><p class="download-icon"><a href="http://brettterpstra.com/downloads/TaskPaperDates.zip?9d7bd4" title="Download TaskPaper Date Scripts (401)"><img src="http://cdn2.brettterpstra.com/wp-content/uploads/downloads/thumbnails/2010/09/taskpaperscripticon.png?9d7bd4" alt="download image for TaskPaper Date Scripts" width="64" /></a><br /><a href="http://brettterpstra.com/downloads/TaskPaperDates.zip?9d7bd4" title="Download TaskPaper Date Scripts (401)" class="download-button">Download</a></p><p class="desc"><a href="http://brettterpstra.com/downloads/TaskPaperDates.zip?9d7bd4" title="Download TaskPaper Date Scripts (401)">TaskPaper Date Scripts</a> — 4 Scripts to increment and decrement start and due dates in TaskPaper. <a href="http://brettterpstra.com/taskpaper-date-scripts/">More Info</a></p></div>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/a-few-scripts-for-taskpaper-users/' rel='bookmark' title='A few scripts for TaskPaper users'>A few scripts for TaskPaper users</a></li>
<li><a href='http://brettterpstra.com/automating-taskpaper-to-day-one-logs/' rel='bookmark' title='Automating TaskPaper to Day One logs'>Automating TaskPaper to Day One logs</a></li>
<li><a href='http://brettterpstra.com/natural-language-date-conversion-for-textmate/' rel='bookmark' title='Natural language date conversion for TextMate'>Natural language date conversion for TextMate</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/taskpaper-date-scripts/">Taskpaper Date Scripts</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/taskpaper-date-scripts/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>EverSave revisited, now with session restore!</title>
		<link>http://brettterpstra.com/eversave-revisited-now-with-session-restore/</link>
		<comments>http://brettterpstra.com/eversave-revisited-now-with-session-restore/#comments</comments>
		<pubDate>Fri, 16 Jul 2010 01:50:46 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[applescript]]></category>
		<category><![CDATA[evernote]]></category>
		<category><![CDATA[safari]]></category>
		<category><![CDATA[service]]></category>
		<category><![CDATA[snow leopard]]></category>
		<category><![CDATA[System Service]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=744</guid>
		<description><![CDATA[<p>Safari 5 has brought several solutions for managing lists of open tabs, from the simple (like my TabLinks extension) to full session-management capabilities (see the beautiful Sessions extension). However, I’ve found I still like using my EverSave script in many situations, primarily because it allows me to annotate, tag and sync my important sessions for later retrieval. One thing’s been&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/eversave-revisited-now-with-session-restore/">EverSave revisited, now with session restore!</a></p>]]></description>
			<content:encoded><![CDATA[<p>Safari 5 has brought several solutions for managing lists of open tabs, from the simple (like my <a href="http://brettterpstra.com/2010/06/18/tablinks-safari-extension/">TabLinks extension</a>) to full session-management capabilities (see the beautiful <a href="http://dl.dropbox.com/u/8247646/sessions/index.html">Sessions extension</a>). However, I’ve found I still like using my <a href="http://brettterpstra.com/2010/03/06/saving-safari-browsing-sessions-to-evernote/">EverSave script</a> in many situations, primarily because it allows me to annotate, tag and sync my important sessions for later retrieval. One thing’s been bugging me, though, and that’s the inability to do a mass restore on a tab list (i.e. open them all at once).</p>

<p>When I decided to fix this, the first issue was that when EverSave creates the Evernote note, it lets Evernote convert the list from HTML to Rich Text. Once it’s stored in Rich Text Format (RTF), manipulating it via any shell language, including AppleScript, becomes quite difficult. It’s not impossible, but I quickly decided it wasn’t a route I wanted to wander down. Here’s what I <strong>did</strong> do…
<span id="more-744"></span></p>

<h3>Saving tabs to Evernote</h3>

<p>What I ended up doing was modifying what EverSave stored, and including the actual URL in the visible text of the note. It’s not the prettiest solution, but it’s the only way that this particular system will work. I did my best to minimize the visual presence of the URL using the rudimentary markup that Evernote actually pays attention to. The final product looks like this:</p>

<p><img src="http://cdn2.brettterpstra.com/wp-content/uploads/2010/07/EverSaveRevisedBookmarks1.jpg?9d7bd4" alt="EverSaveRevisedBookmarks.jpg" border="0" width="650" height="93" /></p>

<p>The actual layout is still fully controlled by the _template property in the first line, which is the only line that’s changed from the original script. I’m posting the whole thing again, with this minor revision, for convenience. With a little bit of HTML (remember to escape your double quotes), you can modify the template to look however you like. Just keep in mind that Evernote strips 90% of markup out when it creates the note from your HTML, so stick with basic tags. See the <a href="http://brettterpstra.com/2010/03/06/saving-safari-browsing-sessions-to-evernote/">original EverSave post</a> for a breakdown of the script.</p>

<p>Be sure to continue reading after the script to see how we handle the “restore” functionality.</p>


<div class="wp_syntax"><div class="code"><pre class="applescript"><span class="kw3">property</span> _template : <span class="st0">&quot;&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;</span><span class="re0">%url</span><span class="st0">&quot;&gt;&amp;uArr;&lt;/a&gt; %name&lt;/strong&gt; &lt; &lt;small&gt;%url&lt;/small&gt; &gt;&quot;</span>
&nbsp;
<span class="co1">--search and replace function for template</span>
<span class="kw3">on</span> snr<span class="br0">&#40;</span>tofind, toreplace, TheString<span class="br0">&#41;</span>
	<span class="kw3">set</span> ditd <span class="kw3">to</span> <span class="kw1">text</span> <span class="kw1">item</span> <span class="kw1">delimiters</span>
	<span class="kw3">set</span> <span class="kw1">text</span> <span class="kw1">item</span> <span class="kw1">delimiters</span> <span class="kw3">to</span> tofind
	<span class="kw3">set</span> textItems <span class="kw3">to</span> <span class="kw1">text</span> <span class="kw1">items</span> <span class="kw3">of</span> TheString
	<span class="kw3">set</span> <span class="kw1">text</span> <span class="kw1">item</span> <span class="kw1">delimiters</span> <span class="kw3">to</span> toreplace
	<span class="kw3">if</span> <span class="br0">&#40;</span>class <span class="kw3">of</span> TheString <span class="kw3">is</span> <span class="kw1">string</span><span class="br0">&#41;</span> <span class="kw3">then</span>
		<span class="kw3">set</span> res <span class="kw3">to</span> textItems <span class="kw2">as</span> <span class="kw1">string</span>
	<span class="kw3">else</span> <span class="co1">-- if (class of TheString is Unicode text) then</span>
		<span class="kw3">set</span> res <span class="kw3">to</span> textItems <span class="kw2">as</span> Unicode <span class="kw1">text</span>
	<span class="kw3">end</span> <span class="kw3">if</span>
	<span class="kw3">set</span> <span class="kw1">text</span> <span class="kw1">item</span> <span class="kw1">delimiters</span> <span class="kw3">to</span> ditd
	<span class="kw3">return</span> res
<span class="kw3">end</span> snr
&nbsp;
<span class="kw3">set</span> prettyDate <span class="kw3">to</span> <span class="kw1">do shell script</span> <span class="st0">&quot;date '+%A, %B %d, %Y at %l:%M %p'&quot;</span>
<span class="kw3">set</span> theTitle <span class="kw3">to</span> <span class="st0">&quot;Bookmarks &quot;</span> <span class="sy0">&amp;</span> prettyDate
<span class="kw3">set</span> urlList <span class="kw3">to</span> <span class="st0">&quot;&lt;ul&gt;&quot;</span>
&nbsp;
<span class="kw3">tell</span> <span class="kw1">application</span> <span class="st0">&quot;Safari&quot;</span>
	<span class="kw3">set</span> tabList <span class="kw3">to</span> <span class="kw2">every</span> <span class="kw1">tab</span> <span class="kw3">of</span> <span class="kw2">front</span> <span class="kw1">window</span>
	<span class="kw3">repeat</span> <span class="kw3">with</span> aTab <span class="kw3">in</span> tabList
		<span class="kw3">set</span> aLink <span class="kw3">to</span> _template
		<span class="kw3">set</span> aLink <span class="kw3">to</span> <span class="kw3">my</span> snr<span class="br0">&#40;</span><span class="st0">&quot;%name&quot;</span>, <span class="kw1">name</span> <span class="kw3">of</span> aTab, aLink<span class="br0">&#41;</span>
		<span class="kw3">set</span> aLink <span class="kw3">to</span> <span class="kw3">my</span> snr<span class="br0">&#40;</span><span class="st0">&quot;%url&quot;</span>, URL <span class="kw3">of</span> aTab, aLink<span class="br0">&#41;</span>
		<span class="kw3">set</span> urlList <span class="kw3">to</span> urlList <span class="sy0">&amp;</span> aLink <span class="sy0">&amp;</span> <span class="kw3">return</span>
	<span class="kw3">end</span> <span class="kw3">repeat</span>
<span class="kw3">end</span> <span class="kw3">tell</span>
<span class="kw3">set</span> urlList <span class="kw3">to</span> urlList <span class="sy0">&amp;</span> <span class="st0">&quot;&lt;/ul&gt;&quot;</span>
&nbsp;
<span class="kw3">tell</span> <span class="kw1">application</span> <span class="st0">&quot;Evernote&quot;</span>
	<span class="kw3">set</span> theNote <span class="kw3">to</span> create note <span class="kw3">with</span> html urlList title theTitle notebook <span class="st0">&quot;Bookmarks&quot;</span>
<span class="kw3">end</span> <span class="kw3">tell</span></pre></div></div>


<p>I have this script saved as “EverSave.scpt” in my <code>~/Library/Scripts/Applications/Safari</code> folder (create it if you don’t have it), and launch it using <a href="http://www.red-sweater.com/fastscripts/">FastScripts</a> with a Command-Shift-S shortcut. Safari doesn’t have anything bound to that key-combo, and it’s easy to remember (Save As in most programs).</p>

<h3>Restoring tabs</h3>

<p>This solution makes a few assumptions, but the script is easily customized to handle any differences in your setup. I went with a System Service (Snow Leopard) for the restore function, primarily because it allows me to act directly on selected text in Evernote. It’s a very simple Ruby script that parses the selected text for urls, and then opens any that it finds in sequential order using your default browser. There’s a commented out line if you want to always target Safari directly when opening them, which may be useful in some situations. I use <a href="http://www.choosyosx.com/">Choosy</a>, and have a rule that just directs all of these to Safari. If you have Safari set as your default browser, and that’s where you want to open your links, this will just work as is.</p>

<p>To set up the service:</p>

<ol>
<li>Open Automator and select “Service” as the new file type.</li>
<li>On the right hand side, tell it that “Service receives selected” <strong><em>text</em></strong> in <strong><em>Evernote.app</em></strong> (choose Other… and select Evernote).</li>
<li>Find “Run Shell Script” in the list on the left and drag it into the area on the right.</li>
<li>Set the Shell dropdown to /usr/bin/ruby</li>
<li>Insert the following code, and feel free to modify</li>
<li>Save the result as “EverRestore”</li>
<li>Assign a shortcut key, if desired, in System Preferences &gt; Keyboard &gt; Keyboard Shortcuts &gt; Services</li>
</ol>

<p>Here’s the code for the service:</p>


<div class="wp_syntax"><div class="code"><pre class="ruby">ARGF.<span class="me1">each</span> <span class="kw1">do</span> <span class="sy0">|</span>f<span class="sy0">|</span>
    links = f.<span class="me1">scan</span> <span class="sy0">/&lt;</span> <span class="br0">&#40;</span>https?:<span class="sy0">//</span>.<span class="sy0">*</span>?<span class="br0">&#41;</span> <span class="sy0">&gt;/</span>mi
    <span class="co1"># The above scans specifically for the angle brackets in my template. </span>
    <span class="co1"># If you remove those from the output of EverSave, be sure to update</span>
    <span class="co1"># the regular expression accordingly.</span>
    <span class="kw1">if</span> links.<span class="me1">empty</span>? <span class="kw1">then</span>
        <span class="kw3">exit</span>
    <span class="kw1">else</span>
        links.<span class="me1">each</span> <span class="br0">&#123;</span><span class="sy0">|</span>link<span class="sy0">|</span> <span class="sy0">%</span>x<span class="br0">&#123;</span>osascript <span class="sy0">-</span>e <span class="sy0">&amp;</span><span class="co1">#x27;open location &quot;#{link[0]}&quot;&amp;#x27;}}</span>
        <span class="co1"># links.each {|link| %x{osascript -e &amp;#x27;tell application &quot;Safari&quot; to open location &quot;#{link[0]}&quot;&amp;#x27;} }</span>
    <span class="kw1">end</span>
<span class="kw1">end</span></pre></div></div>


<p>The simple regular expression in line 2 does scan specifically for the angle brackets I used in the new EverSave template. That just relieves some complexity. If you want a regular expression that doesn’t require the angle brackets, try replacing line 2 with this:</p>


<div class="wp_syntax"><div class="code"><pre class="ruby">links = f.<span class="me1">scan</span> <span class="sy0">/</span><span class="br0">&#40;</span>https?:<span class="sy0">//</span><span class="br0">&#40;</span><span class="br0">&#91;</span>^s<span class="st0">&quot;,;]+)..{2,4}(/[^s&quot;</span>,;!<span class="br0">&#93;</span><span class="sy0">+</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">/</span>mi</pre></div></div>


<p>Once it’s saved in Automator, it should be available when you select text in Evernote. If there are visible URLs in the selected text, running this Service will open them in tabs in Safari (or your default browser). You can selectively open certain urls by only selecting the lines that contain the ones you want to open. Non-contiguous selections will require a little text editing, of course.</p>

<h3>Not as hard as it looks… really.</h3>

<p>The explanation got a little long, and probably seems unnecessarily complex. The fact is, I can save a Safari browsing session with one key combo, edit, annotate and tag it (if I want to), then restore it later by highlighting and typing a new command combination. It’s actually quite convenient, and fairly bulletproof. I’d love to hear how you use it, or what you’re doing instead!</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/antique-safari-reader-hack-update-with-evernote-goodness/' rel='bookmark' title='Antique Safari Reader hack update with Evernote goodness'>Antique Safari Reader hack update with Evernote goodness</a></li>
<li><a href='http://brettterpstra.com/clippable-to-evernote-snow-leopard-service/' rel='bookmark' title='Clippable to Evernote Snow Leopard Service'>Clippable to Evernote Snow Leopard Service</a></li>
<li><a href='http://brettterpstra.com/save-safari-tabs-to-instapaper/' rel='bookmark' title='Save Safari tabs to Instapaper'>Save Safari tabs to Instapaper</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/eversave-revisited-now-with-session-restore/">EverSave revisited, now with session restore!</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/eversave-revisited-now-with-session-restore/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fun with MarsEdit, part I</title>
		<link>http://brettterpstra.com/fun-with-marsedit-part-i/</link>
		<comments>http://brettterpstra.com/fun-with-marsedit-part-i/#comments</comments>
		<pubDate>Sun, 06 Jun 2010 21:02:26 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[applescript]]></category>
		<category><![CDATA[blogging]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[marsedit]]></category>
		<category><![CDATA[os x]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=533</guid>
		<description><![CDATA[<p>I’ll be the first to admit that I get a little obsessed with projects that aren’t really going to improve my life all that much. Those projects can be fun to blog about, though, so I present you my brief obsession for this Sunday afternoon. You may have noticed on this blog that some posts have header images, and some&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/fun-with-marsedit-part-i/">Fun with MarsEdit, part I</a></p>]]></description>
			<content:encoded><![CDATA[<p><img style=' display:none'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2010/06/funwithmarseditheader.jpg?9d7bd4" alt="funwithmarseditheader.jpg" border="0" width="650" height="187" class="headerimg" /></p>

<p>I’ll be the first to admit that I get a little obsessed with projects that aren’t really going to improve my life all that much. Those projects can be fun to blog about, though, so I present you my brief obsession for this Sunday afternoon.</p>

<p><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  src="http://cdn2.brettterpstra.com/wp-content/uploads/2010/06/funwithmarseditbeforeafter.jpg?9d7bd4" alt="Template header before and after" border="0" width="298" height="202" class="alignright" />You may have noticed on this blog that some posts have header images, and some don’t, and that they get styled differently based on whether there’s an image or not. It pulls the header images from one of two places: the post thumbnail (which I can’t edit from MarsEdit) or the first image in the post content with a class of “headerimg”. As long as I’m blogging in <a href="http://​www​.red​-sweater​.com/​m​a​r​s​e​d​it/">MarsEdit</a> (or TextMate for that matter), I’m stuck with the latter option. Because the whole header image deal is handled through PHP in my functions.php file, I can’t really preview how it’s going to look; rather, I get a header image stuck somewhere before, in or after my content. In TextMate, I have a little more “scriptability” at my disposal, and the previews I’ve created there are quite accurate. As far as I can tell, I can’t pre-process content before the template is generated, so I had to try something else…
<span id="more-533"></span>My solution, for now, is jQuery in the preview template. I load the jQuery library up top (inside the header) using Google’s Ajax API:</p>

<div markdown=0>
<pre><code>
&lt;script src=&quot;http://www.google.com/jsapi&quot;&gt;&lt;/script&gt;
&lt;script&gt;google.load(&quot;jquery&quot;, &quot;1.4&quot;);&lt;/script&gt;
</code></pre>
</div>

<p>Then, at the bottom, I just start polling for an image with the right class to show up. I know it’s brute force, but this isn’t exactly public-facing, and it doesn’t seem to cause any hiccups in my writing. I have this right before my closing body tag:</p>

<div markdown=0>
<pre><code>
&lt;script&gt;
function fixHeader() {
    if ($(&#x27;img.headerimg&#x27;).attr(&#x27;src&#x27;) != undefined) {
        headerImg = $(&#x27;img.headerimg&#x27;).removeClass(&#x27;headerimg&#x27;).remove();
        postThumb = $(&#x27;.postthumb:first&#x27;);
        headerImg.prependTo(postThumb);
        postThumb.addClass(&#x27;hasimage&#x27;).removeClass(&#x27;noimage&#x27;);
    }
}
setInterval(fixHeader,2000);
&lt;/script&gt;
</code></pre>
</div>

<p>I’m sharing this just to toss the idea out there, not because I think there’s anyone else with the exact same template setup as mine.</p>

<p>In addition to having Javascript at my disposal, MarsEdit is also AppleScript-able. I haven’t looked very far into that yet, but I did whip up a quick script for adding the “headerimg” class to my images (because I always forget which class I assigned for this):</p>

<div markdown=0>
<pre><code>
tell application &quot;MarsEdit&quot;
    set selectionContents to selected text of document 1
    set {astid, AppleScript&#x27;s text item delimiters} to {AppleScript&#x27;s text item delimiters, &quot;/&gt;&quot;}
    if selectionContents is not &quot;&quot; then
        set textToInsert to (text item 1 of selectionContents) &amp; &quot;class=\&quot;headerimg\&quot; /&gt;&quot;
    end if
    set AppleScript&#x27;s text item delimiters to astid
    set selected text of document 1 to textToInsert
end tell
</code></pre>
</div>

<p>That lets me just select an image (or pending upload tag) and run the script to add the necessary class.</p>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/multimarkdown-in-marsedit/' rel='bookmark' title='MultiMarkdown in MarsEdit'>MultiMarkdown in MarsEdit</a></li>
<li><a href='http://brettterpstra.com/instapaper-beyond-for-safari/' rel='bookmark' title='Instapaper Beyond for Safari'>Instapaper Beyond for Safari</a></li>
<li><a href='http://brettterpstra.com/marked-scripts-nvalt-evernote-marsedit-scrivener/' rel='bookmark' title='Marked scripts: nvALT, Evernote, MarsEdit, Scrivener'>Marked scripts: nvALT, Evernote, MarsEdit, Scrivener</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/fun-with-marsedit-part-i/">Fun with MarsEdit, part I</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/fun-with-marsedit-part-i/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Delicious bookmarks and OpenMeta tags</title>
		<link>http://brettterpstra.com/delicious-bookmarks-and-openmeta-tags/</link>
		<comments>http://brettterpstra.com/delicious-bookmarks-and-openmeta-tags/#comments</comments>
		<pubDate>Tue, 11 May 2010 11:56:50 +0000</pubDate>
		<dc:creator>Brett</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[applescript]]></category>
		<category><![CDATA[bookmarking]]></category>
		<category><![CDATA[delicious]]></category>
		<category><![CDATA[experiments]]></category>
		<category><![CDATA[openmeta]]></category>
		<category><![CDATA[os x]]></category>
		<category><![CDATA[tagging]]></category>
		<category><![CDATA[utilities]]></category>

		<guid isPermaLink="false">http://brettterpstra.com/?p=421</guid>
		<description><![CDATA[<p>There are quite a few things I love when it comes to my Mac. I love Spotlight. I love OpenMeta tagging. I love Evernote. I love being able to collect information from any source, and find anything I’ve saved, anywhere, no matter what program I used to create it. I especially love programs that allow me to accomplish that. Unfortunately,&#8230;</p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/delicious-bookmarks-and-openmeta-tags/">Delicious bookmarks and OpenMeta tags</a></p>]]></description>
			<content:encoded><![CDATA[<p>There are quite a few things I love when it comes to my Mac. I love <a href="http://www.apple.com/macosx/what-is-macosx/spotlight.html">Spotlight</a>. I love <a href="http://code.google.com/p/openmeta/">OpenMeta</a> tagging. I <a href="http://brettterpstra.com/tag/evernote/">love Evernote</a>. I love being able to collect information from any source, and find anything I’ve saved, anywhere, no matter what program I used to create it. I especially love programs that allow me to accomplish that.</p>

<p>Unfortunately, one of my favorite apps right now, <a href="http://www.delibarapp.com/">Delibar</a>, doesn’t integrate with Spotlight or OpenMeta, despite the fact that it would be relatively easy to do. Delibar is an excellent (and sexy) menubar application for creating and searching <a href="http://delicious.com/">Delicious</a> (and <a href="http://pinboard.in/">Pinboard</a>) bookmarks. A similar app, <a href="http://codesorcery.net/pukka">Pukka</a>, pulls off the Spotlight part, but I still wanted OpenMeta tags that matched my Delicious tags for local searching.</p>

<p>I also use <a href="http://www.gravityapps.com/tags/index.html">Tags.app</a> for most of my tagging. OpenMeta tags allow you to group and classify files with simple tags, and provide a Spotlight-compatible way to search more intelligently. When you tag a website with Tags, it creates a <a href="http://www.downloadatoz.com/file-extensions/webloc-file-extension.html">webloc</a> file in your metadata cache and applies the OpenMeta tags to it. I figured a similar approach would be feasible using AppleScript, and it seems to be working out great. Read on to see the script I’m using, and be sure to let me know if you improve on it!</p>

<p><span id="more-421"></span>
What I’m doing is using curl with the <a href="http://delicious.com/help/api#posts_all">Delicious API</a>, and downloading everything that’s been bookmarked within the last hour. I’m running it with <a href="http://en.wikipedia.org/wiki/Launchd">launchd</a> every hour, so I don’t want to grab more than that every time it runs. It parses out the title, tags and url for the bookmark, saves it to a .webloc file, and tags it using Tags.app’s AppleScript commands. If you’re not running Tags, it could be modified pretty easily to work with the <code>openmeta</code> command line application.</p>

<p>I’m leaving the target folder up to the user, so when you define it in the CONFIG section, make sure it’s pointing to an existing folder. The only other config properties are your Delicious username and password (sent securely). As noted in the comments in the script, you can adjust the time/date it retrieves from in the first line after the CONFIG section.</p>

<p>The script is pretty well commented, so I won’t rewrite the whole thing here. Take a look, and then I’ll show you how I installed it.</p>

<div markdown=0>
<pre><code>
-- CONFIG
property _user : &quot;username&quot; -- delicious username
property _pass : &quot;password&quot; -- delicious password
property targetFolder : &quot;/Users/ttscoff/Library/Caches/Metadata/Delicious&quot; -- POSIX path to existing folder
-- END CONFIG

set _date to do shell script &quot;date -v-1d &#x27;+%Y-%m-%dT%H:%M:%SZ&#x27;&quot;
-- returns a date 1 day ago in the format required by the twitter API.
-- you can adjust the date based on the frequency that you run the script
-- by editing the -v-1d part of the date command (-v-1H for 1 hour)
-- Note that the Delicious dates run on GMT, so you have to account for your time offset
-- For me, this means -v+4H if I want to go back one hour

set bookmarks to do shell script &quot;curl https://&quot; &amp; _user &amp; &quot;:&quot; &amp; _pass &amp; &quot;@api.del.icio.us/v1/posts/all?fromdt=&quot; &amp; _date
-- gets the bookmarks starting with the date specified in _date

set _folder to POSIX file targetFolder as alias
-- turns the POSIX path in CONFIG into an AppleScript alias

tell application &quot;System Events&quot;
    set xmlDocument to make new XML data with data bookmarks
    -- create the XML object
    set {astid, AppleScript&#x27;s text item delimiters} to {AppleScript&#x27;s text item delimiters, &quot; &quot;}
    -- store the current delimiter and set the new one to a space for breaking up the tags
    repeat with _post in XML elements of XML element 1 of xmlDocument
        set _url to value of XML attribute &quot;href&quot; of _post as string
        set _tags to text items of (value of XML attribute &quot;tag&quot; of _post as string)
        set end of _tags to &quot;delicious&quot;
        set _title to value of XML attribute &quot;description&quot; of _post as string
        try -- it fails on some files, the try block lets us keep moving if we hit a problem
            tell application &quot;Finder&quot; to set webloc to make new internet location file to _url at _folder with properties {name:_title}
            -- makes a .webloc file in our target folder
            tell application &quot;Tags&quot; to apply tags _tags to files {POSIX path of (webloc as string)}
            -- adds OpenMeta tags to our newly created file
        end try
    end repeat
    set AppleScript&#x27;s text item delimiters to astid
    -- restore the delimiters
end tell
</code></pre>
</div>

<p><a href="applescript://com.apple.scripteditor?action=new&#038;script=%2D%2D%20CONFIG%0Aproperty%20_user%20%3A%20%22username%22%20%2D%2D%20delicious%20username%0Aproperty%20_pass%20%3A%20%22password%22%20%2D%2D%20delicious%20password%0Aproperty%20targetFolder%20%3A%20%22%2FUsers%2Fttscoff%2FLibrary%2FCaches%2FMetadata%2FDelicious%22%20%2D%2D%20POSIX%20path%20to%20existing%20folder%0A%2D%2D%20END%20CONFIG%0A%0Aset%20_date%20to%20do%20shell%20script%20%22date%20%2Dv%2D1d%20%27%2B%25Y%2D%25m%2D%25dT%25H%3A%25M%3A%25SZ%27%22%0A%2D%2D%20returns%20a%20date%201%20day%20ago%20in%20the%20format%20required%20by%20the%20twitter%20API%2E%0A%2D%2D%20you%20can%20adjust%20the%20date%20based%20on%20the%20frequency%20that%20you%20run%20the%20script%0A%2D%2D%20by%20editing%20the%20%2Dv%2D1d%20part%20of%20the%20date%20command%20%28%2Dv%2D1H%20for%201%20hour%29%0A%0Aset%20bookmarks%20to%20do%20shell%20script%20%22curl%20https%3A%2F%2F%22%20%26%20_user%20%26%20%22%3A%22%20%26%20_pass%20%26%20%22%40api%2Edel%2Eicio%2Eus%2Fv1%2Fposts%2Fall%3Ffromdt%3D%22%20%26%20_date%0A%2D%2D%20gets%20the%20bookmarks%20starting%20with%20the%20date%20specified%20in%20_date%0A%0Aset%20_folder%20to%20POSIX%20file%20targetFolder%20as%20alias%0A%2D%2D%20turns%20the%20POSIX%20path%20in%20CONFIG%20into%20an%20AppleScript%20alias%0A%0Atell%20application%20%22System%20Events%22%0A%09set%20xmlDocument%20to%20make%20new%20XML%20data%20with%20data%20bookmarks%0A%09%2D%2D%20create%20the%20XML%20object%0A%09set%20%7Bastid%2C%20AppleScript%27s%20text%20item%20delimiters%7D%20to%20%7BAppleScript%27s%20text%20item%20delimiters%2C%20%22%20%22%7D%0A%09%2D%2D%20store%20the%20current%20delimiter%20and%20set%20the%20new%20one%20to%20a%20space%20for%20breaking%20up%20the%20tags%0A%09repeat%20with%20_post%20in%20XML%20elements%20of%20XML%20element%201%20of%20xmlDocument%0A%09%09set%20_url%20to%20value%20of%20XML%20attribute%20%22href%22%20of%20_post%20as%20string%0A%09%09set%20_tags%20to%20text%20items%20of%20%28value%20of%20XML%20attribute%20%22tag%22%20of%20_post%20as%20string%29%0A%09%09set%20end%20of%20_tags%20to%20%22delicious%22%0A%09%09set%20_title%20to%20value%20of%20XML%20attribute%20%22description%22%20of%20_post%20as%20string%0A%09%09try%20%2D%2D%20it%20fails%20on%20some%20files%2C%20the%20try%20block%20lets%20us%20keep%20moving%20if%20we%20hit%20a%20problem%0A%09%09%09tell%20application%20%22Finder%22%20to%20set%20webloc%20to%20make%20new%20internet%20location%20file%20to%20_url%20at%20_folder%20with%20properties%20%7Bname%3A_title%7D%0A%09%09%09%2D%2D%20makes%20a%20%2Ewebloc%20file%20in%20our%20target%20folder%0A%09%09%09tell%20application%20%22Tags%22%20to%20apply%20tags%20_tags%20to%20files%20%7BPOSIX%20path%20of%20%28webloc%20as%20string%29%7D%0A%09%09%09%2D%2D%20adds%20OpenMeta%20tags%20to%20our%20newly%20created%20file%0A%09%09end%20try%0A%09end%20repeat%0A%09set%20AppleScript%27s%20text%20item%20delimiters%20to%20astid%0A%09%2D%2D%20restore%20the%20delimiters%0Aend%20tell">Open this script in your Script Editor</a></p>

<h3>Installing</h3>

<p>The first thing I did was make a version of the script that excluded the date parameter (fromdt) in the curl call in order to download my entire history and process it so I was up-to-date. This took a while, but didn’t seem to cause any problems. The Delicious API is pretty quick to throttle you, so download the whole bunch in one API call or you’ll be in trouble.</p>

<p>After editing the config options, I saved the file as an <del datetime="2010-05-11T14:25:06+00:00">Application Bundle</del> <ins datetime="2010-05-11T14:25:06+00:00">(see addendum below)</ins> in my own apps directory (~/Applications). It doesn’t matter where you put it (or what you name it), as long as you know the path to get there. Then I set up a launchd plist to run it every 3600 seconds (hour). I highly recommend <a href="http://sourceforge.net/projects/lingon/">Lingon</a>  for editing all things launchd. It will make sense when you get there.</p>

<h3>Addendum</h3>

<p>In reference to the install procedure above, I’ve actually had more luck saving it as a text file to a scripts folder and running it with osascript through launchd. Here’s my launchd plist, which you can edit and load through the “Expert” section of Lingon’s editor.</p>

<p>Also, as I just added into the code comments above, I didn’t originally account for the fact that Delicious dates are in GMT, and my offset is –5 right now, so I have to use –v+4H to get 1 hour back, not –v-1H.</p>

<div markdown=0>
<pre><code>
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;
&lt;plist version=&quot;1.0&quot;&gt;
&lt;dict&gt;
    &lt;key&gt;Label&lt;/key&gt;
    &lt;string&gt;org.brettterpstra.GetDelicious&lt;/string&gt;
    &lt;key&gt;Nice&lt;/key&gt;
    &lt;integer&gt;8&lt;/integer&gt;
    &lt;key&gt;ProgramArguments&lt;/key&gt;
    &lt;array&gt;
        &lt;string&gt;/usr/bin/osascript&lt;/string&gt;
        &lt;string&gt;/Users/ttscoff/scripts/getdelicious&lt;/string&gt;
    &lt;/array&gt;
    &lt;key&gt;RunAtLoad&lt;/key&gt;
    &lt;true/&gt;
    &lt;key&gt;StartInterval&lt;/key&gt;
    &lt;integer&gt;3600&lt;/integer&gt;
&lt;/dict&gt;
&lt;/plist&gt;
</code></pre>
</div>

<p>Areas for improvement:</p>

<ul>
<li>Currently errors out on some bookmarks for unknown reasons</li>
<li>Could have a first-run setting to automatically download and tag ALL bookmarks</li>
<li>Could set the created date of the webloc file based on the date of the bookmark from Delicious</li>
<li>Could provide more feedback or logging</li>
</ul>
<p>Related posts:<ol>
<li><a href='http://brettterpstra.com/delicious-spotlight-and-openmeta-tags-revisited/' rel='bookmark' title='Delicious, Spotlight and OpenMeta tags, revisited'>Delicious, Spotlight and OpenMeta tags, revisited</a></li>
<li><a href='http://brettterpstra.com/mirror-your-pinboard-bookmarks-with-openmeta-tags/' rel='bookmark' title='Mirror your Pinboard bookmarks with OpenMeta tags'>Mirror your Pinboard bookmarks with OpenMeta tags</a></li>
<li><a href='http://brettterpstra.com/natural-language-date-service-update/' rel='bookmark' title='Natural Language Date Service update'>Natural Language Date Service update</a></li>
</ol></p><p>Originally posted on <a href="http://brettterpstra.com" title="BrettTerpstra.com">BrettTerpstra.com</a> at <a href="http://brettterpstra.com/delicious-bookmarks-and-openmeta-tags/">Delicious bookmarks and OpenMeta tags</a></p>]]></content:encoded>
			<wfw:commentRss>http://brettterpstra.com/delicious-bookmarks-and-openmeta-tags/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk: basic (Feed is rejected)
Page Caching using disk: enhanced
Database Caching 35/174 queries in 0.802 seconds using xcache
Object Caching 4366/4550 objects using xcache
Content Delivery Network via cdn2.brettterpstra.com

Served from: brettterpstra.com @ 2012-05-23 02:09:27 -->
