<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="wordpress/2.3.3" -->
<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/"
	>

<channel>
	<title>Vacuous Virtuoso &#187; Review</title>
	<link>http://lipidity.com</link>
	<description>Despotic Development</description>
	<pubDate>Wed, 02 Apr 2008 14:18:15 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.3.3</generator>
	<language>en</language>
			<item>
		<title>More CoreGraphics Hackery</title>
		<link>http://lipidity.com/apple/cocoa/cgsinternal/</link>
		<comments>http://lipidity.com/apple/cocoa/cgsinternal/#comments</comments>
		<pubDate>Sat, 12 Jan 2008 04:21:03 +0000</pubDate>
		<dc:creator>Ankur</dc:creator>
		
		<category><![CDATA[Cocoa]]></category>

		<category><![CDATA[Apple]]></category>

		<category><![CDATA[CoreGraphics]]></category>

		<category><![CDATA[Mac]]></category>

		<category><![CDATA[Review]]></category>

		<guid isPermaLink="false">http://lipidity.com/apple/cocoa/cgsinternal/</guid>
		<description><![CDATA[Alacatia Labs, Inc. bring you the most thorough investigation of undocumented CoreGraphics functions to date, with CGSInternal.

There&#8217;s a subversion repository as well if you&#8217;re keen to stay up to date.
]]></description>
			<content:encoded><![CDATA[<p><a href="http://alacatialabs.com/">Alacatia Labs, Inc.</a> bring you the most thorough investigation of undocumented <a href="http://lipidity.com/tag/core-graphics+animation">CoreGraphics</a> functions to date, with <a href="http://alacatialabs.com/toys/cgsinternal/">CGSInternal</a>.</p>

<p>There&#8217;s a <a href="http://svn.alacatialabs.com/CGSInternal/trunk/">subversion repository</a> as well if you&#8217;re keen to stay up to date.</p>
]]></content:encoded>
			<wfw:commentRss>http://lipidity.com/apple/cocoa/cgsinternal/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Another guide to Quicksilver</title>
		<link>http://lipidity.com/apple/another-guide-to-quicksilver/</link>
		<comments>http://lipidity.com/apple/another-guide-to-quicksilver/#comments</comments>
		<pubDate>Tue, 04 Dec 2007 10:49:13 +0000</pubDate>
		<dc:creator>Ankur</dc:creator>
		
		<category><![CDATA[Apple]]></category>

		<category><![CDATA[Quicksilver]]></category>

		<category><![CDATA[Mac]]></category>

		<category><![CDATA[Review]]></category>

		<category><![CDATA[Source Code]]></category>

		<guid isPermaLink="false">http://lipidity.com/general/another-guide-to-quicksilver/</guid>
		<description><![CDATA[Joe Dunn is doing a nice series of articles on Quicksilver. He&#8217;s covered triggers and scripts so far with more on the way.

One thing I disagree with, though, is the excessive use of the &#8220;do shell script&#8221; AppleScript. I like the &#8220;Run Command in Shell&#8221; action just fine. But if you want an icon, writing [...]]]></description>
			<content:encoded><![CDATA[<p>Joe Dunn is doing a nice series of articles on Quicksilver. He&#8217;s covered <a href="http://jwdunn.com/2007/11/24/how-i-use-quicksilver-i-triggers/">triggers</a> and <a href="http://jwdunn.com/2007/11/29/how-i-use-quicksilver-ii-scripts/">scripts</a> so far with more on the way.</p>

<p>One thing I disagree with, though, is the excessive use of the &#8220;do shell script&#8221; AppleScript. I like the &#8220;Run Command in Shell&#8221; action just fine. But if you want an icon, writing an Obj-C wrapper isn&#8217;t too much work. Especially since you have <a href="http://pub.lipidity.com/CocoaShell.tar.bz2">this source code</a>.</p>

<p>I&#8217;ve also got a bit more on Quicksilver coming up shortly.</p>
]]></content:encoded>
			<wfw:commentRss>http://lipidity.com/apple/another-guide-to-quicksilver/feed/</wfw:commentRss>
		</item>
		<item>
		<title>CTGradient code bloat</title>
		<link>http://lipidity.com/apple/ctgradient-code-bloat/</link>
		<comments>http://lipidity.com/apple/ctgradient-code-bloat/#comments</comments>
		<pubDate>Tue, 20 Nov 2007 21:05:12 +0000</pubDate>
		<dc:creator>Ankur</dc:creator>
		
		<category><![CDATA[Apple]]></category>

		<category><![CDATA[Cocoa]]></category>

		<category><![CDATA[CoreGraphics]]></category>

		<category><![CDATA[Mac]]></category>

		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Review]]></category>

		<category><![CDATA[Source Code]]></category>

		<category><![CDATA[Tutorial]]></category>

		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://lipidity.com/apple/cgradient-code-bloat/</guid>
		<description><![CDATA[While getting rid of extraneous junk in an application package is easy using Trimmit, the only way to prevent &#34;code bloat&#34; (and accompanying excess RAM and CPU usage) is through good programming practices. Where most developers fall short is in poor optimization of borrowed code. Let&#8217;s take CTGradient as an example as it&#8217;s well known [...]]]></description>
			<content:encoded><![CDATA[<p>While getting rid of extraneous junk in an application package is easy using <a href="http://lipidity.com/software/trimmit/">Trimmit</a>, the only way to prevent &quot;code bloat&quot; (and accompanying excess RAM and CPU usage) is through good programming practices. Where most developers fall short is in poor optimization of borrowed code. Let&#8217;s take CTGradient as an example as it&#8217;s well known and used (or more accurately, abused) in dozens of applications.</p>

<!--more-->

<p>CTGradient contains an incredible diversity of built-in gradients, gradient styles, and methods for creating fancy rainbows, radial gradients, linear gradients, aqua gradients, and a number of other interesting class and instance methods. It allows you to dynamically alter gradients by adding or removing colors, changing the level of transparency, filling NSRects or NSBezierPaths, rotating the gradient, etc. For demonstration purposes, all these features are excellent. For production, this is a nightmare.</p>

<p><strong><a href="http://pub.lipidity.com/CTGradient/CTGradient.m">CTGradient.m</a> weighs in at over 1300 lines of code.</strong></p>

<p>Ignoring Mr. Weider&#8217;s unique style of formatting, take a look through the code. If you&#8217;re putting this class in an application, you can immediately remove over a thousand lines. Just like that. But if you take some time to understand what&#8217;s going on, you can optimize this thing till it runs like a Ferrari.</p>

<p>You&#8217;ll notice <a href="http://lipidity.com/software/trimmit/">Trimmit</a> uses a gradient background for it&#8217;s window. Let&#8217;s cut down CTGradient until it matches the level of optimization of Trimmit&#8217;s gradient code.</p>

<h2>Clear the junk</h2>

<p>Firstly, let&#8217;s remove the methods we know for sure we won&#8217;t need. Remove the following methods completely from both the interface and the implementation (scroll down for more):</p>

<pre style='height:340px;overflow:scroll'><code>// We don't need the preset gradients

+ (id)dividerGradient;
+ (id)statusBarGradient;
+ (id)aquaSelectedGradient;
+ (id)aquaNormalGradient;
+ (id)aquaPressedGradient;
+ (id)unifiedSelectedGradient;
+ (id)unifiedNormalGradient;
+ (id)unifiedPressedGradient;
+ (id)unifiedDarkGradient;
+ (id)sourceListSelectedGradient;
+ (id)sourceListUnselectedGradient;
+ (id)rainbowGradient;
+ (id)hydrogenSpectrumGradient;

// We won't make any drastic modifications to the gradient once created

- (CTGradient *)gradientWithAlphaComponent:(float)alpha;
- (CTGradient *)addColorStop:(NSColor *)color atPosition:(float)position;
- (CTGradient *)removeColorStopAtIndex:(unsigned)index;
- (CTGradient *)removeColorStopAtPosition:(float)position;
- (CTGradientBlendingMode)blendingMode;
- (NSColor *)colorStopAtIndex:(unsigned)index;
- (NSColor *)colorAtPosition:(float)position;

// Now we don't need to conform to the NSCopying and NSCoding protocols

- (id)copyWithZone:(NSZone *)zone;
- (void)encodeWithCoder:(NSCoder *)coder;
- (id)initWithCoder:(NSCoder *)coder;

// We only need to fill a simple NSRect

- (void)drawSwatchInRect:(NSRect)rect;
- (void)radialFillRect:(NSRect)rect;
- (void)fillBezierPath:(NSBezierPath *)path angle:(float)angle;
- (void)radialFillBezierPath:(NSBezierPath *)path;

// Remove the entire (Private) category;
// but leave -addElement:

- (void)_commonInit;
// move setBlendingMode code into init
- (void)setBlendingMode:(CTGradientBlendingMode)mode;
- (CTGradientElement *)elementAtIndex:(unsigned)index;
- (CTGradientElement)removeElementAtIndex:(unsigned)index;
- (CTGradientElement)removeElementAtPosition:(float)position;
</code></pre>

<p>The following C functions are now unused:</p>

<pre><code>static void chromaticEvaluation(void *info, const float *in, float *out);
static void inverseChromaticEvaluation(void *info, const float *in, float *out);
static void transformRGB_HSV(float *components);
static void transformHSV_RGB(float *components);
static void resolveHSV(float *color1, float *color2);
</code></pre>

<p>And also remove the following from the header:</p>

<pre><code>typedef enum  _CTBlendingMode
    {
    CTLinearBlendingMode,
    CTChromaticBlendingMode,
    CTInverseChromaticBlendingMode
    } CTGradientBlendingMode;
</code></pre>

<p>Remove the <code>&lt;protocols&gt;</code> and unnecessary instance variables so the interface looks like this:</p>

<pre><code>@interface CTGradient : NSObject {
    CTGradientElement* elementList;
    CGFunctionRef gradientFunction;
}
+ (id)gradientWithBeginningColor:(NSColor *)begin endingColor:(NSColor *)end;
- (void)fillRect:(NSRect)rect angle:(float)angle;
- (void)addElement:(CTGradientElement *)newElement;
@end
</code></pre>

<p>Before we go further, we&#8217;ll need to take a detour and fix the remaining code so that it compiles. That&#8217;s easy enough - just remove any references to code we&#8217;ve removed.</p>

<p>If you&#8217;ve been following along, your CTGradient should now look like <a href="http://pub.lipidity.com/CTGradient/CTGradient2.m">this</a> (also made it readable!).</p>

<p>In a few short minutes, we&#8217;re down from more than <strong>1300</strong> to a little over <strong>200 lines</strong>.</p>

<p><big>It gets better.</big></p>

<h2>Optimize it</h2>

<p>First stop, <code>fillRect:angle:</code>. Since the gradient for Trimmit&#8217;s window only runs vertically (angle 90), we can straight away take out the <var>angle</var> argument, and also cut the entire if / else structure with the angle down to the two lines that are under the <code>if(angle == 90)</code>. Ah, much better.</p>

<p>Now things start getting a teeny bit more complex - and fun.</p>

<hr />

<p>The CTGradient code is written so that one can have many different color stops. The CTGradientElement struct has a nextElement which points to the next CTGradientElement and the position of the current element is stored under the float <var>position</var>. However, we need just two - the starting and ending shades.</p>

<p>Let&#8217;s take a look at cutting the multiple elements down to just two.</p>

<p>The <code>addElement:</code> method has a lot of looping to insert the element at the correct place. However, since we know that we only ever need two, we can cut it down to this:</p>

<pre><code>- (void)addElement:(CTGradientElement *)newElement {
    if(elementList) {
        // elementList exists, add second element
        elementList-&gt;nextElement = malloc(sizeof(CTGradientElement));
        *(elementList-&gt;nextElement) = *newElement;
        elementList-&gt;nextElement-&gt;nextElement = 0;
    } else {
        // no elements - add first element
        elementList = malloc(sizeof(CTGradientElement));
        *elementList = *newElement;
        elementList-&gt;nextElement = 0;
    }
}
</code></pre>

<p>Similarly with <code>dealloc</code>,</p>

<pre><code>- (void)dealloc {
    CGFunctionRelease(gradientFunction);
    free(elementList-&gt;nextElement);
    free(elementList);
    [super dealloc];
}
</code></pre>

<p>While we&#8217;re at it, let&#8217;s clean up <code>init</code> as well:</p>

<pre><code>- (id)init {
    if(self = [super init]) {
        CGFunctionCallbacks evaluationCallbackInfo = {0 , &amp;linearEvaluation, 0};
        static const float input_value_range[2] = { 0, 1 };
        static const float output_value_ranges[8] = { 0, 1, 0, 1, 0, 1, 0, 1 };
        gradientFunction = CGFunctionCreate(&amp;elementList, 1, input_value_range, 4, output_value_ranges, &amp;evaluationCallbackInfo);
    }
    return self;
}
</code></pre>

<p>Now we head to the <code>linearEvaluation</code> function. <var>info</var> passed in refers to <var>elementList</var> (see the CGFunctionCreate call). Again, since we know that we&#8217;ll only ever have two elements we can reduce it to:</p>

<pre><code>void linearEvaluation (void *info, const float *in, float *out) {
    float position = *in;

    CTGradientElement *color1 = *(CTGradientElement **)info;
    CTGradientElement *color2 = color1-&gt;nextElement;

    out[0] = (color2-&gt;red - color1-&gt;red)*position + color1-&gt;red; 
    out[1] = (color2-&gt;green - color1-&gt;green)*position + color1-&gt;green;
    out[2] = (color2-&gt;blue - color1-&gt;blue)*position + color1-&gt;blue;
    out[3] = (color2-&gt;alpha - color1-&gt;alpha)*position + color1-&gt;alpha;
}
</code></pre>

<p>And now we can finally remove the lines from <code>+gradientWithBeginningColor:endingColor:</code> where the positions are set, and also remove the <var>position</var> float from the CTGradientElement struct.</p>

<hr />

<p>We&#8217;re now down to a little over <strong>100 lines</strong>. Your CTGradientElement.m should now be looking something like <a href="http://pub.lipidity.com/CTGradient/CTGradient3.m">this</a>. Going well, but let&#8217;s take things up a notch.</p>

<hr />

<p>For Trimmit&#8217;s background, we&#8217;re not interested in the red, green, blue and alpha components - we just need a grayscale shading. This is the most fun part.</p>

<p>Instead of <code>float red, green, blue, alpha;</code> in the CTGradientElement struct, we can have just <code>float shade;</code>.</p>

<p>Now, during <code>init</code> we have:</p>

<pre><code>CGFunctionCallbacks evaluationCallbackInfo = {0 , &amp;linearEvaluation, 0};
static const float input_value_range[2] = { 0, 1 };
static const float output_value_ranges[8] = { 0, 1, 0, 1, 0, 1, 0, 1 };
gradientFunction = CGFunctionCreate(&amp;elementList, 1, input_value_range, 4, output_value_ranges, &amp;evaluationCallbackInfo);
</code></pre>

<p>The third argument, <var>input_value_range</var> is the domain. This gets passed into linearEvalution through <var>*in</var>.This is the independent variable. When we&#8217;re drawing the gradient, linearEvaluation is called with <var>*in</var> (the domain) starting at the first value of <var>input_value_range</var> and ending up at the second. So, something like 0.000, 0.001, 0.002 &#8230; 0.998, 0.999, 1.000. The function&#8217;s job is to set the the color components for each given value of the domain.</p>

<p>The first optimization we can make here is to return only one channel instead of four. This changes it to:</p>

<pre><code>- (id)init {
    if (self = [super init]) {
        CGFunctionCallbacks evaluationCallbackInfo = {0, &amp;linearEvaluation, 0};
        static const float range[2] = {0, 1};
        static const float domain[2] = {0, 1};
        gradientFunction = CGFunctionCreate(&amp;elementList, 1, domain, 1, range, &amp;evaluationCallbackInfo);
    }
    return self;
}
</code></pre>

<p>This change impacts back on the linearEvaluation function - now it only needs to return one channel:</p>

<pre><code>void linearEvaluation (void *info, const float *in, float *out) {
    CTGradientElement *color1 = *(CTGradientElement **)info;
    out[0] = (color1-&gt;nextElement-&gt;shade - color1-&gt;shade)*(*in) + color1-&gt;shade;
}
</code></pre>

<p>And don&#8217;t forget <code>+gradientWithBeginningColor:endingColor:</code>. We improve performance here, as we only need the shade - not a color. We can rename it to something appropriate.</p>

<pre><code>+ (id)gradientWithBeginningShade:(float)begin endingShade:(float)end {
    id newInstance = [[[self class] alloc] init];
    CTGradientElement color1, color2;

    color1.shade = begin; color2.shade = end;

    [newInstance addElement:&amp;color1];
    [newInstance addElement:&amp;color2];
    return [newInstance autorelease];
}
</code></pre>

<p>Now we&#8217;re only returning one grayscale channel. But hold on, we&#8217;re still in the RGB colorspace! That&#8217;s easily fixed. In <code>fillRect:</code>, replace:</p>

<pre><code>#if MAC_OS_X_VERSION_MAX_ALLOWED &gt;= MAC_OS_X_VERSION_10_4
    CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
#else
    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
#endif
</code></pre>

<p>with:</p>

<pre><code>CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceGray();
</code></pre>

<p class="note">CGColorSpaceCreateDeviceGray is device-dependent on Mac OS X 10.3 and below, but starting from Tiger, it&#8217;s now device-independent which is good in terms of appearance.</p>

<p>While we&#8217;re in <code>fillRect:</code>, we can also make a few more improvements:</p>

<pre><code>- (void)fillRect:(NSRect)rect {
    CGContextRef currentContext = [[NSGraphicsContext currentContext] graphicsPort];
    CGContextSaveGState(currentContext);
    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceGray();
    CGContextClipToRect(currentContext, *(CGRect *)&amp;rect);
    CGShadingRef myCGShading = CGShadingCreateAxial(colorspace, CGPointMake(0, 0), CGPointMake(0, NSMaxY(rect)), gradientFunction, 0, 0);
    CGContextDrawShading(currentContext, myCGShading);

    CGShadingRelease(myCGShading);
    CGColorSpaceRelease(colorspace);
    CGContextRestoreGState(currentContext);
}
</code></pre>

<p>I moved the startPoint and endPoint CGPoints straight into the CGShadingCreateAxial call. Also, we only ever fill the whole view with the gradient, so just put in <code>0</code> instead of using NSMinX and NSMinY. We could replace the <code>CGPointMake(0, 0)</code> with <code>(CGPoint){0,0}</code>, but I&#8217;m not sure if that&#8217;d be noticeably faster.</p>

<hr />

<p>Our code is at a lean <strong>80 lines</strong>. Now for the biggest change yet.</p>

<hr />

<p>Heading back to dear old linearEvaluation. Look at this line:</p>

<pre><code>out[0] = (color1-&gt;nextElement-&gt;shade - color1-&gt;shade)*(*in) + color1-&gt;shade;
</code></pre>

<p>What&#8217;s happening here? Think about it like this:</p>

<p>Essentially, we&#8217;re just &quot;graphing&quot; a straight line:</p>

<pre><code>y = mx + c
</code></pre>

<p>where <var>x</var> is the position, <var>*in</var>, and <var>y</var> is the shade we return (<var>out[0]</var>), and <var>c</var> is the initial shade.</p>

<p>Since our <var>x</var> value only goes from 0 to 1 (see domain in CGFunctionCreate), at <code>x = 0</code>, we will have <code>y = c</code>. At <code>x = 1</code>, we&#8217;ll have <code>y = m + c</code>.</p>

<p><img src='http://lipidity.com/wordpress/wp-content/uploads/2007/11/gradient-graph.png' alt='Graph of Gradient Function' class='feature' /></p>

<p><strong>So</strong> we only need the start shade as our <var>*info</var> value, since we can have <var>m</var> as the difference between the final and initial shades. Let&#8217;s effect this in our code.</p>

<p>We can get rid of the CTGradientElement struct. Remove from the header:</p>

<pre><code>typedef struct _CTGradientElement {
    float shade;
    struct _CTGradientElement *nextElement;
} CTGradientElement;
</code></pre>

<p>Instead of the struct, we&#8217;ll use a single <var>shade</var> instance variable. We don&#8217;t need the <code>+gradientWithBeginningShade:endingShade:</code> anymore, nor do we need <code>-addElement:</code>. So our interface now looks like this:</p>

<pre><code>@interface CTGradient : NSObject {
    float shade;
    CGFunctionRef gradientFunction;
}
- (void)fillRect:(NSRect)rect;
@end
</code></pre>

<p>From the implementation, we can remove the <code>free</code> calls in <code>dealloc</code> as well as the whole of <code>+gradientWithBeginningShade:endingShade:</code> and <code>addElement:</code>. We can set the <code>shade</code> in the init method (and replace <code>&amp;elementList</code> with <code>&amp;shade</code>), and change the linearEvaluation function to:</p>

<pre><code>void linearEvaluation (void *info, const float *in, float *out) {
    out[0] = *(float*)info + (*in)*0.1;
}
</code></pre>

<p>The <code>0.1</code> is what determines how much brighter the top of the gradient is (it&#8217;s the <var>m</var> value of our straight line) compared to the bottom.</p>

<p><strong>But</strong> since the <code>(*in)*0.1</code> will go from <code>0</code> to <code>0.1</code> (as <var>*in</var> goes from 0 to 1), we can actually change the <code>domain</code> we declare for CGFunctionCreate to {0, 0.1} and have our function as:</p>

<pre><code>void linearEvaluation (void *info, const float *in, float *out) {
    out[0] = *(float*)info + *in;
}
</code></pre>

<p>You can now add accessors for <code>shade</code> if you need to change the shade of the gradient or you could even have an <code>initWithShade:</code> method. In fact, here&#8217;s an Xcode project with the gradient.</p>

<p class="download"><a href="http://pub.lipidity.com/CTGradient/GradientSample.tar.bz2">Lean Gradient Xcode Project</a></p>

<p>We now have our gradient code down <big>from <strong>1300 lines</strong> to just over <strong>30 lines</strong></big>.</p>

<hr />

<p>We&#8217;ve almost reached a similar level of optimization to Trimmit&#8217;s gradient. There will be further optimizations you can make, but it depends on what you&#8217;re using the gradient for. For example, if the gradient you&#8217;re drawing is always the same, you can optimize further by removing the <code>shade</code> instance variable and all references to it, and hardcode the value into the linearEvaluation function.</p>

<p>Getting to the end of this article, you&#8217;re probably thinking that it would be a bit of a waste to use CTGradient if by the time you optimize it for your application, it doesn&#8217;t resemble the original at all. And you&#8217;re quite right. The documentation already shows you <a href="http://developer.apple.com/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_shadings/chapter_9_section_6.html">how to draw gradients</a>, yet the number of applications using CTGradient - the whole 1300 lines of it - is astonishing.</p>

<p>Please: When you use other people&#8217;s code, don&#8217;t put it in without a thought. Go through it, understand it, and optimize it for your specific need. For the better performance and reduced RAM usage, computers will thank you.</p>
]]></content:encoded>
			<wfw:commentRss>http://lipidity.com/apple/ctgradient-code-bloat/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Beyond Repair</title>
		<link>http://lipidity.com/apple/beyond-repair/</link>
		<comments>http://lipidity.com/apple/beyond-repair/#comments</comments>
		<pubDate>Thu, 15 Nov 2007 09:16:33 +0000</pubDate>
		<dc:creator>Ankur</dc:creator>
		
		<category><![CDATA[Apple]]></category>

		<category><![CDATA[Review]]></category>

		<category><![CDATA[Application]]></category>

		<category><![CDATA[Download]]></category>

		<category><![CDATA[Mac]]></category>

		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://lipidity.com/apple/beyond-repair/</guid>
		<description><![CDATA[Where can you find an application that comprises a single shell command wrapped in so many layers that it ends up 10,000 times bigger, slower, more obtrusive, less intuitive and full of junk, but still performs the same function as the original command?

Here&#8217;s your answer.

AppleScript can be handy sometimes, but when people release applications like [...]]]></description>
			<content:encoded><![CDATA[<p>Where can you find an application that comprises a single shell command wrapped in so many layers that it ends up 10,000 times bigger, slower, more obtrusive, less intuitive and full of junk, but still performs the same function as the original command?</p>

<p><a href="http://www.nwwnetwork.net/software.php?app=wallsaver">Here&#8217;s your answer</a>.</p>

<p>AppleScript can be handy sometimes, but when people release applications like this, and get awards for it, alarm bells should be going off. WallSaver is almost two megabytes in size. For a single command-line.</p>

<p>Just reinforce the point, I wrote another wrapper for the same command in Objective-C. It&#8217;s 100 kb, or 60 kb without the icon. It can pause the screensaver (which brings it down to 0 CPU usage), resume it or restart it. And not once will it throw an &#8220;AppleScript error&#8221; <img src='http://lipidity.com/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> . <a href="http://lipidity.com/software/desksaver/">Download it</a> and see for yourself.</p>

<p>As for the source code, all you need is:</p>

<pre><code>/System/Library/Frameworks/ScreenSaver.framework/Resources/ScreenSaverEngine.app/Contents/MacOS/ScreenSaverEngine -background
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://lipidity.com/apple/beyond-repair/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Eliminate Bloatware</title>
		<link>http://lipidity.com/apple/eliminate-bloatware/</link>
		<comments>http://lipidity.com/apple/eliminate-bloatware/#comments</comments>
		<pubDate>Fri, 02 Nov 2007 02:00:45 +0000</pubDate>
		<dc:creator>Ankur</dc:creator>
		
		<category><![CDATA[Apple]]></category>

		<category><![CDATA[Application]]></category>

		<category><![CDATA[Cocoa]]></category>

		<category><![CDATA[Download]]></category>

		<category><![CDATA[Mac]]></category>

		<category><![CDATA[Review]]></category>

		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://lipidity.com/apple/eliminate-bloatware/</guid>
		<description><![CDATA[The Vikings left their trash on the ground - Mac developers are stuffing theirs into their apps.]]></description>
			<content:encoded><![CDATA[<p>We&#8217;ve heard the excuses and listened to the complaints; the amount of junk shipped in third-party applications just doesn&#8217;t seem to change. If anything, it&#8217;s getting worse. Just because users may not realise how much bloat they&#8217;re getting along with the app, doesn&#8217;t change the fact that it&#8217;s bloat. Unnecessary junk.</p>

<p>Finder info, .DS_Store files, resource forks, debug symbols&#8230; They do nothing for the user short of wasting disk space. For the developer, extra bandwidth costs. Do people not realise this is a problem, or are they just too lazy to act? Either way, the solution is simple.</p>

<p>You can clean apps (sometimes to less than half their original size) with <a href="http://lipidity.com/apple/cleaning-apps-mac-os-x/">some basic commands</a> in the Terminal. But this takes time, and what&#8217;s more, Mac users in general have an aversion to the command line. Enter <a href="http://lipidity.com/trimmit/">Trimmit</a>.</p>

<p class='centre'><a href='http://lipidity.com/trimmit/' title='Trimmit'><img src='http://lipidity.com/wordpress/wp-content/uploads/2007/11/flow2.jpg' alt='[Trimmit]' title="Trimming Flow.app" /></a></p>

<blockquote><p>Trimmit is a svelte utility which takes the pain out of keeping your applications as tight as possible. I use it on Flow each time I seed a build, and I seriously doubt the process could any easier.</p> <cite><a href="http://extendmac.com/" title="ExtendMac Flow">Brian Amerige</a></cite></blockquote>

<p>Trimmit uses superfast UNIX APIs, Apple&#8217;s own developer tools, and the rock-solid Cocoa framework to automate your cleaning process. Just drop your built app onto it, maybe configure a few settings, and you&#8217;re away. <big>It doesn&#8217;t get any easier - or faster.</big></p>

<p>Other applications claim to save disk space by stripping universal binaries, or removing languages. <big>Trimmit does all of that - and more.</big> But it works. Look at this screenshot from Xslimmer regarding Xcode:</p>

<p class='centre'><img src='http://lipidity.com/wordpress/wp-content/uploads/2007/11/xcode-xslim.jpg' alt='Xslimmer on Xcode' title='Shows only 2 architectures' /></p>

<p>Xslimmer naively believes that only two architectures can exist in any application, but the truth is revealed by Trimmit:</p>

<p class='centre'><img src='http://lipidity.com/wordpress/wp-content/uploads/2007/11/xcodetrim-2.png' alt='i386, ppc, ppc64, x86_64' title='Architectures in Xcode' /></p>

<p><br />Because Trimmit interacts with the shell (<a href="http://zsh.sourceforge.net/FAQ/zshfaq01.html#l3">zsh</a>, in fact), no similar application can even come close to it&#8217;s level of power, accuracy and performance.</p>

<p><big><a href="http://rixstep.com/1/20071101,01.shtml">The results</a> speak for themselves.</big></p>

<p>Use Trimmit to recover disk space that third-party applications so rudely waste.</p>

<p class='centre' style='margin:2em 0'><big><a href="http://lipidity.com/trimmit/">Go get Trimmit.</a></big></p>
]]></content:encoded>
			<wfw:commentRss>http://lipidity.com/apple/eliminate-bloatware/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Getting things done with style</title>
		<link>http://lipidity.com/apple/gtd-inbox-core-graphics/</link>
		<comments>http://lipidity.com/apple/gtd-inbox-core-graphics/#comments</comments>
		<pubDate>Mon, 27 Aug 2007 03:50:33 +0000</pubDate>
		<dc:creator>Ankur</dc:creator>
		
		<category><![CDATA[Apple]]></category>

		<category><![CDATA[Review]]></category>

		<category><![CDATA[CoreGraphics]]></category>

		<category><![CDATA[Mac]]></category>

		<guid isPermaLink="false">http://dev.lipidity.com/apple/gtd-inbox-core-graphics</guid>
		<description><![CDATA[In the world of GTD, Midnight Inbox is surely one of the best designed contenders. It&#8217;s so good it&#8217;s addictive.



I&#8217;ve recently started using Inbox for organizing and collecting all my various projects as well as study materials and schedules. Although it took a while for me to get used to the whole GTD concept, I [...]]]></description>
			<content:encoded><![CDATA[<p>In the world of <acronym title='Getting Things Done'>GTD</acronym>, <a href="http://midnightbeep.com/">Midnight Inbox</a> is surely one of the best designed contenders. It&#8217;s so good it&#8217;s addictive.</p>

<!--more-->

<p>I&#8217;ve recently started using Inbox for organizing and collecting all my various projects as well as study materials and schedules. Although it took a while for me to get used to the whole <acronym title='Getting Things Done'>GTD</acronym> concept, I now use the application constantly.</p>

<p class='centre'>
<img oldsrc="http://lipidity.com/images/Midnight_Inbox-20070827-133833.jpg" src="http://lipidity.com/images/Inbox-20070826-130315.jpg" alt="[Midnight Inbox]" title="Screenshot of the Midnight Inbox app Work screen" width="275" height="211" class='feature' /><br />
<small>Midnight Inbox implements David Allen&#8217;s <acronym title='Getting Things Done'>GTD</acronym> approach</small>
</p>

<p>One of the great things about Inbox is that it looks so good. Good enough to forgive make up for its relatively frequent crashes. The interface is really well designed, keeping in line with many of the Mac metaphors while adding a few unobtrusive features that are generally easy to work out.</p>

<p>It&#8217;s clear this is a great application. It has major potential and <a href="http://www.midnightbeep.com/blog/?p=117">version 2.0</a> looks exciting. Congrats to the developers.</p>

<hr />

<p>Going through the contents of the application, I found CGS.framework and thought, &#8220;Interesting. They&#8217;re using Core Graphics&#8221;. It didn&#8217;t occur to me that I released a framework with the exact same name. Well, I&#8217;ve finally realized that one of my favorite apps is possibly using <a href="http://dev.lipidity.com/apple/the-ultimate-core-graphics-resource">this framework</a> and &#8230; [speechless].</p>

<p>This is the first application (to my knowledge) to use that particular framework, and only the second to use code that I&#8217;ve posted. (Logan Rockmore&#8217;s <a href="http://www.loganrockmore.com/AssignmentPlanner/">Assignment Planner</a> was the first, using the <a href="http://dev.lipidity.com/apple/core-graphics-meet-core-image-demo-app">AnimatingTabView</a>).</p>

<hr />

<p>I&#8217;ve never used another GTD program before, but after trying this app, I doubt I&#8217;ll need to. Go check out the fantabulous <a href="http://midnightbeep.com/">Midnight Inbox</a> and get things done with style.</p>
]]></content:encoded>
			<wfw:commentRss>http://lipidity.com/apple/gtd-inbox-core-graphics/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Shiira 2 released, offers HUD framework</title>
		<link>http://lipidity.com/apple/shiira-2-released-offers-hud-framework/</link>
		<comments>http://lipidity.com/apple/shiira-2-released-offers-hud-framework/#comments</comments>
		<pubDate>Mon, 23 Apr 2007 13:43:47 +0000</pubDate>
		<dc:creator>Ankur</dc:creator>
		
		<category><![CDATA[Apple]]></category>

		<category><![CDATA[Cocoa]]></category>

		<category><![CDATA[News]]></category>

		<category><![CDATA[framework]]></category>

		<category><![CDATA[GUI]]></category>

		<category><![CDATA[Mac]]></category>

		<category><![CDATA[Review]]></category>

		<category><![CDATA[shiira]]></category>

		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://dev.lipidity.com/apple/shiira-2-released-offers-hud-framework</guid>
		<description><![CDATA[If you haven&#8217;t already heard, Shiira 2 has been released. Shiira is a web browser written in Cocoa and based on Webkit that aims to provide a better browsing alternative than Safari.

A sub-project of Shiira is a HUD-type window class. While they&#8217;re not completely accurate to the specifications used by Apple, these are probably the [...]]]></description>
			<content:encoded><![CDATA[<p>If you haven&#8217;t already heard, Shiira 2 has been released. <a href="http://shiira.jp/en.php">Shiira</a> is a web browser written in Cocoa and based on Webkit that aims to provide a better browsing alternative than Safari.</p>

<p>A sub-project of Shiira is a HUD-type window class. While they&#8217;re not completely accurate to the specifications used by Apple, these are probably the best HUD windows I&#8217;ve seen from a third party developer by a long shot.</p>

<p><a href='http://dev.lipidity.com/wp-content/uploads/2007/04/hud-window.png' title='HUD window from Shiira'><img src='http://dev.lipidity.com/wp-content/uploads/2007/04/hud-window.thumbnail.png' alt='HUD window from Shiira' height="64" width="128" /></a></p>

<p>The HUD Windows have the funny name of <a href="http://shiira.jp/hmblkappkit/en.html">HMBLBlkAppKit</a>. The Shiira team has really done a great job!</p>
]]></content:encoded>
			<wfw:commentRss>http://lipidity.com/apple/shiira-2-released-offers-hud-framework/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Brian Amerige on Mac development and Flow</title>
		<link>http://lipidity.com/apple/brian-amerige-on-mac-development-and-flow/</link>
		<comments>http://lipidity.com/apple/brian-amerige-on-mac-development-and-flow/#comments</comments>
		<pubDate>Sat, 07 Apr 2007 03:53:07 +0000</pubDate>
		<dc:creator>Ankur</dc:creator>
		
		<category><![CDATA[Apple]]></category>

		<category><![CDATA[Cocoa]]></category>

		<category><![CDATA[interview]]></category>

		<category><![CDATA[Mac]]></category>

		<category><![CDATA[Review]]></category>

		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://dev.lipidity.com/apple/brian-amerige-on-mac-development-and-flow</guid>
		<description><![CDATA[Brian Amerige, the developer of the much-anticipated (but still unreleased) FTP / connection client <a href="http://flowapp.com">Flow</a>, was kind enough to undertake another interview, this time with a focus on more technical and developmental aspects.]]></description>
			<content:encoded><![CDATA[<p><strong>Hi Brian, thanks for taking the time out to go through yet another interview.</strong></p>

<p>Absolutely &#8212; I&#8217;ve got all the time in the world to answer everyone&#8217;s questions. That&#8217;s what I&#8217;m here for.</p>

<p><strong>How&#8217;s the Flow development going? What sort of feedback are you getting from the private beta testers?</strong></p>

<p>Flow development is going really well. As I&#8217;m sure any other developer could tell you, it&#8217;s just an amazing feeling to wake up everyday and be consistently amazed how far things have progressed in just a day. The private beta testers have been absolutely invaluable to Flow. While I know the topic is a bit controversial, I don&#8217;t believe in unit-testing. Wil Shipley made a great post (<a href="http://wilshipley.com/blog/2005/09/unit-testing-is-teh-suck-urr.html">http://wilshipley.com/blog/2005/09/unit-testing-is-teh-suck-urr.html</a>) a while back on it, which really hits the nail on the head. My private-testers are not only rigorously using Flow with the intention of breaking it  (I always say, don&#8217;t test if a feature works, test if it can be broken), in addition to the fact that they all use it in a practical sense &#8212; they&#8217;re building websites and transferring files &#8212; because real world testing is irreplaceable.</p>

<p><strong>So apart from Objective-C and web development, is there anything else you&#8217;ve tinkered with?</strong></p>

<p>Hell yes!</p>

<p>Before I even learned Objective-C, I ran a small-hosting company named Extendmac. We did a bunch of things in unusual ways (giving users a Plesk Control Panel for $6 USD/mo.), and the customers we had absolutely loved us. Unfortunately, once education and software entered the picture, it became pretty clear that I couldn&#8217;t keep all three up at once. Web-Hosting was obviously the weakest link, so I was forced to give it up. That said, I have to say it’s really a shame the hosting services never saw much of the light of day. The hosting system, user control panels, Direct-Support (I had actually written an entire ticket-based support system, which to this day I consider one of my finer creations) were all really well done, all definitely things I’m proud of. If only I had the infrastructure or team behind me (at the time) to have continued, I believe it would have turned into something really phenomenal.</p>

<p>Aside from business, I&#8217;ve tinkered with lots of other things. I&#8217;ve hacked and modified Roombas and had &#8216;TiVoToGo&#8217; on my TiVo long before it was ever publicly available (in a different way of course &#8212; I just wrote some backend to give me WebDAV access to the hard drive, which is particularly funny, because it&#8217;s the first thing I ever saw appear in Flow&#8217;s Bonjour -&gt; WebDAV category.) As you might expect from a developer, I&#8217;m constantly making easier solutions to everyday things &#8212; just part of the lifestyle I guess!</p>

<p><strong>How do you find the Xcode IDE?</strong></p>

<p>What can I say? I feel right at home in Xcode, and I can&#8217;t imagine developing anywhere else. Apple&#8217;s done a great job with Xcode, but if I were to change one aspect, it&#8217;d be a few of it&#8217;s UI concepts. Then again, many of those (collapsable code. Xray) seem to be addressed in Xcode 3.0, so I can&#8217;t complain.</p>

<p><strong>What are you looking forward to most in Leopard and why?</strong></p>

<p>As you might expect, I&#8217;m most excited about Xcode 3 and IB. Obviously that&#8217;s because a large majority of my time is spent in there! Also, the addition of Core Animation opens us (developers) up to many new opportunities, and I can&#8217;t wait to see where others (and myself) will take that into their apps. I&#8217;m all about creating rich user experiences, and Core Animation is definitely going to help.</p>

<p><strong>Anything else?</strong></p>

<p>Aside from development additions in 10.5, I&#8217;m most excited about time-machine. I use subversion internally for keeping a running source-record of each progressive build of Flow, but it&#8217;s nice to know that in the event that I need it, time-machine can act as a &#8220;backup to my backup&#8221;.</p>

<p><strong>How different is Objective-C to other programming languages that you&#8217;ve encountered? Do you like working with object-oriented languages or do you not worry about the technical aspects of the various languages?</strong></p>

<p>I guess the best way to describe Objective-C is that it&#8217;s very very well-thought out. I love Cocoa, and have immense respect for those responsible for it at Apple; they&#8217;ve created a plethora of technologies which let me spend time developing new features rather than just getting things to work.  While I tend not to look at the technical aspects of the languages (writing great code is very important, but in the end it needs to build a better product), I do prefer working with object-oriented languages.</p>

<p><strong>You say you&#8217;ve worked a lot on little personal projects in various languages. When did you decide you were proficient enough to tackle writing public application, or did you just decide to tackle it and worry about the details later?</strong></p>

<p>I&#8217;m not sure the issue was ever whether or not I was proficient enough to tackle a public-app, but whether or not the app could serve a larger audience than just myself. When I think back, there really wasn&#8217;t ever a question in my mind for Flow &#8212; knowing that the public could benefit from it just as much as I could, I don&#8217;t believe I even thought twice about keeping it private or not.</p>

<p><strong>Writing your first public application must be a good lesson in itself. What&#8217;s one of the things you&#8217;ve found out by undertaking this project?</strong></p>

<p>Writing software is less about programming and technology than it is about people. It&#8217;s surprising to me how many people still fail to realize it, but regardless of how technically challenging your app is, you&#8217;re writing for people, and they&#8217;ve got to be your focus. In the end, an app with less features that&#8217;s more enjoyable to use is always more valuable than it&#8217;s competition.</p>

<p><strong>You obviously decided to write Flow when you found (like a lot of others before you) that something needed to be fixed in the FTP department on the Mac platform. Using an external text editor with an existing FTP client is one that you found needs improvement. Are there any other issues you&#8217;re trying to address with Flow?</strong></p>

<p>Two words. User Experience. FTP clients don&#8217;t feel right today. Many people aren&#8217;t comfortable with them. That just blows me away &#8212; how has this been ignored? I whiteboard my ideas, workflows, and designs quite often, and in the upper right corner, it always says &#8220;Make it feel beautiful.&#8221; It&#8217;s just a core value to me. An app that doesn&#8217;t feel great isn&#8217;t one worth using, regardless of what it does.</p>

<p>In continuation of the previous question, I&#8217;ve spent a lot of time learning what feels natural, and maintaining user-comfort is always my topmost goal.</p>

<p><strong>You obviously planned the application meticulously before you started developing it. How has Flow evolved and changed during its development?</strong></p>

<p>Flow has changed dramatically since the original planning &#8212; but mostly in technical aspects. I&#8217;ve kept consistent with a large majority of the design and feature concepts because something that feels right 6 months ago still feels right today. So in a way, I&#8217;m tackling the same problems, but how I do so programatically is always flexible.</p>

<p><strong>You say Flow is more of a connection client than an FTP client, as it handles a number of protocols. How do you decide which features are worth keeping and which ones would be bloat?</strong></p>

<p>I&#8217;m so glad you asked this question. The ideology behind this is pretty much the same as that behind preventing piracy. I won&#8217;t spend massive amounts of time preventing piracy because that&#8217;s time that should be spent evolving the app for paying customers. In that way, the moment a feature becomes detrimental to the core features, it&#8217;s bloat and should be removed.</p>

<p><strong>Am I correct in thinking Flow does not use Apple&#8217;s FTP framework? Could you elaborate on why you chose to go with Connection Kit instead?</strong></p>

<p>Yep! I chose to go with the Connection Kit for a few reasons. First, I think those in charge of it are doing a terrific job with it. It&#8217;s powerful, robust, efficient, and clean. Equally important, however, is that I get the chance to work really closely with its developers (Greg Hulands, who I can&#8217;t thank enough for all his hard work), which ensures beautiful integration with Flow. There&#8217;s no way I could get that type of relationship with the Apple FTP framework, and as a result it would be foolish of me to pass up on it with CK.</p>

<p><strong>Eye candy and GUI has been a very controversial topic in the Macintosh community in recent months. From a usability point of view, what is your stance on interface customizations? How much time do you spend designing and writing the interface in comparison with the bulk of the application?</strong></p>

<p>Another great question. A while back when I was messing around with some phrases for Flow, I hit on &#8220;Sizzle, meet Steak.&#8221; I think that&#8217;s the very core of my perspective in this case. As I&#8217;m sure you&#8217;ve noticed, I absolutely support making applications beautiful and fun to use &#8212; but there are limits. Compromising the consistency of Mac OS X applications is dangerous water as Apple has worked very hard to maintain consistency in the past. At the same time, Apple is almost always the first to introduce new UI elements &#8212; so where&#8217;s the balance?</p>

<p>In my opinion, the HIG (Human Interface Guidelines) is dead. So if I were to choose a new golden rule, it&#8217;d succinctly state: &#8220;Make your applications look beautiful, compliment existing elements of OS X, and act even more intuitively.&#8221;</p>

<p><strong>Where did you get your inspiration for the Flow interface, or did you design it from scratch?</strong></p>

<p>Flow&#8217;s interface is very complimentary of the Mac OS and it&#8217;s applications. In some aspects, Flow&#8217;s interface was designed from scratch and yet if you look at it now, it&#8217;s friendly and recognizable. To me, this says that Apple and others got it right &#8212; and that&#8217;s a terrific thing.</p>

<p><strong>Do you have any plans or ideas for development after Flow?</strong></p>

<p>Absolutely. We&#8217;ll see where they take me <img src='http://lipidity.com/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>

<p><strong>Any tips for budding developers?</strong></p>

<p>Consistently remind yourself to think of your application in terms of a solution. Every feature, behavior, and action should be focused on that solution, and those that aren&#8217;t should be left out. Remember that applications are for people, and they should be engineered as such.</p>

<p><strong>Brian Amerige, thanks again. Best wishes for your future development and endeavours. May the Force be with you ;).</strong></p>

<p>Haha. It was my pleasure! Cheers!</p>
]]></content:encoded>
			<wfw:commentRss>http://lipidity.com/apple/brian-amerige-on-mac-development-and-flow/feed/</wfw:commentRss>
		</item>
		<item>
		<title>iClip 4 finally released</title>
		<link>http://lipidity.com/news/iclip-4-finally-released/</link>
		<comments>http://lipidity.com/news/iclip-4-finally-released/#comments</comments>
		<pubDate>Thu, 01 Feb 2007 05:53:43 +0000</pubDate>
		<dc:creator>Ankur</dc:creator>
		
		<category><![CDATA[News]]></category>

		<category><![CDATA[Apple]]></category>

		<category><![CDATA[Application]]></category>

		<category><![CDATA[Mac]]></category>

		<category><![CDATA[Review]]></category>

		<guid isPermaLink="false">http://dev.lipidity.com/apple/iclip-4-finally-released</guid>
		<description><![CDATA[The long awaited iClip 4 has been released and looks to be a great improvement over version 3. The GUI is extremely enhanced, and it &#8220;just works&#8221;. The animation effects are also the smoothest I&#8217;ve seen anywhere (I wonder if it&#8217;s Core Graphics?).

I&#8217;ll still be using Quicksilver&#8217;s Clipboard History (you know how much I love [...]]]></description>
			<content:encoded><![CDATA[<p>The long awaited iClip 4 has been released and looks to be a great improvement over version 3. The GUI is extremely enhanced, and it &#8220;just works&#8221;. The animation effects are also the smoothest I&#8217;ve seen anywhere (I wonder if it&#8217;s <a href="http://dev.lipidity.com/feature/tutorial/xcode-transitions-core-graphics-image-2">Core Graphics</a>?).</p>

<p>I&#8217;ll still be using Quicksilver&#8217;s Clipboard History (you know how much I love Quicksilver), but this iClip really takes things to a new level in ease of use and appearance. I can talk about it, but it&#8217;s probably better if you see it for yourself. <a href="http://inventive.us/iClip" rel="external">Check it out</a>.</p>

<p><a href="http://inventive.us/iClip/" class="imagelink"><img src="http://inventive.us/media/product/iClip/features/drag_and_drop.png" alt="iClip 4 screenshot" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://lipidity.com/news/iclip-4-finally-released/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Strange error</title>
		<link>http://lipidity.com/apple/strange-error/</link>
		<comments>http://lipidity.com/apple/strange-error/#comments</comments>
		<pubDate>Tue, 30 Jan 2007 07:29:10 +0000</pubDate>
		<dc:creator>Ankur</dc:creator>
		
		<category><![CDATA[Apple]]></category>

		<category><![CDATA[Mac]]></category>

		<category><![CDATA[Review]]></category>

		<guid isPermaLink="false">http://dev.lipidity.com/apple/strange-error</guid>
		<description><![CDATA[Oops! What happened here?



Just goes to show what one little mistake in your code, or an unforeseen circumstance can do to your code. The file was only a few megabytes.

Remember kids, test your apps in every possible way, and then some. And encourage feedback.

Now, any ideas on what I can do for the next 230,000 [...]]]></description>
			<content:encoded><![CDATA[<p>Oops! What happened here?</p>

<p><img src="http://dev.lipidity.com/wp-content/uploads/2007/01/please-wait.png" alt="Please wait. Archiving…" /></p>

<p>Just goes to show what one little mistake in your code, or an unforeseen circumstance can do to your code. The file was only a few megabytes.</p>

<p>Remember kids, test your apps in every possible way, and then some. And encourage feedback.</p>

<p>Now, any ideas on what I can do for the next 230,000 years?</p>
]]></content:encoded>
			<wfw:commentRss>http://lipidity.com/apple/strange-error/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
