
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>The Exciter</title>
 <link href="http://theexciter.com/atom.xml" rel="self"/>
 <link href="http://theexciter.com/"/>
 <updated>2012-03-29T23:46:04+02:00</updated>
 <id>http://theexciter.com/</id>
 <author>
   <name>Johan Sørensen</name>
   <email>johan@johansorensen.com</email>
 </author>

  
   <entry>
     <title>Pausing and controlling the speed of Core Animation</title>
     <link href="/articles/pausing and controlling the speed of Core Animation.html"/>
     <updated>2012-03-24T10:47:00+01:00</updated>
     <id>tag:theexciter.com,2012-03-24:1332582420</id>
     <content type="html">
       &lt;p&gt;Core Animation is one of the finer frameworks in the SDK, it abstracts away a lot pesky details in a declaritive way. What declaritive means here is that you tell a CALayer to, for instance, go somewhere by changing its &lt;code&gt;position&lt;/code&gt; property and it&amp;#8217;ll animate it&amp;#8217;s way there. You can also build up your own animations with the varius CAAnimation subclasses, such as CABasicAnimation and CAKeyframeAnimation. With these animation classes you set various properties (to/from values, keyframe values) along with things such as the length and the timing function, but I became curious on how one would stop an animation &amp;#8220;mid-flight&amp;#8221; or change the speed once it has started. Turns out it&amp;#8217;s fairly easy.&lt;/p&gt;
&lt;h2&gt;Stopping and resuming animations&lt;/h2&gt;
&lt;p&gt;In Core Animation, time is modelled in a tree-like fashion, with the speed of one animation being relative to the speed of its parent animation. What that means that if you set a child animation to take 10 seconds it&amp;#8217;ll still take 10 seconds, however, if you change the speed of the parent animation any child animations will will change its speed relative to that. Both CAAnimation and CALayer&amp;#8217;s themselves adopt the &lt;a href=&quot;http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/CAMediaTiming_protocol/Introduction/Introduction.html#//apple_ref/occ/intf/CAMediaTiming&quot;&gt;CAMediaTiming&lt;/a&gt; protocol which models this time space relationship.&lt;/p&gt;
&lt;p&gt;Like Apple describes in this &lt;a href=&quot;https://developer.apple.com/library/ios/#qa/qa2009/qa1673.html&quot;&gt;Technote&lt;/a&gt;, in order to pause an animation you set the speed to 0.0 and its timeoffset to the current time (relative to its parent time). It may seem counter intuitive that just settings the speed to zero isn&amp;#8217;t enough, but if you only did that then it would simply return to its initial starting point as we don&amp;#8217;t freeze the time and the &lt;code&gt;speed&lt;/code&gt; property simply maps the child animations time space from its parent time space.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;layer.speed = 0.0;
layer.timeOffset = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Starting it involves setting the speed to 1.0, but also finding the current &lt;code&gt;timeOffset&lt;/code&gt; (where we paused it), resetting it, and setting the &lt;code&gt;beginTime&lt;/code&gt; based on the time difference between now and when it was paused so the animation will start exactly from where it was paused.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;layer.speed = 1.0;
CFTimeInterval pausedTime = layer.timeOffset;
layer.timeOffset = 0.0;
layer.beginTime = 0.0;
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
layer.beginTime = timeSincePause;
&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;Slowing down time&lt;/h2&gt;
&lt;p&gt;Slowing down time or speeding it up becomes easy once we learn how Core Animation maps time spaces:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;layer.timeOffset = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
layer.beginTime = CACurrentMediaTime();
layer.speed = 0.5;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Chaning the speed of an animation means we have to change the speed obviously, but we also have to remap the time space into the current time. So we set the timeOffset to the layer&amp;#8217;s current time and the beginTime to our global time.&lt;/p&gt;
&lt;p&gt;I haven&amp;#8217;t actually had a use for this in a real app, as it was one of those &amp;#8220;I wonder how…&amp;#8221; moments, but it might be useful for someone out there.&lt;/p&gt;
      </content>
   </entry>
  
   <entry>
     <title>Headphones</title>
     <link href="/articles/headphones.html"/>
     <updated>2012-01-12T19:12:02+01:00</updated>
     <id>tag:theexciter.com,2012-01-12:1326391922</id>
     <content type="html">
       &lt;p&gt;If you spend any amount of time in front your computer with headphones, you should invest in a decent pair. Just as you should invest in a decent desk and chair. I&amp;#8217;ve been through a few headphones, from cheap and crap to expensive and wonderful and even expensive and crap.&lt;/p&gt;
&lt;p&gt;Listening to music is very much an individual taste whether it&amp;#8217;s genre or how the music actually sounds through a pair of speakers or headphones. Audiophiles will spend the gross national product of a small country (and half of that on cables) to try and figure it out, but even if you&amp;#8217;ll only invest a smaller amount (say $170-$600), you&amp;#8217;ll hear a difference when it comes to headphones and it&amp;#8217;s definitely something I recommend investing in if you enjoy listening to music all day long. Even a specialized headphone-amplifier can lift some dull-sounding headphones to new heights.&lt;/p&gt;
&lt;h2&gt;Requirements&lt;/h2&gt;
&lt;p&gt;I have the following three requirements for a pair of headphones:&lt;/p&gt;
&lt;h3&gt;Comfort&lt;/h3&gt;
&lt;p&gt;They must be comfortable. No point in having a pair of expensive headphones if you can&amp;#8217;t stand to wear them. In a perfect world you should forget you&amp;#8217;re wearing them completely.&lt;/p&gt;
&lt;p&gt;Things that may affect comfort are weight and how tight they clamp on your head and ears. Personally I only want to use full-size (circumaural) headphones, it&amp;#8217;s the only kind of headphone that I can easily forget is there, as over- or in-ear headphones have a tendency to physically remind me that they&amp;#8217;re there all the time either by squeezing on my ear or itching.&lt;/p&gt;
&lt;h3&gt;Sound quality&lt;/h3&gt;
&lt;p&gt;Sound quality must be enjoyable. They don&amp;#8217;t have to measure perfectly on some random audiophile scale, but the sound must not wear me out or sound artificially enhanced. Those two usually go hand in hand, as headphones that enhance for instance the bass will over time wear my ears out due to being pumped full of bass all day long.&lt;/p&gt;
&lt;p&gt;I find that I prefer headphones that seem light on bass when you try them in the store compared to other offerings, but when you get home and listen to them for extended periods my ears don&amp;#8217;t get as worn out as with a pair of bass-heavy ones. The same goes for the upper tones, constantly having those high tones tickling your ears gets weary as well. So fairly neutral is what I&amp;#8217;m going for in a pair of headphones.&lt;/p&gt;
&lt;p&gt;If you troll any random audiophile forum you&amp;#8217;ll read much about some hunt for the magically neutral sound, but with a wide soundstage that makes you feel like you where transported to the same room where the recording took place. Which is of course like hunting for a unicorn, the sound is already mutated by the microphone(s&amp;#8217;) placement and how the sound engineer mixed the sound. The kind of neutral I&amp;#8217;m hunting for is the kind that makes my ears feel comfortable and the music sound &lt;em&gt;enjoyable&lt;/em&gt;, according to my own mental impression and scale.&lt;/p&gt;
&lt;h3&gt;No unwanted noise leaking&lt;/h3&gt;
&lt;p&gt;This one is optional. But not if you use them in a public place, whether that&amp;#8217;s on the subway or in an office. Doesn&amp;#8217;t matter if everyone share your taste in music, no-one wants to hear your muffled noise. At the office I only use closed headphones, in my home office I got a pair of open ones as I&amp;#8217;m not likely to disturb any else in the same room.&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s a tradeoff here between open and closed headphones, as open headphones &lt;em&gt;generally&lt;/em&gt; tend to sound better, since it&amp;#8217;s easier to control the sound as it doesn&amp;#8217;t bounce around next to your ear so much.&lt;/p&gt;
&lt;p&gt;Remember, not everyone listens to music when they work and they&amp;#8217;ll hate you if they can hear you listening to something through your open headphones.&lt;/p&gt;
&lt;h2&gt;Ohms &amp;amp; Amplifiers&lt;/h2&gt;
&lt;p&gt;Generally headphones are rated, among other things, in impedance as a measure of how much power is required to drive them. As a rule of thumb, if your headphones have an impedance above around 32 Ohms your average computer, laptop or portable music player isn&amp;#8217;t going to be able to drive them reasonably and you need an amplifier in-between.&lt;br /&gt;
Luckily the market for headphone specific amplifiers are equally vast (and confusing) as the actual headphones themselves and you can easily break your budget on these things as well. Not only that, but they also affect the sound a bit, making it sound &amp;#8220;warmer&amp;#8221; or &amp;#8220;colder&amp;#8221; or with less or more bass and so forth. But unless you&amp;#8217;re a total audiophile the difference is negligible, but certainly something to pay attention to as it&amp;#8217;s noticeable.&lt;/p&gt;
&lt;h2&gt;My headphones&lt;/h2&gt;
&lt;p&gt;I&amp;#8217;ve been through a lot of headphones. Let&amp;#8217;s take a look at some of the recent ones, there&amp;#8217;s both good and terrible purchases here. I&amp;#8217;m not going to do a full review here as frankly I&amp;#8217;m not authoritative enough on this, but these are a few of my choices from the past year:&lt;/p&gt;
&lt;h3&gt;AKG K-271 MKII + Maverick Audio TubeMagic D1&lt;/h3&gt;
&lt;p&gt;My current office setup at work. While the &lt;a href=&quot;http://www.headphone.com/headphones/akg-k-271-mk-ii.php&quot;&gt;K 271&lt;/a&gt; will do fine without an amp, they really shine when they receive a bit of power. The &lt;a href=&quot;http://www.mav-audio.com/base/product/tube_magic_d1&quot;&gt;TubeMagic D1&lt;/a&gt; really makes them open up a bit more than straight from the iMac&amp;#8217;s audio jack. The D1 is a tube amplifier but sadly you don&amp;#8217;t get to hear any of those smooth tubes when using the headphone jack, only through the RCA analog out. Still the D1 is a dirt cheap DAC with decent quality and enough power to drive most headphones.&lt;/p&gt;
&lt;h3&gt;Monster Beats Pro&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://beatsbydre.com/products/Products.aspx?pid=B5616&amp;amp;cat=1&quot;&gt;This&lt;/a&gt; was one of those regrettable spontaneous purchases. They fooled me completely, bought when I was at WWDC in San Francisco and sold when I got back to Norway. They enhance bass. They enhance bass &lt;em&gt;a lot&lt;/em&gt;. They enhance bass a &lt;em&gt;metric ton&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;They &lt;del&gt;impressed&lt;/del&gt; fooled me at the noisy store but when worn for any length of time the enhanced bass just got annoying and wore me out, in addition to the weight. All that aluminum really makes them heavy.&lt;/p&gt;
&lt;p&gt;I really regretted buying ever buying these, probably because I mostly felt fooled when I got home and compared them to me existing headphones, so they got sold again quickly. One of my coworkers swear by them though, so each to their own.&lt;/p&gt;
&lt;h3&gt;Hifiman HE-300 + Nuforce Icon HDP&lt;/h3&gt;
&lt;p&gt;My home office setup. The &lt;a href=&quot;http://www.head-direct.com/Products/?act=detail&amp;amp;id=108&quot;&gt;HE-300&lt;/a&gt; is currently my favorite pair of headphones. They&amp;#8217;re open headphones so sadly I can&amp;#8217;t use them at work, but I just love sitting and listening to these at home. They&amp;#8217;re rated at 32 ohms so they can be driven by an iPhone or laptop, but like the K271 they really open up when given some power from an amp. The &lt;a href=&quot;http://www.nuforce.com/hp/products/iconhdp/index.php&quot;&gt;Nuforce HDP&lt;/a&gt; gives plenty of power to these and has a very good USB DAC (better than the TubeMagic D1).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/hifiman-he-300.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Parting words&lt;/h2&gt;
&lt;p&gt;Must of the music I listen to is of the instrumental kind, various kind of classic and heavy rock all the way up to metal, so the choices above mostly reflect this and as you&amp;#8217;ve already guessed I&amp;#8217;m not a fan of artificially enhanced bass as it easily drowns out other details on headphones in this price range.&lt;/p&gt;
&lt;p&gt;Like most gadgets, spending a lot of money upgrading headphone gear is easy once you get into it, but sooner or later you&amp;#8217;ll find a sweet spot of price versus performance for your taste where upgrading doesn&amp;#8217;t make any sense. While I&amp;#8217;ve occasionally contemplated toying with other amplifier combinations I&amp;#8217;m currently satisfied enough with my HE-300 setup at home and the K-271 at work.&lt;/p&gt;
&lt;p&gt;You should buy some decent headphones. Try a few different ones first as there&amp;#8217;s quite a difference and it is very much a matter of taste, but the reviews don&amp;#8217;t always reflect that.&lt;/p&gt;
      </content>
   </entry>
  
   <entry>
     <title>A scrollview in a tableview cell, properly</title>
     <link href="/articles/scrollview-in-tableview-cell-properly.html"/>
     <updated>2011-12-21T08:58:02+01:00</updated>
     <id>tag:theexciter.com,2011-12-21:1324454282</id>
     <content type="html">
       &lt;p&gt;Looking at what search terms people use to find this site I see that my article on &lt;a href=&quot;/articles/touches-and-uiscrollview-inside-a-uitableview.html&quot;&gt;embedding a UIScrollView inside a UITableViewCell&lt;/a&gt; is among the ones that gets the most hits. Which is a shame since that approach is a &lt;em&gt;terrible way&lt;/em&gt; of solving it these days.&lt;/p&gt;
&lt;p&gt;After iOS 2.1 (or iPhoneOS as it was called back then) or thereabout that terrible responder chain hack is no longer needed, all you need to do is add the scrollview as a subview of the cell and you&amp;#8217;re good to go:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 50.0f;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellIdentifier = @&quot;ScrollCell&quot;;
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
        UIScrollView *scroller = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 25, 320, 25)];
        scroller.showsHorizontalScrollIndicator = NO;

        UILabel *contentLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320*4, 25)];
        contentLabel.backgroundColor = [UIColor blackColor];
        contentLabel.textColor = [UIColor whiteColor];
        NSMutableString *str = [[NSMutableString alloc] init];
        for (NSUInteger i = 0; i &amp;lt; 100; i++) { [str appendFormat:@&quot;%i &quot;, i]; }
        contentLabel.text = str;

        [scroller addSubview:contentLabel];
        scroller.contentSize = contentLabel.frame.size;
        [cell addSubview:scroller];
    }

    cell.textLabel.text = [NSString stringWithFormat:@&quot;cell #%i&quot;, indexPath.row];

    return cell;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing fancy going on here, just creating a scrollview, add a wider subview, set the contentSize of the scrollview and add it to the UITableViewCells view hierarchy.&lt;br /&gt;
I usually prefer to use a UITableView subclass instead of setting up cell view hierarchies in the view controller, but you wouldn&amp;#8217;t just copy-paste example code without thinking now would you?&lt;/p&gt;
      </content>
   </entry>
  
   <entry>
     <title>Nibs vs. code, a journeyman's perspective (or lack thereof)</title>
     <link href="/articles/nibs-vs-code.html"/>
     <updated>2011-08-06T01:18:02+02:00</updated>
     <id>tag:theexciter.com,2011-08-06:1312586282</id>
     <content type="html">
       &lt;p&gt;Like all languages and frameworks, Cocoa has some topics that will polarize its programmers. This one isn&amp;#8217;t about dot-notation, for once, but laying out user interface in nibs/xibs (&lt;a href=&quot;http://en.wikipedia.org/wiki/Interface_Builder&quot;&gt;interface builder&lt;/a&gt; files) versus building it in plain old Objective-C code. With nibs (even though their modern extension is .xib) you layout the user interface ín a graphical UI and connect it with your code. With code you allocate, initialize and place the UI element(s) entirely in code, most likely within your controller.&lt;/p&gt;
&lt;p&gt;First things first, at its core programming is a discipline of &lt;em&gt;balance&lt;/em&gt;. Balance with performance and implementation time. Balance between readability and understandability. Balance between implementation time and understanding it in one, two, twelve months from now ad infinium.&lt;br /&gt;
Some times it&amp;#8217;s faster to add some UI elements in code, sometimes it&amp;#8217;s faster with nibs. That&amp;#8217;s the diplomatic aspect, let&amp;#8217;s try and look at in what situations you might prefer one over the other, enumerated as a list since my editor let it slip through;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;I like nibs when I have to layout UI elements from a mockup or &amp;#8220;final&amp;#8221; design.&lt;/li&gt;
	&lt;li&gt;I like nibs when I got the feeling my designer will change his mind and he can edit the nibs himself, or sit next to me dictating where the elements should be.&lt;/li&gt;
	&lt;li&gt;I like nibs when there&amp;#8217;s lots of graphical elements to layout; writing code, compiling, running, editing, recompiling running is slower than seeing it WYSIWYG-ish in interface builder.&lt;/li&gt;
	&lt;li&gt;I like code when there&amp;#8217;s dynamic &amp;#8220;things&amp;#8221; involved, except when it&amp;#8217;s combined with one of the above, then it&amp;#8217;s faster to just hook it up with an outlet.&lt;/li&gt;
	&lt;li&gt;I like code when I have to place elements relative to other elements (and I can&amp;#8217;t use &lt;a href=&quot;http://developer.apple.com/library/mac/#documentation/UserExperience/Conceptual/AutolayoutPG/Articles/Introduction.html&quot;&gt;auto layout&lt;/a&gt;), as long as I cannot make it work with autoresizingMask&amp;#8217;s in the nib.&lt;/li&gt;
	&lt;li&gt;I like nibs when it means there&amp;#8217;s less -layoutSubviews or -initWithFrame: boilerplate code to scroll past.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The last one is probably the most important to me. A lot of programmers seem to take a Conan the Barbarian approach to code; &lt;a href=&quot;http://www.youtube.com/watch?v=W5K3AKl5qpc#?t=1m57s&quot;&gt;&amp;#8220;if you do not like code, then TO HELL WITH YOU&amp;#8221;&lt;/a&gt; and forgetting that when they look at the code in six months from now they&amp;#8217;ll wasting time scrolling past code that may be important layout logic or just simple layout logic or worst of all, they&amp;#8217;ll waste lots of time compile-run cycles trying to get their CGRect&amp;#8217;s to align properly.&lt;/p&gt;
&lt;p&gt;Code is craft, crafting is balance between getting your message across and getting your message out there. And sometimes there&amp;#8217;s not a single right answer. That&amp;#8217;s what makes this profession a  craft, the hard part is often crafting it together in a team.&lt;/p&gt;
      </content>
   </entry>
  
   <entry>
     <title>Migrating from Google Apps email</title>
     <link href="/articles/migrating-away-from-google-apps-email.html"/>
     <updated>2011-08-05T23:37:02+02:00</updated>
     <id>tag:theexciter.com,2011-08-05:1312580222</id>
     <content type="html">
       &lt;p&gt;I&amp;#8217;ve long been a paying user of Google&amp;#8217;s Apps for Your Domain, in particular the email aspect of it. I don&amp;#8217;t care for online documents, spreadsheets, buzz or whatever random flailing product they shove down your throat, only email. The web based gmail client showed the world how web applications should be done, for better or for worse.&lt;/p&gt;
&lt;p&gt;One thing is the constant slowdowns, the 10-30 seconds waiting time for something to happen. The other being a matter of trust. Is it really wise to have so many things hosted and logged with one single provider? One who so obviously has only figured out how to earn money one one thing; namely selling your content and data for advertising? I decided it wasn&amp;#8217;t.&lt;/p&gt;
&lt;p&gt;I almost like the gmail interface, it&amp;#8217;s one of the better web apps out there. But it still has all the flaws of a web app, along with questionable motives from its provider.&lt;/p&gt;
&lt;p&gt;So in an effort to minimize risks, or at least distribute them a bit further, I decided to change my personal email provider away from Google to &lt;a href=&quot;http://fastmail.fm&quot;&gt;fastmail.fm&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;My personal email address (first name @ johansorensen.com) has mostly been functioning as a dumpster for all sorts of email: some personal, but mostly mailing lists and automatic notifications from various projects I&amp;#8217;ve either worked on, with or somehow needed temporarily knowledge of the development of. In other words, and non-practical implementation of the hoarding syndrome. Which sucks. So, a few days ago I unsubscribed from every single mailing list except a few and deleted seven gigabytes of archived email (of which I&amp;#8217;ve contributed only a few megabytes), changed my MX records and am now only using fastmail.fm through IMAP. Click. Click. Done. Almost.&lt;/p&gt;
&lt;p&gt;The migration was slightly annoying as Google has some pretty strict bandwidth and/or usage limits in place, preventing you from downloading all your email at once (ding ding), so the actual migration consisted of downloading all IMAP mailboxes over a few days, and re-uploading them to the fastmail.fm IMAP account (fastmail didn&amp;#8217;t have any arbitrary limits in place preventing me from doing with my own data as I saw fit).&lt;/p&gt;
&lt;p&gt;Email was a solved problem long before Gmail. My email is now stored offline and owned by me, I can move it anywhere I want to. With modern tablets and smartphones, &amp;#8220;access anywhere&amp;#8221; is also a solved problem.&lt;/p&gt;
&lt;p&gt;Distributing your online &amp;#8220;cloud-ness&amp;#8221; is a must, don&amp;#8217;t put all your personal data with one provider, no matter how much you trust them. It&amp;#8217;s like backups; if you have them all in one place, you&amp;#8217;re going to get burned sooner or later.&lt;/p&gt;
      </content>
   </entry>
  
   <entry>
     <title>Diffing images with Core Graphics</title>
     <link href="/articles/diffing-images-with-core-graphics.html"/>
     <updated>2011-04-10T18:00:00+02:00</updated>
     <id>tag:theexciter.com,2011-04-10:1302451200</id>
     <content type="html">
       &lt;p&gt;Few of the popular version control systems treat images as much more than the binary blobs they technically are. So it&amp;#8217;s up to third party tools such as &lt;a href=&quot;https://github.com/blog/817-behold-image-view-modes&quot;&gt;Github&lt;/a&gt; or &lt;a href=&quot;http://www.kaleidoscopeapp.com/&quot;&gt;Kaleidoscope&lt;/a&gt; to provide more reasonable and user-friendly means of comparing images.&lt;/p&gt;
&lt;p&gt;On a whim, let&amp;#8217;s explore how to implement one of the ways the above tools provides image comparison with Core Graphics; difference comparison. Conceptually it means we&amp;#8217;ll blend the new image onto the old image and subtract any pixels that are different from the other and pixels that are unchanged will be black. It&amp;#8217;s the same blending mode you&amp;#8217;ll find in image editors such as Photoshop and Pixelmator.&lt;/p&gt;
&lt;p&gt;Doing it with Core Graphics is pretty easy: draw the old image as-is into a drawing context, change the blendmode and draw the new image and extract the composed image.&lt;/p&gt;
&lt;p&gt;First we need a method for creating a &lt;code&gt;CGContextRef&lt;/code&gt; from a CGImage. I like boilerplate things like this to stay out of the main method and live in its own private method:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- (CGContextRef)createCGContextFromCGImage:(CGImageRef)img
{
    size_t width = CGImageGetWidth(img);
    size_t height = CGImageGetHeight(img);
    size_t bitsPerComponent = CGImageGetBitsPerComponent(img);
    size_t bytesPerRow = CGImageGetBytesPerRow(img);

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef ctx = CGBitmapContextCreate(NULL, // Let CG allocate it for us
                                             width,
                                             height,
                                             bitsPerComponent,
                                             bytesPerRow,
                                             colorSpace,
                                             kCGImageAlphaPremultipliedLast); // RGBA
    CGColorSpaceRelease(colorSpace);
    NSAssert(ctx, @&quot;CGContext creation fail&quot;);

    return ctx;
}
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;In other words, pretty much standard Core Graphics creation of a CGContext. In this example we just extract the size and pixel format from the supplied CGImageRef. As per normal Cocoa memory semantics we return an object which the caller is responsible for releasing since our method starts with &lt;code&gt;create&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now for the actual blending of the two images, represented as the &lt;code&gt;_oldImage&lt;/code&gt; and &lt;code&gt;_newImage&lt;/code&gt; UIImage&amp;#8217;s:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- (UIImage *)diffedImage
{
    // We assume both images are the same size, but it's just a matter of finding the biggest
    // CGRect that contains both image sizes and create the CGContext with that size
    CGRect imageRect = CGRectMake(0, 0,
                                  CGImageGetWidth(_oldImage.CGImage),
                                  CGImageGetHeight(_oldImage.CGImage));
    // Create our context based on the old image
    CGContextRef ctx = [self createCGContextFromCGImage:_oldImage.CGImage];

    // Draw the old image with the default (normal) blendmode 
    CGContextDrawImage(ctx, imageRect, _oldImage.CGImage);
    // Change the blendmode for the remaining drawing operations
    CGContextSetBlendMode(ctx, kCGBlendModeDifference);
    // Draw the new image &quot;on top&quot; of the old one
    CGContextDrawImage(ctx, imageRect, _newImage.CGImage);

    // Grab the composed CGImage
    CGImageRef diffed = CGBitmapContextCreateImage(ctx);
    // Cleanup and return a UIImage
    CGContextRelease(ctx);
    UIImage *diffedImage = [UIImage imageWithCGImage:diffed];
    CGImageRelease(diffed);

    return diffedImage;
}
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Core Graphics will do the hard work of subtracting the pixels, even if the two images are of different formats or sizes, however the example here doesn&amp;#8217;t accommodate different sizes to keep things brief.&lt;/p&gt;
&lt;p&gt;I always enjoy working with Apple&amp;#8217;s C-based APIs, they&amp;#8217;re often well designed both when it comes to naming and functionality, while feeling strangely familiar due to their memory management semantics.&lt;/p&gt;
      </content>
   </entry>
  
   <entry>
     <title>Command line arguments with NSUserDefaults</title>
     <link href="/articles/command-line-arguments-with-nsuserdefaults.html"/>
     <updated>2011-02-20T12:30:00+01:00</updated>
     <id>tag:theexciter.com,2011-02-20:1298201400</id>
     <content type="html">
       &lt;p&gt;Whenever I&amp;#8217;m in need of some quick and dirty command line arguments for a simple tool, I find using NSUserDefaults to be the easiest:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ./mjau -input mjau.m
#import &lt;Foundation/Foundation.h&gt;

int main (int argc, const char * argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    NSString *inputFile = [[NSUserDefaults standardUserDefaults]
                           objectForKey:@&quot;input&quot;];
    NSStringEncoding usedEncoding;
    NSError *error = nil;
    NSString *content = [NSString stringWithContentsOfFile:inputFile
                                              usedEncoding:&amp;usedEncoding 
                                                     error:&amp;error];
    if (error) {
        fprintf(stderr, &quot;Error: %s\n&quot;,
                [[error localizedDescription] UTF8String]);
        return -1;
    }
    fprintf(stdout, &quot;%s\n&quot;, [content UTF8String]);

    [pool drain];
    return 0;
}

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;No need to bother with &lt;code&gt;getopt(3)&lt;/code&gt; if you just need some simple option parsing.&lt;/p&gt;
&lt;p&gt;Of course, this also means you can use it to set existing NSUserDefaults from the command line. One such useful toggle is the &lt;a href=&quot;http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/LoadingResources/Strings/Strings.html&quot;&gt;&lt;code&gt;-NSShowNonLocalizedStrings YES&lt;/code&gt;&lt;/a&gt; default, turning non-localized strings into all caps making them easier to spot.&lt;/p&gt;
      </content>
   </entry>
  
   <entry>
     <title>It's the message</title>
     <link href="/articles/it-is-the-message.html"/>
     <updated>2011-02-11T17:30:00+01:00</updated>
     <id>tag:theexciter.com,2011-02-11:1297441800</id>
     <content type="html">
       &lt;h3&gt;Nokia/Microsoft&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&amp;#8220;By leveraging new synergies in partnerships that will escalate our mindshare to new global opportunities beyond this fiscal year we&amp;#8217;re securing valuable fluff. Also, we&amp;#8217;re still committed to Symbian and Meego. Except when we&amp;#8217;re commited to Microsoft. Maybe next year. We&amp;#8217;re not really sure what&amp;#8217;s going on here either.&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Google&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&amp;#8220;We, the largest technology and advertising business in the world, is here to save you from an entirely different draconian future than ours. Also, we&amp;#8217;re like open and junk and if you can&amp;#8217;t update to Cherrybomb just tell your mom to flash her ROM!&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Blackberry&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&amp;#8220;Something something business something. Something QNX. Something something Flash.&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Apple, and now HP/Palm&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;&amp;#8220;Here&amp;#8217;s our things. This is what they do and this is what &lt;em&gt;you&lt;/em&gt; can do with them.&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Simplified and obviously subjective, but which one of the above can the consumer relate to?&lt;/p&gt;
      </content>
   </entry>
  
   <entry>
     <title>Passing on the Gitorious torch</title>
     <link href="/articles/passing-on-the-gitorious-torch.html"/>
     <updated>2011-01-12T21:22:00+01:00</updated>
     <id>tag:theexciter.com,2011-01-12:1294863720</id>
     <content type="html">
       &lt;p&gt;My initial, and the very first, commit to Gitorious &lt;a href=&quot;http://gitorious.org/gitorious/mainline/commit/61e76a818d8e072b48ebf093d9e72699a1e6ecfb&quot;&gt;was august 14th, 2007&lt;/a&gt;. It all started as scratching an itch I had about hosting my own Git repositories, eventually it was adopted by many others, then by commercial open source projects such as &lt;a href=&quot;http://qt.gitorious.org&quot;&gt;Nokias Qt&lt;/a&gt; and &lt;a href=&quot;http://meego.gitorious.org&quot;&gt;MeeGo&lt;/a&gt; and behind-the-firewall installations. My company did consulting and other work on custom features for Gitorious.org and custom installations.&lt;/p&gt;
&lt;p&gt;Last year I started spending most of my time and energy on Objective-C and Cocoa applications again, while one of my fellow co-founders Marius kept chugging along and I did less and less work on Gitorious. Eventually we decided to formalize this whole arrangement.&lt;/p&gt;
&lt;p&gt;Gitorious is now a wholly owned subsidiary of &lt;a href=&quot;http://shortcut.no&quot;&gt;Shortcut&lt;/a&gt;, employing &lt;a href=&quot;http://gitorious.org/~zmalltalker&quot;&gt;Marius&lt;/a&gt; and &lt;a href=&quot;http://gitorious.org/~cjohansen&quot;&gt;Christian&lt;/a&gt; full time. They&amp;#8217;re running the show and got the keys now, which is great for all parties involved; I get to focus on other things, and Gitorious receives the full attention it deserves, while being developed and maintained by a company devoted exclusively to its cause.&lt;/p&gt;
      </content>
   </entry>
  
   <entry>
     <title>Focusing on the Canon 7D</title>
     <link href="/articles/focusing-on-the-7d.html"/>
     <updated>2010-12-28T23:57:00+01:00</updated>
     <id>tag:theexciter.com,2010-12-28:1293577020</id>
     <content type="html">
       &lt;p&gt;Close to a decade ago I did a lot of photography, mostly black and white since I had free access to a darkroom but also with the one of the first digital flagships, the &lt;a href=&quot;http://www.dpreview.com/reviews/nikond1/&quot;&gt;Nikon D1&lt;/a&gt; with a whooping 2.7 megapixels. Film vs. digital was still a topic then. Then I went and pursued interests and the prosumer part of my photography was put on standby, apart from a short stint with a Konica-Minolta digital body (shortly before Sony bought their SLR division).&lt;/p&gt;
&lt;p&gt;Earlier this year I decided to give it another go, bought a Canon 500D and some lenses. Thousands of exposures later (and relearning the tricks of the trade again) I upgraded to the 7D a few weeks ago.&lt;/p&gt;
&lt;p&gt;One of the nicer features if the 7D is the focusing system, while it seems Canon is still behind Nikon a bit on this, they&amp;#8217;re making progress. My favorite customization of the 7D is moving the half-press-shutter-to-focus to the AF-On button and setting the half-press shutter button to &amp;#8220;metering start&amp;#8221;. This is done under the &amp;#8220;C.Fn IV&amp;#8221; screen.&lt;br /&gt;
This allows me to stay in the continuous autofocus mode, while still being able to use the classic &amp;#8220;focus, then recompose&amp;#8221; approach, &lt;em&gt;without&lt;/em&gt; losing the ability to quickly move to continuous focus on moving subjects, just by keeping the AF-On button pressed.&lt;/p&gt;
&lt;p&gt;The problem I&amp;#8217;ve always had is that by the time I&amp;#8217;ve changed my camera focus setting from single shot to continuous autofocus whatever action I wanted to capture is long gone. Staying on continuous autofocus and remapping the focus button to the AF-On button allows me to keep the best of both worlds; focus, then recompose for single shots and continuous focus to nail the action, coupled with the 7D&amp;#8217;s ~8 fps continuous shooting mode.&lt;/p&gt;
      </content>
   </entry>
  
   <entry>
     <title>Why Google TV is fundamentally flawed</title>
     <link href="/articles/why-google-tv-is-fundamentally-flawed.html"/>
     <updated>2010-05-21T09:57:02+02:00</updated>
     <id>tag:theexciter.com,2010-05-21:1274428622</id>
     <content type="html">
       &lt;p&gt;Yesterday at Google&amp;#8217;s I/O event they announced &lt;a href=&quot;http://google.com/tv/&quot;&gt;Google TV&lt;/a&gt;. It seems that Google is starting to look more and more like the Microsoft of the 90&amp;#8217;s; partnering up with OEM vendors to get their products in front of as many people as possible. Granted, many businesses, if not all, partner with other businesses, but the Microsoft analogy seems more fitting than ever these days.&lt;/p&gt;
&lt;p&gt;However I think that their approach for interaction is fundamentally flawed. In fact, I think everyone, such as Boxee and Apple TV, gets it completely wrong, especially as (or rather; if) they start to &amp;#8220;enrich&amp;#8221; their products with things such as web browsing and apps.&lt;/p&gt;
&lt;p&gt;The problem is that they&amp;#8217;re all viewing the TV is an input device, meaning that you interact directly with it via some kind of remote or keyboard and mouse-like device (or worst of all; an actual keyboard and mouse). This may make sense if you think of the TV as a &amp;#8220;some kind of PC&amp;#8221;, or because people of recent generations have always interacted with the TV via a remote. &lt;br /&gt;
However, as soon as the interaction goes beyond simple things such as volume control and channel flipping it becomes extremely painful. If you&amp;#8217;re browsing a website you&amp;#8217;re in a world of pain, even the on-stage demos looked extremely painful to navigate (if you look beyond the amount of technical issues with remotes/keyboards dropping connections and the terrible presentations with other presenters mumbling on the mic in the background while the main presenter was talking, I&amp;#8217;ve seen high-school presentations better than that).&lt;/p&gt;
&lt;p&gt;The TV shouldn&amp;#8217;t be viewed as an interactive terminal, but rather as a passive projector that receives its input from other things. Imagine instead if the remote for a storage, OS and video-decoding &amp;#8220;media box&amp;#8221; was an iPad(-like) tablet on which you did all the interactions and the TV simply mirrored those when you where browsing, or presented the results of such interactions, like playing a show from a playlist you just created.&lt;/p&gt;
&lt;p&gt;By interacting with the device directly in front of you, through a touch interface, you&amp;#8217;ll have a much more user-friendly interaction model, especially when browsing but also when browsing the content on the media box and creating playlists, viewing IMDb entries on the movie you&amp;#8217;re about to watch (or while watching it). Need to show other people what you&amp;#8217;re viewing? Just flip on mirroring directly to the TV, or select an item from the tablet to play on the TV. Easy, fast and much more enjoyable.&lt;/p&gt;
&lt;p&gt;Simple interactions works fine with a simple remote, but if there&amp;#8217;s a lot of button clicking and text input having to do it in such a detached manner from the screen is a terrible idea, and the Google TV demos was chock-full of buttons and text input.&lt;/p&gt;
      </content>
   </entry>
  
   <entry>
     <title>Why you wouldn't want to write your mobile application in a dynamic language</title>
     <link href="/articles/why-you-wouldnt-want-to-write-your-application-in-a-dynamic-language.html"/>
     <updated>2010-04-12T21:36:42+02:00</updated>
     <id>tag:theexciter.com,2010-04-12:1271101002</id>
     <content type="html">
       &lt;p&gt;With the current flavor of the week being a certain new section in Apple&amp;#8217;s iPhone SDK license, there&amp;#8217;s no shortage of sane and not-quite-as-sane commentary being thrown around. This post isn&amp;#8217;t really about that, but it has triggered some people to argue that they should be able to write their applications in Ruby or any other interpreted language. Which shows that they either have no clue about mobile platforms, or think their users&amp;#8217; device is something they can just abuse at will.&lt;/p&gt;
&lt;p&gt;I love Ruby, but it has little place running an entire application on a mobile device, as awesome as that would be. On a device (fruit logo engraved or not) with limited processing power, memory and battery time, do you &lt;em&gt;really&lt;/em&gt; want to run an &lt;em&gt;entire&lt;/em&gt; application that &lt;del&gt;wastes&lt;/del&gt; spends many CPU hours just interpreting things? I&amp;#8217;m pretty sure your potential users would have an issue with your application draining the battery much faster than your competitors application, or using substantially more memory.&lt;/p&gt;
&lt;p&gt;&amp;#8220;CPU time is cheap, programmer time is not&amp;#8221; has become the mantra of the dynamic language world, with good reason. But it falls short when you&amp;#8217;re no longer running on a machine with 16 or more CPU cores and eight gigabytes of RAM. In fact, if you spend some time reading through the iPhone SDK APIs you&amp;#8217;ll find numerous encouragements to be mindful of battery use (I imagine the same being true for Android and other mobile platforms as well). CPU time and memory is the currency your application has to trade, if you waste it your users will not be too impressed with either your application or the platform as a whole (for good or for worse they reflect upon each other), both being a very bad thing for you.&lt;/p&gt;
&lt;p&gt;Moore&amp;#8217;s law of course applies to mobile CPUs as well, the difference between this years hardware and the previous one is significant regardless of manufacturer, but it&amp;#8217;s more of a steady improvement than a giant leap forward, so you don&amp;#8217;t quite have the luxury to trade in all your programmer time for CPU time just yet since there&amp;#8217;s only so much to go around.&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s also some interesting economics in this from the perspective of the mobile device manufacturers. Faster CPUs are more expensive, so if you can provide adequate performance at a reasonable price (cheaper CPUs means cheaper hardware for consumers, thus a competitive advantage) by only using a compiled language in your SDK (along with an API to save even more resources for things such as multitasking), then we&amp;#8217;re suddenly talking about a significant difference in dollars and cents.&lt;/p&gt;
&lt;p&gt;If your entire SDK is fairly resource intensive, such as Palm&amp;#8217;s WebOS (both rendering HTML and interpreting javascript is a significant investment for a mobile CPU), then your device suddenly becomes much more expensive and it&amp;#8217;ll still run out of battery in less than a day. The internet reviewers and know-it-alls does not approve of such shenanigans.&lt;/p&gt;
      </content>
   </entry>
  
   <entry>
     <title>A Late Note About Recent Gitorious Developments</title>
     <link href="/a-late-note-about-recent-gitorious-developments.html"/>
     <updated>2009-05-20T10:02:42+02:00</updated>
     <id>tag:theexciter.com,2009-05-20:1242806562</id>
     <content type="html">
       &lt;p&gt;Just under a week I deployed a new version of &lt;a href=&quot;http://gitorious.org&quot;&gt;Gitorious.org&lt;/a&gt; and announced some big changes, not only in functionality but also some things that&amp;#8217;ll make Gitorious live long and prosper.&lt;/p&gt;
&lt;h2&gt;The non-technical stuff&lt;/h2&gt;
&lt;p&gt;On the non-technical side, one of the bigger changes is that Gitorious is now officially a Shortcut production. &lt;a href=&quot;http://shortcut.no&quot;&gt;Shortcut&lt;/a&gt; is a company I started together with three other gentlemen at the beginning of last year and we&amp;#8217;re now a six person company who has been making money since day one, financial crisis or not. With Shortcut maintaining and developing Gitorious.org, as well as keeping &lt;a href=&quot;http://gitorious.org/gitorious&quot;&gt;Gitorious open source&lt;/a&gt;, we now have additional resources to bring the project forwards beyond what was feasible for me as a single developer doing Gitorious in my spare time.&lt;/p&gt;
&lt;p&gt;A few months ago I was invited to the Qt offices and as it turned out they where running their own internal installation of Gitorious. Qt Software has been keeping busy since they got acquired by Nokia last year and one of the reasons I was invited was that they wanted to use Gitorious.org as the platform for the contribution model for the (then to be announced) LGPL licensed Qt products.&lt;/p&gt;
&lt;p&gt;For the past few months Qt has funded development of &lt;a href=&quot;http://blog.gitorious.org/2009/05/09/weve-made-a-few-changes/&quot;&gt;new Gitorious features&lt;/a&gt; and continues to do so. Qt has been absolutely wonderful to work with. I&amp;#8217;ve done my fair share of consulting over the years and it&amp;#8217;s not often you get so much freedom to work on stuff that&amp;#8217;s both important to your client &lt;em&gt;and&lt;/em&gt; to yourself as we&amp;#8217;ve gotten working while with Qt. Something I think is really a testament to the engineering culture at Qt.&lt;/p&gt;
&lt;p&gt;However, our collaboration with Qt doesn&amp;#8217;t end with Shortcut developing Gitorious. Since Qt wanted to use Gitorious for their contribution model it was only natural that we took care of hosting it as well so they could reap the benefits of a growing community. So they &lt;a href=&quot;http://labs.trolltech.com/blogs/2009/05/11/qt-public-repository-launched/&quot;&gt;launched their contribution model&lt;/a&gt; on Gitorious.org.&lt;/p&gt;
&lt;p&gt;Qt is now the first &amp;#8220;premier hosting&amp;#8221; customer of Gitorious, meaning they get to be a an intregrated part of Gitorious with custom branding for their projects and their own portal at &lt;a href=&quot;http://qt.gitorious.org&quot;&gt;qt.gitorious.org&lt;/a&gt; as well as other infrastructure needed for a big open source vendor, such as digitally signing off contribution agreements. The wonderful thing about this is that it goes full circle back to gitorious.org, with everybody benefitting along the way.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s worth pointing out that in no way is this premier hosting reserved for Qt alone. We don&amp;#8217;t make a big fuzz about it on Gitorious.org, but we&amp;#8217;re open for business from other companies who&amp;#8217;d like to be a part of the growing community and in return pay for things like SLAs, support, reporting and customizations. Stay tuned for more announcements here.&lt;/p&gt;
&lt;h2&gt;The technical details&lt;/h2&gt;
&lt;p&gt;The Gitorious code has received some major overhauls in the past few months. Early on we decided to aim for Ruby 1.9 as the deployment target. That means for the past few months we have been developing 100% on Ruby 1.9. Why? Because &lt;a href=&quot;http://theexciter.com/articles/why-you-should-deploy-your-next-application-on-ruby-1.html&quot;&gt;it&amp;#8217;s the only way we can move forward&lt;/a&gt;. Waiting for someone else is not going to cut it, especially not when the gains are this big, making the gems that break on 1.9 work isn&amp;#8217;t a lot of work, really. The bad news is that if no-one else has done it you have to do it yourself, just don&amp;#8217;t take it as a road-blocker (you do know how to code ruby after all, right?) but as an excuse to actually fix those gems. We did, and as a result &lt;a href=&quot;http://gitorious.org&quot;&gt;Gitorious.org&lt;/a&gt; now runs on Ruby 1.9. I can&amp;#8217;t see what everyone is waiting for, but we seem to be one of the few actually willing to take this step.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re curious about what other changes we&amp;#8217;ve made to Gitorious then head over &lt;a href=&quot;http://blog.gitorious.org/2009/05/09/weve-made-a-few-changes/&quot;&gt;to the Gitorious blog&lt;/a&gt; for the details on faster queuing, multiple repositories per project and namespaced user and team clones.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m really excited about the future of Gitorious and I hope you are as well. If not, then maybe &lt;a href=&quot;http://gitorious.org/gitorious&quot;&gt;consider submitting us a merge request with your patches&lt;/a&gt; if you find a feature lacking or missing. After all, Gitorious is open source for a reason.&lt;/p&gt;
      </content>
   </entry>
  
   <entry>
     <title>Why You Should Deploy Your Next Application on Ruby 1.9 and a Rant in General</title>
     <link href="/articles/why-you-should-deploy-your-next-application-on-ruby-1.html"/>
     <updated>2009-02-25T22:47:43+01:00</updated>
     <id>tag:theexciter.com,2009-02-25:1235598463</id>
     <content type="html">
       &lt;p&gt;No, it&amp;#8217;s not speed. That&amp;#8217;s just icing on the cake. The real reason is more obvious than that; library compatibility.&lt;/p&gt;
&lt;p&gt;Dispite the fact the fact that the Ruby 1.9-preview releases has been out for months, there&amp;#8217;s quite a few gems that&amp;#8217;s not compatible. Rails works fine though. Can you believe that? Rails is better than most of your gems.&lt;/p&gt;
&lt;p&gt;Targeting Ruby 1.9 for your next major deployment of your application (or your next application) is a perfect excuse to do some janitorial duty and make the gems not working 1.9 compatible. Don&amp;#8217;t just report it &lt;a href=&quot;http://isitruby19.com/&quot;&gt;on a site&lt;/a&gt;, fit it! Unless the gem does some hardcore thread scheduling in a C-extentions, chances are it&amp;#8217;ll take you less than half an hour to make the tests pass on 1.9.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://boga.wordpress.com/2008/04/15/ruby-19-porting-notes/&quot;&gt;This post&lt;/a&gt; pretty much cover how you&amp;#8217;ll fix 85% of the gems not working out of the box on 1.9, you&amp;#8217;ll even manage to do it before your coffee is ready.&lt;/p&gt;
&lt;p&gt;I know I&amp;#8217;ll be launching my next application on 1.9. It&amp;#8217;s the only way to move things forward.&lt;/p&gt;
&lt;p&gt;But I can&amp;#8217;t shake this feeling of that something is heading down the wrong path in the Ruby community at large. Nevermind the fact that most of us went &lt;em&gt;&lt;b&gt;oh shi-&lt;/b&gt;&lt;/em&gt; (that sound you&amp;#8217;d make just before the universe blows up) when Ruby 1.9.1-p0 dropped and we &lt;a href=&quot;http://isitruby19.com/&quot;&gt;act all surprised when nothing works&lt;/a&gt;, despite the fact that it&amp;#8217;s been a long time coming, with several preview releases along the way. What&amp;#8217;s more important is that the &lt;em&gt;art of release management&lt;/em&gt; is slowly diminishing in certain parts of our little community. I happen to be of the persuasion that &amp;#8220;just download whatever the current HEAD is&amp;#8221;  isn&amp;#8217;t a proper deployment strategy. My clients sysadmins tend to agree, shuffling the responsibility of security updates back on me if it isn&amp;#8217;t an &amp;#8220;official&amp;#8221; package. And that&amp;#8217;s cool, I can wear both hats; the developer wanting the most whizz-bang for the buck and the sysadmin wanting the most stability-bang for the buck, there&amp;#8217;s a balance in there somewhere. But there&amp;#8217;s still this bearded guy sitting on my shoulder telling me something is wrong.&lt;/p&gt;
&lt;p&gt;You see, I have little interest in spending time maintaining my own personal patches because that&amp;#8217;s not going to scale in time and that&amp;#8217;s not why I use open source to begin with. I have no problem in trusting that to someone who does it proper; spends a little bit of time writing up a release announcement and packages it all up on an pseudo-official community site. The problem is when that person goes away. Not so much the &amp;#8220;why&amp;#8221;, we all move on eventually. But more the &amp;#8220;how&amp;#8221;? Today, there&amp;#8217;s a certain amount of digital paperwork involved; giving away admin permissions on rubyforge/sourceforge/whateverforge, communicating that change and so on. Of course, the post-modern developer might say &amp;#8220;just find a git clone that works&amp;#8221;. Except that means I have to do actual work (!), instead of putting that trust into the hands of the package maintainers, I have to go hunting for updated repositories, audit the code lightly to check if they&amp;#8217;re high on crack or not and generally waste everyones time. There&amp;#8217;s a reason debian (and &lt;em&gt;many&lt;/em&gt; other projects) has successfully done this over the years. Yes, you may complain about the fact that they split up the ruby packages into many. But at least you have somewhere to direct that frustration, to everyones benefit, instead of simply acting nonchalantly and maintain it yourself, but only for as long as you can keep the steam running, thus degrading the system at large.&lt;/p&gt;
&lt;p&gt;The rubyforge gems model may not be perfect, but damnit people, when there&amp;#8217;s a gem update I know that it has actually been tested somewhat and it&amp;#8217;s not just whatever random point HEAD happens to be at, at that point in time, by some random Joe who just bought TextMate.&lt;/p&gt;
      </content>
   </entry>
  
   <entry>
     <title>Touches and UIScrollView inside a UITableView</title>
     <link href="/articles/touches-and-uiscrollview-inside-a-uitableview.html"/>
     <updated>2008-12-28T18:40:07+01:00</updated>
     <id>tag:theexciter.com,2008-12-28:1230486007</id>
     <content type="html">
       &lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; please don&amp;#8217;t don&amp;#8217;t do it like this, it was only needed on iPhoneOS 2.&amp;#215;. A lot have changed in iOS since then and you can &lt;a href=&quot;/articles/scrollview-in-tableview-cell-properly.html&quot;&gt;now do it properly&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/articles/trafikanten-for-the-iphone.html&quot;&gt;&amp;quot;Trafikanten&amp;quot; for the iPhone&lt;/a&gt; is the iPhone incarnation of the betabrite-style signs hanging around Oslo, providing travellers with real-time departure information on busses, trams and subways. So incorporating some of that feeling into the application, while still maintaining that iPhone look n&amp;#8217; feel was a crucial UI design issue for us.&lt;/p&gt;
&lt;p style=&quot;float:right;&quot;&gt;&lt;img src=&quot;http://kunder.shortcut.no/shortcutting/trafikanten-departure.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;A betabrite sign is basically a set of LED lamps that turn on and off in sequences, usually to portray text scrolling across the screen. Bringing this metaphor over to the iPhone means that the user should be able to scroll said text across the screen with his fingers. When this text lives in a subview of UITableView (which in turn is a UIScrollView subclass), there be dragons ahead!&lt;/p&gt;
&lt;p&gt;The thing is, a UITableView takes completely control of the responder chain (and therefore touches) so that it can try and figure out if the user intents to scroll the scrollview, as described in the documentation overview for the UIScrollView class. So in order to be able to scroll part of a single cell sideways, while still being able to scroll the entire tableview up and down, we have to do some careful juggling with events and the responder chain.&lt;/p&gt;
&lt;p&gt;Please observe this artist rendition of the view hierarchy:&lt;br /&gt;
&lt;notextile&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; ______________________
|  UITableView         |
|  __________________  |
| | UITableViewCell  | |
| |  ______________  | |
| | | UIScrollView | | |
| | |______________| | |
| |__________________| |
|  __________________  |
| | UITableViewCell  | |
| |  ______________  | |
| | | UIScrollView | | |
| | |______________| | |
| |__________________| |
|______________________|
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;/notextile&gt;The innermost UIScrollView holds the departure times and it&amp;#8217;s the view we want to be able to move horizontally. It&amp;#8217;s worth pointing out that generally, for UITableViewCells, you&amp;#8217;d want to flatten the view hierarchy as much as posible (e.g. less subviews) to achieve smooth scrolling performance. But in this case we knew that there would always be less than two dozens or so of UITableViewCells displayed in the tableview.&lt;/p&gt;
&lt;p&gt;I created a UIScrollView subclass for the innermost one, that overrides all the &lt;code&gt;touchesMoved:withEvent:&lt;/code&gt; and friends delegates, and then in each one try to figure out which direction an ongoing touch was heading. If the touch went up or down we&amp;#8217;d call super, otherwise &lt;em&gt;pass it along the responder chain&lt;/em&gt; (up to the tableview), so that it can do its thing:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
  if ([self isTouchGoingLeftOrRight:[touches anyObject]]) {
    [super touchesMoved:touches withEvent:event];
  } else {
    [self.nextResponder touchesMoved:touches withEvent:event];
  }
}
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;code&gt;isTouchGoingLeftOrRight:&lt;/code&gt; tries to figure out the general direction of the gesture, by comparing the current location with the previous location, and sets an instance variable that things like &lt;code&gt;touchesEnded:withEvent:&lt;/code&gt; can react to. Make sure to leave some &amp;#8220;wiggle room&amp;#8221; in the direction detection, since the user seldom moves completely linearly.&lt;/p&gt;
&lt;p&gt;So that takes care of that right? We can go up and down, otherwise we pass it along to the next responder. Turns out there&amp;#8217;s one more thing you&amp;#8217;d need to pull out of the sleeve; hit detection.&lt;/p&gt;
&lt;p&gt;We have to override &lt;code&gt;hitTest:withEvent:&lt;/code&gt; on the actual UITableView itself. Remember that it takes control of the responder chain, so the subviews won&amp;#8217;t get a chance to handle it first, unless we explicitly override that behavior:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
  if (self.decelerating) {
    // don't try anything when the tableview is moving..
    return [super hitTest:point withEvent:event];
  }
  
  // Find the cell
  NSIndexPath *indexPathAtHitPoint = [self indexPathForRowAtPoint:point];
  id cell = [self cellForRowAtIndexPath:indexPathAtHitPoint];
  // if the cell has a scrollView property, it's the one we want
  if (cell != nil &amp;&amp; [cell respondsToSelector:@selector(scrollView)]) {
    [[cell scrollView] setScrollEnabled:YES];
    // Return the innermost scrollview
    return (UIView *)[cell scrollView];
  }
  
  return [super hitTest:point withEvent:event];
}
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;code&gt;hitTest:withEvent:&lt;/code&gt; is responsible for telling the system which view that was &lt;em&gt;hit&lt;/em&gt;, by default UITableView assumes itself (or one of its cells), so we have to figure out if the user touches our inner scrollview, and if so return that view instead.&lt;/p&gt;
&lt;p&gt;I can&amp;#8217;t help but feel that there must be a better way of doing this, rather than try and outsmart the UIScrollView&amp;#8217;s intended behaviour. But I guess that&amp;#8217;s the tax for straying just a tad off the beaten path.&lt;/p&gt;
      </content>
   </entry>
  
   <entry>
     <title>Getting Webby With It</title>
     <link href="/articles/getting-webby-with-it.html"/>
     <updated>2008-12-28T17:00:46+01:00</updated>
     <id>tag:theexciter.com,2008-12-28:1230480046</id>
     <content type="html">
       &lt;p&gt;This site have been through its share of blogging systems over the years, wordpress, textpattern and mephisto in recent times. I finally grew tired of trying to bring my now ancient Mephisto install back to life whenever I wanted to write something (thankfully it writes completely cached pages on the frontend).&lt;/p&gt;
&lt;p&gt;I decided to go with something a little more low-fi, and thus comfortable this time around. &lt;a href=&quot;http://webby.rubyforge.org&quot;&gt;Webby&lt;/a&gt; is a nice little website generator framework that generates markup from static text files. No databases and myriad of frameworks to deal with, just plain old textfiles in a git repository with a post-commit hook. Another upside is the fact that I can &amp;#8220;update&amp;#8221; the site during offline periods, like a holiday season like this.&lt;/p&gt;
&lt;p&gt;The only problem with static sites is the fact that they are static; no comments. So I&amp;#8217;m trying out &lt;a href=&quot;http://disqus.com&quot;&gt;Disqus&lt;/a&gt;, even though I hate being dependent on other services like this.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s the script I used to write out all the existing entries from Mephisto:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;require &quot;rubygems&quot;
require &quot;activerecord&quot;

ActiveRecord::Base.establish_connection({
  :adapter =&gt;  &quot;mysql&quot;,
  :database =&gt; &quot;theexciter_mephisto_prod&quot;,
  :username =&gt; &quot;user&quot;,
  :password =&gt;  &quot;pass&quot;,
  :host =&gt; &quot;localhost&quot;,
})

class Content &lt; ActiveRecord::Base; end
class Article &lt; Content
  has_many :comments
end
class Comment &lt; Content
  belongs_to :article
end

Content.find(:all, :conditions =&gt; &quot;type = 'Article'&quot;).each do |article|
  outfile = File.join(File.dirname(__FILE__), &quot;content/articles&quot;, &quot;#{article.permalink}.txt&quot;)
  header = &lt;&lt;-eoh
#{'-'*3}
layout:     post
title:      #{article.title}
created_at: #{article.published_at.to_yaml.sub(/^-\-\-\s/, &quot;&quot;).chomp}
filter:
  - erb
  - textile
#{'-'*3}
eoh
  
  File.open(outfile, &quot;w&quot;) do |f|
    f.puts header
    f.puts
    f.puts article.body
    f.puts
    article.comments.each do |comment|
      # comment markup omitted for brevity
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Changing blog software is the ultimate exercise in yak-shaving, since what you really should be doing is writing posts instead…&lt;/p&gt;
      </content>
   </entry>
  
   <entry>
     <title>&quot;Trafikanten&quot; for the iPhone</title>
     <link href="/articles/trafikanten-for-the-iphone.html"/>
     <updated>2008-12-27T17:30:10+01:00</updated>
     <id>tag:theexciter.com,2008-12-27:1230395410</id>
     <content type="html">
       &lt;p&gt;Looking over my rather stale archives I realize I never wrote about the fact that I started a company together with three other guys back in march, called &lt;a href=&quot;http://shortcut.no&quot;&gt;Shortcut&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So far, we&amp;#8217;ve mostly spent our time on consulting and it&amp;#8217;s still a bigger part of our core business. But we&amp;#8217;ve also struck out into some product development, including acquiring a company that provides white-label mobile services such as SMS/MMS integration solutions. Good fun all around, including having a few employees now and a really exiting next year ahead of us. But enough of that.&lt;/p&gt;
&lt;p&gt;Ever since the iPhone SDK was released, we&amp;#8217;ve all been playing around with it. One of the most useful apps that we could think up for ourselves was something that combined the GPS, network connection and realtime information &lt;em&gt;of some sort&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;We all use public transportation between home, work and pubs. All the busses, tram-lines and subways in Oslo is equipped with a GPS that transmits information on whether they&amp;#8217;re on time or not. This information is then in turn displayed on betabrite-like signs on various stops. However, what we really wanted is being able to get this information regardless on whether you&amp;#8217;re waiting at the actual stop or not.&lt;/p&gt;
&lt;p style=&quot;float:right;&quot;&gt;&lt;img src=&quot;http://kunder.shortcut.no/shortcutting/trafikanten-departure.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Enter the &amp;#8220;Trafikanten&amp;#8221; iPhone app. Using either CoreLocation, searching by name or the recently used list it fetches realtime departure info for the greater Oslo area. Being able decide whether or not to wait another five minutes before walking out into Scandinavia&amp;#8217;s notoriously bad weather is turning out to be pretty damn useful. &lt;br /&gt;
Next to MobileMail, &lt;a href=&quot;http://products.shortcut.no/trafikanten&quot;&gt;Trafikanten&lt;/a&gt; has turned out to be one of the most used applications I have on my iPhone.&lt;/p&gt;
&lt;p&gt;Developing the application was a lot fun, the Cocoa Touch API quickly became familiar from when I dabbled with Cocoa on the desktop, and the framework is overall well thought out. &lt;br /&gt;
But there&amp;#8217;s still a few things that turned out to be slightly non-trivial which I hope to blog some more about. Things such as how UITableView really deals with touches and how to work around it. In the case of the Trafikanten app, each UITableViewCell has information that can be slided sideways to mimic the way the public betabrite-style signs scrolls their departure info across (turns out most users we&amp;#8217;ve tested this on understands the metaphor perfectly) as well as how we did custom font rendering, but had to cut it from the initial release due to unsatisfactional results.&lt;/p&gt;
&lt;p style=&quot;float:left;&quot;&gt;&lt;img src=&quot;http://kunder.shortcut.no/shortcutting/trafikanten-nearby.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;But to be honest, the most important lesson I&amp;#8217;ve learned developing for the iPhone is how much UI matters. Most, if not all, of the slightly &amp;#8220;heated&amp;#8221; discussions we&amp;#8217;ve had internally has been about the UI and interaction, not the actual implementation in code. The device already looks and feels so polished that you&amp;#8217;d feel like a fool pushing out something that looks and feels unpolished.&lt;/p&gt;
&lt;p&gt;After release the application jumped to the number one spot in the &amp;#8220;Top Free Apps&amp;#8221; category of the norwegian App Store, after less than a day out in the wild.&lt;/p&gt;
&lt;p&gt;The application is in Norwegian, and only useful in the general Oslo area. But if you&amp;#8217;re in this area, you now as the chance to always appear superhuman by always arriving &lt;em&gt;exactly&lt;/em&gt; when the bus arrives!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://products.shortcut.no/trafikanten/itms&quot;&gt;iTunes link&lt;/a&gt;&lt;/p&gt;
&lt;hr class=&quot;comment-divider&quot; /&gt;
&lt;div class=&quot;commentsblock&quot;&gt;
&lt;h3 id=&quot;comments&quot;&gt;Comments:&lt;/h3&gt;
&lt;ol class=&quot;commentlist&quot;&gt;
&lt;li class=&quot;alt&quot; id=&quot;comment-741&quot;&gt;
&lt;p&gt;&lt;cite&gt;&lt;a href=&quot;http://blog.youngbloods.org/&quot;&gt;Carl Youngblood&lt;/a&gt;&lt;/cite&gt; Says:&lt;br /&gt;
		&lt;small class=&quot;commentmetadata&quot;&gt;&lt;a href=&quot;#comment-741&quot; title=&quot;&quot;&gt;December 19th, 2008 at 05:20 PM&lt;/a&gt;&lt;/small&gt;&lt;br /&gt;
		&lt;p&gt;Congrats on a great iphone app Johan! We are also starting to develop iphone apps in addition to our Rails work here at Surgeworks. There are even rumors that iphone development in Ruby will someday be possible. Right now it&amp;#8217;s definitely more painful than it needs to be, despite Apple&amp;#8217;s nice &lt;span class=&quot;caps&quot;&gt;SDK&lt;/span&gt;.&lt;/p&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li class=&quot;&quot; id=&quot;comment-742&quot;&gt;
&lt;p&gt;&lt;cite&gt;&lt;a href=&quot;http://derailer.org/&quot;&gt;Wevah&lt;/a&gt;&lt;/cite&gt; Says:&lt;br /&gt;
		&lt;small class=&quot;commentmetadata&quot;&gt;&lt;a href=&quot;#comment-742&quot; title=&quot;&quot;&gt;December 20th, 2008 at 02:05 AM&lt;/a&gt;&lt;/small&gt;&lt;br /&gt;
		&lt;p&gt;Nice job!&lt;/p&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
      </content>
   </entry>
  
   <entry>
     <title>What's interesting about MagLev</title>
     <link href="/articles/whats-interesting-about-maglev.html"/>
     <updated>2008-06-02T21:15:00+02:00</updated>
     <id>tag:theexciter.com,2008-06-02:1212434100</id>
     <content type="html">
       &lt;p&gt;One of the more interesting presentations at this years RailsConf seems (I wasn&amp;#8217;t at the conference myself) to have been &lt;a href=&quot;http://www.avibryant.com/2008/06/maglev-recap.html&quot;&gt;the one about MagLev&lt;/a&gt;. &lt;a href=&quot;http://blog.amber.org/2008/06/01/sacred-cows/&quot;&gt;Lots&lt;/a&gt; of &lt;a href=&quot;http://blog.obiefernandez.com/content/2008/05/maglev-is-gemst.html&quot;&gt;excitement&lt;/a&gt;, a fair bit of koolaid-drinking and a good &lt;a href=&quot;http://fukamachi.org/wp/2008/06/02/maglev-and-the-naiivety-of-the-rails-community/&quot;&gt;round of healty&lt;/a&gt; &lt;a href=&quot;http://headius.blogspot.com/2008/06/maglev.html&quot;&gt;sceptism&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But the real interesting part of MagLev to me isn&amp;#8217;t the claimed performance numbers (though that in itself may be interesting, but not until we know how ruby-conformant the final product is going to be). What&amp;#8217;s really interesting is the Gemstone/S based persistance part of MagLev, along with the distributed VM part, and not at least Gemstone (the company) itself, with a long experience of creating dynamic language VMs.&lt;/p&gt;
&lt;p&gt;And yes, so far it might be mostly koolaid (since none of us outside Gemstone has used it), but I seem to remember a certain Ruby webframework being called samething similar in 2004, and continued to receive trash even after its release. History will probably repeat itself here with the arm-chair experts.&lt;/p&gt;
&lt;p&gt;I for one find traditional relational databases lacking in a lot of problem-domains, that&amp;#8217;s why I&amp;#8217;m interested in (admititly young) projects such as &lt;a href=&quot;http://incubator.apache.org/couchdb&quot;&gt;CouchDB&lt;/a&gt;, &lt;a href=&quot;http://strokedb.com/&quot;&gt;StrokeDB&lt;/a&gt; and &lt;a href=&quot;http://neo4j.org/&quot;&gt;Neo4j&lt;/a&gt;, and anything else that teases my mind with new posibilities. Yes, Facebook, Skype and others scales MySQL/Postgres indeed, but it&amp;#8217;s interesting to note that the reasons for that is probably more developer culture and experience related. While the Gemstone Smalltalk implementation seems to cater more towards wildly enterprising sectors, such as the financial and shipping markets, where the demand is quite different from sending virtual vampires to your friends. Then again, that argument works the other way as well.&lt;/p&gt;
&lt;p&gt;I don&amp;#8217;t think ActiveRecord is no-where near being the perfect way to persist objects, rather I think it&amp;#8217;s one of the better ways to map objects to a relational database. There&amp;#8217;s a small syntactic difference there, between an enhanced class (by inheriting from ActiveRecord::Base) and an object you interact with just as you would with any other object, which in turn is persisted across machines and sessions as those very same pure objects.&lt;/p&gt;
&lt;p&gt;People playing around with a shared global object store made by a company who has been doing it for 15+ years is a good thing. Who knows, &lt;del&gt;maybe&lt;/del&gt; hopefully someone will get inspired to write something new based on ideas we&amp;#8217;ll get from using MagLev. Maybe Seaside (or something similar in spirit) will find its way back to its Ruby roots. Maybe even other Ruby implementation hackers will start to implement something similar to Gemstone at the bottom.&lt;/p&gt;
&lt;p&gt;What&amp;#8217;s also interesting is that Gemstone the company even does this to begin with. I hope it&amp;#8217;s because they see Ruby as something they could help with their dynamic language VM experience. But moreso it might be because they see real business value in Ruby, and being able to provide a fast, scalable platform for enterprises who mgiht feel that Smalltalk is a bit old fashioned for todays developers, but dynamic enough to give them flexibility while being able lean against a &lt;em&gt;vendor&lt;/em&gt;. Of course, I know little of Gemstone the company or their customers, but that that seems to be the tune as of lately.&lt;/p&gt;
&lt;p&gt;From the sounds of it, MagLev is not going to be completely open source, but I&amp;#8217;m with &lt;a href=&quot;http://gilesbowkett.blogspot.com/2008/06/maglev-jruby-and-rubinius-who-will-win.html&quot;&gt;Giles Bowkett&lt;/a&gt; and &lt;a href=&quot;http://fukamachi.org/wp/2008/06/02/maglev-and-the-naiivety-of-the-rails-community/#comment-22087&quot;&gt;Wincent Colaiuta&lt;/a&gt; on this one, while the majority of the Rails community says things &lt;em&gt;should&lt;/em&gt; be F/OSS, that has never stopped them from using mostly closed-source things like Macs and Textmate. As long as it&amp;#8217;s shiny, works great and gets the job done, the majority of Rails developers will happily use it. And that in itself is fine.&lt;/p&gt;
&lt;p&gt;Maybe it&amp;#8217;ll MagLev really will be fast, maybe it&amp;#8217;ll inspire people and make their work enjoyable, maybe it&amp;#8217;ll allow certain applications to scale easier, maybe it&amp;#8217;s persistance model will be a joy to work with. And Maybe, just maybe, it&amp;#8217;ll be &lt;em&gt;friggin&amp;#8217; sweet&lt;/em&gt;. But I, for one, welcome our new Object overlords and can&amp;#8217;t wait to see what they&amp;#8217;re upto because anything doing interesting things to, or with, Ruby is a good thing.&lt;/p&gt;
&lt;hr class=&quot;comment-divider&quot; /&gt;
&lt;div class=&quot;commentsblock&quot;&gt;
&lt;h3 id=&quot;comments&quot;&gt;Comments:&lt;/h3&gt; 
&lt;ol class=&quot;commentlist&quot;&gt;
&lt;li id=&quot;comment-733&quot;&gt;
&lt;cite&gt;&lt;a href=&quot;http://drnicwilliams.com&quot;&gt;Dr Nic&lt;/a&gt;&lt;/cite&gt; Says:
&lt;p&gt;&lt;small class=&quot;commentmetadata&quot;&gt;&lt;a href=&quot;#comment-733&quot; title=&quot;&quot;&gt;Jun 03 at 01:10&lt;/a&gt;&lt;/small&gt;&lt;br /&gt;
Whilst macs + textmate are closed-source they are both very extensible + configurable and have thriving OSS communities built off them, fwiw.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;comment-734&quot;&gt;
&lt;cite&gt;&lt;a href=&quot;http://theexciter.com&quot;&gt;Johan Sørensen&lt;/a&gt;&lt;/cite&gt; Says:
&lt;p&gt;&lt;small class=&quot;commentmetadata&quot;&gt;&lt;a href=&quot;#comment-734&quot; title=&quot;&quot;&gt;Jun 03 at 07:48&lt;/a&gt;&lt;/small&gt;&lt;br /&gt;
Indeed there is, and from the sound of it Maglev will also be partially OSS, so there&amp;#8217;s no reason why the same kind of community couldn&amp;#8217;t be built around it.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;comment-735&quot;&gt;
&lt;cite&gt;&lt;span&gt;David Whittington&lt;/span&gt;&lt;/cite&gt; Says:
&lt;p&gt;&lt;small class=&quot;commentmetadata&quot;&gt;&lt;a href=&quot;#comment-735&quot; title=&quot;&quot;&gt;Jun 03 at 14:23&lt;/a&gt;&lt;/small&gt;&lt;br /&gt;
I actually do not use Textmate or a Mac in large part because they are closed source. That&amp;#8217;s not to say I mind other people using them, but it does make a difference to me.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;comment-736&quot;&gt;
&lt;cite&gt;&lt;a href=&quot;http://tammersaleh.com&quot;&gt;Tammer Saleh&lt;/a&gt;&lt;/cite&gt; Says:
&lt;p&gt;&lt;small class=&quot;commentmetadata&quot;&gt;&lt;a href=&quot;#comment-736&quot; title=&quot;&quot;&gt;Jun 03 at 16:24&lt;/a&gt;&lt;/small&gt;&lt;br /&gt;
Another difference is that we so far haven&amp;#8217;t staked our production applications on close source platforms.  There&amp;#8217;s an easy migration path from textmate to any other editor (and the same is true for all development tools we use), but once you start using the object persistence of maglev, you&amp;#8217;re locked in.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;comment-737&quot;&gt;
&lt;cite&gt;&lt;span&gt;Adrian Madrid&lt;/span&gt;&lt;/cite&gt; Says:
&lt;p&gt;&lt;small class=&quot;commentmetadata&quot;&gt;&lt;a href=&quot;#comment-737&quot; title=&quot;&quot;&gt;Jun 03 at 18:17&lt;/a&gt;&lt;/small&gt;&lt;br /&gt;
I wasn&amp;#8217;t at RailsConf so I didn&amp;#8217;t witness the presentation but I&amp;#8217;m interested mostly in the replicated OODB built into the environment. If the performance was upto par with MRI I would still use something like that. My problem is that it is still something I can&amp;#8217;t get my hands on and who knows when I would be able to. I don&amp;#8217;t mind the business model either as long they only target Fortune 500 companies and poor folks like me can use it. I guess I&amp;#8217;ll have to learn to be patient.&lt;/p&gt;
&lt;p&gt;AEM&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;comment-738&quot;&gt;
&lt;cite&gt;&lt;a href=&quot;http://sensei.coretech.net.au&quot;&gt;sensei&lt;/a&gt;&lt;/cite&gt; Says:
&lt;p&gt;&lt;small class=&quot;commentmetadata&quot;&gt;&lt;a href=&quot;#comment-738&quot; title=&quot;&quot;&gt;Jun 04 at 06:32&lt;/a&gt;&lt;/small&gt;&lt;br /&gt;
Maybe it&amp;#8217;ll sell more copies of GemStone/S ;-) GemStone &lt;strong&gt;is&lt;/strong&gt; bloody awesome.&lt;/p&gt;
&lt;/li&gt;
&lt;p&gt;&lt;/ol&gt;&lt;/div&gt;&lt;/p&gt;
      </content>
   </entry>
  
   <entry>
     <title>Gitorious, so far…</title>
     <link href="/articles/gitorious-so-far.html"/>
     <updated>2008-03-19T01:00:00+01:00</updated>
     <id>tag:theexciter.com,2008-03-19:1205884800</id>
     <content type="html">
       &lt;p&gt;It seems that Git is getting more and more mindshare by the day, which is great because I&amp;#8217;m loving working with it. It&amp;#8217;s a little over three months since I made &lt;a href=&quot;http://gitorious.org&quot;&gt;Gitorious.org&lt;/a&gt; public and I&amp;#8217;ve been having lots of fun with it since then.&lt;/p&gt;
&lt;p&gt;In particular I&amp;#8217;m happy about the wide range of projects there, ruby based projects are in the majority there including semi-official mirrors of both the &lt;a href=&quot;http://gitorious.org/projects/ruby-on-rails&quot;&gt;Rails&lt;/a&gt;, &lt;a href=&quot;http://gitorious.org/projects/rspec&quot;&gt;RSpec&lt;/a&gt; and &lt;a href=&quot;http://gitorious.org/projects/macruby&quot;&gt;MacRuby&lt;/a&gt; projects. But some python things, such as &lt;a href=&quot;http://gitorious.org/projects/gdb-python&quot;&gt;gdb-python&lt;/a&gt;, a bit of &lt;a href=&quot;http://gitorious.org/projects/cl-randist&quot;&gt;lisp&lt;/a&gt; along with some Erlang, C/C++ and two linux kernel mirrors. Good times.&lt;/p&gt;
&lt;p&gt;The last two are interesting because they are some of the biggest git repositories around, yet they only take up about 200 megs worth of diskspace. Heck, take  all the repositories combined on Gitorious, and the cache for the web frontend of gitorious.org is still bigger than those. However neither disk nor bandwidth charges are anywhere near hurting my wallet, and it&amp;#8217;ll stay that way for quite a while. I don&amp;#8217;t contribute as much as I should back to most of the open-source projects I use on a day to day basis at the $dayjob (or otherwise) so I consider Gitorious as my way of giving back. Long term I have some ideas that would allow gitorious to give back even more (&lt;a href=&quot;http://rubymendicant.wikidot.com/proposal&quot;&gt;things like this&lt;/a&gt; is awefully inspiring), without resorting to cheap tricks such as ads all over the place.&lt;/p&gt;
&lt;p&gt;So far, most of my focus on the Gitorious codebase has been on stability and speed (it&amp;#8217;s really quite snappy now I think), but also a few new features such as merge requests and searching. But soon it&amp;#8217;s time to add some of the bigger things on the list, that&amp;#8217;ll help dealing with managing an open source project hosted on Gitorious.&lt;/p&gt;
&lt;p&gt;But first I want to talk about &amp;#8220;the competition&amp;#8221;, namely &lt;a href=&quot;http://github.com&quot;&gt;github&lt;/a&gt;, &amp;#8220;competition&amp;#8221; is in quotes because I honestly don&amp;#8217;t see it like that (git &lt;em&gt;is&lt;/em&gt; distributed after all), however a lot of people seem to lay it out like that whenever the two are mentioned in the same sentence. It says a lot about the workflow that git presents, that we both had the same idea and ran with it, only to release each others thing publicly a week or so apart.&lt;/p&gt;
&lt;p&gt;But I find it slightly peculiar that a lot of open-source projects (ruby/rails projects in particular) has jumped on it, despite it being closed-source. What&amp;#8217;s the point of being &lt;a href=&quot;http://tomayko.com/writings/github-is-myspace-for-hackers&quot;&gt;myspace for hackers&lt;/a&gt; (not that that&amp;#8217;s a particular flattering comparison to begin with) if I can&amp;#8217;t hack on it? But that&amp;#8217;s me being seemlingly more idealistic about this stuff than most people. &lt;a href=&quot;https://launchpad.net/&quot;&gt;Launchpad&lt;/a&gt; is closed-source and seems to be doing well despite it being a total mess to use, and even the Apache Foundation offers their incubator projects an option to use JIRA and/or Confluence (&amp;#8220;The Enterprise Wiki&amp;#8221; &amp;#8212; that cracks me up everytime).&lt;br /&gt;
Anyway, not crying about this at night, just finding it interesting. What&amp;#8217;s really important is that more people discover the advantages of a distributed SCM such as Git, even for internal (&amp;#8220;dayjob&amp;#8221;) projects, regardless of whether they host their code on a third-party server or on their own using &lt;a href=&quot;http://eagain.net/gitweb/?p=gitosis.git&quot;&gt;Gitosis&lt;/a&gt; and gitweb, a custom Gitorious install (I hear there&amp;#8217;s a few already) or just a plain old git repository somewhere.&lt;/p&gt;
&lt;p&gt;I don&amp;#8217;t want Gitorious to end up like the mess that is Launchpad, but I do think there&amp;#8217;s a few good idaes floating around when it comes to dealing with the practicalities of running, or contributing to, an opensource project that&amp;#8217;s worth looking into. In particular the notion of a distributed bug tracking system is too cool to pass up, even if distributed just means that I can track bugs across projects and different repositories. Imagine Jane having cloned Bobs project publicly and fixing that damn bug #2353, all Bob has to do now to fix the bug is to pull in Janes changes into the mainline repository. &lt;a href=&quot;http://youtube.com/watch?v=r8L39UwOS-Y&quot;&gt;Boom&lt;/a&gt;, no need to mess around with patch files.&lt;/p&gt;
&lt;p&gt;Having the ticket system &lt;em&gt;truly&lt;/em&gt; distributed is of course &lt;a href=&quot;http://groups.google.com/group/gitorious/browse_thread/thread/40a541377060cb34&quot;&gt;something to strive for&lt;/a&gt;, but I think I&amp;#8217;ll start with a slightly less lofty target for Gitorious and use tracer bullets from there to hit the sweetspot of a ticketing system that fits git, and humans, well.&lt;/p&gt;
&lt;hr class=&quot;comment-divider&quot; /&gt;
&lt;div class=&quot;commentsblock&quot;&gt;
&lt;h3 id=&quot;comments&quot;&gt;Comments:&lt;/h3&gt; 
&lt;ol class=&quot;commentlist&quot;&gt;
&lt;li id=&quot;comment-725&quot;&gt;
&lt;cite&gt;&lt;a href=&quot;http://tomayko.com/&quot;&gt;Ryan Tomayko&lt;/a&gt;&lt;/cite&gt; Says:
&lt;p&gt;&lt;small class=&quot;commentmetadata&quot;&gt;&lt;a href=&quot;#comment-725&quot; title=&quot;&quot;&gt;Mar 19 at 05:35&lt;/a&gt;&lt;/small&gt;&lt;br /&gt;
Gitorious and GitHub (and repo.or.cz for that matter) definitely compete, IMO, but not in a who-can-make-the-same-exact-widget-most-efficiently type way. There&amp;#8217;s so much room for innovation here and no one service is going to be able to experiment with all the interesting possibilities by themselves.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;d actually like to see you guys collaborate a bit. The &amp;#8220;Associated repositories&amp;#8221; (Gitorious) and &amp;#8220;Network page&amp;#8221; (GitHub) could be so much better for everybody if they were capable of showing all clones everywhere. I realize that information isn&amp;#8217;t really recorded anywhere in a Git repo but it seems like something that could be done with a bit of cooperation.&lt;/p&gt;
&lt;p&gt;Or maybe not. But, ideally, the decision to put repos on GitHub vs. Gitorious should be made based on the service preferred by each individual. Right now, that decision is more likely to be made based on where the repo you&amp;#8217;re cloning resides or where a majority of your collaborators hang out. That seems very much against the spirit of Git.&lt;/p&gt;
&lt;p&gt;With regards to the phenomenon of F/OSS projects choosing GitHub over Gitorious, I&amp;#8217;m afraid I can&amp;#8217;t offer any single explanation, but I do have a few thoughts:&lt;/p&gt;
&lt;p&gt;First, from what I can tell, idealists who care about (or even know about) Freedom 0 are actually a pretty tiny minority of the overall community. And a lot of people who claim to value open development don&amp;#8217;t actually value it when compared to a bunch of other things. It&amp;#8217;s sad, really.&lt;/p&gt;
&lt;p&gt;Next, I&amp;#8217;m not sure we&amp;#8217;re at a place where the benefits of open development outweigh the benefits of focused, opinionated design. It&amp;#8217;s definitely possible to build coherent, usable systems in an open model but you need a BDFL type personality to keep the crack out and you take on some not-insignificant overhead simply maintaining an open project; where, in a closed project, you can go cowboy for a while and focus purely on making the app meet your vision. The benefits of the open model clearly outweigh the benefits of the closed model in the long run but these are early days. (That&amp;#8217;s a general observation &amp;#8211; I&amp;#8217;m not saying GitHub has a more coherent design or anything)&lt;/p&gt;
&lt;p&gt;And finally, even though GitHub and Gitorious were released within a few days of each other, it sure feels like GitHub sucked up a bunch of projects right out of the gate somehow. I have no idea why. I can tell you that when I personally first looked at Gitorious, I somehow missed a whole bunch of great features. I&amp;#8217;m more than willing to accept that it was me not being rigorous enough in my evaluation but if you get the same sort of feedback from others, I&amp;#8217;d say it would be well worth it to spend some time ensuring that the first visit shows off as many of Gitorious&amp;#8217;s features as possible. And, here, I really think its almost entirely about networking &amp;#8211; the project search and code browser and everything that&amp;#8217;s been a part of the forges is damned near irrelevant.&lt;/p&gt;
&lt;p&gt;Keep up the good work, Johan. I&amp;#8217;m absolutely blown away with what you&amp;#8217;ve accomplished so far and am anxious to see what&amp;#8217;s next.&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;comment-728&quot;&gt;
&lt;cite&gt;&lt;a href=&quot;http://theexciter.com&quot;&gt;Johan Sørensen&lt;/a&gt;&lt;/cite&gt; Says:
&lt;p&gt;&lt;small class=&quot;commentmetadata&quot;&gt;&lt;a href=&quot;#comment-728&quot; title=&quot;&quot;&gt;Mar 19 at 13:04&lt;/a&gt;&lt;/small&gt;&lt;br /&gt;
Good comments&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I’d actually like to see you guys collaborate a bit. The “Associated repositories” (Gitorious) and “Network page” (GitHub) could be so much better for everybody if they were capable of showing all clones everywhere. I realize that information isn’t really recorded anywhere in a Git repo but it seems like something that could be done with a bit of cooperation [..]  That seems very much against the spirit of Git.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Me too, it&amp;#8217;s actually been on &lt;a href=&quot;http://gitorious.org/projects/gitorious/repos/mainline/blobs/master/TODO.txt#line32&quot;&gt;the list since the beginning&lt;/a&gt;, but I imagine it no way being specific for repo.or.cz/github/other, just a general remote repository hosted somewhere else. We could even peek at it periodically to fetch recent activity there. It&amp;#8217;s also possible to fetch which remotes that a repository often pull in and display that somehow.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;And a lot of people who claim to value open development don’t actually value it when compared to a bunch of other things. It’s sad, really.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&amp;#8217;m as pragmatic as the next guy when it comes to getting work done, but I view open source and a completely different way, there it&amp;#8217;s a matter of principles for me, and especially so if you&amp;#8217;re marketing whatever you&amp;#8217;re doing as &amp;#8220;suitable for open source projects&amp;#8221;. Anything less is like Al Gore driving around in a Hummer as I see it. But in the end, I supposed all that really matter is that a (F/OSS) project being hosted somewhere produce useful code.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I can tell you that when I personally first looked at Gitorious, I somehow missed a whole bunch of great features. I’m more than willing to accept that it was me not being rigorous enough in my evaluation but if you get the same sort of feedback from others, I’d say it would be well worth it to spend some time ensuring that the first visit shows off as many of Gitorious’s features as possible. And, here, I really think its almost entirely about networking – the project search and code browser and everything that’s been a part of the forges is damned near irrelevant.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That&amp;#8217;s some really good points, and something that&amp;#8217;s been nagging in the back of my head since the start, thanks for putting words to it. The overall UI (as in conveying what it does and general discoverability) needs some &lt;em&gt;uhmph&lt;/em&gt;, and I&amp;#8217;ve put the networking-type things a bit on the backburner in favor of individual per-project features, but maybe it&amp;#8217;s indeed time to change that approach.&lt;/p&gt;
&lt;p&gt;Again, thanks for the comments Ryan!&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;comment-730&quot;&gt;
&lt;cite&gt;&lt;a href=&quot;http://priit.mx.ee&quot;&gt;Priit Tamboom&lt;/a&gt;&lt;/cite&gt; Says:
&lt;p&gt;&lt;small class=&quot;commentmetadata&quot;&gt;&lt;a href=&quot;#comment-730&quot; title=&quot;&quot;&gt;Mar 20 at 08:38&lt;/a&gt;&lt;/small&gt;&lt;br /&gt;
In the service world it gets really fuzzy about open source or not, i&amp;#8217;m still puzzled. However as a programmer I support open source way of doing as much as I can. However as Ryan told for most users it does not matter so much at all as we would like to think (especially in the sort term).&lt;/p&gt;
&lt;p&gt;In my view, there is no need for direct competition, solve only your (or core contributors) needs and visions. If you start competition feature-to-feature basis, you might need some revenue plan to keep things sustainable etc.&lt;/p&gt;
&lt;p&gt;By the way I don&amp;#8217;t mind ads if it is unobtrusive and correctly placed for users (similar to gmail), however aggressive ads would be deal-breakers for sure.&lt;/p&gt;
&lt;p&gt;Thanks for driving gitorious!&lt;br /&gt;
Priit@still.not.yet.so.diligent.committer&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;comment-731&quot;&gt;
&lt;cite&gt;&lt;a href=&quot;http://theexciter.com&quot;&gt;Johan Sørensen&lt;/a&gt;&lt;/cite&gt; Says:
&lt;p&gt;&lt;small class=&quot;commentmetadata&quot;&gt;&lt;a href=&quot;#comment-731&quot; title=&quot;&quot;&gt;Mar 20 at 09:02&lt;/a&gt;&lt;/small&gt;&lt;br /&gt;
In the long term, there&amp;#8217;s definitely a revenue plan (that doesn&amp;#8217;t mean I&amp;#8217;ll have to charge directly for usage) it just doesn&amp;#8217;t make sense to implement it yet since, like I mentioned, the cost is abysmal and a) I need it myself to host my own personal projects, b) I need the app itself (internally) for my company and c) I don&amp;#8217;t mind &amp;#8220;giving back&amp;#8221; in the indirect way it currently does.&lt;/p&gt;
&lt;/li&gt;
&lt;p&gt;&lt;/ol&gt;&lt;/div&gt;&lt;/p&gt;
      </content>
   </entry>
  
   <entry>
     <title>Gitorious source pushed - and a freebie!</title>
     <link href="/articles/gitorious-source-pushed-and-a-freebie.html"/>
     <updated>2008-01-13T19:56:00+01:00</updated>
     <id>tag:theexciter.com,2008-01-13:1200250560</id>
     <content type="html">
       &lt;p&gt;I&amp;#8217;ve pushed the source to &lt;a href=&quot;http://gitorious.org/projects/gitorious&quot;&gt;Gitorious&lt;/a&gt; to&amp;#8230; Gitorious! &lt;a href=&quot;http://rashkovskii.com/&quot;&gt;Yurii&lt;/a&gt; has already made a &lt;a href=&quot;http://gitorious.org/projects/gitorious/repos/yrashk-gitorious-clone&quot;&gt;clone of it&lt;/a&gt; and I think he&amp;#8217;s hacking on some SVN mirroring he needed for one of his projects. Very cool.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve also added a &lt;a href=&quot;http://gitorious.org/projects/tumbline&quot;&gt;project called Tumbline&lt;/a&gt;, which is an 80% done tumblelogging application I wrote during the summer when I was really unhappy about &lt;a href=&quot;http://tumblr.com&quot;&gt;Tumblr&lt;/a&gt; (where I host &lt;a href=&quot;http://application-error.com&quot;&gt;Application Error&lt;/a&gt;), they have since shaped up a bit and I&amp;#8217;ll probably continue using them. But I&amp;#8217;ve open sourced the application I wrote in case someone wants to use it for something, rather than it collecting dust in my &lt;code&gt;~/Projects&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;Enjoy!&lt;/p&gt;
      </content>
   </entry>
 
 
</feed>
