<?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>Safe from the Losing Fight &#187; Programming</title>
	<atom:link href="http://losingfight.com/blog/category/programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://losingfight.com/blog</link>
	<description>smarter than your average squirrel, on most non-acorn related topics</description>
	<lastBuildDate>Fri, 09 Apr 2010 15:14:34 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
		<atom:link rel='hub' href='http://losingfight.com/blog/?pushpress=hub'/>
		<item>
		<title>The Story of Hearts Attack</title>
		<link>http://losingfight.com/blog/2010/03/30/the-story-of-hearts-attack/</link>
		<comments>http://losingfight.com/blog/2010/03/30/the-story-of-hearts-attack/#comments</comments>
		<pubDate>Tue, 30 Mar 2010 22:30:31 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Career]]></category>
		<category><![CDATA[Order N]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=379</guid>
		<description><![CDATA[I&#8217;ve already posted the press release for Hearts Attack, but I thought I&#8217;d share a little about how Hearts Attack came about.
Way back in 2008 the original iPhone SDK came out, and I, like a lot of people, was excited about developing apps for the iPhone. My company is primarily a software development services company [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve already posted the <a href="/blog/2010/03/30/hearts-attack-1-0-announced-fun-card-game-for-the-iphone/">press release for Hearts Attack</a>, but I thought I&#8217;d share a little about how <a href="http://www.orderndev.com/hearts-attack.html">Hearts Attack</a> came about.</p>
<p>Way back in 2008 the original iPhone SDK came out, and I, like a lot of people, was excited about developing apps for the iPhone. My company is primarily a <a href="http://www.orderndev.com">software development services company</a> so I was mainly interested in learning the SDK so we could pick up iPhone contracts in addition to Mac ones. It also happens to be the case that my favorite card game is hearts, so I decided a good way to learn the iPhone SDK was to write my own hearts game. </p>
<p>After a couple of weeks I had the basic functionality implemented, and noticed I was playing it a lot. I realized then that I could probably make this into a product. Furthermore, releasing an iPhone app through the App Store seemed like a good way for us as a company to begin making the transition from a services based company to a product based one.</p>
<p>If I was going to release Hearts Attack as a published app, I knew the UI and presentation had to be greatly improved. I went through a lot of mockups for the main playing view, including one where everyone&#8217;s cards &mdash; all 52 of them &mdash; were always visible somewhere on the table (a truly horrible idea). Unfortunately I don&#8217;t seem to have most of the mockups around anymore, but I found a couple which you can see below. (See the <a href="http://www.orderndev.com/hearts-attack.html">product page</a> for the end result.)</p>
<table>
<tr>
<td><a href="/blog/wp-content/uploads/2010/03/HorizontalLayout.jpg"><img src="/blog/wp-content/uploads/2010/03/HorizontalLayout.jpg" alt="HorizontalLayout.jpg" border="0" width="240" height="160" /></a></td>
<td><a href="/blog/wp-content/uploads/2010/03/VerticalLayout.jpg"><img src="/blog/wp-content/uploads/2010/03/VerticalLayout.jpg" alt="VerticalLayout.jpg" border="0" width="160" height="240" /></a></td>
</tr>
<tr>
<td><a href="/blog/wp-content/uploads/2010/03/VerticalLayout3.jpg"><img src="/blog/wp-content/uploads/2010/03/VerticalLayout3.jpg" alt="VerticalLayout3.jpg" border="0" width="160" height="240" /></a></td>
<td><a href="/blog/wp-content/uploads/2010/03/HorizontalLayout3.jpg"><img src="/blog/wp-content/uploads/2010/03/HorizontalLayout3.jpg" alt="HorizontalLayout3.jpg" border="0" width="240" height="160" /></a></td>
</tr>
</table>
<p>The biggest challenge I had was fitting everything on the screen and it still being legible and usable. By trial and error I figured out how small I could make the cards and still make them tappable, as well as their optimal position to make them accessible with one hand.</p>
<p>I began thinking about what would make Hearts Attack unique or different from its competitors. Back then there were literally just two iPhone hearts games in the App Store, and I felt pretty confident that what I had was already better than them, but I wanted to be sure. I decided on: oddball talking computer opponents, a tutorial that gave not only card suggestions but the rationale behind the choice (a pet peeve of mine), and multiple undo support for mis-taps and tactical errors.</p>
<p>The last step was to get professionals to do the sound and graphics. I ended up hiring a sound designer, a graphics designer, and a character illustrator. The <a href="/blog/2008/12/13/experiences-with-a-sound-designer/">sound design went smoothly</a>, but getting the graphics done was a lot more involved than I anticipated, which is another story for another day. Jordan of <a href="http://onetoad.com">OneToad Design</a> created the app icon, playing backgrounds, and the special card backgrounds for the queen of spades and jack of diamonds. Lara Kehler did the character illustrations, which turned out great.</p>
<p>Unfortunately, Hearts Attack went on hiatus in early 2009. I was working full time on an iPhone contract, and simply didn&#8217;t have a lot of time to put into Hearts. Secondly, I had lost all desire in finishing it. It was becoming increasingly apparent that iPhone users didn&#8217;t want to pay more than $0.99 for anything, despite <a href="/blog/2008/11/15/how-to-price-your-iphone-app-out-of-existence/">all the whining I did about it</a>. I convinced myself it wasn&#8217;t worth releasing Hearts because it would never make back the money it cost us to make. Hearts stayed dormant for an entire year.</p>
<p>A couple of months ago, I decided to pick Hearts Attack back up again. I had the time and, as someone pointed out to me, it would never make money if I didn&#8217;t release it. I was tempted to update the app to the latest SDK (I started Hearts back before you could even use nibs on the iPhone) and add some features. I decided against this, because I really just wanted to ship it. I did have to update it to the 2.2.1 SDK because the current Xcode tools no longer ship with the 2.0 SDK.</p>
<p>Instead I focused on fixing the bugs and adding polish. Fortunately for me my wife happens to be a professional software tester with iPhone experience, so I got lots of good bugs to fix. I also prepared a press release, created a website, and otherwise got ready for the release. After I felt the app was stable enough, I submitted it to Apple on Friday. It was approved on Monday.</p>
<p>At this point, I&#8217;m still not convinced I&#8217;ll ever make back the money we spent on sound and graphic designers. A hearts card game simply is never going to be a big seller, and price point isn&#8217;t high enough to make up for that. Right now, I&#8217;m tending to think pessimistically about sales, but I&#8217;m going to do what I can to drum up sales and see how things go. </p>
<p>It&#8217;s a &#8220;wait and see&#8221; situation as to if we develop any more iPhone applications to sell ourselves. Of course, regardless of how well Hearts Attack does, we&#8217;d be <a href="http://www.orderndev.com/hire.html">happy to develop your iPhone app</a> for you.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2010/03/30/the-story-of-hearts-attack/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Distributed Version Control and Other Religions</title>
		<link>http://losingfight.com/blog/2010/03/22/distributed-version-control-and-other-religions/</link>
		<comments>http://losingfight.com/blog/2010/03/22/distributed-version-control-and-other-religions/#comments</comments>
		<pubDate>Mon, 22 Mar 2010 07:07:30 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Writing]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=371</guid>
		<description><![CDATA[Lately it seems there&#8217;s been a lot of talk about distributed version control systems &#8212; especially git and Mercurial &#8212; and how they&#8217;re the bee&#8217;s knees or possibly even the cat&#8217;s pajamas.
But at the risk of having my programmer&#8217;s license revoked, I have to confess I don&#8217;t really care about version control systems. I mean, [...]]]></description>
			<content:encoded><![CDATA[<p>Lately it seems there&#8217;s been a lot of talk about distributed version control systems &mdash; especially <a href="http://git-scm.com/">git</a> and <a href="http://mercurial.selenic.com/">Mercurial</a> &mdash; and how they&#8217;re the bee&#8217;s knees or possibly even the cat&#8217;s pajamas.</p>
<p>But at the risk of having my programmer&#8217;s license revoked, I have to confess I don&#8217;t really care about version control systems. I mean, I think it&#8217;s important to use version control, but I don&#8217;t get all excited about the latest ideas in version control technology or the newest VCS on the block. It&#8217;s just a tool. It keeps versions of all my code, and allows me to revert to previous versions, see when and how things changed, and collaborate with other programmers working in the same codebase. Beyond that I don&#8217;t much care.</p>
<p>The tools don&#8217;t make the programmer.</p>
<p>What&#8217;s new with DVCS is the proponents seem to think they need to evangelize their system. Unfortunately they rather suck at it, and their arguments usually leave me feeling that I don&#8217;t want to use software used by such jerks, on account that it might make me into a jerk. Or at least a bigger one.</p>
<p>However, I do think that a DVCS can be a really useful tool so I&#8217;ve come up with some suggestions for those wanting to effectively evangelize their favorite version control system, or at least annoy me less when they talk.</p>
<ol>
<li>
<h2>Don&#8217;t be condescending or insulting</h2>
<p>I think it&#8217;s part of human nature &mdash; or at least programmer nature &mdash; to assume you&#8217;re the smartest guy in the room, and think that anyone who disagrees with you is a real buffon. Programmers seem to take great pleasure in showing that the other person is an idiot, or didn&#8217;t know something they did, or is at least not as clever as they are. A lot of arguments for git or Mercurial seem to revolve around explaining how git or Mercurial are so clearly superior that only morons would use something else.</p>
<p>While this works great for rallying the troops, it&#8217;s counterproductive when trying to win someone over to your side.</p>
<p>Think of it this way: suppose someone comes to your door to tell you about their religion. During the discussion they are self righteous and condescending; they don&#8217;t listen to your arguments, but are only interested in proving that they&#8217;re right. Are you likely to be swayed to believe in their religion? If you&#8217;re like the other hairless bipedal mammals inhabiting this planet you won&#8217;t be, even if they had some valid points.</p>
<p>As soon as you become insulting or condescending, your arguments will be rejected out of hand. I know this will upset some programmers because they believe if you show your argument is superior, everyone will accept it. But that&#8217;s not the way people work.</p>
</li>
<li>
<h2>Try to be helpful</h2>
<p>The best way to introduce someone to your DVCS is by trying to help them. Not in the &#8220;I have all the answers&#8221; way, but in the &#8220;I&#8217;ve dealt with that before, and here&#8217;s what I did&#8221; kind of way. People <em>will</em> run into the kinds of problems that DVCS are good at solving. When they do, you can helpfully suggest a solution.
<p>However, some care should be taken so the suggestion doesn&#8217;t come off the wrong way.</p>
<table>
<tr>
<th>Wrong</th>
<th>Right</th>
</tr>
<tr>
<td>Dude, why are you using subversion?</td>
<td>I&#8217;ve run into that problem before. I solved it by using feature X of git/hg in this way.</td>
<tr>
<td>Dude, just use git/hg.</td>
<td>You smell nice.</td>
</tr>
</table>
<p>Be aware that people may not know where their pain points are. I&#8217;ve seen customers jump through some excruciating hoops to get a piece of software to do something when there was an easier way. People get used to pain and begin to assume it&#8217;s normal. If you notice something like that, even if they&#8217;re not complaining about it, you can politely suggest a better way.</p>
<p>Instead of a list of features that a DVCS provides or abstract arguments as to why they should be using it, people respond better to concrete examples of how a piece of software can make their lives better. People are also more responsive when they know you&#8217;re on their side, trying to help them, even if they don&#8217;t &mdash; or currently can&#8217;t &mdash; take your suggestion. Keep in mind switching VCS in the middle of product cycle is likely something most people can&#8217;t do.</p>
<p>The right attitude is that of trying to help a friend, not conquer an enemy.</p>
</li>
<li>
<h2>Be willing to answer questions, even dumb ones</h2>
<p>Distributed version control works differently from centralized version control, and it does require a different way of thinking. I know I was confused by it when I first started looking into it. A lot of tutorials jump into the mechanics of how to perform certain tasks, but rarely talk about the philosophy of the system or why things are the way they are. If you want to successfully persuade people that your DVCS is the best then you need to be willing to do a lot of patient education.</p>
<p>I say &#8220;patient&#8221; because after using centralized version control they might have difficulty switching over to a new mental model. Or they might have heard a lot of <a href="http://en.wikipedia.org/wiki/Fear,_uncertainty_and_doubt">FUD</a> about your DVCS that you need to put to rest. It&#8217;s important to do this patiently, respectfully, and not insultingly because they&#8217;ve picked up misinformation or don&#8217;t immediately &#8220;get it&#8221; like you do. Otherwise they might ignore your DVCS so they don&#8217;t have to deal with people who look down on them because they don&#8217;t &#8220;get it.&#8221;</p>
</li>
<li>
<h2>Make it trivial to install and use</h2>
<p>This seems like a no brainer, but it is an important part of any software. If it&#8217;s hard to try out and use your DVCS, it simply won&#8217;t get used. I think that for the most part both git and Mercurial succeed in this respect. My only complaint is neither has a good Mac GUI client. Contrast that with Subversion which has both <a href="http://versionsapp.com/">Versions</a> and <a href="http://www.zennaware.com/cornerstone/">Cornerstone</a> on the Mac. You shouldn&#8217;t underestimate the draw of an easy to use, beautiful GUI.</p>
</li>
</ol>
<p>I think <a href="http://www.joelonsoftware.com/">Joel Spolsky</a> has given the best example of how to properly promote and evangelize a DVCS. He wrote a blog post &mdash; <a href="http://www.joelonsoftware.com/items/2010/03/17.html">Distributed Version Control is here to stay, baby</a> &mdash; about how he came to learn and use DVCS. It&#8217;s well written, and instead of condescending, he&#8217;s actually humble and admits he was wrong about DVCS to begin with. Joel also created a site called <a href="http://hginit.com">HgInit</a> that does an amazing job of explaining the philosophy behind Mercurial and gives a solid introduction to right way to use it. It&#8217;s actually the site that convinced me to start using Mercurial for real.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2010/03/22/distributed-version-control-and-other-religions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Compiling OpenCL Kernels with Xcode</title>
		<link>http://losingfight.com/blog/2009/12/17/compiling-opencl-kernels-with-xcode/</link>
		<comments>http://losingfight.com/blog/2009/12/17/compiling-opencl-kernels-with-xcode/#comments</comments>
		<pubDate>Thu, 17 Dec 2009 23:49:44 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Macintosh]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=358</guid>
		<description><![CDATA[The talk I&#8217;m working on for NSConference 2010 involves a decent amount of OpenCL kernel code. Originally, I thought I would develop the kernel code the same way I develop Core Image kernel code: build the kernel in Quartz Composer and then copy paste the code into Xcode when I got it working. 
Unfortunately, I&#8217;ve [...]]]></description>
			<content:encoded><![CDATA[<p>The talk I&#8217;m working on for <a href="http://www.nsconference.com">NSConference 2010</a> involves a decent amount of OpenCL kernel code. Originally, I thought I would develop the kernel code the same way I develop Core Image kernel code: build the kernel in Quartz Composer and then copy paste the code into Xcode when I got it working. </p>
<p>Unfortunately, I&#8217;ve not had much luck with Quartz Composer in way of meaningful compiler errors. Sometimes it returns good errors, sometimes inscrutable ones.</p>
<div align="center">
<a href="/blog/wp-content/uploads/2009/12/QuartzComposer1.png"><img src="/blog/wp-content/uploads/2009/12/QuartzComposer1.png" alt="Quartz Composer" border="0" width="259" height="320" /></a></p>
<div style="font-size:0.7em;">Composer: Wait, wait, I remember this&#8230; it&#8217;s COBOL, right?</div>
</div>
<p>&nbsp;</p>
<p>However, I&#8217;ve found debugging OpenCL kernels to be much easier thanks to the invention of a function I like to call &#8220;printf.&#8221; If you run your kernel on the CPU, then you can print out values just like in C. With debugging solved, I just needed to figure out how to find compiler errors without having to run my code.</p>
<p>Unlike Core Image, OpenCL actually requires you to compile your kernel code explicitly before using it. The API&#8217;s required to do this will return nice compiler error messages and everything. The obvious thing to do would be wrap up these API&#8217;s in a command line tool and invoke the tool from Xcode, which is what I did.</p>
<h2>The Code</h2>
<p>You can download the Xcode project for <a href="/blog/wp-content/uploads/2009/12/clc.zip" title="clc.zip">clc, the OpenCL Compiler here</a>. It requires Mac OS X 10.6 Snow Leopard and the associated Xcode tools. To install, just build the project and copy the resulting binary into your path somewhere. I used ~/bin.</p>
<p>Most of the code is self explanatory, with the possible exception of the output. Unlike most compilers, clc doesn&#8217;t output object code because the host and runtime CPU/GPU&#8217;s could easily be different. It could simply copy the source code as is for the output, but that was a little too obvious for my tastes. Instead clc compresses the source code and stuffs it into a binary plist. It has the slight benefit of potentially being smaller on disk, and making your source code negligibly less accessible to prying eyes, if you&#8217;re into that sort of thing.</p>
<p>There are definite possibilities for improvement. For example, there could be an option to encrypt the source code to be more &#8220;secure.&#8221; Or it could store the binary code generated by the host machine in the output on the chance that the host and runtime machines have the same hardware.</p>
<h2>Setting up Xcode</h2>
<p>To use clc, you&#8217;ll need to set up a build rule in your app&#8217;s target settings to run all OpenCL source files through it. Selecting the menu item Project &gt; Edit Active Target, and then selecting the Rules tab, should land you here:</p>
<p><img src="/blog/wp-content/uploads/2009/12/TargetSettings.png" alt="TargetSettings.png" border="0" width="577" height="306" /></p>
<p>Add another rule, set it to process OpenCL source files using a Custom script. For the custom script enter:</p>
<p><code>~/bin/clc ${INPUT_FILE_PATH} -o ${TARGET_BUILD_DIR}/${PRODUCT_NAME}.app/Contents/Resources/${INPUT_FILE_BASE}.clar</code></p>
<p>Finally, you&#8217;ll need to tell Xcode where you&#8217;re putting the output file, which is:</p>
<p><code>${TARGET_BUILD_DIR}/${PRODUCT_NAME}.app/Contents/Resources/${INPUT_FILE_BASE}.clar</code></p>
<p>By default, Xcode won&#8217;t put OpenCL source files (.cl) into the target, meaning they won&#8217;t get compiled. For each of your OpenCL source files<br />
you&#8217;ll need to explicitly add them to your target. There are several ways to do this, but the easiest is probably selecting all of them, and doing a Get Info (File &gt; Get Info). Switch to the Targets tab and check the target they should be compiled into.</p>
<h2>Runtime Code</h2>
<p>At runtime, it&#8217;s pretty easy to retrieve the original OpenCL source code using the <var>+ (NSString *) openCLSourceWithData:(NSData *)data error:(NSError **)error;</var> method on <var>ONOpenCLArchive</var>. However, there are a couple of convenience methods on NSBundle that makes retrieving the kernel easier. For example:</p>
<p><code></p>
<pre>
#import "ONOpenCLArchive.h"

NSString *kernelSource = [[NSBundle mainBundle] openCLResource:@"MyKernel"];
</pre>
<p></code></p>
<p>That&#8217;s pretty much all there is to it.</p>
<h2>Conclusion</h2>
<p>Although not ground breaking, this little tool has certainly been helpful to me by finding compiler errors at compile time instead of runtime. Hopefully it will be useful to other people as well.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2009/12/17/compiling-opencl-kernels-with-xcode/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>NSConference 2010 Quiz</title>
		<link>http://losingfight.com/blog/2009/12/15/nsconference-2010-quiz/</link>
		<comments>http://losingfight.com/blog/2009/12/15/nsconference-2010-quiz/#comments</comments>
		<pubDate>Wed, 16 Dec 2009 03:49:44 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Macintosh]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=347</guid>
		<description><![CDATA[For the uninformed, NSConference is a Mac developer&#8217;s conference put on by Scotty &#8220;The Scottster&#8221; Scott and his faithful sidekick, Tim &#8220;The Faithful Sidekick&#8221; Isted. They&#8217;re kind of the Batman and Robin of the Mac programming conference world, but have a slightly lower probability of bat-gassing you than the real dynamic duo.
This year they aren&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<p>For the uninformed, <a href="http://www.nsconference.com">NSConference</a> is a Mac developer&#8217;s conference put on by Scotty &#8220;The Scottster&#8221; Scott and his faithful sidekick, Tim &#8220;The Faithful Sidekick&#8221; Isted. They&#8217;re kind of the Batman and Robin of the Mac programming conference world, but have a slightly lower probability of bat-gassing you than the real dynamic duo.</p>
<p>This year they aren&#8217;t content with bringing conference justice to only the UK, so they&#8217;re branching out to the good &#8216;ole U.S. of A. by way of Atlanta, GA. To help you decide which conference you should attend, US or Europe, I&#8217;ve prepared the following quiz:</p>
<ol>
<li>
<p>What is your opinion of Seattle?</p>
<ol>
<li>It&#8217;s nice, but isn&#8217;t nearly rainy or dreary enough.</li>
<li>I like their coffee.</li>
<li>The residents have too many teeth.</li>
</ol>
</li>
<li>
<p>Describe your driving habits</p>
<ol>
<li>I like to drive on the left side of the road.</li>
<li>I like to drive on both sides of the road.</li>
<li>I like to merge right six lanes without signaling while going 147 mph on the off ramp and giving the finger with both hands in my black Camaro.</li>
</ol>
</li>
<li>
<p>The pinnacle of human achievement is&#8230;</p>
<ol>
<li><a href="http://en.wikipedia.org/wiki/Tea_(meal)">Afternoon tea</a></li>
<li>Sliced bread</li>
<li><a href="http://en.wikipedia.org/wiki/Hee_Haw">Hee Haw</a></li>
</ol>
</li>
</ol>
<p>Scoring: Give yourself -1 points for any <strong>1</strong> answer, 0 points for any <strong>2</strong> answer, and 1 point for any <strong>3</strong> answer.</p>
<p>If you scored is less than zero, you should attend NSConference Europe; if greater than zero, NSConference USA. If you scored exactly zero, you are truly a cultured individual and should attend both.</p>
<p>Personally, I&#8217;ll be attending both, and not just because of peer pressure and insightful quizzes. I&#8217;ll be presenting a talk on how to implement a watercolor brush using Core Image and OpenCL and maybe some duct tape. If you enjoy the graphics articles that I post here, you&#8217;ll probably enjoy my presentation. If not, I hear Steve &#8220;I&#8217;m Batman&#8221; Scott does a mean <a href="http://en.wikipedia.org/wiki/Adam_West">Adam West</a> impression.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2009/12/15/nsconference-2010-quiz/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Implementing AppleScript Recordability</title>
		<link>http://losingfight.com/blog/2009/11/02/implementing-applescript-recordability/</link>
		<comments>http://losingfight.com/blog/2009/11/02/implementing-applescript-recordability/#comments</comments>
		<pubDate>Tue, 03 Nov 2009 05:13:59 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Macintosh]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=340</guid>
		<description><![CDATA[For one of my side projects that I&#8217;m currently working on, I decided to implement an AppleScript interface. Designing and implementing one wasn&#8217;t that bad, although Apple&#8217;s AppleScript documentation was sometimes confusing. Fortunately, CocoaDev has a good overview on how to implement AppleScript support.
However, one of my frustrations with working with other app&#8217;s AppleScript interfaces [...]]]></description>
			<content:encoded><![CDATA[<p>For one of my side projects that I&#8217;m currently working on, I decided to implement an AppleScript interface. Designing and implementing one wasn&#8217;t <em>that</em> bad, although <a href="http://www.red-sweater.com/blog/195/we-need-a-hero">Apple&#8217;s AppleScript documentation was sometimes confusing</a>. Fortunately, CocoaDev has a good <a href="http://www.cocoadev.com/index.pl?HowToSupportAppleScript">overview on how to implement AppleScript support</a>.</p>
<p>However, one of my frustrations with working with other app&#8217;s AppleScript interfaces was trying to figure out how the interface was intended to be used. Sure, the AppleScript Editor would show me all the actions and classes, but it isn&#8217;t always obvious how things are supposed to fit together. Something that would help in these cases is AppleScript recording. I could record the app performing the actions I cared about, then examine how the app itself used the actions and classes. Unfortunately, it seems like only the Finder and <a href="http://www.barebones.com/products/bbedit/">BBEdit</a> ever got around to implementing AppleScript recording.</p>
<p>In the hopes of increasing the number of apps with AppleScript recordability, I&#8217;m going to document my approach to implementing it. For brevity, I&#8217;ll assume you&#8217;ve already an AppleScript interface implemented for your Cocoa app.</p>
<h2>Thinking Big Design Thoughts</h2>
<p>If you have an AppleScript interface for your application, you may think of your app architecture as something like this:</p>
<p><img src="/blog/wp-content/uploads/2009/11/TraditionalModel1.png" alt="Traditional Model for Implementing AppleScript" width="301" height="246" /></p>
<p>Here your AppleScript interface and graphical interface are independent peers, and both modify your model classes directly to accomplish your application&#8217;s tasks. Each interface is separate and largely ignorant of the other.</p>
<p>However, when implementing AppleScript recordability it is helpful to think about your app&#8217;s architecture in a different way:</p>
<p><img src="/blog/wp-content/uploads/2009/11/RecordableModel1.png" alt="Recordable Model for Implementing AppleScript" width="300" height="294" /></p>
<p>In this case the GUI is dependent on, and implemented in terms of, the AppleScript interface. The general guideline is that anything the GUI does that mutates or alters the model goes through the AppleScript interface. However, if the GUI simply needs to access or get information from the model, it would go directly to the model, not through the AppleScript interface. Accessing the model can happen at seemingly random times to the user, and spamming the AppleScript Editor with these accesses when recording only confuses the user.</p>
<p>Suppose an application has table view and a button that deletes the currently selected item in that table view. The table view data source would be implemented the standard way, simply going directly to the model, bypassing the AppleScript layer. However, the delete button, since it alters the model, would be implemented by invoking the AppleScript delete command on the object represented by the current table row.</p>
<p>This design has some other benefits besides recordability. Notably it helps test your AppleScript interface design and implementation. If you find that implementing a GUI feature in terms of your AppleScript interface is impossible or difficult, congratulations, you found a bug! Also, merely testing your GUI also exercises your AppleScript interface. It is not a replacement for testing your AppleScript interface explicitly, but it certainly helps.</p>
<h2>Implementation Hardships</h2>
<p>Everything I&#8217;ve talked about so far hasn&#8217;t been all that novel, and probably has been met with large bucket fulls of &#8220;well, duh&#8221;s by anyone who&#8217;s ever looked into implementing AppleScript recording. The problem isn&#8217;t thinking about how to design in recordability, but actually implementing recordability.</p>
<p>As things stand now, doing something as simple as &#8220;invoking the AppleScript delete command on the object represented by the current table row&#8221; is incredibly involved and painful. You have to manually build up the AppleEvent that represents the delete command and the target model object using functions like <var>AEBuildAppleEvent</var> or classes like <var>NSAppleEventDescriptor</var>. Then you have to remember to target your app by specifying the kCurrentProcess process serial number (specifying kCurrentProcess as the ProcessSerialNumber is currently the only way to enable recording. Bundle identifiers, urls, and pid_t&#8217;s do not work.), and parse the AppleEvent you get back into something useful. You&#8217;d have to do this for <strong>every</strong> property or method on your model object you want exposed for recordability.</p>
<h3>Dreaming of Ponies</h3>
<p>The thing is, the Cocoa runtime has a lot of the AppleScript information from your SDEF file at its disposal and could theoretically generate these interfaces for you. In the ideal hypothetical situation, invoking the delete action via AppleScript inside your app could be as simple as:</p>
<p><code></p>
<pre>
// Suppose ONEmployee is our model object, with the appropriate AppleScript interface implemented
ONEmployee *employee = [_employees objectAtIndex:0];
ONEmployeeASProxy *proxy = employee.appleScriptInterface;
[proxy delete];
</pre>
<p></code></p>
<p>Here, any object that implemented the <var>objectSpecifier</var> method for AppleScript support would automatically get an <var>appleScriptInterface</var> property. The object returned by <var>appleScriptInterface</var> would be a proxy object implementing the same methods and properties as the original object. The proxy object would implement these methods by building up the appropriate AppleEvents, sending them, and parsing the resulting event back into a usable object.</p>
<p>Apple actually gets tantalizingly close to this with the Scripting Bridge. Outside users of your app can run your SDEF file through the <a href="http://developer.apple.com/mac/library/documentation/Darwin/Reference/ManPages/man1/sdp.1.html">sdp</a> command line tool and get a nice Objective-C interface of proxy objects that build, send, and parse AppleEvents to and from your app. However, there is not currently a way tell these proxy objects to target kCurrentProcess, or to initialize one of the proxy objects by passing in a model object that implements <var>objectSpecifier</var>. (I&#8217;ve written this up as <a href="rdar://problem/7359646">rdar://problem/7359646</a>.)</p>
<h3>Harsh Reality</h3>
<p>Since I didn&#8217;t want to wait on Apple to extend the Scripting Bridge to make my life easier, I decided to write a couple of classes to help out. You can <a href="/blog/wp-content/uploads/2009/11/ASObject.zip" title="ASObject.zip">download the code here</a>. The code is under the <a href="/blog/2007/09/05/license-for-sample-code/">MIT license</a>.</p>
<p>The classes work similar to the <var>SBObject</var> and <var>SBElementArray</var> classes in the Scripting Bridge framework. Using these classes, you can invoke the delete AppleScript method like so:</p>
<p><code></p>
<pre>
// Suppose ONEmployee is our model object, with the appropriate AppleScript interface implemented
ONEmployee *employee = [_employees objectAtIndex:0];
[ASObj(employee) invokeCommand:@"delete"];
</pre>
<p></code></p>
<p>The <var>ASObj</var> function creates an <var>ASObject</var> proxy object for any NSObject that implements <var>objectSpecifier</var>. <var>invokeCommand</var> takes care of marshalling the parameters into an AppleEvent, sending it, and unmarshalling the return value into an NSObject. The name of the command is the name of the name used in AppleScript, not the Cocoa implementation.</p>
<p><var>invokeCommand</var> can take parameters, although it gets more tricky:</p>
<p><code></p>
<pre>
ONEmployee *employee = [_employees objectAtIndex:0];
[ASObj(employee) invokeCommand:@"giveRaise" with:[NSNumber numberWithInt:10], @"Percent", nil];
</pre>
<p></code></p>
<p>First, the parameters must be named (it&#8217;s not done by parameter order), and those names must match the Cocoa Key in the SDEF, not the user visible parameter name. Second, the marshalling code (from random NSObjects to AppleEvents) is a bit sparse. I&#8217;ve only added code for the types I needed for my project. If you use it, you may need to add support for other types. The same goes for return values; I only added support for the types that I use.</p>
<p><var>ASObject</var> also has support for properties. For example this marks an employee as exempt:</p>
<p><code></p>
<pre>
ONEmployee *employee = [_employees objectAtIndex:0];
[ASObj(employee) setObject:[NSNumber numberWithBool:YES] forProperty:@"isExempt"];
</pre>
<p></code></p>
<p>The same type restrictions for parameters apply to properties as well. The Cocoa Key for the property must be used here, the same as parameters.</p>
<p>Elements also have basic support, which is where the <var>ASElementArray</var> comes in. Right now the only interesting thing to do with an element array is retrieve a reference to a specific element:</p>
<p><code></p>
<pre>
ONEmployee *employee = [_employees objectAtIndex:0];
ASObject *dependent = [[ASObj(employee) elementForKey:@"dependents"] objectAtIndex:0];
[dependent setObject:[NSNumber numberWithBool:YES] forProperty:@"insured"];
</pre>
<p></code></p>
<p>Unlike other methods, <var>ASElementArray</var>&#8217;s <var>objectAtIndex</var> does not execute an AppleEvents or otherwise take any actions. Instead it constructs an object specifier (i.e. an ASObject) for the given element.</p>
<p>The code is still somewhat rough and incomplete, but should help with anyone wanting to implement AppleScript recording. If nothing else, it should serve as a starting point or sample code for anyone rolling their own solution.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2009/11/02/implementing-applescript-recordability/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>How to implement sharpen and blur tools</title>
		<link>http://losingfight.com/blog/2009/09/17/how-to-implement-sharpen-and-blur-tools/</link>
		<comments>http://losingfight.com/blog/2009/09/17/how-to-implement-sharpen-and-blur-tools/#comments</comments>
		<pubDate>Fri, 18 Sep 2009 05:53:48 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Core Image]]></category>
		<category><![CDATA[Macintosh]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=212</guid>
		<description><![CDATA[The sharpen and blur tools are simple bitmap tools. They allow you to blur or sharpen parts of an image using a brush metaphor. In addition to being able to control the strength of the sharpen or blur, these tools also typically allow you to control the blend mode when applying the effect.
The sharpen tool [...]]]></description>
			<content:encoded><![CDATA[<p>The sharpen and blur tools are simple bitmap tools. They allow you to blur or sharpen parts of an image using a brush metaphor. In addition to being able to control the strength of the sharpen or blur, these tools also typically allow you to control the blend mode when applying the effect.</p>
<p>The sharpen tool has the following effect on this tweed pattern:</p>
<p><img src="/blog/wp-content/uploads/2009/09/TweedSharpen50.png" alt="Tweed pattern with sharpen applied" width="200" height="200" /></p>
<p>Notice the stripe through the middle where the edges are more strongly defined.</p>
<p>The blur tool has the opposite effect of sharpen on the tweed pattern:</p>
<p><img src="/blog/wp-content/uploads/2009/09/TweedBlur50.png" alt="Tweed pattern with blur applied" width="200" height="200" /></p>
<h2>Implementation Overview</h2>
<p>Like the <a href="/blog/2009/09/16/how-to-implement-a-sponge-tool/">sponge tool</a>, the sharpen and blur tools are subclasses of the <var>FilterBrush</var> class introduced in the <a href="/blog/2007/09/26/how-to-implement-dodge-and-burn-tools/">dodge and burn tutorial</a>. However, unlike sponge, they do require a slight modification to the <var>GenericBrush</var> class to work.</p>
<p>Since almost all of the code in this tutorial has been covered before, I&#8217;ll just highlight the single change to the <var>GenericBrush</var> class, and the new <var>Sharpen</var> and <var>Blur</var> classes. If you want to see everything, <a href="/blog/wp-content/uploads/2009/09/SharpenBlur.zip" title="Sharpen and blur sample code">download the code</a>.</p>
<h2>Changing GenericBrush</h2>
<p>If you recall, at the very beginning of this article I mentioned that sharpen and blur tools typically allow the user to modify the blend mode. This is the blend mode used when stamping the filtered image back on to the original image. <var>GenericBrush</var> contains the code that handles the stamping, so it will need to be modified.</p>
<p>We change the <var>render:at:</var> method for <var>GenericBrush</var> to be:</p>
<p><code>
<pre>
- (void) render:(Canvas *)canvas at:(NSPoint)point
{
	CGContextRef canvasContext = [canvas context];
	CGContextSaveGState(canvasContext);

	CGPoint bottomLeft = CGPointMake( point.x - CGImageGetWidth(mMask) * 0.5, point.y - CGImageGetHeight(mMask) * 0.5 );

	// Our brush has a shape and soft edges. These are replicated by using our
	//	brush tip as a mask to clip to. No matter what we render after this,
	//	it will be in the proper shape of our brush.
	CGRect brushBounds = CGRectMake(bottomLeft.x, bottomLeft.y, CGImageGetWidth(mMask), CGImageGetHeight(mMask));

	CGContextClipToMask(canvasContext, brushBounds, mMask);
	CGContextSetBlendMode(canvasContext, [self blendMode]);
	[self renderInCanvas:canvas bounds:brushBounds at:point];

	CGContextRestoreGState(canvasContext);
}
</pre>
<p></code></p>
<p>The only change made is the call to <var>CGContextSetBlendMode</var> that allows brush subclasses to determine the blend mode to use. The default implementation is simply:</p>
<p><code>
<pre>
- (CGBlendMode) blendMode
{
	return kCGBlendModeNormal;
}
</pre>
<p></code></p>
<p>That&#8217;s it for <var>GenericBrush</var>.</p>
<h2>Sharpen Tool</h2>
<p>The sharpen tool has just two parameters: <var>mMode</var>, which is the blend mode, and <var>mStrength</var> which determines how strong the sharpen effect is applied. They are initialized in <var>init</var> like so:</p>
<p><code>
<pre>
- (id) init
{
	self = [super init];
	if ( self != nil ) {
		// Set the default values for our parameters
		mMode = kCGBlendModeDarken;
		mStrength = 1.0;
	}
	return self;
}
</pre>
<p></code></p>
<p>Here are some examples of the sharpen tool parameters:</p>
<table>
<tr>
<th>mMode</th>
<th>mStrength</th>
<th>Result</th>
</tr>
<tr>
<td>kCGBlendModeNormal</td>
<td>0.5</td>
<td><img src="/blog/wp-content/uploads/2009/09/TweedSharpenNormal50.png" alt="Tweed with sharpen, normal blend mode, 50%" border="0" width="200" height="200" /></td>
</tr>
<tr>
<td>kCGBlendModeNormal</td>
<td>1.0</td>
<td><img src="/blog/wp-content/uploads/2009/09/TweedSharpenNormal100.png" alt="Tweed with sharpen, normal blend mode, 100%" border="0" width="200" height="200" /></td>
</tr>
<tr>
<td>kCGBlendModeDarken</td>
<td>1.0</td>
<td><img src="/blog/wp-content/uploads/2009/09/TweedSharpenDarken100.png" alt="Tweed with sharpen, darken blend mode, 100%" border="0" width="200" height="200" /></td>
</tr>
<tr>
<td>kCGBlendModeLighten</td>
<td>1.0</td>
<td><img src="/blog/wp-content/uploads/2009/09/TweedSharpenLighten100.png" alt="Tweed with sharpen, lighten blend mode, 100%" border="0" width="200" height="200" /></td>
</tr>
</table>
<p>The blend modes typically offered for a sharpen tool are kCGBlendModeNormal, kCGBlendModeDarken, kCGBlendModeLighten, kCGBlendModeHue, kCGBlendModeSaturation, kCGBlendModeColor, and kCGBlendModeLuminosity. In the examples above, kCGBlendModeDarken causes the sharpening to only affect light pixels and kCGBlendModeLighten only affects dark pixels.</p>
<p>The heart of the sharpen tool is the filter it creates. The code for that is:</p>
<p><code>
<pre>
- (CIFilter *) filter
{
	// We need to create and configure our filter here
	CIFilter * filter = [CIFilter filterWithName:@"CIUnsharpMask"];
	[filter setDefaults];
	[filter setValue:[NSNumber numberWithFloat:mStrength * 100.0] forKey:@"inputRadius"];
	return filter;
}
</pre>
<p></code></p>
<p>You&#8217;ll notice that I&#8217;m using the unsharp mask filter to do the sharpening. I should point out that most image editors don&#8217;t use this filter to do the sharpening. Instead, they seem to use a convolution filter to do the sharpening. However, the convolution filter means it is easy for the user to overdue the effect. Unsharp mask does not have that problem, plus unsharp mask is provided by the system.</p>
<p>The final bit of the sharpen tool is returning the correct blend mode:</p>
<p><code>
<pre>
- (CGBlendMode) blendMode
{
	return mMode;
}
</pre>
<p></code></p>
<h2>Blur Tool</h2>
<p>The blur tool is very similar to the sharpen tool. It even takes the same parameters. The only real difference is the filter that it creates, so that&#8217;s what I&#8217;ll present first:</p>
<p><code>
<pre>
- (CIFilter *) filter
{
	// We need to create and configure our filter here.
	CIFilter * filter = [CIFilter filterWithName:@"CIBoxBlur"];
	[filter setDefaults];
	[filter setValue:[NSNumber numberWithFloat:mStrength * 7.0] forKey:@"inputRadius"];

	return filter;
}
</pre>
<p></code></p>
<p>Here I use the built in CIBoxBlur. <var>mStrength</var> ranges from 0 to 1, inclusive. I set the coefficient of 7 simply by trial and error until I got something that &#8220;looked right.&#8221;</p>
<p>Here are some examples of the blur tool:</p>
<table>
<tr>
<th>mMode</th>
<th>mStrength</th>
<th>Result</th>
</tr>
<tr>
<td>kCGBlendModeNormal</td>
<td>0.5</td>
<td><img src="/blog/wp-content/uploads/2009/09/TweedBlurNormal50.png" alt="Tweed with 50% blur, normal blend mode" border="0" width="200" height="200" /></td>
</tr>
<tr>
<td>kCGBlendModeNormal</td>
<td>1.0</td>
<td><img src="/blog/wp-content/uploads/2009/09/TweedBlurNormal100.png" alt="Tweed with 100% blur, normal blend mode" border="0" width="200" height="200" /></td>
</tr>
<tr>
<td>kCGBlendModeDarken</td>
<td>1.0</td>
<td><img src="/blog/wp-content/uploads/2009/09/TweedBlurDarken100.png" alt="Tweed with 100% blur, darken blend mode" border="0" width="200" height="200" /></td>
</tr>
<tr>
<td>kCGBlendModeLighten</td>
<td>1.0</td>
<td><img src="/blog/wp-content/uploads/2009/09/TweedBlurLighten100.png" alt="Tweed with 100% blur, lighten blend mode" border="0" width="200" height="200" /></td>
</tr>
</table>
<h2>Conclusion</h2>
<p>Sharpen and blur are the last of the common filter brushes. Enjoy, and <a href="/blog/wp-content/uploads/2009/09/SharpenBlur.zip" title="Sharpen and blur sample code">download the sample code</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2009/09/17/how-to-implement-sharpen-and-blur-tools/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to implement a sponge tool</title>
		<link>http://losingfight.com/blog/2009/09/16/how-to-implement-a-sponge-tool/</link>
		<comments>http://losingfight.com/blog/2009/09/16/how-to-implement-a-sponge-tool/#comments</comments>
		<pubDate>Wed, 16 Sep 2009 07:25:29 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Core Image]]></category>
		<category><![CDATA[Macintosh]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=195</guid>
		<description><![CDATA[There aren&#8217;t many bitmap tools that I look at and think &#8220;hmmm&#8230; I could probably crank that out in about half an hour.&#8221; But because of some previous work I had done, it turned out I wasn&#8217;t too far from the mark when it comes to the sponge tool.
Overview
In concept, the sponge tool is a [...]]]></description>
			<content:encoded><![CDATA[<p>There aren&#8217;t many bitmap tools that I look at and think &#8220;hmmm&#8230; I could probably crank that out in about half an hour.&#8221; But because of some <a href="/blog/2007/09/26/how-to-implement-dodge-and-burn-tools/">previous work I had done</a>, it turned out I wasn&#8217;t too far from the mark when it comes to the sponge tool.</p>
<h2>Overview</h2>
<p>In concept, the sponge tool is a simple tool. It either increases or decreases the saturation of an image. Saturation describes how intense a given color is. 0% saturation means the color is gray. In the implementation that I will show, the sponge tool will behave like a brush.</p>
<p>Thus, if I have a simple red square with about 50% saturation, the sponge tool in the saturation mode affects it like so:</p>
<p><img src="/blog/wp-content/uploads/2009/09/Saturation.png" alt="Red square with saturation applied" border="0" width="200" height="200" /></p>
<p>The desaturation mode has the opposite effect on the same image:</p>
<p><img src="/blog/wp-content/uploads/2009/09/Desaturation.png" alt="Red square with desaturation applied" width="200" height="200" /></p>
<p>In addition to the saturate/desaturate mode, the sponge tool has  a &#8220;flow&#8221; parameter, which determines how much to saturate or desaturate the image.</p>
<h2>Implementation Overview</h2>
<p>The sponge tool is simply a subclass of the <var>FilterBrush</var> class, which I created for the <a href="/blog/2007/09/26/how-to-implement-dodge-and-burn-tools/">dodge and burn tutorial</a>. In fact the only difference between this tutorial and that one is the new subclass <var>Sponge</var>. For that reason I&#8217;ll only be covering the <var>Sponge</var> class in this tutorial. For an explanation as to how the rest of the code works, please refer back to the <a href="/blog/2007/09/26/how-to-implement-dodge-and-burn-tools/">dodge and burn tutorial</a>.</p>
<p>As always, I&#8217;ve provided <a href="/blog/wp-content/uploads/2009/09/Sponge.zip" title="Sponge sample code">sample code for this article</a>.</p>
<h2>Sponge</h2>
<h3>Parameters</h3>
<p>The sponge tool has two parameters which are initialized in the init method:</p>
<p><code></p>
<pre>
- (id) init
{
	self = [super init];
	if ( self != nil ) {
		// Set the default values for our parameters
		mFlow = 0.5;
		mMode = kSpongeMode_Desaturate;
	}
	return self;
}
</pre>
<p></code></p>
<p>The two parameters for the sponge tool are <var>mFlow</var> and <var>mMode</var>.</p>
<ul>
<li><var>mFlow</var> Flow determines how strong the saturation or desaturation effect is applied to the image. It ranges from 0.0 to 1.0, where 0.0 means the effect isn&#8217;t applied, and 1.0 is where the effect is at its strongest.
<p>	Sponge in saturate mode, varying flow:</p>
<table>
<tr>
<th>mFlow</th>
<th>Result</th>
</tr>
<tr>
<td>0.25</td>
<td><img src="/blog/wp-content/uploads/2009/09/Saturation_25.png" alt="Red square with 25% saturation applied" border="0" width="200" height="200" /></td>
</tr>
<tr>
<td>0.5</td>
<td><img src="/blog/wp-content/uploads/2009/09/Saturation.png" alt="Red square with 50% saturation applied" border="0" width="200" height="200" /></td>
</tr>
<tr>
<td>1.0</td>
<td><img src="/blog/wp-content/uploads/2009/09/Saturation_100.png" alt="Red square with 100% saturation applied" border="0" width="200" height="200" /></td>
</tr>
</table>
</li>
<li><var>mMode</var> Mode determines if the sponge saturates or desaturates the image. It has only two settings: saturate or desaturate. Saturate increases the color&#8217;s saturation, while desaturate decreases saturation.
<p>	Sponge examples:</p>
<table>
<tr>
<th>mMode</th>
<th>Result</th>
</tr>
<tr>
<td>kSpongeMode_Saturate</td>
<td><img src="/blog/wp-content/uploads/2009/09/Saturation.png" alt="Red square with saturation applied" border="0" width="200" height="200" /></td>
</tr>
<tr>
<td>kSpongeMode_Desaturate</td>
<td><img src="/blog/wp-content/uploads/2009/09/Desaturation.png" alt="Red square with desaturation applied" width="200" height="200" /></td>
</tr>
</table>
</li>
</ul>
<p>In the examples I used a red rectangle with about a 50% saturation. That way, both saturation and desaturation effects will show up on it.</p>
<h3>Creating the filter</h3>
<p>If you recall from the dodge and burn tutorial, the only real responsibility of a <var>FilterBrush</var> subclass is to create a filter that will be applied to each brush stamp.</p>
<p><code></p>
<pre>
- (CIFilter *) filter
{
	// We need to create and configure our filter here. CIColorControls has controls
	//	for saturation which is what we care about.
	CIFilter * filter = [CIFilter filterWithName:@"CIColorControls"];
	[filter setDefaults];
	if ( mMode == kSpongeMode_Saturate )
		[filter setValue:[NSNumber numberWithFloat:1 + mFlow] forKey:@"inputSaturation"];
	else
		[filter setValue:[NSNumber numberWithFloat:1 - mFlow] forKey:@"inputSaturation"];

	return filter;
}
</pre>
<p></code></p>
<p>Unlike the dodge and burn tools, I don&#8217;t use a custom filter. Instead, I use the system provided CIColorControls, which has a parameter for saturation. The saturation parameter has a range of 0 to 2, where 1 is the identity value. Thus, if I&#8217;m trying to saturate the image, I add 1.0 to mFlow, and if I&#8217;m trying to desaturate the image, I subtract mFlow from 1.0.</p>
<p>That&#8217;s it. The rest of the heavy lifting is done by the framework I created in the dodge and burn tutorial.</p>
<h2>Conclusion</h2>
<p>The main thing this tutorial demonstrates to me is that the time spent building a framework for filter brushes paid off. It should help in the future if I decide to tackle the blur and sharpen brushes as well.</p>
<p>Hopefully you found this post enlightening. Don&#8217;t forget to <a href="/blog/wp-content/uploads/2009/09/Sponge.zip" title="Sponge sample code">download the source code</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2009/09/16/how-to-implement-a-sponge-tool/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[UIImage imageNamed:] is a memory leak, but only on 2.x</title>
		<link>http://losingfight.com/blog/2009/09/14/uiimage-imagenamed-is-a-memory-leak-but-only-on-2-x/</link>
		<comments>http://losingfight.com/blog/2009/09/14/uiimage-imagenamed-is-a-memory-leak-but-only-on-2-x/#comments</comments>
		<pubDate>Mon, 14 Sep 2009 23:12:17 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=177</guid>
		<description><![CDATA[Update: I was contacted by an Apple engineer saying this bug was fixed in 3.0, and asked if I could reproduce it there. I tried my sample project again, and I was unable to reproduce it on 3.0. This problem only seems to affect 2.x devices.
Not too long ago I was profiling an iPhone app [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Update: I was contacted by an Apple engineer saying this bug was fixed in 3.0, and asked if I could reproduce it there. I tried my sample project again, and I was unable to reproduce it on 3.0. This problem only seems to affect 2.x devices.</strong></p>
<p>Not too long ago I was profiling an iPhone app that I had written for a client. Their testers had found that using a certain feature for long enough ended up causing the app to be ejected because of a low memory situation.</p>
<p>After some quality, yet painful, time with Instruments I discovered I was never deallocating image memory in the form of CGImageRef and its internal drawing cache. (It turns out that if you draw a CGImageRef while on a thread other than the main thread, it creates a cache of the bitmap data. However, this wasn&#8217;t my problem.)</p>
<p>At first I thought I simply forgot to release the UIImages somewhere. I put in some logging code and was able to confirm that I was releasing the UIImages the correct number of times, in the right places. But it appeared that someone had called retain on it an extra time.</p>
<p>That&#8217;s when I happened to notice that only the UIImages I had constructed with imageNamed: were failing to be released. I suspected that they were being retained in a global cache. The only problem with this cache is not released in low memory situations. Even when my app receives a low memory notification and I free up all the memory I can, the UIImage global cache just sits there clutching it&#8217;s unused UIImages to its chest, muttering.</p>
<p>Unfortunately for me, some of the UIImages I was loading were large, and I was expecting them to be deallocated when I released them. As the feature was used, different UIImages were loaded with imageNamed: and never released until the phone ran out of memory and my app was ejected.</p>
<p>The solution was to write a replacement method for imageNamed: that didn&#8217;t cache the UIImage. Here&#8217;s what it looks like:</p>
<p><code>
<pre>
@implementation UIImage (OrderNDev)

+ (id) imageNamedNoCache:(NSString *)name
{
	NSString *basename = [name stringByDeletingPathExtension];
	NSString *extension = [name pathExtension];
	NSString *path = [[NSBundle mainBundle] pathForResource:basename ofType:extension];
	return [[[UIImage alloc] initWithContentsOfFile:path] autorelease];
}

@end
</pre>
<p></code></p>
<p>The moral of the story is imageNamed: is only for use with small images that are used constantly throughout the app&#8217;s lifetime. Don&#8217;t use imageNamed: if you want that memory back on a 2.x device. Everything will work fine on a 3.x device though.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2009/09/14/uiimage-imagenamed-is-a-memory-leak-but-only-on-2-x/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Don&#8217;t lose your keys</title>
		<link>http://losingfight.com/blog/2008/10/16/dont-lose-your-keys/</link>
		<comments>http://losingfight.com/blog/2008/10/16/dont-lose-your-keys/#comments</comments>
		<pubDate>Thu, 16 Oct 2008 20:16:51 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://www.losingfight.com/blog/?p=171</guid>
		<description><![CDATA[There are many difficult parts to creating and distributing an iPhone application. Don&#8217;t let the loss of an important file be one of them.
A client of mine recently had a scare when he (temporarily) lost his private key. Allow me to explain: for an iPhone application to be distributed, it has to be signed by [...]]]></description>
			<content:encoded><![CDATA[<p>There are many difficult parts to creating and distributing an iPhone application. Don&#8217;t let the loss of an important file be one of them.</p>
<p>A client of mine recently had a scare when he (temporarily) lost his private key. Allow me to explain: for an iPhone application to be distributed, it has to be signed by a cryptographic key created by the developer. The signing is done by the private key, and verifying that the application is signed is done by the public key.</p>
<p>There are couple of things to note about the private key:</p>
<ol>
<li>The private key never leaves the machine it was created on. Ever.</li>
<li>No one, including Apple, can regenerate your private key, if something were to happen to it.</li>
</ol>
<p>While it is true that Apple has a copy of the developer&#8217;s certificate, they only have the <em>public</em> key, not the private. This makes sense, because whoever has your private key can distribute applications under your name. Thus, it&#8217;s not something you want to be storing just anywhere.</p>
<p>Losing your private key has a couple of implications, since it cannot be recovered and because developers can only have one distribution certificate at a time. This means the old certificate must be revoked before a new one can be created<del>, which will caused all applications signed with the old certificate to die</del> (<strong>Edit:</strong> I&#8217;ve been told by someone who revoked their certificate that it did not effect already distributed apps).</p>
<p><del>If you lose your private key your choice is to either never update your application ever again, or kill all existing copies of it.</del></p>
<p>After you upload a new version signed with the new certificate, your old customers can get the application<del>, but only after paying for it again. Not a huge deal if your application is free, but if it&#8217;s not your customers will probably be upset</del>.</p>
<p>All of this to say: you should be backing up your private key. Your private key is stored in the Keychain, and will have to be exported first. Here&#8217;s how you do it:</p>
<ol>
<li>Launch Keychain Access, which lives in /Applications/Utilities.</li>
<li>In the Category list on the left, select Keys.</li>
<li>In the Keys list, select the keys used for code signing. They will have disclosure triangles next to them, which reveal iPhone Developer/Distribution certificates.</li>
<li>From the menu, select File &gt; Export Items. Be sure to save the key in the Personal Information Exchange (.p12) format.</li>
<li>During the export, you will be prompted to create a password which will protect the exported file. Be sure to pick a secure password that you will either remember or that you will store in a safe place.</li>
</ol>
<p>Now you have your private keys in a file that you can backup or check into source control. You will also probably want to backup the password you created in step 5.</p>
<p>Installing the private keys on a new machine is easy:</p>
<ol>
<li>Copy the exported file to the machine you want to install it on.</li>
<li>Double click the .p12 file, which will launch Keychain Access.</li>
<li>When prompted, entered the password you created in the previous step 5.</li>
</ol>
<p>That&#8217;s all there is to it. Hopefully this will save someone pain in the future.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2008/10/16/dont-lose-your-keys/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>How to get application data from the iPhone</title>
		<link>http://losingfight.com/blog/2008/08/14/how-to-get-application-data-from-the-iphone/</link>
		<comments>http://losingfight.com/blog/2008/08/14/how-to-get-application-data-from-the-iphone/#comments</comments>
		<pubDate>Fri, 15 Aug 2008 02:04:06 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://www.losingfight.com/blog/?p=169</guid>
		<description><![CDATA[If you&#8217;ve written any kind of non-trivial application from the iPhone, you&#8217;ve had to deal with debugging it while not in the debugger. Sometimes you may even need to get at the preferences file and other support files, such as &#8220;saved state&#8221; files to see what went wrong.
There are two main ways to go about [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;ve written any kind of non-trivial application from the iPhone, you&#8217;ve had to deal with debugging it while not in the debugger. Sometimes you may even need to get at the preferences file and other support files, such as &#8220;saved state&#8221; files to see what went wrong.</p>
<p>There are two main ways to go about retrieving application data for your iPhone applications, depending on whose phone you want to get it off of. If it&#8217;s your personal phone you do development on, it&#8217;s pretty easy. If you need to get data from someone else, like say a beta user, it&#8217;s much more involved.</p>
<h2>For your iPhone</h2>
<p>If you&#8217;re on your development machine and iPhone, Xcode provides a pretty simple way to get at the data.</p>
<ol>
<li>
<p>First, dock your iPhone, then open Xcode.</p>
</li>
<li>
<p>In Xcode, open the Organizer, via the Window > Organizer menu item.</p>
</li>
<li>
<p>Select your iPhone in the source list on the left.</p>
<p><img src="/blog/wp-content/uploads/2008/08/organizersourcelist.png" alt="OrganizerSourceList.png" border="0" width="231" height="186" /> </p>
</li>
<li>
<p>On the right, locate the Applications list. Find your application, and disclose the disclosure triangle to the left of the name.</p>
<p><img src="/blog/wp-content/uploads/2008/08/organizerapplications.png" alt="OrganizerApplications.png" border="0" width="556" height="197" /></p>
</li>
<li>
<p>Select &#8220;Application Data&#8221; underneath the name of your application, and press the button on the right, the down arrow image.</p>
</li>
<li>
<p>You will be prompted for a place to save it. Pick a place, and press &#8220;Save.&#8221;</p>
</li>
</ol>
<p>You now have your application data onto your Mac, where you can debug it. You can either go to the Finder to browser it, or it is also added to the Organizer window in Xcode, under the &#8220;Projects &#038; Sources&#8221; tree.</p>
<h2>For a beta tester&#8217;s iPhone</h2>
<p>If you are running a beta and you need to get data from your application to debug, things get pretty tricky. The general idea is you get your beta user to find the iTunes backup files (yes, more than one) that contain your application data, and have them send them to you. Then, using a third party python script, you uncompress the backup files, and hope that they actually contain the correct files.</p>
<ol>
<li>
<p>First, if the user does not yet have a backup (unlikely), they should force one. Do this by selecting the iPhone in iTunes, right clicking (or control-click) and selecting &#8220;Backup&#8221;.</p>
<p><img src="/blog/wp-content/uploads/2008/08/itunesbackup.png" alt="iTunesBackup.png" border="0" width="335" height="206" /></p>
</li>
<li>
<p>Next, the beta user should open the Finder and go to ~/Library/Application Support/MobileSync/Backup. With any luck, there will be one folder here, which will be the 40 character hexadecimal device ID of their iPhone. Navigate inside this folder.</p>
</li>
<li>
<p>In the Finder, switch to list view and sort by modification date.</p>
<p><img src="/blog/wp-content/uploads/2008/08/itunesbackupfiles.png" alt="iTunesBackupFiles.png" border="0" width="690" height="419" /></p>
</li>
<li>
<p>At this point, your beta user needs to select the appropriate backup files that contain the data you need (haha). Depending on your user, you may want them to just zip up the entire folder and send it to you. Be warned though &#8212; it&#8217;s huge.</p>
<p>To be more selective, you only want the files ending in &#8220;mdbackup.&#8221; These files can be grouped based on modification date. For example, in the screenshot above, you can see that a backup happened Today, at 5:06 PM. The beta user could select all of the mdbackup files with a modification date of &#8220;Today, 5:06 PM&#8221;, zip them up, and email them to you.</p>
<p>The thing to note here is that iTunes only does incremental backups. If your application data has not been modified since the previous backup, the current backup will not have your data in it. So you may need to repeat this step several times with your beta user until they find the right backup.</p>
</li>
<li>
<p>At this point the beta user should zip up the &#8220;mdbackup&#8221; files, however you had them select them, and email them to you.</p>
</li>
</ol>
<p>Things are now in your, the developer&#8217;s, hands. You need to convert the mdbackup files into something you can use.</p>
<ol>
<li>
<p>First, download <a href="http://code.google.com/p/iphone-backup-decoder/">iphone-backup-decoder</a> from <a href="http://code.google.com">Google Code</a>. iphone-backup-decode is a Python script that will unarchive all those mdbackup files you now have.</p>
</li>
<li>
<p>Next, make a directory that you can work in, called &#8220;Backups&#8221; (or whatever you want to call it). Place all your mdbackup files in here, and move decode_iphone_backup_v2.1.py file here as well.</p>
</li>
<li>
<p>Before you can run the python script, you need to make it executable. In Terminal.app, cd to your &#8220;Backups&#8221; folder, and type the following:</p>
<p><code>chmod a+rx decode_iphone_backup_v2.1.py</code></p>
</li>
<li>
<p>You are now ready to run the decoder, by typing in Terminal:</p>
<p><code>./decode_iphone_backup_v2.1.py *.mdbackup</code></p>
<p>This will unarchive all mdbackup files current in the &#8220;Backup&#8221; folder, so keep that in mind if you&#8217;re going through multiple backups.</p>
</ol>
<p>The results should now be in a folder called &#8220;MobileSyncExport&#8221; inside your &#8220;Backups&#8221; folder. If you are very lucky, it will contain the files you need.</p>
<p>If you need to repeat these steps, I would advise deleting all the mdbackup files and the MobileSyncExport folder from your Backups folder. The decoder script will most likely give undesirable results if you decode two backups that contain the same file.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2008/08/14/how-to-get-application-data-from-the-iphone/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
	</channel>
</rss>
