<?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"
	>

<channel>
	<title>Fetch Softworks</title>
	<atom:link href="http://fetchsoftworks.com/feed" rel="self" type="application/rss+xml" />
	<link>http://fetchsoftworks.com</link>
	<image>
		<url>/i/screen/fetch-softworks-favorite-icon.png</url>
		<title>Fetch Softworks</title>
		<link>http://fetchsoftworks.com</link>
	</image>
	<description>Just another WordPress weblog</description>
	<pubDate>Mon, 24 May 2010 22:08:00 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
			<item>
		<title>Quick Look in Fetch</title>
		<link>http://fetchsoftworks.com/fetch/news/quick-look-in-fetch</link>
		<comments>http://fetchsoftworks.com/fetch/news/quick-look-in-fetch#comments</comments>
		<pubDate>Mon, 24 May 2010 22:07:58 +0000</pubDate>
		<dc:creator>Jim Matthews</dc:creator>
				<category><![CDATA[Fetch]]></category>
		<category><![CDATA[News]]></category>

		<guid isPermaLink="false">http://fetchsoftworks.com/?p=365</guid>
		<description><![CDATA[<p>Fetch makes it easy to edit server files (<a href="http://fetchsoftworks.com/fetch/news/pick-an-editor-any-editor">using any application you like</a>), but sometimes you don't want to open the file, you just want to take a peek at it.</p><span id="more-365"></span><p>Apple responded to a similar need in the Finder by introducing the <a href="http://www.apple.com/macosx/what-is-macosx/quick-look.html">Quick Look</a> feature in Mac OS X 10.5 Leopard. Tapping the space bar displays a preview of the selected file (or files), and tapping it again dismisses that preview. Quick Look can preview text, images, videos, audio, and many other documents, including those created by Microsoft Word and Excel. And the Quick Look system is extensible: as developers release Quick Look plugins, <a href="http://www.quicklookplugins.com/">more</a> and <a href="http://www.qlplugins.com/">more</a> file types are supported.</p>
<p><img class="floatleft" src="/i/blog/quicklook-icon.png" alt="Quick Look button" />We've had Quick Look support in Fetch since releasing 5.5 last June. Just as in the Finder, tapping the space bar (or clicking the Quick Look button, or choosing the <span class="ui menu-path"><span class="menu">Remote</span><span class="menu last">Quick Look</span></span> menu command) shows a Quick Look preview of the selected file on the server. Of course Fetch has to download the file contents before they can be previewed, but that happens automatically (and Fetch remembers the file so that it doesn't have to be re-downloaded if you preview the file again). Double-clicking in the Quick Look window opens the file in the appropriate application.</p>
<p><img class="floatleft" src="/i/blog/quicklook-album-iphoto-icons.png" alt="Quick Look Album View" />Thanks to new support in Mac OS X 10.6 Snow Leopard, we were able to improve Fetch's Quick Look behavior as of Fetch 5.5.2. Now, on Snow Leopard, you can switch back and forth between viewing a bunch of files as thumbnails or as a slideshow, and you can add previewed images to iPhoto.</p>
<p><img class="floatleft" src="/i/blog/viewtextfile-icon.png" alt="" />One weakness we found with Quick Look in Fetch 5.5 has to do with its handling of text files. Quick Look does not support selecting text, so there is no way to copy a bunch of text out of the Quick Look preview in order to paste it in another application. To address this we added a <span class="ui command">View as Text</span> command to Fetch 5.5.3. <span class="ui command">View as Text</span> opens text files in separate windows, with support for selecting text.</p>
<p>Together, Quick Look and View as Text make previewing your files in Fetch easier than ever.</p>]]></description>
			<content:encoded><![CDATA[<style type="text/css" media="screen"><!--
@import "http://fetchsoftworks.com/c/screen.css";
--></style><style type="text/css" media="screen"><!--
@import "http://fetchsoftworks.com/c/feed.css";
--></style><div class="feeditem"><p>Fetch makes it easy to edit server files (<a href="http://fetchsoftworks.com/fetch/news/pick-an-editor-any-editor">using any application you like</a>), but sometimes you don't want to open the file, you just want to take a peek at it.</p><span id="more-365"></span><p>Apple responded to a similar need in the Finder by introducing the <a href="http://www.apple.com/macosx/what-is-macosx/quick-look.html">Quick Look</a> feature in Mac OS X 10.5 Leopard. Tapping the space bar displays a preview of the selected file (or files), and tapping it again dismisses that preview. Quick Look can preview text, images, videos, audio, and many other documents, including those created by Microsoft Word and Excel. And the Quick Look system is extensible: as developers release Quick Look plugins, <a href="http://www.quicklookplugins.com/">more</a> and <a href="http://www.qlplugins.com/">more</a> file types are supported.</p>
<p><img class="floatleft" src="/i/blog/quicklook-icon.png" alt="Quick Look button" />We've had Quick Look support in Fetch since releasing 5.5 last June. Just as in the Finder, tapping the space bar (or clicking the Quick Look button, or choosing the <span class="ui menu-path"><span class="menu">Remote</span><span class="menu last">Quick Look</span></span> menu command) shows a Quick Look preview of the selected file on the server. Of course Fetch has to download the file contents before they can be previewed, but that happens automatically (and Fetch remembers the file so that it doesn't have to be re-downloaded if you preview the file again). Double-clicking in the Quick Look window opens the file in the appropriate application.</p>
<p><img class="floatleft" src="/i/blog/quicklook-album-iphoto-icons.png" alt="Quick Look Album View" />Thanks to new support in Mac OS X 10.6 Snow Leopard, we were able to improve Fetch's Quick Look behavior as of Fetch 5.5.2. Now, on Snow Leopard, you can switch back and forth between viewing a bunch of files as thumbnails or as a slideshow, and you can add previewed images to iPhoto.</p>
<p><img class="floatleft" src="/i/blog/viewtextfile-icon.png" alt="" />One weakness we found with Quick Look in Fetch 5.5 has to do with its handling of text files. Quick Look does not support selecting text, so there is no way to copy a bunch of text out of the Quick Look preview in order to paste it in another application. To address this we added a <span class="ui command">View as Text</span> command to Fetch 5.5.3. <span class="ui command">View as Text</span> opens text files in separate windows, with support for selecting text.</p>
<p>Together, Quick Look and View as Text make previewing your files in Fetch easier than ever.</p></div>]]></content:encoded>
			<wfw:commentRss>http://fetchsoftworks.com/fetch/news/quick-look-in-fetch/feed</wfw:commentRss>
		</item>
		<item>
		<title>Still More Reliability</title>
		<link>http://fetchsoftworks.com/fetch/news/still-more-reliability</link>
		<comments>http://fetchsoftworks.com/fetch/news/still-more-reliability#comments</comments>
		<pubDate>Mon, 17 May 2010 16:15:55 +0000</pubDate>
		<dc:creator>Jim Matthews</dc:creator>
				<category><![CDATA[Fetch]]></category>
		<category><![CDATA[News]]></category>

		<guid isPermaLink="false">http://fetchsoftworks.com/?p=364</guid>
		<description><![CDATA[<p>In <a href="/fetch/news/how-reliable-is-reliable-abridged">How Reliable Is Reliable Enough?</a> I wrote about the steps we took to make Fetch 5.5 more reliable, in particular its support for automatically resuming failed or stalled uploads.</p>
]]></description>
			<content:encoded><![CDATA[<style type="text/css" media="screen"><!--
@import "http://fetchsoftworks.com/c/screen.css";
--></style><style type="text/css" media="screen"><!--
@import "http://fetchsoftworks.com/c/feed.css";
--></style><div class="feeditem"><p>In <a href="/fetch/news/how-reliable-is-reliable-abridged">How Reliable Is Reliable Enough?</a> I wrote about the steps we took to make Fetch 5.5 more reliable, in particular its support for automatically resuming failed or stalled uploads. In the time since we released Fetch 5.5 we’ve heard from numerous users who’ve been helped by this feature. It is especially useful when transferring a large collection of files in many folders, for example a large web software package (e.g. WordPress or SugarCRM). In a big transfer there are hundreds of opportunities for one small part of the operation to stall or fail ﻿due to a server hiccup or network glitch. In versions of Fetch before 5.5, that would bring the entire transfer to a halt. Then you would be stuck figuring out what you still had left to transfer, or you might toss what you'd done and start over, just to be safe.</p>
<p>Fetch 5.5’s automatic resume feature fixed that problem for most uploads, but we heard about a few cases where it could do better. We also heard from users facing similar problems with large downloads. So in Fetch 5.6 we improved the performance for uploads, and extended the automatic resume feature to cover downloads as well. It also covers mirror transfers in either direction, and folder delete commands. We think we've eliminated nearly all of the common situations where a temporary glitch can cause a large operation to fail.</p>
<p>Please give <a href="/fetch">Fetch 5.6</a> a try with your most challenging transfers, and let us know how it goes!</p></div>]]></content:encoded>
			<wfw:commentRss>http://fetchsoftworks.com/fetch/news/still-more-reliability/feed</wfw:commentRss>
		</item>
		<item>
		<title>Fetch 5.6 keeps transfers moving</title>
		<link>http://fetchsoftworks.com/fetch/news/fetch-5-6-keeps-transfers-moving</link>
		<comments>http://fetchsoftworks.com/fetch/news/fetch-5-6-keeps-transfers-moving#comments</comments>
		<pubDate>Thu, 29 Apr 2010 21:04:43 +0000</pubDate>
		<dc:creator>Jim Matthews</dc:creator>
				<category><![CDATA[Fetch]]></category>
		<category><![CDATA[News]]></category>

		<guid isPermaLink="false">http://fetchsoftworks.com/?p=363</guid>
		<description><![CDATA[<p>Etna, NH — Reliability is the watchword for Fetch 5.6, the latest version of the original Macintosh file transfer program, released today.</p> <span id="more-363"></span><p>Transient errors or stalls can all too often cause a website update or large download to grind to a halt, wasting time and requiring tedious and error-prone manual intervention. Fetch 5.6 automatically resumes uploads, downloads, and mirror operations, to ensure that network glitches and server hiccups do not stand in the way of successful FTP or SFTP transfers.</p>

<p>Fetch 5.6 is a Universal binary, compatible with Mac OS X 10.4 or later, including Mac OS X 10.5 Leopard and Mac OS X 10.6 Snow Leopard, and can be downloaded from <a href="http://fetchsoftworks.com">http://fetchsoftworks.com</a>.</p>

<p>Fetch 5.6 is free to try for 15 days, and a single-user license is $29. Upgrades are free for Fetch 5.5 users and customers who purchased Fetch after January 28, 2009; otherwise, upgrades are $10. Free licenses and upgrades are available for educational and charitable use.</p>]]></description>
			<content:encoded><![CDATA[<style type="text/css" media="screen"><!--
@import "http://fetchsoftworks.com/c/screen.css";
--></style><style type="text/css" media="screen"><!--
@import "http://fetchsoftworks.com/c/feed.css";
--></style><div class="feeditem"><p>Etna, NH — Reliability is the watchword for Fetch 5.6, the latest version of the original Macintosh file transfer program, released today.</p> <span id="more-363"></span><p>Transient errors or stalls can all too often cause a website update or large download to grind to a halt, wasting time and requiring tedious and error-prone manual intervention. Fetch 5.6 automatically resumes uploads, downloads, and mirror operations, to ensure that network glitches and server hiccups do not stand in the way of successful FTP or SFTP transfers.</p>

<p>Fetch 5.6 is a Universal binary, compatible with Mac OS X 10.4 or later, including Mac OS X 10.5 Leopard and Mac OS X 10.6 Snow Leopard, and can be downloaded from <a href="http://fetchsoftworks.com">http://fetchsoftworks.com</a>.</p>

<p>Fetch 5.6 is free to try for 15 days, and a single-user license is $29. Upgrades are free for Fetch 5.5 users and customers who purchased Fetch after January 28, 2009; otherwise, upgrades are $10. Free licenses and upgrades are available for educational and charitable use.</p></div>]]></content:encoded>
			<wfw:commentRss>http://fetchsoftworks.com/fetch/news/fetch-5-6-keeps-transfers-moving/feed</wfw:commentRss>
		</item>
		<item>
		<title>iPad Déjà Vu</title>
		<link>http://fetchsoftworks.com/blog/ipad-deja-vu</link>
		<comments>http://fetchsoftworks.com/blog/ipad-deja-vu#comments</comments>
		<pubDate>Fri, 05 Feb 2010 14:14:58 +0000</pubDate>
		<dc:creator>Jim Matthews</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://fetchsoftworks.com/?p=358</guid>
		<description><![CDATA[<p>The announcement of the iPad, and the recognition by some (e.g. <a href="http://stevenf.tumblr.com/post/359224392/i-need-to-talk-to-you-about-computers-ive-been">Steven Frank</a>, <a href="http://speirs.org/blog/2010/1/29/future-shock.html">Frasier Spiers</a> and <a href="http://www.macworld.com/article/146040/2010/02/ipad.html">Dan Moren</a>) that this represents a new era of computing, gives me a powerful sensation of déjà vu.</p>
]]></description>
			<content:encoded><![CDATA[<style type="text/css" media="screen"><!--
@import "http://fetchsoftworks.com/c/screen.css";
--></style><style type="text/css" media="screen"><!--
@import "http://fetchsoftworks.com/c/feed.css";
--></style><div class="feeditem"><p>My son Dylan is away at college, and on January 27 &mdash; the day of the iPad announcement &mdash; I was on my way to visit him when I noticed that I was walking by the campus bookstore. I flashed back to January 24, 1984, when I was a freshman at the same college, and had eagerly hurried into that same bookstore to witness the unveiling of Apple's new Macintosh computer. On both days it felt as if the world of computers was being made anew.</p><span id="more-358"></span><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/e/e3/Macintosh_128k_transparency.png/180px-Macintosh_128k_transparency.png" class="floatleft" height="105" width="90" alt="The Original Macintosh" title="The old new world">

<p>The announcement of the iPad, and the recognition by some (e.g. <a href="http://stevenf.tumblr.com/post/359224392/i-need-to-talk-to-you-about-computers-ive-been">Steven Frank</a>, <a href="http://speirs.org/blog/2010/1/29/future-shock.html">Frasier Spiers</a> and <a href="http://www.macworld.com/article/146040/2010/02/ipad.html">Dan Moren</a>) that this represents a new era of computing, gives me a powerful sensation of déjà vu. Like the iPad, the Macintosh that Apple unveiled in 1984 was intended to radically simplify computing. Jef Raskin, who started the Macintosh project at Apple, believed that personal computers should be more like appliances: simple, rather than complicated, focused on specific tasks, rather than general-purpose. Raskin left Apple in 1982, but the idea of computer-as-appliance lived on in the Macintosh. If you wanted to write, you put in your MacWrite floppy disk and it became a word processing machine. If you wanted to draw, you put in your MacPaint disk and it became a digital sketchpad. Every application took over the entire screen, and turned the machine into a specialized device. In that way it was not so different from the iPhone of today (or the iPad of this coming April).</p>


<img src="http://upload.wikimedia.org/wikipedia/commons/thumb/9/98/Canon_Cat.jpg/180px-Canon_Cat.jpg" class="floatright" height="68" width="90" alt="Canon Cat" title="Not designed by Jonathan Ive">

<p>Raskin went on to create an even more appliance-like computer, the Canon Cat, which was a commercial failure. And the Macintosh itself only barely escaped an early demise. While Apple had planned to sell millions, the first year&rsquo;s sales did not reach 100,000, and it was only the fortuitous  emergence of desktop publishing that saved the Mac from cancellation. Over time the Mac acquired new features and capabilities, and new complexity, such that today we can look at it as an example of &ldquo;Old World&rdquo; computing that we hope to move beyond.</p>

<img class="floatleft" src="/i/blog/ipad.png" alt="iPad" width="79" height="110" title="The computer for the rest of us?">

<p>For the iPad to truly usher in a new age of user-centric computing it needs to succeed commercially, and it needs to avoid the creeping complexity that turned the 128k Mac into the MacBook Pro of today. There are reasons for optimism on both scores. Past efforts &mdash; the Mac, the Cat, and the Newton &mdash; tried to build a new world from scratch, offering no compatibility with existing platforms. As John Gruber has persuasively <a href="http://daringfireball.net/2004/08/parlay">argued</a>, it was that incompatibility more than anything else that doomed the Mac to its small market share. It is simply too difficult to sell a computer that forces consumers to throw away everything they have learned and done before. The iPad does not have this weakness: it builds on the iPhone, which in turn built on the iPod and iLife and Safari and Mac OS X, which in turn built on the classic Mac OS and NeXTSTEP. The Mac started with three applications (MacWrite, MacPaint, and Multiplan); the iPad will start with over 100,000. The iPad, like the iPhone, also starts with the web, the most critical and adaptable &ldquo;application&rdquo; of all.</p>

<p>The iPad will therefore not succumb to the usual new platform Catch-22 of having neither enough market share to attract software, nor enough software to build market share. But will Apple resist the temptation to add new features until an iPad requires as much training and expertise as a general-purpose personal computer? It&rsquo;s much too early to tell, but the design decisions Apple has made to date suggest an encouraging restraint. They are helped by the fact that the iPhone and iPad can be huge successes without trying to be all things to all users. Customers who need a more flexible and complicated device can buy one, but most will be perfectly happy with an iPad. As new uses and technologies become mainstream Apple can incorporate them, while ensuring that the simplicity and usability of the platform is protected.</p>

<img src="/i/blog/att-logo.png" class="floatright" height="46" width="46" alt="AT&#038;T Bell logo" title="The Anti-Internet">

<p>As a developer I have mixed feelings about this incipient new age. I remember when the U.S. telecommunications system was run by a benevolent monopoly, with awesome reliability and ease of use, and equally awesome resistance to change. Ma Bell imposed a narrow bottleneck for technological progress, a bottleneck that was ultimately smashed by the anarchic personal computer market. It was the wide-open personal computer that let hobbyist developers write and sell BBS systems, PPP drivers, and ultimately web browsers &mdash; without having to first ask permission. It is not difficult to imagine some great new idea dying because it can&rsquo;t get through the App Store, or because the developer decides it is not even worth trying.</p>

<p>That said, I fervently hope that the iPad does represent a new world for computers. We developers build things to help people, but it is all too easy to focus on the things rather than the people. Today&rsquo;s computers are wonderful, but they aren&rsquo;t good enough for people. The iPad is another chance to do better.</p></div>]]></content:encoded>
			<wfw:commentRss>http://fetchsoftworks.com/blog/ipad-deja-vu/feed</wfw:commentRss>
		</item>
		<item>
		<title>Readability in NetNewsWire</title>
		<link>http://fetchsoftworks.com/blog/readability-in-netnewswire</link>
		<comments>http://fetchsoftworks.com/blog/readability-in-netnewswire#comments</comments>
		<pubDate>Thu, 04 Feb 2010 02:47:59 +0000</pubDate>
		<dc:creator>Jim Matthews</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://fetchsoftworks.com/?p=357</guid>
		<description><![CDATA[<p>I read a lot of articles online, and sometimes the ads and navigation links make it difficult to concentrate on the text of article, much less on the ideas that the text is trying to communicate. The folks at <a href="http://www.arc90.com/">arc90</a> have come to the rescue with <a href="http://lab.arc90.com/experiments/readability/">Readability</a>, a JavaScript bookmarklet that reformats the current web page as a clean page of text:</p><span id="more-357"></span><p class="centerbar">
<a href="/i/blog/nyt-before-readability.png" class="thickbox" title="Before Readability"><img src="/i/blog/nyt-before-readability-thumbnail.png" class="inline" alt="Before Readability"></a>
<span class="bigrightarrow">&#8594;</span>
<a href="/i/blog/nyt-after-readability.png" class="thickbox" title="After Readability"><img src="/i/blog/nyt-after-readability-thumbnail.png" class="inline" alt="After Readability"></a>
</p>

<p>Readability works great in Safari, but I do most of my web reading in <a href="http://www.newsgator.com/INDIVIDUALS/NETNEWSWIRE/">NetNewsWire</a>, the RSS reader by Brent Simmons of Newsgator. And NetNewsWire does not have a bookmarks bar where I could put the Readability bookmarklet.</p>

<p>Fortunately, NetNewsWire does have a Script<span class="ui menu"><img src="/i/blog/script-menu-icon.png"></span>menu, and support for the <span class="ui command">do JavaScript</span> AppleScript command. That makes it possible to add Readability support to NetNewsWire by following these steps:</p>

<ol>
<li><p>Run Script Editor and create an AppleScript like the following: </p>
<pre class="applescript code">
<span class="keyword">set</span> <span class="variable">theJS</span> <span class="keyword">to</span> <span class="literal">"<span class="substitution">bookmarklet link</span>"</span>
set <span class="variable">jsScheme</span> to <span class="literal">"javascript:"</span>
<span class="keyword">if</span> (<span class="command">offset</span> of <span class="variable">jsScheme</span> in <span class="variable">theJS</span>) <span class="keyword">is</span> 1 <span class="keyword">then</span>
	set <span class="variable">theJS</span> to (<span class="class">characters</span> from (1 + (<span class="property">length</span> of <span class="variable">jsScheme</span>)) <span class="keyword">to</span> -1 <span class="keyword">of</span> <span class="variable">theJS</span>) <span class="keyword">as</span> <span class="class">string</span>
<span class="keyword">end if</span>
<span class="keyword">tell</span> <span class="class">application</span> <span class="literal">"NetNewsWire"</span>
	<span class="command">do JavaScript</span> <span class="variable">theJS</span>
<span class="keyword">end tell</span>
</pre>
</li>
<li>Go to the Readability <a href="http://lab.arc90.com/experiments/readability/">web page</a> to create a bookmarklet with your preferred settings</li>
<li>Right-click (or Control-click) the bookmark and choose <span class="ui command">Copy Link</span></li>
<li>Back in Script Editor, paste the link you just copied in place of the text <span class="applescript substitution">bookmarklet link</span>; it will start with "javascript:" and will be quite long
<li>Save your script (e.g. to the Desktop)</li>
<li>Choose <span class="ui command">Open Scripts Folder</span> from the Script<span class="ui menu"><img src="/i/blog/script-menu-icon.png"></span>menu in NetNewsWire</li>
<li>Copy your saved script to the NetNewsWire Scripts folder</li>
</ol>

<p>
Once you&#8217;ve followed these steps your script will be listed in NetNewsWire&#8217;s Script<span class="ui menu"><img src="/i/blog/script-menu-icon.png"></span>menu, and you can choose it to invoke Readability for the currently displayed web page.
</p>
]]></description>
			<content:encoded><![CDATA[<style type="text/css" media="screen"><!--
@import "http://fetchsoftworks.com/c/screen.css";
--></style><style type="text/css" media="screen"><!--
@import "http://fetchsoftworks.com/c/feed.css";
--></style><div class="feeditem"><p>I read a lot of articles online, and sometimes the ads and navigation links make it difficult to concentrate on the text of article, much less on the ideas that the text is trying to communicate. The folks at <a href="http://www.arc90.com/">arc90</a> have come to the rescue with <a href="http://lab.arc90.com/experiments/readability/">Readability</a>, a JavaScript bookmarklet that reformats the current web page as a clean page of text:</p><span id="more-357"></span><p class="centerbar">
<a href="/i/blog/nyt-before-readability.png" class="thickbox" title="Before Readability"><img src="/i/blog/nyt-before-readability-thumbnail.png" class="inline" alt="Before Readability"></a>
<span class="bigrightarrow">&rarr;</span>
<a href="/i/blog/nyt-after-readability.png" class="thickbox" title="After Readability"><img src="/i/blog/nyt-after-readability-thumbnail.png" class="inline" alt="After Readability"></a>
</p>

<p>Readability works great in Safari, but I do most of my web reading in <a href="http://www.newsgator.com/INDIVIDUALS/NETNEWSWIRE/">NetNewsWire</a>, the RSS reader by Brent Simmons of Newsgator. And NetNewsWire does not have a bookmarks bar where I could put the Readability bookmarklet.</p>

<p>Fortunately, NetNewsWire does have a Script<span class="ui menu"><img src="/i/blog/script-menu-icon.png"></span>menu, and support for the <span class="ui command">do JavaScript</span> AppleScript command. That makes it possible to add Readability support to NetNewsWire by following these steps:</p>

<ol>
<li><p>Run Script Editor and create an AppleScript like the following: </p>
<pre class="applescript code">
<span class="keyword">set</span> <span class="variable">theJS</span> <span class="keyword">to</span> <span class="literal">"<span class="substitution">bookmarklet link</span>"</span>
set <span class="variable">jsScheme</span> to <span class="literal">"javascript:"</span>
<span class="keyword">if</span> (<span class="command">offset</span> of <span class="variable">jsScheme</span> in <span class="variable">theJS</span>) <span class="keyword">is</span> 1 <span class="keyword">then</span>
	set <span class="variable">theJS</span> to (<span class="class">characters</span> from (1 + (<span class="property">length</span> of <span class="variable">jsScheme</span>)) <span class="keyword">to</span> -1 <span class="keyword">of</span> <span class="variable">theJS</span>) <span class="keyword">as</span> <span class="class">string</span>
<span class="keyword">end if</span>
<span class="keyword">tell</span> <span class="class">application</span> <span class="literal">"NetNewsWire"</span>
	<span class="command">do JavaScript</span> <span class="variable">theJS</span>
<span class="keyword">end tell</span>
</pre>
</li>
<li>Go to the Readability <a href="http://lab.arc90.com/experiments/readability/">web page</a> to create a bookmarklet with your preferred settings</li>
<li>Right-click (or Control-click) the bookmark and choose <span class="ui command">Copy Link</span></li>
<li>Back in Script Editor, paste the link you just copied in place of the text <span class="applescript substitution">bookmarklet link</span>; it will start with "javascript:" and will be quite long
<li>Save your script (e.g. to the Desktop)</li>
<li>Choose <span class="ui command">Open Scripts Folder</span> from the Script<span class="ui menu"><img src="/i/blog/script-menu-icon.png"></span>menu in NetNewsWire</li>
<li>Copy your saved script to the NetNewsWire Scripts folder</li>
</ol>

<p>
Once you&rsquo;ve followed these steps your script will be listed in NetNewsWire&rsquo;s Script<span class="ui menu"><img src="/i/blog/script-menu-icon.png"></span>menu, and you can choose it to invoke Readability for the currently displayed web page.
</p>
</div>]]></content:encoded>
			<wfw:commentRss>http://fetchsoftworks.com/blog/readability-in-netnewswire/feed</wfw:commentRss>
		</item>
		<item>
		<title>Buy Fetch, Help Haiti</title>
		<link>http://fetchsoftworks.com/fetch/news/buy-fetch-help-haiti</link>
		<comments>http://fetchsoftworks.com/fetch/news/buy-fetch-help-haiti#comments</comments>
		<pubDate>Wed, 20 Jan 2010 13:41:41 +0000</pubDate>
		<dc:creator>Jim Matthews</dc:creator>
				<category><![CDATA[Fetch]]></category>
		<category><![CDATA[News]]></category>

		<guid isPermaLink="false">http://fetchsoftworks.com/?p=356</guid>
		<description><![CDATA[<p><a href="http://www.indierelief.com"><img src="http://www.indierelief.com/images/ir_250.png"></a>
<p>If you <a href="/fetch/buy/cc">purchase</a> a Fetch 5.5 license on Wednesday, January 20, 2010, 100% of the proceeds will be donated to Partners In Health.</p>
<p><strong>UPDATE:</strong> Thank you to everyone who purchased Fetch 5.5 yesterday &#8212; you raised $3,742 for Partners In Health!</p>
]]></description>
			<content:encoded><![CDATA[<style type="text/css" media="screen"><!--
@import "http://fetchsoftworks.com/c/screen.css";
--></style><style type="text/css" media="screen"><!--
@import "http://fetchsoftworks.com/c/feed.css";
--></style><div class="feeditem"><p><a href="http://www.indierelief.com"><img src="http://www.indierelief.com/images/ir_250.png"></a>
</p>
<span id="more-356"></span><p>I am a fan of the writer Tracy Kidder (<em>The Soul of a New Machine</em>, <em>House</em>) and a few years ago I picked up his then-latest book, <a href="http://www.amazon.com/Mountains-Beyond-Quest-Farmer-Would/dp/0812973011/ref=tmm_pap_title_0"><em>Mountains Beyond Mountains</em></a>. It tells the story of a doctor, <a href="http://en.wikipedia.org/wiki/Paul_Farmer">Paul Farmer</a>, who (along with friends <a href="http://en.wikipedia.org/wiki/Ophelia_Dahl">Ophelia Dahl</a> and <a href="http://en.wikipedia.org/wiki/Jim_Yong_Kim">Jim Yong Kim</a>) created an organization called <a href="http://pih.org/">Partners In Health</a>. PIH was founded to deliver high quality health care to the people of Haiti&rsquo;s Central Plateau. Working with the people of Haiti, PIH&rsquo;s efforts there have grown from a single clinic in 1985 to a system of hospitals, clinics, and community health workers that provided 2.6 million patient visits in 2009, all of them free of charge. It is a moving and inspiring story that convinced me to become a financial supporter of PIH&rsquo;s work.</p>

<p>In the aftermath of the earthquake that struck Port-au-Prince on January 12, 2010, Partners In Health is perhaps the largest functioning medical provider left in Haiti. Their own facilities are far enough from the epicenter to have escaped serious damage, and their trained medical teams have been working around the clock to treat survivors. If they can afford to purchase the supplies they need, they will be able to save thousands of lives, not only from earthquake injuries, but also from the infections and other public health threats that will emerge in the weeks and months ahead.</p>

<p>To help make that happen, Fetch Softworks is one of nearly 150 independent Mac and iPhone developers participating in <a href="http://www.indierelief.com">Indie+Relief</a>, a group fundraiser for Haiti. If you <a href="/fetch/buy/cc">purchase</a> a Fetch 5.5 license on Wednesday, January 20, 2010, 100% of the proceeds will be donated to Partners In Health. If you already have a Fetch license, please take a look at the other applications that are <a href="http://www.indierelief.com">for sale</a>: you can pick up a great app and help Haiti at the same time. And if you do not need any software, please visit the PIH <a href="http://pih.org">website</a>, learn more about their work, make a <a href="http://standwithhaiti.org/haiti">donation</a>, and spread the word.</p>

<p>Many thanks to Justin Williams of <a href="http://secondgearsoftware.com">Second Gear Software</a> for organizing <a href="http://www.indierelief.com">Indie+Relief</a>.</p>

<p><strong>UPDATE:</strong> Thank you to everyone who purchased Fetch 5.5 yesterday &mdash; you raised $3,742 for Partners In Health!</p></div>]]></content:encoded>
			<wfw:commentRss>http://fetchsoftworks.com/fetch/news/buy-fetch-help-haiti/feed</wfw:commentRss>
		</item>
		<item>
		<title>Believe it or not: a live iPhone reality show and 50% off Fetch</title>
		<link>http://fetchsoftworks.com/fetch/news/believe-it-or-not-a-live-iphone-reality-show-and-50-off-fetch</link>
		<comments>http://fetchsoftworks.com/fetch/news/believe-it-or-not-a-live-iphone-reality-show-and-50-off-fetch#comments</comments>
		<pubDate>Thu, 10 Dec 2009 08:08:52 +0000</pubDate>
		<dc:creator>Jim Matthews</dc:creator>
				<category><![CDATA[Fetch]]></category>
		<category><![CDATA[News]]></category>

		<guid isPermaLink="false">http://fetchsoftworks.com/?p=355</guid>
		<description><![CDATA[<p>Hello from Italy! While my Fetch colleagues are toiling away at their posts, I am taking a break from Fetch to have an adventure. </p>
]]></description>
			<content:encoded><![CDATA[<style type="text/css" media="screen"><!--
@import "http://fetchsoftworks.com/c/screen.css";
--></style><style type="text/css" media="screen"><!--
@import "http://fetchsoftworks.com/c/feed.css";
--></style><div class="feeditem"><p>Hello from Italy!</p>

<p>While my Fetch colleagues are toiling away at their posts, I am taking a break from Fetch to have an adventure. I am one of ten developers from around the world gathered together in Venice, Italy by <a href="http://commandguru.com">Command Guru</a> to develop an iPhone app from scratch in seven days. If that were not enough, the entire experience is being streamed live at <a href="http://commandguru.com">commandguru.com</a>. </p>

<p>So if you ever wondered what goes on behind the scenes to produce the apps you use, you can tune in to watch us sketch, discuss, argue, and type our way to actual software. We have been at it for three days now, and it&rsquo;s been great fun to work with this terrific group of developers, and to get instant feedback from viewers around the globe. Not to mention all the fantastic Italian food!</p>

<p>In honor of this unlikely event we&rsquo;re offering an equally improbable promotion: a Fetch half-off sale. Today and tomorrow, December 10 and 11, 2009, you can get a 50% discount on Fetch by entering the coupon code <a href="https://secure.esellerate.net/secure/prefill.aspx?s=STR0527091555&#038;page=cart.htm&#038;cmd=BUY&#038;_cartitem0.skurefnum=SKU27707691229&#038;_cartitem0.quantity=1&#038;_Shopper.CouponName=COMMANDGURU&#038;options=PREVALIDATECOUPON">COMMANDGURU</a>.</p>

<p>Ciao!</p>
</div>]]></content:encoded>
			<wfw:commentRss>http://fetchsoftworks.com/fetch/news/believe-it-or-not-a-live-iphone-reality-show-and-50-off-fetch/feed</wfw:commentRss>
		</item>
		<item>
		<title>Subversion and SSH authentication shenanigans</title>
		<link>http://fetchsoftworks.com/blog/subversion-and-ssh-authentication-shenanigans</link>
		<comments>http://fetchsoftworks.com/blog/subversion-and-ssh-authentication-shenanigans#comments</comments>
		<pubDate>Mon, 23 Nov 2009 19:15:28 +0000</pubDate>
		<dc:creator>Ben Artin</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://fetchsoftworks.com/?p=353</guid>
		<description><![CDATA[<p>The default behavior of Subversion when tunneled over SSH works well for simple cases. I encountered some more complex situations which required digging into advanced SSH features, and built some simple tools that make our Subversion life easier.</p><span id="more-353"></span><h4>Specifying a username for SSH repositories</h4>

<p>By default, when you connect to a Subversion repository over SSH, Subversion will assume that the remote username is the same as the local username. When this is not true, you can force a different username to be used. When you check out the repository, use:</p>

<pre class="code"><span class="keyword">svn</span> <span class="keyword">checkout</span> <span class="literal">svn+ssh://svn-username@svn-hostname/svn-path</span></pre>

<p>Subversion will parse the username out of the URL, and pass it through to SSH, which will then prompt you for the password for the correct account.</p>

<h4>Avoiding multiple password prompts</h4>

<p>If you have a simple SSH repository, you will be asked for your password once at the beginning of a Subversion command. However, if your repository contains <a href="http://svnbook.red-bean.com/en/1.0/ch07s03.html">externals</a>, you will be asked for your password again for each external that requires it. If you have multiple externals on the same server, you get to enter the same password multiple times.</p>

<p>To work around this you can use SSH session sharing. Session sharing lets multiple SSH connections to the same server share a single network connection. That also causes multiple SSH connections to the same server to share credentials, and therefore you don&#8217;t have to reenter your passwords during a single Subversion command.</p>

<p>To set up SSH session sharing, you need to add this to your <code>~/.ssh/config</code>:</p>

<pre class="code"><span class="keyword">ControlMaster</span> <span class="literal">auto</span>
<span class="keyword">ControlPath</span> <span class="literal">~/.ssh/master-%r@%h:%p</span></pre>

<p>To verify that it works, open an SSH connection in Terminal, then open a new Terminal window and open another SSH connection to the same account as the first one. The second will not ask for your password.</p>

<p>The configuration above enables SSH connection sharing for all SSH connections. If, instead, you want to only enable connection sharing for your Subversion server, put the following <strong>at the bottom</strong> of your <code>~/.ssh/config</code>:</p>

<pre class="code"><span class="keyword">Host</span> <span class="literal">svn-hostname</span>
<span class="keyword">ControlMaster</span> <span class="literal">auto</span>
<span class="keyword">ControlPath</span> <span class="literal">~/.ssh/master-%r@%h:%p</span></pre>

<h4>Avoiding multiple password prompts &#8212; the pair.com users&#8217; version</h4>

<p>On <a href="http://www.pair.com/">pair.com</a> &#8212; I imagine this may also be true of some other hosting providers &#8212; the above recipe with SSH session sharing works great as long as your repository has fewer than ten externals. Once you get to ten externals, you see a &#8220;channel 10: open failed&#8221; message and your Subversion command dies.</p>

<p>This is because pair.com limits SSH session sharing to ten simultaneous connections to a given server. Unfortunately, Subversion keeps every SSH connection open until it&#8217;s done with all of them. If you have ten externals on the same server, you wind up with eleven simultaneous SSH connections (ten for the externals and one for the root of the repository), and so your SSH and Subversion error out.</p>

<p>The good news is that SSH already has a mechanism to delegate its password prompting to another tool (this is what programs like Fetch use to give a graphical user interface for entering your SFTP password). If you had a tool that handled SSH password prompting, but was also capable of remembering the passwords you gave it and not asking you to reenter them, you would only get asked for your password once.</p>

<p>An SSH password prompter is relaunched for every prompt, so it needs a place to stash passwords during a single Subversion command. An easy way to handle this is to write a tool which creates a password store and then launches Subversion. Using that tool instead of Subversion will provide the password prompter with the password repository it needs to work correctly.</p>

<p>This is what the Subversion replacement looks like:</p>

<pre id="svn-wrapper" class="code"><span class="comment">#!/usr/local/bin/python</span>

<span class="keyword">from</span> <span class="system module">__future__</span> <span class="keyword">import</span> <span class="system constant">with_statement</span>
<span class="keyword">from</span> <span class="system module">subprocess</span> <span class="keyword">import</span> <span class="system function">call</span>
<span class="keyword">from</span> <span class="system module">tempfile</span> <span class="keyword">import</span> <span class="system function">mkdtemp</span>
<span class="keyword">from</span> <span class="system module">os</span> <span class="keyword">import</span> <span class="system function">mkfifo</span>, <span class="system variable">environ</span>
<span class="keyword">from</span> <span class="system module">os</span>.<span class="system module">path</span> <span class="keyword">import</span> <span class="system function">join</span>, <span class="system function">expanduser</span>
<span class="keyword">from</span> <span class="system module">sys</span> <span class="keyword">import</span> <span class="system variable">argv</span>
<span class="keyword">from</span> <span class="system module">threading</span> <span class="keyword">import</span> <span class="system class">Thread</span>
<span class="keyword">from</span> <span class="system module">pickle</span> <span class="keyword">import</span> <span class="system function">load</span>, <span class="system function">dump</span>
<span class="keyword">from</span> <span class="system module">getpass</span> <span class="keyword">import</span> <span class="system function">getpass</span>

<span class="local variable">request_pipe_path</span> = <span class="system function">join</span>(<span class="system function">mkdtemp</span>(), <span class="literal">"svn-askpass-requests"</span>)
<span class="local variable">response_pipe_path</span> = <span class="system function">join</span>(<span class="system function">mkdtemp</span>(), <span class="literal">"svn-askpass-responses"</span>)

<span class="system function">mkfifo</span>(<span class="local variable">request_pipe_path</span>)
<span class="system function">mkfifo</span>(<span class="local variable">response_pipe_path</span>)

<span class="local variable">args</span> = <span class="system variable">argv</span>[<span class="literal">1</span>:]

<span class="keyword">def</span> <span class="local function">prompt_loop</span>():
    <span class="local variable">cache</span> = {}

    <span class="keyword">while</span> <span class="system constant">True</span>:
        <span class="keyword">with</span> <span class="system function">open</span>(<span class="local variable">request_pipe_path</span>, <span class="literal">"r"</span>) <span class="keyword">as</span> <span class="local variable">request_pipe</span>:
            <span class="local variable">hidden</span>, <span class="local variable">request</span> = <span class="system function">load</span>(<span class="local variable">request_pipe</span>)

        <span class="keyword">if</span> <span class="keyword">not</span> <span class="local variable">request</span> <span class="keyword">in</span> <span class="local variable">cache</span>:
            <span class="keyword">if</span> <span class="local variable">hidden</span>:
                <span class="local variable">cache</span>[<span class="local variable">request</span>] = <span class="system function">getpass</span>(<span class="local variable">request</span>)
            <span class="keyword">else</span>:
                <span class="local variable">cache</span>[<span class="local variable">request</span>] = <span class="system function">raw_input</span>(<span class="local variable">request</span>)
            
        <span class="keyword">with</span> <span class="system function">open</span>(<span class="local variable">response_pipe_path</span>, <span class="literal">"w"</span>) <span class="keyword">as</span> <span class="local variable">response_pipe</span>:
            <span class="system function">dump</span>(<span class="local variable">cache</span>[<span class="local variable">request</span>], <span class="local variable">response_pipe</span>)
            
<span class="local variable">prompter</span> = <span class="system class">Thread</span>(target=<span class="local function">prompt_loop</span>)
<span class="local variable">prompter</span>.<span class="field">daemon</span> = <span class="system constant">True</span>

<span class="system variable">environ</span>[<span class="literal">"SSH_ASKPASS"</span>] = <span class="system function">expanduser</span>("~/.subversion/svn-ssh-askpass")
<span class="system variable">environ</span>[<span class="literal">"SSH_ASKPASS_REQUEST_PIPE"</span>] = <span class="local variable">request_pipe_path</span>
<span class="system variable">environ</span>[<span class="literal">"SSH_ASKPASS_RESPONSE_PIPE"</span>] = <span class="local variable">response_pipe_path</span>

<span class="local variable">prompter</span>.<span class="system function">start</span>()

<span class="system function">exit</span>(<span class="system function">call</span>([<span class="literal">"/usr/local/bin/svn"</span>] + <span class="local variable">args</span>))</pre>

<p>There isn&#8217;t much to it &#8212; it creates two pipes, on one of which it reads prompts and on the other of which it provides user responses. Before starting Subversion, it spawns a background thread, from which it listens for prompts. If it receives a prompt that it has already seen, it returns the same answer as before; if it receives a prompt it hasn&#8217;t already seen, it presents it to the user and stores the answer for later.</p>

<p>If you weren&#8217;t familiar with them before, you may find these interesting:</p>
<ul>
<li><a href="http://docs.python.org/library/tempfile.html#tempfile.mkdtemp">tempfile.mkdtemp</a>: securely creates a temporary directory readable only by its owner</li>
<li><a href="http://docs.python.org/library/getpass.html#getpass.getpass">getpass.getpass</a>: securely prompts for a password</li>
<li><a href="http://docs.python.org/library/threading.html#threading.Thread.daemon">threading.Thread.daemon</a>: if set on a thread, then the thread is automatically killed off when all other threads are done</li>
<li><a href="http://docs.python.org/library/os.path.html#os.path.expanduser">os.path.expanduser</a>: expands &#8764; to user&#8217;s home path</li>
<li>os.environ["SSH_ASKPASS"]: the way to tell SSH to delegate password prompting</li>
</ul>

<p>This Subversion wrapper sets up SSH to use <code>~/.subversion/svn-ssh-askpass</code> for password prompting. However, SSH doesn't use the value of <code>SSH_ASKPASS</code> unless a few specific conditions are met, and those conditions are not met when Subversion command line invokes SSH. Therefore, we also need to create a wrapper for SSH, which will set things up so that password prompting is delegated to the prompter, and then we need to tell Subversion to invoke that SSH wrapper instead of SSH.</p>

<p>This is what the wrapper looks like:</p>

<pre id="ssh-wrapper" class="code"><span class="comment">#!/usr/local/bin/python</span>
<span class="keyword">from</span> <span class="system module">os</span> <span class="keyword">import</span> <span class="system function">setsid</span>, <span class="system variable">environ</span>
<span class="keyword">from</span> <span class="system module">subprocess</span> <span class="keyword">import</span> <span class="system function">call</span>
<span class="keyword">from</span> <span class="system module">sys</span> <span class="keyword">import</span> <span class="system ">argv</span>

<span class="comment"># We have to invoke SSH from a process with no controlling terminal
# in order to get SSH_ASKPASS to work</span>
<span class="system function">setsid</span>()
<span class="system variable">environ</span>[<span class="literal">"DISPLAY"</span>] = <span class="literal">"0"</span>

<span class="system function">exit</span>(<span class="system function">call</span>([<span class="literal">"/usr/bin/ssh"</span>] + <span class="system variable">argv</span>[<span class="literal">1</span>:]))</pre>

<p>If you don&#8217;t really get all the details of this, that&#8217;s OK. I don&#8217;t either; it&#8217;s Soviet-era UNIX programming, I just Googled until I pieced it together.</p>

<p>Save that at <code>~/.subversion/svn-ssh-detach</code> and tell Subversion to use this SSH wrapper by adding this to your <code>~/.subversion/config</code>:</p>

<pre id="svn-config" class="code">[<span class="keyword">tunnels</span>]
<span class="keyword">ssh</span> = <span class="literal">/Users/ben/.subversion/svn-ssh-detach</span></pre>

<p>Sadly, Subversion doesn&#8217;t expand <code>~</code> in tunnel configuration, so you have to put the full path to your home there.</p>

<p>OK, now we have a Subversion wrapper that can cache passwords, and we have an SSH wrapper that can delegate its password prompting to a custom prompter. All we need to do to close the loop is write a custom prompter that talks to the Subversion wrapper instead of directly prompting you:</p>

<pre id="ssh-askpass" class="code"><span class="comment">#!/usr/local/bin/python</span>

<span class="keyword">from</span> <span class="system module">__future__</span> <span class="keyword">import</span> <span class="system constant">with_statement</span>
<span class="keyword">from</span> <span class="system module">sys</span> <span class="keyword">import</span> <span class="system variable">argv</span>
<span class="keyword">from</span> <span class="system module">os</span> <span class="keyword">import</span> <span class="system variable">environ</span>
<span class="keyword">from</span> <span class="system module">pickle</span> <span class="keyword">import</span> <span class="system function">load</span>, <span class="system function">dump</span>

<span class="local variable">prompt</span> = <span class="system variable">argv</span>[<span class="literal">1</span>]
<span class="local variable">secret</span> = <span class="literal">False</span>

<span class="keyword">if</span> <span class="literal">"password:"</span> <span class="keyword">in</span> <span class="local variable">prompt</span>:
	<span class="local variable">secret</span> = <span class="literal">True</span>

<span class="keyword">with</span> <span class="system function">open</span>(<span class="system variable">environ</span>[<span class="literal">"SSH_ASKPASS_REQUEST_PIPE"</span>], <span class="literal">"w"</span>) <span class="keyword">as</span> <span class="local variable">request_pipe</span>:
	<span class="system function">dump</span>((<span class="local variable">secret</span>, <span class="local variable">prompt</span>), <span class="local variable">request_pipe</span>)

<span class="keyword">with</span> <span class="system function">open</span>(<span class="system variable">environ</span>[<span class="literal">"SSH_ASKPASS_RESPONSE_PIPE"</span>], <span class="literal">"r"</span>) <span class="keyword">as</span> <span class="local variable">response_pipe</span>:
	<span class="keyword">print</span> <span class="system function">load</span>(<span class="local variable">response_pipe</span>)
</pre>

<p>And there you have it. To recap:</p>
<ul>
<li><a href="#svn-wrapper">Subversion wrapper</a>: put it anywhere you like, make sure it&#8217;s executable</li>
<li><a href="#svn-config">Subversion configuration changes</a>: put them in <code>~/.subversion/config</code></li>
<li><a href="#ssh-wrapper">SSH wrapper</a>: put it in <code>~/.subversion/svn-ssh-detach</code>, make sure it&#8217;s executable</li>
<li><a href="#ssh-askpass">SSH prompter</a>: put it in <code>~/.subversion/svn-ssh-askpass</code>, make sure it&#8217;s executable</li>
</ul>

<p>From there on, invoke your Subversion wrapper instead of <code>svn</code> (or create an alias that runs the wrapper when you type <code>svn</code>).</p>]]></description>
			<content:encoded><![CDATA[<style type="text/css" media="screen"><!--
@import "http://fetchsoftworks.com/c/screen.css";
--></style><style type="text/css" media="screen"><!--
@import "http://fetchsoftworks.com/c/feed.css";
--></style><div class="feeditem"><p>The default behavior of Subversion when tunneled over SSH works well for simple cases. I encountered some more complex situations which required digging into advanced SSH features, and built some simple tools that make our Subversion life easier.</p><span id="more-353"></span><h4>Specifying a username for SSH repositories</h4>

<p>By default, when you connect to a Subversion repository over SSH, Subversion will assume that the remote username is the same as the local username. When this is not true, you can force a different username to be used. When you check out the repository, use:</p>

<pre class="code"><span class="keyword">svn</span> <span class="keyword">checkout</span> <span class="literal">svn+ssh://svn-username@svn-hostname/svn-path</span></pre>

<p>Subversion will parse the username out of the URL, and pass it through to SSH, which will then prompt you for the password for the correct account.</p>

<h4>Avoiding multiple password prompts</h4>

<p>If you have a simple SSH repository, you will be asked for your password once at the beginning of a Subversion command. However, if your repository contains <a href="http://svnbook.red-bean.com/en/1.0/ch07s03.html">externals</a>, you will be asked for your password again for each external that requires it. If you have multiple externals on the same server, you get to enter the same password multiple times.</p>

<p>To work around this you can use SSH session sharing. Session sharing lets multiple SSH connections to the same server share a single network connection. That also causes multiple SSH connections to the same server to share credentials, and therefore you don&rsquo;t have to reenter your passwords during a single Subversion command.</p>

<p>To set up SSH session sharing, you need to add this to your <code>~/.ssh/config</code>:</p>

<pre class="code"><span class="keyword">ControlMaster</span> <span class="literal">auto</span>
<span class="keyword">ControlPath</span> <span class="literal">~/.ssh/master-%r@%h:%p</span></pre>

<p>To verify that it works, open an SSH connection in Terminal, then open a new Terminal window and open another SSH connection to the same account as the first one. The second will not ask for your password.</p>

<p>The configuration above enables SSH connection sharing for all SSH connections. If, instead, you want to only enable connection sharing for your Subversion server, put the following <strong>at the bottom</strong> of your <code>~/.ssh/config</code>:</p>

<pre class="code"><span class="keyword">Host</span> <span class="literal">svn-hostname</span>
<span class="keyword">ControlMaster</span> <span class="literal">auto</span>
<span class="keyword">ControlPath</span> <span class="literal">~/.ssh/master-%r@%h:%p</span></pre>

<h4>Avoiding multiple password prompts &mdash; the pair.com users&rsquo; version</h4>

<p>On <a href="http://www.pair.com/">pair.com</a> &mdash; I imagine this may also be true of some other hosting providers &mdash; the above recipe with SSH session sharing works great as long as your repository has fewer than ten externals. Once you get to ten externals, you see a &ldquo;channel 10: open failed&rdquo; message and your Subversion command dies.</p>

<p>This is because pair.com limits SSH session sharing to ten simultaneous connections to a given server. Unfortunately, Subversion keeps every SSH connection open until it&rsquo;s done with all of them. If you have ten externals on the same server, you wind up with eleven simultaneous SSH connections (ten for the externals and one for the root of the repository), and so your SSH and Subversion error out.</p>

<p>The good news is that SSH already has a mechanism to delegate its password prompting to another tool (this is what programs like Fetch use to give a graphical user interface for entering your SFTP password). If you had a tool that handled SSH password prompting, but was also capable of remembering the passwords you gave it and not asking you to reenter them, you would only get asked for your password once.</p>

<p>An SSH password prompter is relaunched for every prompt, so it needs a place to stash passwords during a single Subversion command. An easy way to handle this is to write a tool which creates a password store and then launches Subversion. Using that tool instead of Subversion will provide the password prompter with the password repository it needs to work correctly.</p>

<p>This is what the Subversion replacement looks like:</p>

<pre id="svn-wrapper" class="code"><span class="comment">#!/usr/local/bin/python</span>

<span class="keyword">from</span> <span class="system module">__future__</span> <span class="keyword">import</span> <span class="system constant">with_statement</span>
<span class="keyword">from</span> <span class="system module">subprocess</span> <span class="keyword">import</span> <span class="system function">call</span>
<span class="keyword">from</span> <span class="system module">tempfile</span> <span class="keyword">import</span> <span class="system function">mkdtemp</span>
<span class="keyword">from</span> <span class="system module">os</span> <span class="keyword">import</span> <span class="system function">mkfifo</span>, <span class="system variable">environ</span>
<span class="keyword">from</span> <span class="system module">os</span>.<span class="system module">path</span> <span class="keyword">import</span> <span class="system function">join</span>, <span class="system function">expanduser</span>
<span class="keyword">from</span> <span class="system module">sys</span> <span class="keyword">import</span> <span class="system variable">argv</span>
<span class="keyword">from</span> <span class="system module">threading</span> <span class="keyword">import</span> <span class="system class">Thread</span>
<span class="keyword">from</span> <span class="system module">pickle</span> <span class="keyword">import</span> <span class="system function">load</span>, <span class="system function">dump</span>
<span class="keyword">from</span> <span class="system module">getpass</span> <span class="keyword">import</span> <span class="system function">getpass</span>

<span class="local variable">request_pipe_path</span> = <span class="system function">join</span>(<span class="system function">mkdtemp</span>(), <span class="literal">"svn-askpass-requests"</span>)
<span class="local variable">response_pipe_path</span> = <span class="system function">join</span>(<span class="system function">mkdtemp</span>(), <span class="literal">"svn-askpass-responses"</span>)

<span class="system function">mkfifo</span>(<span class="local variable">request_pipe_path</span>)
<span class="system function">mkfifo</span>(<span class="local variable">response_pipe_path</span>)

<span class="local variable">args</span> = <span class="system variable">argv</span>[<span class="literal">1</span>:]

<span class="keyword">def</span> <span class="local function">prompt_loop</span>():
    <span class="local variable">cache</span> = {}

    <span class="keyword">while</span> <span class="system constant">True</span>:
        <span class="keyword">with</span> <span class="system function">open</span>(<span class="local variable">request_pipe_path</span>, <span class="literal">"r"</span>) <span class="keyword">as</span> <span class="local variable">request_pipe</span>:
            <span class="local variable">hidden</span>, <span class="local variable">request</span> = <span class="system function">load</span>(<span class="local variable">request_pipe</span>)

        <span class="keyword">if</span> <span class="keyword">not</span> <span class="local variable">request</span> <span class="keyword">in</span> <span class="local variable">cache</span>:
            <span class="keyword">if</span> <span class="local variable">hidden</span>:
                <span class="local variable">cache</span>[<span class="local variable">request</span>] = <span class="system function">getpass</span>(<span class="local variable">request</span>)
            <span class="keyword">else</span>:
                <span class="local variable">cache</span>[<span class="local variable">request</span>] = <span class="system function">raw_input</span>(<span class="local variable">request</span>)
            
        <span class="keyword">with</span> <span class="system function">open</span>(<span class="local variable">response_pipe_path</span>, <span class="literal">"w"</span>) <span class="keyword">as</span> <span class="local variable">response_pipe</span>:
            <span class="system function">dump</span>(<span class="local variable">cache</span>[<span class="local variable">request</span>], <span class="local variable">response_pipe</span>)
            
<span class="local variable">prompter</span> = <span class="system class">Thread</span>(target=<span class="local function">prompt_loop</span>)
<span class="local variable">prompter</span>.<span class="field">daemon</span> = <span class="system constant">True</span>

<span class="system variable">environ</span>[<span class="literal">"SSH_ASKPASS"</span>] = <span class="system function">expanduser</span>("~/.subversion/svn-ssh-askpass")
<span class="system variable">environ</span>[<span class="literal">"SSH_ASKPASS_REQUEST_PIPE"</span>] = <span class="local variable">request_pipe_path</span>
<span class="system variable">environ</span>[<span class="literal">"SSH_ASKPASS_RESPONSE_PIPE"</span>] = <span class="local variable">response_pipe_path</span>

<span class="local variable">prompter</span>.<span class="system function">start</span>()

<span class="system function">exit</span>(<span class="system function">call</span>([<span class="literal">"/usr/local/bin/svn"</span>] + <span class="local variable">args</span>))</pre>

<p>There isn&rsquo;t much to it &mdash; it creates two pipes, on one of which it reads prompts and on the other of which it provides user responses. Before starting Subversion, it spawns a background thread, from which it listens for prompts. If it receives a prompt that it has already seen, it returns the same answer as before; if it receives a prompt it hasn&rsquo;t already seen, it presents it to the user and stores the answer for later.</p>

<p>If you weren&rsquo;t familiar with them before, you may find these interesting:</p>
<ul>
<li><a href="http://docs.python.org/library/tempfile.html#tempfile.mkdtemp">tempfile.mkdtemp</a>: securely creates a temporary directory readable only by its owner</li>
<li><a href="http://docs.python.org/library/getpass.html#getpass.getpass">getpass.getpass</a>: securely prompts for a password</li>
<li><a href="http://docs.python.org/library/threading.html#threading.Thread.daemon">threading.Thread.daemon</a>: if set on a thread, then the thread is automatically killed off when all other threads are done</li>
<li><a href="http://docs.python.org/library/os.path.html#os.path.expanduser">os.path.expanduser</a>: expands &sim; to user&rsquo;s home path</li>
<li>os.environ["SSH_ASKPASS"]: the way to tell SSH to delegate password prompting</li>
</ul>

<p>This Subversion wrapper sets up SSH to use <code>~/.subversion/svn-ssh-askpass</code> for password prompting. However, SSH doesn't use the value of <code>SSH_ASKPASS</code> unless a few specific conditions are met, and those conditions are not met when Subversion command line invokes SSH. Therefore, we also need to create a wrapper for SSH, which will set things up so that password prompting is delegated to the prompter, and then we need to tell Subversion to invoke that SSH wrapper instead of SSH.</p>

<p>This is what the wrapper looks like:</p>

<pre id="ssh-wrapper" class="code"><span class="comment">#!/usr/local/bin/python</span>
<span class="keyword">from</span> <span class="system module">os</span> <span class="keyword">import</span> <span class="system function">setsid</span>, <span class="system variable">environ</span>
<span class="keyword">from</span> <span class="system module">subprocess</span> <span class="keyword">import</span> <span class="system function">call</span>
<span class="keyword">from</span> <span class="system module">sys</span> <span class="keyword">import</span> <span class="system ">argv</span>

<span class="comment"># We have to invoke SSH from a process with no controlling terminal
# in order to get SSH_ASKPASS to work</span>
<span class="system function">setsid</span>()
<span class="system variable">environ</span>[<span class="literal">"DISPLAY"</span>] = <span class="literal">"0"</span>

<span class="system function">exit</span>(<span class="system function">call</span>([<span class="literal">"/usr/bin/ssh"</span>] + <span class="system variable">argv</span>[<span class="literal">1</span>:]))</pre>

<p>If you don&rsquo;t really get all the details of this, that&rsquo;s OK. I don&rsquo;t either; it&rsquo;s Soviet-era UNIX programming, I just Googled until I pieced it together.</p>

<p>Save that at <code>~/.subversion/svn-ssh-detach</code> and tell Subversion to use this SSH wrapper by adding this to your <code>~/.subversion/config</code>:</p>

<pre id="svn-config" class="code">[<span class="keyword">tunnels</span>]
<span class="keyword">ssh</span> = <span class="literal">/Users/ben/.subversion/svn-ssh-detach</span></pre>

<p>Sadly, Subversion doesn&rsquo;t expand <code>~</code> in tunnel configuration, so you have to put the full path to your home there.</p>

<p>OK, now we have a Subversion wrapper that can cache passwords, and we have an SSH wrapper that can delegate its password prompting to a custom prompter. All we need to do to close the loop is write a custom prompter that talks to the Subversion wrapper instead of directly prompting you:</p>

<pre id="ssh-askpass" class="code"><span class="comment">#!/usr/local/bin/python</span>

<span class="keyword">from</span> <span class="system module">__future__</span> <span class="keyword">import</span> <span class="system constant">with_statement</span>
<span class="keyword">from</span> <span class="system module">sys</span> <span class="keyword">import</span> <span class="system variable">argv</span>
<span class="keyword">from</span> <span class="system module">os</span> <span class="keyword">import</span> <span class="system variable">environ</span>
<span class="keyword">from</span> <span class="system module">pickle</span> <span class="keyword">import</span> <span class="system function">load</span>, <span class="system function">dump</span>

<span class="local variable">prompt</span> = <span class="system variable">argv</span>[<span class="literal">1</span>]
<span class="local variable">secret</span> = <span class="literal">False</span>

<span class="keyword">if</span> <span class="literal">"password:"</span> <span class="keyword">in</span> <span class="local variable">prompt</span>:
	<span class="local variable">secret</span> = <span class="literal">True</span>

<span class="keyword">with</span> <span class="system function">open</span>(<span class="system variable">environ</span>[<span class="literal">"SSH_ASKPASS_REQUEST_PIPE"</span>], <span class="literal">"w"</span>) <span class="keyword">as</span> <span class="local variable">request_pipe</span>:
	<span class="system function">dump</span>((<span class="local variable">secret</span>, <span class="local variable">prompt</span>), <span class="local variable">request_pipe</span>)

<span class="keyword">with</span> <span class="system function">open</span>(<span class="system variable">environ</span>[<span class="literal">"SSH_ASKPASS_RESPONSE_PIPE"</span>], <span class="literal">"r"</span>) <span class="keyword">as</span> <span class="local variable">response_pipe</span>:
	<span class="keyword">print</span> <span class="system function">load</span>(<span class="local variable">response_pipe</span>)
</pre>

<p>And there you have it. To recap:</p>
<ul>
<li><a href="#svn-wrapper">Subversion wrapper</a>: put it anywhere you like, make sure it&rsquo;s executable</li>
<li><a href="#svn-config">Subversion configuration changes</a>: put them in <code>~/.subversion/config</code></li>
<li><a href="#ssh-wrapper">SSH wrapper</a>: put it in <code>~/.subversion/svn-ssh-detach</code>, make sure it&rsquo;s executable</li>
<li><a href="#ssh-askpass">SSH prompter</a>: put it in <code>~/.subversion/svn-ssh-askpass</code>, make sure it&rsquo;s executable</li>
</ul>

<p>From there on, invoke your Subversion wrapper instead of <code>svn</code> (or create an alias that runs the wrapper when you type <code>svn</code>).</p></div>]]></content:encoded>
			<wfw:commentRss>http://fetchsoftworks.com/blog/subversion-and-ssh-authentication-shenanigans/feed</wfw:commentRss>
		</item>
		<item>
		<title>Fetch 5.5.3 released</title>
		<link>http://fetchsoftworks.com/fetch/news/fetch-553-released</link>
		<comments>http://fetchsoftworks.com/fetch/news/fetch-553-released#comments</comments>
		<pubDate>Mon, 16 Nov 2009 21:15:09 +0000</pubDate>
		<dc:creator>Scott McGuire</dc:creator>
				<category><![CDATA[Fetch]]></category>
		<category><![CDATA[News]]></category>

		<guid isPermaLink="false">http://fetchsoftworks.com/?p=352</guid>
		<description><![CDATA[<p>Fetch 5.5.3, a bug-fix update to Fetch 5.5, is now available.  This release fixes a number of problems reported by our users.</p><span id="more-352"></span><p>The changes in Fetch 5.5.3 include:</p>

<ul>
<li>Fixed Mac OS -8905 errors when opening Fetch or saving shortcuts on Mac OS X 10.6 Snow Leopard</li>
<li>Fixed rare freezes when quitting</li>
<li>Fixed a problem where Fetch displayed the copy cursor when moving a file</li>
<li>Fixed problem displaying file lists with Norwegian month names from vsFTPd servers</li>
<li>Fixed a problem where items moved to a parent folder would sometimes not appear in the parent folder's file list</li>
<li>Improved compatibility with certain versions of the VanDyke VShell server that send non-standard TYPE replies</li>
</ul>

<p>For a complete list of changes, see the <a href="/fetch/release-notes"> Fetch 5.5.3 Release Notes</a>.</p>

<p>The Fetch 5.5.3 update is free if you purchased your Fetch license after January 28, 2009; otherwise an upgrade is $10, and a new license is $29.</p>

<p>Please download Fetch 5.5.3 from the <a href="/fetch/download">Fetch Download</a> page, or by choosing <span class="ui command">Check for Update…</span> from the <span class="ui menu">Fetch</span> menu in an earlier version, and let us know what you think of the new release.

<p>Fetch 5.5.3 is a Universal binary, compatible with Mac OS X 10.3.9 or later, including Mac OS X 10.5 Leopard and Mac OS X 10.6 Snow Leopard.</p>]]></description>
			<content:encoded><![CDATA[<style type="text/css" media="screen"><!--
@import "http://fetchsoftworks.com/c/screen.css";
--></style><style type="text/css" media="screen"><!--
@import "http://fetchsoftworks.com/c/feed.css";
--></style><div class="feeditem"><p>Fetch 5.5.3, a bug-fix update to Fetch 5.5, is now available.  This release fixes a number of problems reported by our users.</p><span id="more-352"></span><p>The changes in Fetch 5.5.3 include:</p>

<ul>
<li>Fixed Mac OS -8905 errors when opening Fetch or saving shortcuts on Mac OS X 10.6 Snow Leopard</li>
<li>Fixed rare freezes when quitting</li>
<li>Fixed a problem where Fetch displayed the copy cursor when moving a file</li>
<li>Fixed problem displaying file lists with Norwegian month names from vsFTPd servers</li>
<li>Fixed a problem where items moved to a parent folder would sometimes not appear in the parent folder's file list</li>
<li>Improved compatibility with certain versions of the VanDyke VShell server that send non-standard TYPE replies</li>
</ul>

<p>For a complete list of changes, see the <a href="/fetch/release-notes"> Fetch 5.5.3 Release Notes</a>.</p>

<p>The Fetch 5.5.3 update is free if you purchased your Fetch license after January 28, 2009; otherwise an upgrade is $10, and a new license is $29.</p>

<p>Please download Fetch 5.5.3 from the <a href="/fetch/download">Fetch Download</a> page, or by choosing <span class="ui command">Check for Update…</span> from the <span class="ui menu">Fetch</span> menu in an earlier version, and let us know what you think of the new release.

<p>Fetch 5.5.3 is a Universal binary, compatible with Mac OS X 10.3.9 or later, including Mac OS X 10.5 Leopard and Mac OS X 10.6 Snow Leopard.</p></div>]]></content:encoded>
			<wfw:commentRss>http://fetchsoftworks.com/fetch/news/fetch-553-released/feed</wfw:commentRss>
		</item>
		<item>
		<title>Signed applications are easier to upgrade</title>
		<link>http://fetchsoftworks.com/blog/signed-applications-are-easier-to-upgrade</link>
		<comments>http://fetchsoftworks.com/blog/signed-applications-are-easier-to-upgrade#comments</comments>
		<pubDate>Mon, 09 Nov 2009 18:58:42 +0000</pubDate>
		<dc:creator>Ben Artin</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://fetchsoftworks.com/?p=350</guid>
		<description><![CDATA[<p>Upgrading an application can be an annoying process. In the best case, you click an Upgrade button and go on with your work; in the worst case, you spend hours in frustration trying to make the new version work. For some applications &#8212; such as Fetch &#8212; the upgrade experience is made simpler by code signing, a Mac OS X 10.5 Leopard technology.</p><span id="more-350"></span><p>From the earliest days of Mac OS X, Apple made it easy to securely store passwords in the keychain. A password in the keychain no longer has to be remembered, making it easy for you to log into different accounts, websites, and servers.</p>

<p>An application can only see those passwords that you let it see. The first time an application tries to access a password saved by another application, you have to give it permission. For example, without your permission, Fetch can&#8217;t access your bank account password, and Safari can&#8217;t access your Fetch passwords.</p>

<p>Before Mac OS X 10.5, every time you upgraded an application, you had to re-approve it for password access. A new version of Fetch would need to get your permission to access your web host password, even though the old version of Fetch already had that permission.</p>

<p>This was because there was no way for Mac OS X to tell a new version from a fake. The fear was not that a new version of Fetch would steal your passwords, but that someone would fool you into installing a Fetch lookalike that emails all your passwords to a miscreant.</p>

<p>Requiring new versions to ask for permissions was a safe thing to do, but it made it rather tedious to upgrade some applications. After you installed a new version, the first time you tried to access a password-protected account, you would see something like this:</p>

<p><img class="centered" src="/i/blog/keychain-allow-1.png" title="An application approval dialog." /></p>

<p>&#8220;Huh?&#8221; you&#8217;d say. <span class="ui button">Change All</span> sounds ominous, given that you were probably just logging in and not yet trying to change anything, but good luck figuring out from that dialog if this was change you could believe in.</p>

<p>Of course, if you click <span class="ui button">Don&#8217;t Change</span>, you&#8217;ll get the same question next time. Your computer is giving you a not-so-subtle hint: if you want to get on with your life, you might want to click <span class="ui button">Change All</span>, whatever in the world that means.

<p>To make matters worse, you wouldn&#8217;t always get the same dialog; depending on how you upgraded, you may see a completely different dialog. Even worse, sometimes you might see the dialog once <strong>for each password</strong>&#8230; every time you upgrade.</p>

<p>All in all, this made upgrading confusing and annoying. Nobody was happy about this state of affairs, and, starting with Mac OS X 10.5 Leopard &#8212; released in 2007 &#8212; Apple made it possible for developers to give the <span class="ui button">Change All</span> mole one final whack. Using a technology called <a href="http://en.wikipedia.org/wiki/Code_signing">code signing</a>, information about who created an application can be stored inside the application in a way that can&#8217;t be tampered with or falsified.</p>

<p>Once an application contains its author&#8217;s identity, Mac OS X can tell the difference between a new version of an application (which has the same author identity as the old version) and a fake (which would have someone else&#8217;s identity, or no identity at all). This way, Mac OS X can give new versions of Fetch access to all the passwords that older versions of Fetch had access to. At the end of the day, this is one less reason for having to sweet-talk your computer into letting you get work done.</p>

<p>This is so obviously good for our users that we ran off to sign Fetch two years ago, when we were working on Fetch 5.3, aiming to release it concurrently with Mac OS X 10.5. To gain some other benefits of code signing, we needed to obtain an official code-signing certificate&#8482;, issued by an official certificate authority&#8482;.</p>

<p>We applied for a certificate, and the issuer conscientiously asked for all sorts of information about the company. Nothing too complicated &#8212; company name, company address, a proof that we are a legitimate business, and so on.</p>

<p>This is when we somewhat unexpectedly found out that, while we were busy shipping software, our company ceased to be. Our corporate registration with the New Hampshire Secretary of State had lapsed; before we could proceed, we had to have our status as a legitimate business reinstated. Several months and layers of red tape later, we finally got our hands on a certificate, but by now it was much too late to sign Fetch 5.3 &#8212; as planned, we had released it shortly after Mac OS X 10.5 came out.</p>

<p>We signed the next version &#8212; Fetch 5.3.1, released in March 2009. Since then, we have been delivering you features and bug fixes without the pesky keychain approval alerts. Enjoy!</p>]]></description>
			<content:encoded><![CDATA[<style type="text/css" media="screen"><!--
@import "http://fetchsoftworks.com/c/screen.css";
--></style><style type="text/css" media="screen"><!--
@import "http://fetchsoftworks.com/c/feed.css";
--></style><div class="feeditem"><p>Upgrading an application can be an annoying process. In the best case, you click an Upgrade button and go on with your work; in the worst case, you spend hours in frustration trying to make the new version work. For some applications &mdash; such as Fetch &mdash; the upgrade experience is made simpler by code signing, a Mac OS X 10.5 Leopard technology.</p><span id="more-350"></span><p>From the earliest days of Mac OS X, Apple made it easy to securely store passwords in the keychain. A password in the keychain no longer has to be remembered, making it easy for you to log into different accounts, websites, and servers.</p>

<p>An application can only see those passwords that you let it see. The first time an application tries to access a password saved by another application, you have to give it permission. For example, without your permission, Fetch can&rsquo;t access your bank account password, and Safari can&rsquo;t access your Fetch passwords.</p>

<p>Before Mac OS X 10.5, every time you upgraded an application, you had to re-approve it for password access. A new version of Fetch would need to get your permission to access your web host password, even though the old version of Fetch already had that permission.</p>

<p>This was because there was no way for Mac OS X to tell a new version from a fake. The fear was not that a new version of Fetch would steal your passwords, but that someone would fool you into installing a Fetch lookalike that emails all your passwords to a miscreant.</p>

<p>Requiring new versions to ask for permissions was a safe thing to do, but it made it rather tedious to upgrade some applications. After you installed a new version, the first time you tried to access a password-protected account, you would see something like this:</p>

<p><img class="centered" src="/i/blog/keychain-allow-1.png" title="An application approval dialog." /></p>

<p>&ldquo;Huh?&rdquo; you&rsquo;d say. <span class="ui button">Change All</span> sounds ominous, given that you were probably just logging in and not yet trying to change anything, but good luck figuring out from that dialog if this was change you could believe in.</p>

<p>Of course, if you click <span class="ui button">Don&rsquo;t Change</span>, you&rsquo;ll get the same question next time. Your computer is giving you a not-so-subtle hint: if you want to get on with your life, you might want to click <span class="ui button">Change All</span>, whatever in the world that means.

<p>To make matters worse, you wouldn&rsquo;t always get the same dialog; depending on how you upgraded, you may see a completely different dialog. Even worse, sometimes you might see the dialog once <strong>for each password</strong>&hellip; every time you upgrade.</p>

<p>All in all, this made upgrading confusing and annoying. Nobody was happy about this state of affairs, and, starting with Mac OS X 10.5 Leopard &mdash; released in 2007 &mdash; Apple made it possible for developers to give the <span class="ui button">Change All</span> mole one final whack. Using a technology called <a href="http://en.wikipedia.org/wiki/Code_signing">code signing</a>, information about who created an application can be stored inside the application in a way that can&rsquo;t be tampered with or falsified.</p>

<p>Once an application contains its author&rsquo;s identity, Mac OS X can tell the difference between a new version of an application (which has the same author identity as the old version) and a fake (which would have someone else&rsquo;s identity, or no identity at all). This way, Mac OS X can give new versions of Fetch access to all the passwords that older versions of Fetch had access to. At the end of the day, this is one less reason for having to sweet-talk your computer into letting you get work done.</p>

<p>This is so obviously good for our users that we ran off to sign Fetch two years ago, when we were working on Fetch 5.3, aiming to release it concurrently with Mac OS X 10.5. To gain some other benefits of code signing, we needed to obtain an official code-signing certificate&trade;, issued by an official certificate authority&trade;.</p>

<p>We applied for a certificate, and the issuer conscientiously asked for all sorts of information about the company. Nothing too complicated &mdash; company name, company address, a proof that we are a legitimate business, and so on.</p>

<p>This is when we somewhat unexpectedly found out that, while we were busy shipping software, our company ceased to be. Our corporate registration with the New Hampshire Secretary of State had lapsed; before we could proceed, we had to have our status as a legitimate business reinstated. Several months and layers of red tape later, we finally got our hands on a certificate, but by now it was much too late to sign Fetch 5.3 &mdash; as planned, we had released it shortly after Mac OS X 10.5 came out.</p>

<p>We signed the next version &mdash; Fetch 5.3.1, released in March 2009. Since then, we have been delivering you features and bug fixes without the pesky keychain approval alerts. Enjoy!</p></div>]]></content:encoded>
			<wfw:commentRss>http://fetchsoftworks.com/blog/signed-applications-are-easier-to-upgrade/feed</wfw:commentRss>
		</item>
	</channel>
</rss>
