<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>&#60;&#60; shiftedbits</title>
	<atom:link href="http://shiftedbits.org/feed/" rel="self" type="application/rss+xml" />
	<link>http://shiftedbits.org</link>
	<description>Bits were made to be shifted</description>
	<pubDate>Wed, 03 Sep 2008 05:38:09 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.1</generator>
	<language>en</language>
			<item>
		<title>Key Value Observing Improvements v1.2</title>
		<link>http://shiftedbits.org/2008/09/03/key-value-observing-improvements-v12/</link>
		<comments>http://shiftedbits.org/2008/09/03/key-value-observing-improvements-v12/#comments</comments>
		<pubDate>Wed, 03 Sep 2008 05:35:57 +0000</pubDate>
		<dc:creator>Devin Lane</dc:creator>
		
		<category><![CDATA[Leopard]]></category>

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

		<guid isPermaLink="false">http://shiftedbits.org/?p=46</guid>
		<description><![CDATA[Hot on the heels of the 1.1 bug fix release comes version a freshly rewritten 1.2 with API cleanup, bug fixes, and a great new feature.
Lately, I&#8217;ve been using observers to allow an object to observe changes to its own properties. This means I don&#8217;t have to override the setter method (I&#8217;m using synthesized properties) [...]]]></description>
			<content:encoded><![CDATA[<p>Hot on the heels of the 1.1 bug fix release comes version a freshly rewritten 1.2 with API cleanup, bug fixes, and a great new feature.</p>
<p>Lately, I&#8217;ve been using observers to allow an object to observe changes to its own properties. This means I don&#8217;t have to override the setter method (I&#8217;m using synthesized properties) and the observation is managed the same way that it would be externally. The current KVO implementation (at least, in non-GC land,) however, doesn&#8217;t allow you to remove observations from yourself in your -dealloc method. This is due to the way KVO works, by interposing a KVODeallocate function before your -dealloc method. It expects that all observers of the object have been removed at this point, and warns if they are not. This is, of course, blindingly annoying &#8212; you now have to create a method that gets called on your objects by their owner before they dealloc so that they can remove their observers.</p>
<p>To fix this, I&#8217;ve done a little interposing of my own, putting in another dealloc method before KVODealloc that will remove self observers and call a -KVODealloc method on the deallocating observer object before KVODeallocate is called. If you don&#8217;t want automatic removal, simply return NO from +automaticallyRemoveSelfObservations on the class of your choice.</p>
<p>The new updates are in SVN at <code>http://svn.shiftedbits.org/public/KVOAdditions/trunk</code> and tagged at <code>http://svn.shiftedbits.org/public/KVOAdditions/tags/1.2</code><br />
<span id="more-46"></span><br />
Version 1.2 also adds new methods for removing an observer that include a selector parameter.</p>
<p><code>NSObject:</code></p>
<pre>- (void)removeObserver:(NSObject *)observer
            forKeyPath:(NSString *)keyPath
              selector:(SEL)selector;
</pre>
<p><code>NSArray:</code></p>
<pre>- (void)removeObserver:(NSObject *)observer
  fromObjectsAtIndexes:(NSIndexSet *)indexes
            forKeyPath:(NSString *)keyPath
              selector:(SEL)selector;
</pre>
<p>The selector is now considered a unique part of the observation, and so a class can observe a single property on a single object using multiple selectors. This allows a class and its subclass to avoid collisions when observing a single object.</p>
<p>The <code>-removeObserver:forKeyPath:</code> method now no longer removes selector-based observers.</p>
]]></content:encoded>
			<wfw:commentRss>http://shiftedbits.org/2008/09/03/key-value-observing-improvements-v12/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Key Value Observing Improvements</title>
		<link>http://shiftedbits.org/2008/07/24/key-value-observing-improvements/</link>
		<comments>http://shiftedbits.org/2008/07/24/key-value-observing-improvements/#comments</comments>
		<pubDate>Thu, 24 Jul 2008 08:26:28 +0000</pubDate>
		<dc:creator>Devin Lane</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://shiftedbits.org/?p=23</guid>
		<description><![CDATA[Key value observing is quite a useful tool, no doubt about it. But it has a singularly annoying manner of informing the observer of a change. The -[NSObject observeValueForKeyPath:ofObject:change:context:] method is sent to the observer when a change occurs. It&#8217;s up to the implementor to parse the `change&#8217; dictionary to figure out what changed.
When I [...]]]></description>
			<content:encoded><![CDATA[<p>Key value observing is quite a useful tool, no doubt about it. But it has a singularly annoying manner of informing the observer of a change. The <code>-[NSObject observeValueForKeyPath:ofObject:change:context:]</code> method is sent to the observer when a change occurs. It&#8217;s up to the implementor to parse the `change&#8217; dictionary to figure out what changed.</p>
<p>When I use observers, I usually want a method called on my class when a change occurs, similar to target/action with UI elements. So my <code>-[NSObject observeValueForKeyPath:ofObject:change:context:]</code> is basically a set of if&#8217;s for each key I&#8217;m observing that calls the appropriate method.</p>
<p>This turns out to be pretty nasty, especially when you have multiple classes in a hierarchy implementing the method. It wasn&#8217;t obvious to me that I needed to call super in this method. Thirty minutes of debugging later, and I was convinced there had to be a better way of doing it.</p>
<p>To this effort, I present two new APIs. To NSObject, I add <code>-[NSObject addObserver:forKeyPath:options:selector:]</code> and to NSArray, <code>-[NSArray addObserver:toObjectsAtIndexes:forKeyPath:options:selector]</code>. The code is <a href="/static/KVOAdditions.zip">available here</a>, or keep reading for the details.</p>
<p><strong>Update 1.1: Two critical bug fixes</strong>. Please update to the new version if you have the old one. Also, anonymous svn is now available if you want to use an external. http://svn.shiftedbits.org/public/KVOAdditions/trunk.<span id="more-23"></span></p>
<p><code>NSObject:</code></p>
<pre>@interface NSObject (KVOAdditions)

- (void)addObserver:(NSObject *)observer
         forKeyPath:(NSString *)keyPath
            options:(NSKeyValueObservingOptions)options
           selector:(SEL)aSelector;

@end
</pre>
<p><code>NSArray:</code></p>
<pre>@interface NSArray (KVOAdditions)

- (void)addObserver:(NSObject *)observer
 toObjectsAtIndexes:(NSIndexSet *)indexes
         forKeyPath:(NSString *)keyPath
            options:(NSKeyValueObservingOptions)options
           selector:(SEL)aSelector;

@end
</pre>
<p>These allow you to observe a keyPath on an object and receive a message to the designated selector when the change occurs. Furthermore, the selector can have four different signatures that allow for different levels of information to be received. These selector formats are as follows:</p>
<pre>/* Receive no information about the change */
- (void)valueDidChange;

/* Receive the raw change dictionary */
- (void)valueDidChange:(NSDictionary *)change;

/* If the observing options include either
 * NSKeyValueObservingOptionOld or NSKeyValueObservingOptionNew,
 * receive the old and new values */
- (void)valueDidChange:(id)old newValue:(id)new;

/* If the observing options include either
 * NSKeyValueObservingOptionOld or NSKeyValueObservingOptionNew,
 * receive the old and new values */
- (void)valueDidChange:(id)old newValue:(id)new prior:(BOOL)isPrior;
</pre>
<p>Feedback on these APIs, including suggestions and criticism (and even bugs!) are of course welcome. </p>
]]></content:encoded>
			<wfw:commentRss>http://shiftedbits.org/2008/07/24/key-value-observing-improvements/feed/</wfw:commentRss>
		</item>
		<item>
		<title>SSE Optimized Compositing</title>
		<link>http://shiftedbits.org/2008/01/29/sse-optimized-compositing/</link>
		<comments>http://shiftedbits.org/2008/01/29/sse-optimized-compositing/#comments</comments>
		<pubDate>Tue, 29 Jan 2008 06:08:46 +0000</pubDate>
		<dc:creator>Devin Lane</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://shiftedbits.org/2008/01/29/sse-optimized-compositing/</guid>
		<description><![CDATA[As part of a graphics API I&#8217;ve been working on (for my own use, it&#8217;s hardly ready for production,) I decided to try learning SSE optimization by making the compositing routine faster.
I came up with an implementation which, according to my tests, is 3-5X faster than the non-optimized version. The optimized version below composites a [...]]]></description>
			<content:encoded><![CDATA[<p>As part of a graphics API I&#8217;ve been working on (for my own use, it&#8217;s hardly ready for production,) I decided to try learning SSE optimization by making the compositing routine faster.</p>
<p>I came up with an implementation which, according to my tests, is 3-5X faster than the non-optimized version. The optimized version below composites a single color starting at a destination pixel buffer for a specified run of pixels. It uses source over compositing on a RGBA, 8bpc, integer pixel buffer.</p>
<p>The optimized version is presented below:</p>
<p><span id="more-14"></span></p>
<pre>
static __m128i zero =
        _mm_set_epi32(0x0, 0x0, 0x0, 0x0);
static __m128i one =
        _mm_set_epi32(0x00010001U, 0x00010001U, 0x00010001U, 0x00010001U);
static __m128i mask1 =
        _mm_set_epi32(0x00FF00FFU, 0x00FF00FFU, 0x00FF00FFU, 0x00FF00FFU);
static __m128i mask2 =
        _mm_set_epi32(0xFF00FF00U, 0xFF00FF00U, 0xFF00FF00U, 0xFF00FF00U);

if (_comp[3] == 255) {
    /* We're compositing a fully opaque pixel, just copy onto the destination */

    unsigned int *dst = (unsigned int *)_dst;

    /* The pixel offset from dst */
    size_t i = 0;

    /* The number of quad-pixels processed */
    size_t j = 0;

    /* Leading 0..3 pixels */
    while (((intptr_t)(dst+i) &#038; (intptr_t)0xF) != 0) {
        *(dst + i) = *(unsigned int *)_comp;
        i++; run--;
    }

    /* Start at the pixel i */
    __m128i *mdst = (__m128i *)(dst + i);

    /* Set 4 pixel chunks */
    for (j = 0; j < (run>>2); j++) {
        _mm_prefetch(mdst+1, _MM_HINT_T0);
        _mm_store_si128(mdst++, _src);
    }

    /* If we couldn't get all of the run in 4 pixel chunks, get them now */
    for (size_t k = 0; k < run % 4; k++) {
        *(dst + i + k + (j<&lt;2)) = *(unsigned int *)_comp;
    }
} else {
    /* We need full composition as this pixel has transparency */

    unsigned char *dst = (unsigned char *)_dst;

    /* char offset from dst */
    size_t i = 0;

    /* Quad-pixels processed */
    size_t j = 0;

    /* get the non-aligned starting 0..3 pixels */
    while (((intptr_t)(dst+i) &#038; (intptr_t)0xF) != 0) {
        dst[0+i] = _comp[0] + dst[0+i] -
            (dst[0+i] > 0? ((((unsigned short)dst[0+i] * _comp[3]) >> 8) + 1) : 0); //R
        dst[1+i] = _comp[1] + dst[1+i] -
            (dst[1+i] > 0? ((((unsigned short)dst[1+i] * _comp[3]) >> 8) + 1) : 0); //G
        dst[2+i] = _comp[2] + dst[2+i] -
            (dst[2+i] > 0? ((((unsigned short)dst[2+i] * _comp[3]) >> 8) + 1) : 0); //B
        dst[3+i] = _comp[3] + dst[3+i] -
            (dst[3+i] > 0? ((((unsigned short)dst[3+i] * _comp[3]) >> 8) + 1) : 0); //A
        i += 4; run--;
    }

    /* Load in 2 pixels */
    __m128i *mdst = (__m128i *)(dst+i);
    __m128i d, d1, d2, res;
    for (j; j < (run>>2); j++) {
        /* Load 4 pixels */
        d = _mm_load_si128(mdst);

        /* Take chars 0,2,4,6,8,10,12,14 and composite */
        d1 = _mm_and_si128(d, mask1);
        d1 = _mm_add_epi16(_mm_subs_epi16(d1, _mm_add_epi16(
                    _mm_srli_epi16(_mm_mullo_epi16(d1, _c3), 8),
                    _mm_and_si128(_mm_cmpgt_epi16(d1, zero), one))), _ce);

        /* Take chars 1,3,5,7,9,11,13,15 and composite */
        d2 = _mm_srli_epi16(_mm_and_si128(d, mask2), 8);

        /* prefetch the next 4 pixels */
        _mm_prefetch(mdst+1, _MM_HINT_T0);

        d2 = _mm_add_epi16(_mm_subs_epi16(d2, _mm_add_epi16(
                    _mm_srli_epi16(_mm_mullo_epi16(d2, _c3), 8),
                    _mm_and_si128(_mm_cmpgt_epi16(d2, zero), one))), _co);

        /* shift odd chars (d2) to high 8 bits and or with d1 */
        res = _mm_or_si128(d1, _mm_slli_epi16(d2, 8));

        /* Store 4 pixels */
        _mm_store_si128(mdst, res);

        mdst++;
    }

    // Get the trailing 0..3 pixels
    dst += i + (j< &lt;4);
    for (size_t k = 0; k < (run % 4) * 4; k+=4) {
        dst[0+k] = _comp[0] + dst[0+k] -
            (dst[0+k] > 0? ((((unsigned short)dst[0+k] * _comp[3]) >> 8) + 1) : 0); //R
        dst[1+k] = _comp[1] + dst[1+k] -
            (dst[1+k] > 0? ((((unsigned short)dst[1+k] * _comp[3]) >> 8) + 1) : 0); //G
        dst[2+k] = _comp[2] + dst[2+k] -
            (dst[2+k] > 0? ((((unsigned short)dst[2+k] * _comp[3]) >> 8) + 1) : 0); //B
        dst[3+k] = _comp[3] + dst[3+k] -
            (dst[3+k] > 0? ((((unsigned short)dst[3+k] * _comp[3]) >> 8) + 1) : 0); //A
    }
}
</pre>
<p>_c3 is a vector composed solely of the alpha value of the color.<br />
_ce is a vector composed of pairs of the red and blue components.<br />
_co is a vector composed of pairs of the green and alpha components.<br />
_src is the start address of the pixel buffer.</p>
<p>_c3, _ce, _co, and _src are set from the following function:</p>
<pre>
unsigned short r = _comp[0], g = _comp[1], b = _comp[2], a = _comp[3];
_c3 = _mm_setr_epi16(a, a, a, a, a, a, a, a);
_ce = _mm_setr_epi16(r, b, r, b, r, b, r, b);
_co = _mm_setr_epi16(g, a, g, a, g, a, g, a);

_src = _mm_set_epi32(*(int*)_comp, *(int*)_comp, *(int*)_comp, *(int*)_comp);
</pre>
]]></content:encoded>
			<wfw:commentRss>http://shiftedbits.org/2008/01/29/sse-optimized-compositing/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Transparency Layer Slowdowns</title>
		<link>http://shiftedbits.org/2008/01/22/transparency-layer-slowdowns/</link>
		<comments>http://shiftedbits.org/2008/01/22/transparency-layer-slowdowns/#comments</comments>
		<pubDate>Tue, 22 Jan 2008 19:38:00 +0000</pubDate>
		<dc:creator>Devin Lane</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://shiftedbits.org/2008/01/22/transparency-layer-slowdowns/</guid>
		<description><![CDATA[As the documentation mentions, a transparency layer allows subsequent drawing to be rendered in a separate, fully transparent buffer before being composited to the destination context. In the absence of a clipping region, this buffer is the same size as the destination context, requiring a context-sized buffer regardless of the actual drawing bounds. Creating a [...]]]></description>
			<content:encoded><![CDATA[<p>As the documentation mentions, a transparency layer allows subsequent drawing to be rendered in a separate, fully transparent buffer before being composited to the destination context. In the absence of a clipping region, this buffer is the same size as the destination context, requiring a context-sized buffer regardless of the actual drawing bounds. Creating a transparency layer for a small section of content, then drawing this layer in a window, for example, results in a window-sized buffer for the layer. When the layer is composited into the destination, the entire buffer must be composited &#8212; CoreGraphics doesn&#8217;t keep track of where the actual drawing is.</p>
<p>This, of course, is slow, especially for several transparency layers.</p>
<p>To help speed things up, clip the context to the bounds of any drawing in a transparency layer before beginning the transparency layer, such as below:</p>
<pre>CGRect artRect = CGRectMake(50,50,100,50);
CGContextClipToRect(context, artRect);

CGContextBeginTransparencyLayer(context, NULL);

/* Draw layer content here */

CGContextEndTransparencyLayer(context);
</pre>
<p>I&#8217;ve created a <a href="/static/transparency_layer.zip">demonstration program</a> to illustrate the effects of clipped vs. unclipped transparency layers. To see the effects, open Quartz Debug (/Developer/Applications/Graphics Tools/Quartz Debug.app) and turn on &#8220;Flash screen updates.&#8221; Then, open the Transparency Layer program. There are two windows, the left showing the drawing without clipping and the right clipping to the approximate art bounds. The views are redrawing four times per second. Notice that the unclipped view redraws its entire content while the clipped view redraws only the actual art.</p>
<p>Finally, using <code>-[NSView setNeedsDisplayInRect:]</code> clips the drawing to the specified rect.</p>
]]></content:encoded>
			<wfw:commentRss>http://shiftedbits.org/2008/01/22/transparency-layer-slowdowns/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Leopard CGWindowList* APIs</title>
		<link>http://shiftedbits.org/2007/11/08/leopard-cgwindowlist-apis/</link>
		<comments>http://shiftedbits.org/2007/11/08/leopard-cgwindowlist-apis/#comments</comments>
		<pubDate>Thu, 08 Nov 2007 05:07:39 +0000</pubDate>
		<dc:creator>Devin Lane</dc:creator>
		
		<category><![CDATA[Leopard]]></category>

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

		<guid isPermaLink="false">http://shiftedbits.org/2007/11/08/leopard-cgwindowlist-apis/</guid>
		<description><![CDATA[Leopard brings new APIs at the CoreGraphics layer to gather information about windows on the system. These functions let you find windows relative to a known window, find all windows on the system, including those offscreen, and obtain images of one or more windows as composited by the Window Server.
However, these API&#8217;s have an interesting [...]]]></description>
			<content:encoded><![CDATA[<p>Leopard brings new APIs at the CoreGraphics layer to gather information about windows on the system. These functions let you find windows relative to a known window, find all windows on the system, including those offscreen, and obtain images of one or more windows as composited by the Window Server.</p>
<p>However, these API&#8217;s have an interesting peculiarity: when the documentation says &#8220;a CFArray of CGWindowID values&#8221; they mean a CFArray of uint32s, not CFNumbers as programmers familiar with CoreFoundation might expect. This holds true for the <code>CGWindowListCreate()</code>, <code>CGWindowListCreateDescriptionFromArray()</code>, and <code>CGWindowListCreateImageFromArray</code> functions, but the two functions that return window information (<code>CGWindowListCopyWindowInfo()</code> and <code>CGWindowListCreateDescriptionFromArray()</code>) wrap all numeric values in CFNumbers.</p>
<p>To create such an array, you&#8217;ll have to create it with CFArrayCreateMutable(), such as the following:</p>
<pre>/* Make an array with no callbacks */
CFMutableArrayRef windows = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);

/* myWindow is a NSWindow */
CFArrayAppendValue(windows, (void *)[myWindow windowNumber]);
</pre>
<p>To get the <code>CGWindowID</code> of a <code>NSWindow</code>, you&#8217;ll want to use <code>-[NSWindow windowNumber]</code>. Even though the documentation specifies that this isn&#8217;t the same number as assigned by the WindowServer, it turns out that it works fine with the CGWindow* APIs.</p>
]]></content:encoded>
			<wfw:commentRss>http://shiftedbits.org/2007/11/08/leopard-cgwindowlist-apis/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Time Machine Menu</title>
		<link>http://shiftedbits.org/2007/11/01/time-machine-menu/</link>
		<comments>http://shiftedbits.org/2007/11/01/time-machine-menu/#comments</comments>
		<pubDate>Thu, 01 Nov 2007 02:36:51 +0000</pubDate>
		<dc:creator>Devin Lane</dc:creator>
		
		<category><![CDATA[Leopard]]></category>

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

		<guid isPermaLink="false">http://shiftedbits.org/2007/11/01/time-machine-menu/</guid>
		<description><![CDATA[The Time Machine application, when in the dock, enables access to functions for showing Time Machine, backing up now, stopping an existing backup, browsing other Time Machine disks and showing Time Machine preferences. If you&#8217;re like me, you&#8217;d like access to these features without the app in the dock; unfortunately, you can&#8217;t &#8212; by default.
I&#8217;ve [...]]]></description>
			<content:encoded><![CDATA[<p>The Time Machine application, when in the dock, enables access to functions for showing Time Machine, backing up now, stopping an existing backup, browsing other Time Machine disks and showing Time Machine preferences. If you&#8217;re like me, you&#8217;d like access to these features without the app in the dock; unfortunately, you can&#8217;t &#8212; by default.</p>
<p>I&#8217;ve done a bit of digging and was able to implement all but one of these features in a menu extra. Download it and the source <a href="/static/Time%20Machine%20Menu.zip">here</a>.</p>
<p>And yes, the menu icon doesn&#8217;t scale nicely :)</p>
]]></content:encoded>
			<wfw:commentRss>http://shiftedbits.org/2007/11/01/time-machine-menu/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Time Machine Exclusions</title>
		<link>http://shiftedbits.org/2007/10/31/time-machine-exclusions/</link>
		<comments>http://shiftedbits.org/2007/10/31/time-machine-exclusions/#comments</comments>
		<pubDate>Wed, 31 Oct 2007 07:08:12 +0000</pubDate>
		<dc:creator>Devin Lane</dc:creator>
		
		<category><![CDATA[Leopard]]></category>

		<guid isPermaLink="false">http://shiftedbits.org/2007/10/31/time-machine-exclusions/</guid>
		<description><![CDATA[So Time Machine is a pretty convenient way to backup your machine, and I use it to backup my laptop to an external FireWire drive. Although Time Machine backs up the &#8220;whole system,&#8221; I assumed there had to be some exclusions, such as cache files or /dev, for example. After a short bit of digging, [...]]]></description>
			<content:encoded><![CDATA[<p>So Time Machine is a pretty convenient way to backup your machine, and I use it to backup my laptop to an external FireWire drive. Although Time Machine backs up the &#8220;whole system,&#8221; I assumed there had to be some exclusions, such as cache files or /dev, for example. After a short bit of digging, I discovered that these paths are specified in a standard property list at <code>/System/Library/CoreServices/backupd.bundle/Contents/Resources/StdExclusions.plist</code></p>
<p>The full list is some 57 items, and is available below. Besides the expected cache items, the list includes some items I thought interesting:</p>
<pre>
/home
*/Library/Logs
/Users/Guest
/Library/Safari/Icons.db
/.Spotlight-V100
</pre>
<p>Of these, the only one I find odd is the exclusion of logs. If your system goes haywire such that you restore it completely from a backup, it might be nice to see what went wrong.</p>
<p>[Update] Fixed the path to the StdExclusions.plist file.</p>
<p><span id="more-11"></span>Here&#8217;s the full list of the excluded paths:</p>
<h4>Contents Excluded</h4>
<p>The contents of these paths are excluded, but the directories themselves are preserved as they are required for a successful restore.</p>
<pre>
/Volumes
/Network
/automount
/.vol
/tmp
/cores
/private/tmp
/private/Network
/private/tftpboot
/private/var/automount
/private/var/log
/private/var/folders
/private/var/log/apache2
/private/var/log/cups
/private/var/log/fax
/private/var/log/ppp
/private/var/log/sa
/private/var/log/samba
/private/var/log/uucp
/private/var/run
/private/var/spool
/private/var/tmp
/private/var/vm
/private/var/db/dhcpclient
/private/var/db/fseventsd
/Library/Caches
/Library/Logs
/System/Library/Caches
/System/Library/Extensions/Caches
</pre>
<h4>Paths Excluded</h4>
<p>These directories and their contents are excluded completely.</p>
<pre>
/.Spotlight-V100
/.Trashes
/.fseventsd
/.hotfiles.btree
/Backups.backupdb
/Desktop DB
/Desktop DF
/Network/Servers
/Previous Systems
/Users/Shared/SC Info
/Users/Guest
/dev
/home
/net
/private/var/db/Spotlight
/private/var/db/Spotlight-V100
</pre>
<h4>User Paths Excluded</h4>
<p>These directories are and their contents are excluded per-user. The path is relative to the user&#8217;s home folder.</p>
<pre>Library/Application Support/MobileSync
Library/Application Support/SyncServices
Library/Caches
Library/Logs
Library/Mail/Envelope Index
Library/Mail/AvailableFeeds
Library/Mirrors
Library/PubSub/Database
Library/PubSub/Downloads
Library/PubSub/Feeds
Library/Safari/Icons.db
Library/Safari/HistoryIndex.sk
</pre>
]]></content:encoded>
			<wfw:commentRss>http://shiftedbits.org/2007/10/31/time-machine-exclusions/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Quicksilver Plugins</title>
		<link>http://shiftedbits.org/2007/10/28/quicksilver-plugins/</link>
		<comments>http://shiftedbits.org/2007/10/28/quicksilver-plugins/#comments</comments>
		<pubDate>Sun, 28 Oct 2007 20:38:17 +0000</pubDate>
		<dc:creator>Devin Lane</dc:creator>
		
		<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://shiftedbits.org/2007/10/28/quicksilver-plugins/</guid>
		<description><![CDATA[As the Quicksilver site seems to be down right as everyone is reinstalling for Leopard, I&#8217;ve packaged the plugins I have into a zip available here. Quicksilver itself is available here. To install, just put the PlugIns folder in your Library/Application Support/Quicksilver folder or double click the plugins.
[Update] Zon Wakest was nice enough to upload [...]]]></description>
			<content:encoded><![CDATA[<p>As the Quicksilver site seems to be down right as everyone is reinstalling for Leopard, I&#8217;ve packaged the plugins I have into a zip available <a href="/static/qsplugins.zip">here</a>. Quicksilver itself is available <a href="http://blacktree.meadgroup.com/quicksilver/application/QS.3814.dmg">here</a>. To install, just put the PlugIns folder in your Library/Application Support/Quicksilver folder or double click the plugins.</p>
<p>[Update] Zon Wakest was nice enough to upload additional plugins. Thanks Zon! These are now added into my archive and the combined list is below. If you got the old archive, download <a href="/static/qsplugins2.zip">just the additional plugins</a>.</p>
<p>[Update2] Quicksilver now links to 3814 instead of 3813.</p>
<p>The plugins included are as follows:</p>
<p><span id="more-10"></span></p>
<p class="code"><code>Adium Module.qsplugin<br />
Airport Module.qsplugin<br />
Apple Address Book Module.qsplugin<br />
Apple Mail Module.qsplugin<br />
Automator Module.qsplugin<br />
Bezel Interface.qsplugin<br />
Calculator Module.qsplugin<br />
Camino Module.qsplugin<br />
Chat Support.qsplugin<br />
Clipboard Module.qsplugin<br />
Command Line Tool.qsplugin<br />
Cube Interface.qsplugin<br />
Desktop Picture Action.qsplugin<br />
Developer Module.qsplugin<br />
Deviant Module.qsplugin<br />
Dictionary Module.qsplugin<br />
Download Actions.qsplugin<br />
Email Support.qsplugin<br />
Extra Scripts.qsplugin<br />
File Attribute Actions.qsplugin<br />
File Compression Module.qsplugin<br />
File Tagging Module.qsplugin<br />
Finder Module.qsplugin<br />
Firefox Module.qsplugin<br />
Flashlight Interface.qsplugin<br />
Flickr Upload.qsplugin<br />
Gmail Module.qsplugin<br />
Google Calendar Module.qsplugin<br />
Growl Module.qsplugin<br />
HotKey Triggers.qsplugin<br />
Keychain Module.qsplugin<br />
Menu Interface.qsplugin<br />
Mini Interface.qsplugin<br />
Music Support.qsplugin<br />
NotificationHub.qsplugin<br />
Primer Interface.qsplugin<br />
Process Manipulation Actions.qsplugin<br />
QSFumoInterface.qsplugin<br />
SSH Plugin.qsplugin<br />
Safari Module.qsplugin<br />
SafariStand Queries.qsplugin<br />
Services Menu Module.qsplugin<br />
Shelf Module.qsplugin<br />
Slideshow Action.qsplugin<br />
Social Bookmarks.qsplugin<br />
Spotlight Module.qsplugin<br />
Tatau Module.qsplugin<br />
Terminal Module.qsplugin<br />
Text Manipulation Actions.qsplugin<br />
TextMate Ranker.qsplugin<br />
Todoist Module.qsplugin<br />
Transmit Module.qsplugin<br />
UI Access.qsplugin<br />
Web Search Module.qsplugin<br />
Window Interface.qsplugin<br />
iCal Module.qsplugin<br />
iChat Module.qsplugin<br />
iPhoto Module.qsplugin<br />
iTunes Module.qsplugin<br />
</code></p>
<p>If you have other plugins that I don&#8217;t, upload them somewhere and post the link in the comments and I&#8217;ll add them to my collection.</p>
]]></content:encoded>
			<wfw:commentRss>http://shiftedbits.org/2007/10/28/quicksilver-plugins/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Pointless Optimization</title>
		<link>http://shiftedbits.org/2007/10/22/pointless-optimization/</link>
		<comments>http://shiftedbits.org/2007/10/22/pointless-optimization/#comments</comments>
		<pubDate>Mon, 22 Oct 2007 07:03:43 +0000</pubDate>
		<dc:creator>Devin Lane</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://shiftedbits.org/2007/10/22/pointless-optimization/</guid>
		<description><![CDATA[The other day I needed to write a function to give me a formatted string representation of a quantity of bytes. Pretty trivial function, but nontheless, I found myself optimizing it. I ended up with the following:
static uint64_t count = 7;
static NSString *suffixes[7] =
    { @"B", @"KiB", @"MiB", @"GiB", @"TiB", @"PiB", @"EiB"};
uint64_t [...]]]></description>
			<content:encoded><![CDATA[<p>The other day I needed to write a function to give me a formatted string representation of a quantity of bytes. Pretty trivial function, but nontheless, I found myself optimizing it. I ended up with the following:</p>
<pre>static uint64_t count = 7;
static NSString *suffixes[7] =
    { @"B", @"KiB", @"MiB", @"GiB", @"TiB", @"PiB", @"EiB"};
uint64_t i, c;
for (i = 1024, c = 0; i < (count << 60); i <<= 10, c++) {
    if (bytes < i)
        return [NSString stringWithFormat:  @"%0.2f%@",
                                            (double)bytes / (double)(i >> 10),
                                            suffixes[c]];
}
return @"Big";
</pre>
<p> Now, optimizing away divisions (except for the final conversion to string) really doesn&#8217;t save any time at all. The creation and subsequent autorelease of a NSString will take far longer than the division operations, even for large byte counts. Thus, I believe this code sample qualifies as pointless optimization, although it was entertaining to write.</p>
]]></content:encoded>
			<wfw:commentRss>http://shiftedbits.org/2007/10/22/pointless-optimization/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Color Setting Performance</title>
		<link>http://shiftedbits.org/2007/10/06/color-setting-performance/</link>
		<comments>http://shiftedbits.org/2007/10/06/color-setting-performance/#comments</comments>
		<pubDate>Sat, 06 Oct 2007 08:28:18 +0000</pubDate>
		<dc:creator>Devin Lane</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://shiftedbits.org/2007/10/06/color-setting-performance/</guid>
		<description><![CDATA[ If you&#8217;re looking to eek some extra performance out of your drawing code, take a look at how you&#8217;re setting your fill and stroke colors. Setting the color using CGContextSetRGBFillColor() or creating a new CGColorRef/NSColor object each time you set the color is quite expensive to do each time you draw. Depending on how [...]]]></description>
			<content:encoded><![CDATA[<p> If you&#8217;re looking to eek some extra performance out of your drawing code, take a look at how you&#8217;re setting your fill and stroke colors. Setting the color using <code>CGContextSetRGBFillColor()</code> or creating a new CGColorRef/NSColor object each time you set the color is quite expensive to do each time you draw. Depending on how many colors you use in your drawing, consider caching the CGColorRef objects and using <code>CGContextSetFillColorWithColor()</code> or <code>-[NSColor setFill]</code> instead.</p>
<p>A CGColorRef is 48 bytes for a RGB color. A NSColor is 32 bytes for a RGB color, plus 48 bytes for a CGColorRef. If you can afford the memory hit, you’ll see quite a bit of speed improvement from caching colors.</p>
<p>Below is the output from a small test app (source available <a href="/static/code/ColorPerformance.m">here</a>) that tests various color setting methods: (Each test is 1,000,000 iterations.)</p>
<pre>
CGContextSetRGBFillColor: 4.368422 seconds
CGContextSetFillColorWithColor, static CGColorRef: 0.599552 seconds
-[NSColor setFillColor], static NSColor: 0.832328 seconds
-[NSColor setFillColor], dynamic NSColor: 5.847799 seconds
</pre>
]]></content:encoded>
			<wfw:commentRss>http://shiftedbits.org/2007/10/06/color-setting-performance/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.337 seconds -->
