<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2947441758360063609</id><updated>2012-01-24T14:02:22.754-08:00</updated><category term='Me'/><category term='Apple DTS'/><category term='Testers'/><category term='WWDC'/><category term='GCD'/><category term='Performance'/><category term='NSDate'/><category term='Pilgrimage'/><category term='fonts'/><category term='Workshop'/><category term='SQLitePersistentObjects'/><category term='UI'/><category term='UIAlertView'/><category term='iOS4'/><category term='SQLite'/><category term='iPhone OS 3.0'/><category term='Apple'/><category term='Steve-Note'/><category term='KVO'/><category term='NSZombie'/><category term='Code'/><category term='Charity'/><category term='Other'/><category term='dealloc'/><category term='Tech Talks'/><category term='iPhoneSDK'/><category term='OpenGL ES'/><category term='spam'/><category term='Background Processing'/><category term='Debugging'/><category term='Mac OS X'/><category term='Appsterdam'/><category term='Censorship'/><category term='WTF'/><category term='App Store'/><category term='New Category'/><category term='iOS'/><category term='Persistence'/><category term='UITextField'/><category term='3D Models'/><category term='iPhone SDK PNG'/><category term='Threading'/><category term='Mac App Store'/><category term='File Template'/><category term='iPhone Simulator'/><category term='Job Opportunities.'/><category term='Discussion Forums'/><category term='Shaders'/><category term='Macworld Expo'/><category term='App Store.'/><category term='Paired Arrays'/><category term='Subversion'/><category term='Images'/><category term='Google Code'/><category term='Wolf Shirt'/><category term='Tririga'/><category term='Design'/><category term='free code'/><category term='Tips'/><category term='MacTech Magazine'/><category term='Dot Notation'/><category term='Gotcha'/><category term='networking'/><category term='Teaching'/><category term='Object-Oriented Design'/><category term='Sockets'/><category term='ATT'/><category term='ADC'/><category term='Rumors'/><category term='Graphics Programming'/><category term='Tip'/><category term='NSStream'/><category term='NSFetchedResultsController'/><category term='MacBook Air'/><category term='Landscape Mode'/><category term='NSExpression'/><category term='iPhone Applications'/><category term='conferences'/><category term='Blog'/><category term='Code Reuse'/><category term='jailbreak'/><category term='.NET'/><category term='RIM'/><category term='Help'/><category term='blocks'/><category term='GLKit'/><category term='Party'/><category term='Microsoft'/><category term='Xcode'/><category term='HTTP PUT'/><category term='Anaglyphs'/><category term='iOS Development'/><category term='iPhone Developers'/><category term='Gestures'/><category term='ARM'/><category term='CFFoundation'/><category term='Core Data'/><category term='Threads'/><category term='Encryption'/><category term='Ad Hoc Distribution'/><category term='UUID'/><category term='iPhone Apps'/><category term='MapKit'/><category term='Strings'/><category term='goof'/><category term='App Design'/><category term='Steve Jobs'/><category term='UITableViewController'/><category term='Ohter Blogs'/><category term='Library of Congress'/><category term='Blackberry'/><category term='Resources'/><category term='Awards'/><category term='k'/><category term='Core Animation'/><category term='UIImage'/><category term='Learn Cocoa'/><category term='UIView'/><category term='SSL'/><category term='Apple HQ'/><category term='UIImagePickerController'/><category term='comments'/><category term='Duh'/><category term='App Review'/><category term='Scroll Views'/><category term='Software Development'/><category term='iPhone OS'/><category term='iPhone 4s'/><category term='Design Awards'/><category term='Memory Management'/><category term='Google'/><category term='Open Source'/><category term='Bug Reporting'/><category term='Piracy'/><category term='Instruments'/><category term='category'/><category term='NSMutableURLRequest'/><category term='NSConference'/><category term='Clang'/><category term='Daring Fireball'/><category term='Review Process'/><category term='Database'/><category term='virus'/><category term='Marketplace'/><category term='source code'/><category term='Responder Chain'/><category term='Cocoa'/><category term='Clang Static Analyzer'/><category term='Keynote'/><category term='UITableView'/><category term='Reverse Engineering'/><category term='Optimizations'/><category term='Thumb'/><category term='Getting Started'/><category term='New Release'/><category term='A4'/><category term='Speaking'/><category term='Utilities'/><category term='Xcode 4'/><category term='Alert Views'/><category term='mobile'/><category term='Voices That Matter'/><category term='C'/><category term='Amazon'/><category term='predictions'/><category term='Rejected'/><category term='Palm'/><category term='Parsing'/><category term='Briefs'/><category term='NSString'/><category term='MDN'/><category term='Barcodes'/><category term='iPhone SDK 4'/><category term='CGAffineTransform'/><category term='Computer'/><category term='Flash'/><category term='Cocoaheads'/><category term='Community'/><category term='Source'/><category term='iPHone'/><category term='iPhone Dev Center'/><category term='Cocoa Touch'/><category term='NeHe'/><category term='Apress'/><category term='iPod'/><category term='PeopleSoft'/><category term='MultiTouch'/><category term='Beta'/><category term='Mac'/><category term='Quicktime'/><category term='UIPickerView'/><category term='DRM'/><category term='Address Book'/><category term='NSPreciate'/><category term='History'/><category term='Book project'/><category term='iPhone SDK 3'/><category term='Mono'/><category term='Press Releases WTF'/><category term='Blogs'/><category term='Beta Testers'/><category term='NSFileHandle'/><category term='Status'/><category term='Sample Code'/><category term='Adobe'/><category term='Power VR'/><category term='Bill Atkinson'/><category term='UIWebView'/><category term='iPhone SDK'/><category term='Mac Developers'/><category term='Nokia'/><category term='Version Control'/><category term='Web Services'/><category term='Screencast'/><category term='CES'/><category term='Pink Screen of Death'/><category term='XML'/><category term='Developer'/><category term='Exercise'/><category term='multi-core'/><category term='Vacation'/><category term='UIkit'/><category term='Blogger'/><category term='Refactoring'/><category term='Apple Store'/><category term='Pixar'/><category term='HIG'/><category term='Controller Classes'/><category term='products'/><category term='Frameworks'/><category term='Developers'/><category term='Enterprise'/><category term='iPhone SDK Agreement'/><category term='PR'/><category term='Upgrading'/><category term='Taps'/><category term='Rants'/><category term='Random Numbers'/><category term='tutorials'/><category term='Game development'/><category term='Payment'/><category term='screenshot'/><category term='private APIs Google'/><category term='More iPhone 3 Development'/><category term='Palm Pre'/><category term='Other blogs'/><category term='Interface Builder'/><category term='Core Graphics'/><category term='employment opportunities'/><category term='Status Update'/><category term='articles'/><category term='Google Maps'/><category term='PSA'/><category term='Twitter'/><category term='Template'/><category term='Multitasking'/><category term='Award'/><category term='Podcasts'/><category term='iPhone 3GS'/><category term='SuperDB'/><category term='NDA'/><category term='Particle Engine'/><category term='Splash Screen'/><category term='Full Screen'/><category term='Categories'/><category term='Code Signing'/><category term='Windows 7 Phone'/><category term='LLVM'/><category term='iPhone OS 4.0'/><category term='Idle Timer'/><category term='Blender'/><category term='consulting'/><category term='Objective-C'/><category term='Conference'/><category term='Key Value Observing'/><category term='Edit Mode'/><category term='Settings'/><category term='OpenGL. Cocoa'/><category term='Writing'/><category term='Runtime'/><category term='UIColor'/><category term='Idiots'/><category term='Universal'/><category term='Android'/><category term='Contracting'/><category term='Animation'/><category term='Windows 7 Mobile'/><category term='MIsc'/><category term='Licensing'/><category term='snippet'/><category term='NSOperationQueue'/><category term='NSMutableArray'/><category term='Project Template'/><category term='Press Release WTF'/><category term='NSXML'/><category term='iOS SDK'/><category term='REST'/><category term='Free software'/><category term='tutorial'/><category term='Errata'/><category term='iBooks'/><category term='Learn Cocoa on the Mac'/><category term='developer tools'/><category term='YouTube'/><category term='Table Views'/><category term='Search'/><category term='Blogspot'/><category term='iPhone SDK 3.2'/><category term='localizations'/><category term='UIScrollView'/><category term='Delegates'/><category term='Blogging'/><category term='SOAP'/><category term='iPhone OS 3.1'/><category term='Application Store'/><category term='Captain Obvious'/><category term='libxml'/><category term='Stencil'/><category term='3D'/><category term='Properties'/><category term='Xcode Project'/><category term='Defect'/><category term='iPhone 4'/><category term='Stack Overflow'/><category term='Developer Certifications'/><category term='Update'/><category term='Rant'/><category term='Foundation'/><category term='MartianCraft'/><category term='fail'/><category term='iPad'/><category term='Game Programming'/><category term='Stupidity'/><category term='Tablet'/><category term='Snow Leopard.'/><category term='Training'/><category term='Joy of Tech'/><category term='Tricks'/><category term='Treadmill Desk'/><category term='Books'/><title type='text'>iPhone Development</title><subtitle type='html'>Application Development for the iPhone using Apple's official SDK.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://iphonedevelopment.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default?start-index=101&amp;max-results=100'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>762</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-7141484124312417812</id><published>2012-01-24T14:02:00.001-08:00</published><updated>2012-01-24T14:02:22.759-08:00</updated><title type='text'>Wow.</title><content type='html'>Just… &lt;a href="http://www.apple.com/pr/library/2012/01/24Apple-Reports-First-Quarter-Results.html"&gt;wow&lt;/a&gt;. Those are crazy numbers any way you cut it.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-7141484124312417812?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/7141484124312417812'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/7141484124312417812'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2012/01/wow.html' title='Wow.'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-6980027498414562187</id><published>2012-01-23T17:58:00.000-08:00</published><updated>2012-01-23T20:14:22.357-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iBooks'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><title type='text'>How I Learned to Stop Worrying and Love the iBooks Author EULA</title><content type='html'>I've been debating whether to post about the iBooks Author EULA or not. In general, I've been trying to avoid hotly debated and controversial subjects here for the simple fact that those discussions tend to eat up a lot of time and often aren't very productive. My opinion on iBooks Author and iBooks 2 is fairly close to &lt;a href="http://dimsumthinking.com/2012/01/21/a-writers-eula/"&gt;some other&lt;/a&gt; &lt;a href="http://www.subfurther.com/blog/2012/01/20/the-whiny-little-bitch-contingent-meets-ibooks-author/"&gt;authors&lt;/a&gt; I know. Because this is something that's near and dear to my heart, however, I figure it's worth a few words. And with me, a few words is usually more than a few.&lt;br /&gt;&lt;br /&gt;There's been a lot of foofooraw since the iBooks 2 announcement last week. There's been all sorts of stories, tweets, and blog posts about how Apple is going to "steal your work" if you use iBooks Author. There's also been the all-too-familiar refrains of just how evil Apple is. It all seems vaguely familiar. Almost like… almost like we've been here before, what with all the people gnashing their teeth, rending their clothes, and complaining to the heavens about how evil Apple is because of the &lt;strike&gt;developer agreement&lt;/strike&gt; &lt;strike&gt;app store guidelines&lt;/strike&gt; iBooks 2 EULA.&lt;br /&gt;&lt;br /&gt;There's also been a lot of complaints about the fact that Apple is using a proprietary format rather than using and extending ePub 3.&lt;br /&gt;&lt;br /&gt;None of this bothers me terribly. Oh, it's not that there aren't things I would want different if I were King of the World, but the reality is that deciding whether to use iBooks Author is just another business decision for me. Emotional outcries and hyperbole are all well and good, but they don't change the parameters of the decision. Business decisions inherently involve risk, and the risk here is at a level that I'm perfectly comfortable with.&lt;br /&gt;&lt;br /&gt;Before I explain why, though, I want to put up front that I'm not a lawyer. Well, that's not technically true, but I'm not a practicing lawyer and I'm not &lt;strong&gt;YOUR&lt;/strong&gt; lawyer, so don't take anything I say as legal advice. I'm just explaining why I'm not concerned. If &lt;strong&gt;you&lt;/strong&gt; have concerns, you should take those concerns to your lawyer before making up your mind.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The EULA&lt;/h3&gt;Make no mistake, the iBooks 2 EULA is poorly written and vague. The mere fact that people are up in arms is testament to that fact. And if the ambiguity that is there bothers you, &lt;em&gt;don't use it&lt;/em&gt;. There are plenty of tools for creating eBooks, so if you think the risk of Apple "stealing" your work is too high, using another tool solves the problem.&lt;br /&gt;&lt;br /&gt;There are several reasons why I'm perfectly comfortable with &amp;nbsp;the risk involved. In no particular order, those reasons are:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It's simply not in Apple's long-term interest to take ownership of authors' books and Apple can almost always be relied upon to do what's in their own long-term best interest. Getting 30% of every iBook sale means they are motivated to keep authors happy. More than that, though, they need authors to want to write for this new platform in order to establish it as the dominant interactive next-generation eBook platform. Stealing books won't get them to that goal. Suing authors who publish non-interactive versions of their content for other platforms like the Kindle or ePub won't either.&lt;/li&gt;&lt;li&gt;Although the wording is certainly vague enough that you could argue more than one interpretation, the capitalization of "Work" in the EULA (meaning it has a specific contractual meaning) combined with the verbiage, "Work you create with this software" implies that the intent is to restrict only the application-specific output. In other words, the most likely intent as I read it is to cover the proprietary file format used for the new features not supported by other existing eBook platforms.&lt;/li&gt;&lt;li&gt;Even if that weren't the intent, from a purely evidentiary point of view, the other file formats that iBooks Author exports to are open, standard formats and it would be difficult for Apple to prove a particular non-interactive work was "generated" with iBooks Author even if they really did want to try and "steal our books". A PDF generated from iBooks Author would be nearly impossible to distinguish from one generated using Pages by simply copying and pasting the content from iBooks Author .&lt;/li&gt;&lt;li&gt;The EULA contains the following phrase: &lt;em&gt;Title and intellectual property rights in and to any content displayed by or accessed through the Apple Software belongs to the respective content owner.&lt;/em&gt;&amp;nbsp;Basically, it explicitly states that the ownership of any content you create outside of the app and import into it is completely unaffected by any "book stealing" clause, even if such a thing existed. This seems to counter the notion that Apple is trying steal our intellectual property in the first place because unless the words and images were created directly in iBooks (as opposed to being imported from Pages, Word, Photoshop, etc.), Apple would have no claim to the content anyway. Their claim would be limited to the way the content is formatted. Again, from an evidentiary standpoint, it would be incredibly hard for Apple to prove you created the content in iBooks.&lt;/li&gt;&lt;li&gt;The deal we're getting with iBooks Author isn't all that different from the deal we get when using Xcode as iOS developers, and the language of the agreements aren't all that different from each other either, and that's worked out pretty well so far.&lt;/li&gt;&lt;li&gt;And last, but not least, the kicker: Let's say, for giggles, that "book stealing" &lt;strong&gt;was&lt;/strong&gt; Apple's intent, and such an intent was found to be both legal and the actual intent of the contract, and Apple decided to exercise those rights to steal my books. You know what? Even with all that, &lt;em&gt;it's still a hell of a lot better deal than I've ever gotten from a traditional publisher.&lt;/em&gt; Apple is offering 70% of the sale price to me. The most favorable contract I've ever gotten from a publisher starts at 12% of the net price the publisher gets from the distributor, wholesaler, or retailer (which is half or less of the retail price). That percentage does slowly escalate up to 20% if I sell a ton of books, but if I publish a new edition of an existing book, the escalators go back down to 12% and I have to start all over. To put this in more concrete terms, if I were to sell a book in the iBooks Store for $9.99, I would get $6.99 per book sold, which is about four times what I get when one of my current $39.99 books sells, and I'd get that money months sooner. Oh, and guess what? I don't own those books published through a traditional publisher, either. My publisher can even have someone else update the book and can continue to use my name to promote it, even if I don't like the revisions or think the update sucks.&lt;/li&gt;&lt;/ul&gt;You can go on about what Apple "might do" or "could do", but the fact is that contracts aren't magic. If Apple wanted to screw me, there's no doubt they could, with or without this language. They've got a disproportionate amount of power in this contractual relationship because they have the audience and the platform, and they also have a ton of money and lots of really, really good lawyers. If they came after me, the merits of the case would matter little because I couldn't afford to defend myself against them, anyway. That's a risk, sure, but based on my past dealings with Apple, them trying to use the legal system to screw me seems a very remote possibility, and I'm willing to accept that risk. The language of the contract does almost nothing to change the amount of risk here for me. It's little more than a red herring as far as I'm concerned.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;ePub 3 vs. iBooks 2&lt;/h3&gt;&lt;br /&gt;Many people have suggested that Apple should have used the existing ePub 3 standard and worked with the standards body to extend it in whatever ways Apple needed it extended. Instead, they decided to create a proprietary file format using the older ePub 2 specification as a starting point. It is important to note, however, that Apple is not advertising this new format as &lt;em&gt;being&lt;/em&gt; ePub; we only know it's based on ePub 2 because people have reverse engineered the generated .ibooks files.&lt;br /&gt;&lt;br /&gt;Now, I'll be honest. In a perfect world, I'd prefer to see Apple using an open standard here. But, there isn't an existing open standard that does what Apple wanted to do, and working with a standards body to revise existing standards to meet their needs for a yet-to-be-released piece of software would have tipped their hand about the software they were developing. People would have known exactly what Apple was working on from the things they were requesting of the standards body, which would have given competitors an advantage and could have hurt Apple's negotiations with publishers. Apple's culture is steeped in secrecy, and many would argue that this secrecy has been a contributing factor to their repeated successes over the last decade. Anybody who follows the company and understands the way they work knows exactly why they made the choice that they did here. Was it the best choice for Apple? Only time will tell, but there are obvious reasons why they would think it might be.&lt;br /&gt;&lt;br /&gt;It's also important to note that iBooks Author is completely and totally &lt;em&gt;free&lt;/em&gt;. But really, nothing is free. &lt;a href="http://en.wikipedia.org/wiki/TANSTAAFL"&gt;TANSTAAFL&lt;/a&gt;. Developing both a platform to do what iBooks 2 can do and developing a tool to create content for that platform was not a trivial task and Apple almost certainly devoted a lot of resources to getting it done and to getting existing publishers on board. Apple doesn't write software to be nice, they write software to make money. In this case, they're not making money directly, but make no mistake, it was written to make Apple money. The fact that they are not letting people use this free product to compete with them, or to create works for competing platforms should surprise no one. We, as users, authors, and publishers might desire such a tool and might have all sorts of reasons why such a tool would be an awesome thing for us. But so what? I'd like a pink unicorn that farts money. That doesn't mean I should expect somebody else to find one and give it to me for free.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Embrace, Extend, Extinguish&lt;/h3&gt;&lt;br /&gt;Lastly, several people on Twitter have pointed out that Apple's move here seems frighteningly similar to what Microsoft did throughout the nineties with their infamous "embrace, extend, extinguish" campaign. There's definitely some uncomfortable similarities, but I'm not quite ready to put this in the same camp… yet.&lt;br /&gt;&lt;br /&gt;First, iBooks is not the dominant eBook platform, so any suggestion of a monopoly would be silly. Amazon sells far more Kindle books than Apple sells iBooks, and there are other eBook platforms, including Barnes &amp;amp; Noble's Nook, Kobo, and Sony's eReader to name &lt;a href="http://en.wikipedia.org/wiki/Comparison_of_e-book_readers"&gt;just a few of many&lt;/a&gt;. The very idea of embrace, extend, extinguish requires monopoly-like control of a market to be effective, which Apple doesn't remotely have here (yet). There's also been no evidence (yet) of an attempt to "extinguish" the open ePub standard, or to brand the proprietary extended version as the standard. iBooks still supports ePub, and until Apple moves to change that, we're missing the most important and deadly of the three Es, without which there's really no harm, no foul.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The Bottom Line&lt;/h3&gt;To quote the narrator in Peter Pan, "all of this has happened before, and it will all happen again." Many developers railed against the "unfair" restrictions of the iOS developer agreement, the inability to sell apps outside the App Store, and the review process. I'm sure there will be similar teeth-gnashing the next time Apple creates a new market or platform, or revises any of the agreements related to any of the existing ones.&lt;br /&gt;&lt;br /&gt;And certainly, there have been bumps in the road, some of which are still around. But overall, iOS  has proved to be a great platform for developers to be on. The number of iOS devices in the world now numbers in the hundreds of millions, and many of the owners of those devices have shown a willingness to pay for content, including apps, movies, and books. It's not the gold rush the mass media thought it was four years ago, but it has been fertile grounds providing a great many people with a living, including me. &lt;br /&gt;&lt;br /&gt;It's not a perfect place, but personally, there's no other place I'd rather be. The fact that I can now do both of the things I do professionally (write apps and write books) on those same fertile grounds, excites me. The fact that I can do things while writing my books that simply weren't possible before excites me even more. &lt;br /&gt;&lt;br /&gt;Absolutely, things could change in the future, but I'll worry about the future in the future if I need to. For now, I'm happy here and thrilled about the possibilities that iBooks 2 and iBooks Author represent.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-6980027498414562187?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/6980027498414562187'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/6980027498414562187'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2012/01/how-i-learned-to-stop-worrying-and-love.html' title='How I Learned to Stop Worrying and Love the iBooks Author EULA'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-8085038208279268011</id><published>2012-01-09T05:56:00.001-08:00</published><updated>2012-01-09T05:56:56.492-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Code'/><category scheme='http://www.blogger.com/atom/ns#' term='Blog'/><title type='text'>Blog Files</title><content type='html'>As my inbox can well attest this morning, the web server that hosted most of my blog files is gone. I moved all the blog &lt;a href="https://github.com/jlamarche/Old-Blog-Code"&gt;files over to Github&lt;/a&gt;, but forgot to post about the new repository.&lt;br /&gt;&lt;br /&gt;Unfortunately, I just don't have time to go back and update all the old links, but every bit of code that I've posted that's now missing, can be found at GitHub.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://github.com/jlamarche/Old-Blog-Code"&gt;Old code repository at GitHub.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Sorry for the inconvenience.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-8085038208279268011?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/8085038208279268011'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/8085038208279268011'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2012/01/blog-files.html' title='Blog Files'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-3495976215971547430</id><published>2011-12-30T07:41:00.001-08:00</published><updated>2011-12-30T07:41:44.360-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Speaking'/><category scheme='http://www.blogger.com/atom/ns#' term='iOS'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Speaking at MDevCon</title><content type='html'>I'm proud to publicly announce my first speaking opportunity of 2012. I'll be speaking at &lt;a href="http://mdevcon.com/2011/12/30/first-speaker-announced/"&gt;MDevCon&lt;/a&gt; in Amsterdam this year on March 10th. This will be my first trip to Amsterdam and I'm incredibly excited to have the opportunity. I'm so excited, actually, that I'll be staying in the city for several days after the conference to hang out in Appsterdam and visit. When I know exactly which days I'll be in the city, I'll let you know.&lt;br /&gt;&lt;br /&gt;I have one other conference that I've already agreed to speak at this year, but that one hasn't been publicly announced yet, so I can't spill the beans quite yet, but I'm equally excited about that one.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-3495976215971547430?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3495976215971547430'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3495976215971547430'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/12/speaking-at-mdevcon.html' title='Speaking at MDevCon'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-1131802460217747728</id><published>2011-12-29T11:48:00.001-08:00</published><updated>2011-12-29T11:48:15.772-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Treadmill Desk'/><title type='text'>Treadmill Desk Update</title><content type='html'>I'm coming up on the end of my second week using my &lt;a href="http://iphonedevelopment.blogspot.com/2011/12/brilliantly-simple-idea-treadmill-desk.html"&gt;treadmill desk&lt;/a&gt;, albeit two relatively quiet work weeks thanks to the holidays. I haven't put together the plans yet for those who might be interested in building a similar one, but the desk does seem to be holding up well. It's still very sturdy and has been working great for me.&lt;br /&gt;&lt;br /&gt;After a really great first day where I put in over nine miles, my daily averages have backed off a bit to more in the 6-7 mile range and I'm averaging about 800 calories a day burned according to the treadmill. It seems that 1.6 MPH is my sweet spot for being able to type and mouse, though I sometimes go a little slower if I'm tired. I also usually start the morning at about 1.3 MPH, but after about 15 minutes, I'm usually up to 1.6.&lt;br /&gt;&lt;br /&gt;I'm not finding it difficult to work for the most part. In fact, often I feel more alert and able to deal with complex problems. However, late in the day, I often feel just the opposite. I start to get fatigued, and when I do, then I often find that a difficult problem requires me to go over to my sitting desk or else needs to be pushed off until the next morning when I'm fresh. I suspect that this problem will go away as I continue to get used to it and am able to walk longer. &lt;br /&gt;&lt;br /&gt;I currently spend about 4 hours walking, another 1-2 standing at my new desk, and the rest of my workday right now is at my old sitting desk. My goal is to get up to at least 8 hours of walking, but I'm really happy with this so far. It's not hard to do. There's no motivation for me to find. It's just part of my routine. When I go to my office, I start the treadmill. Easy-peazy.&lt;br /&gt;&lt;br /&gt;I'm walking slow enough that I'm not experiencing much in the way of muscle soreness. A tiny bit in my calf last week, but none this week. There are some other problems that go along with the treadmill desk, however. First and foremost, my feet start to hurt something fierce by the end of the day. This week was better than last, and I suspect in a few weeks it will be a non-issue. A lot of it, admittedly, was poor shoe choice. More on that later.&lt;br /&gt;&lt;br /&gt;Another problem with spending this amount of time moving is the potential for chafing and rashes. It goes away relatively quickly if you're smart enough to wear appropriate clothing, which I wasn't at first. If you experience chafing, here's two words to remember: coconut oil. Yep, the kind you buy for cooking. It's a solid at room temperature, but will turn into liquid from the heat of your hands. It's magic for irritated skin and it's also a lubricant. It's better than any lotion or salve I've ever tried.&lt;br /&gt;&lt;br /&gt;I close my office door and open the window while I'm working, even though it's winter and I wear shorts and a t-shirt while working. Even at that, I'm a little warm, but I'm a warm person in general, always have been. I haven't broken out my winter jacket yet this year, so your experience might be different. Nobody I've talked to has mentioned being this warm, so it might just be me.&lt;br /&gt;&lt;br /&gt;This one's important. Get some good walking shoes. Don't wear your existing sneakers or shoes, or worse, don't be stupid and go barefoot or wear sandals, crocs or whatever shoes happen to be closest to you. Good shoes, designed for walking, fitted by somebody who knows WTF they are doing. Four or more hours of walking is a lot of steps you're taking each day. Your feet will thank you.&lt;br /&gt;&lt;br /&gt;So, the big question people probably want to know is: Have I lost weight?&lt;br /&gt;&lt;br /&gt;It's really too early to tell. The scale says I've lost between two and four pounds, but honestly, my weight can fluctuate more than that just from water weight over the course of a single day. I might have lost nothing, or I might have lost more than that. I need more data points before I can form any conclusions. But, I suspect I have lost some. Even with a holiday party last weekend, I've been eating less than normal. I'm not sure if it's psychological or physiological, but I'm hungry less, and when I do eat, I'm tending to eat less and to eat healthier. I also haven't been tempted  by my personal demon, the midnight snack. Well, more like the 2:30am-up-late-coding snack. Part of that may simply be that I'm too tired to work until 2:30am these days, though.&lt;br /&gt;&lt;br /&gt;Overall, I'm declaring the experiment a success already. I'm able to work just as well walking as I am sitting except when I get fatigued, I'm burning calories while I work, and am just generally feeling better than I have in a long time.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-1131802460217747728?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/1131802460217747728'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/1131802460217747728'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/12/treadmill-desk-update.html' title='Treadmill Desk Update'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-8671717511264490927</id><published>2011-12-20T10:47:00.000-08:00</published><updated>2011-12-20T10:52:35.529-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Software Development'/><category scheme='http://www.blogger.com/atom/ns#' term='MIsc'/><category scheme='http://www.blogger.com/atom/ns#' term='Exercise'/><title type='text'>Brilliantly Simple Idea: the Treadmill Desk</title><content type='html'>Software development is not the easiest vocation for getting or staying in shape. For that matter, being part-owner of a relatively young business isn't either. &lt;br /&gt;&lt;br /&gt;I've been steadily putting on weight and getting in worse shape since before the dot com boom. Since we started MartianCraft, I've had very few days off, and my average work day has been probably twelve hours, possibly longer. Every time I try and get into a routine of exercising, something happens: a client emergency, a deadline, a build, a new prospective client, a minor family emergency. When there's not enough hours in the day (and there never are), the exercise was always the first thing to get cut.&lt;br /&gt;&lt;br /&gt;Recently, I came across this &lt;a href="http://www.mayoclinic.org/news2008-rst/4924.html"&gt;brilliantly simple idea&lt;/a&gt; from a Mayo Clinic cardiologist. It's called the Treadmill Desk. Essentially, you replace your chair with a treadmill, and instead of trying to get a good strenuous calorie-burning bout of exercise in a few times a week, you just walk while you're working. You don't walk fast; in fact, you go quite slow. They typically recommend that you walk between one and two miles per hour, which is about half of most people's normal walking speed. This speed allows you to function fairly normally. After just a few minutes, you can type and mouse normally. If it gets hard to type, you back off on the speed a little. It's not a race. It's not even exercise in the traditional sense.&lt;br /&gt;&lt;br /&gt;I'm typing this blog post while walking on a treadmill.&lt;br /&gt;&lt;br /&gt;The goal with this walking is not to break a sweat, but rather to just be in constant motion. You will want your office a touch cooler than normal, though, as even slow walking does raise your body temperature. Despite the low-key nature of the movement, a typical person burns an additional 100 - 130 calories &lt;em&gt;per hour they're at their  desk&lt;/em&gt;. For a typical person working an eight hour day, that's between 800 and 1040 calories per day. If you work longer hours or weigh more than the average person, it's even more calories. Now, think about that. You have to burn approximately 3500 calories to lose a pound of weight, so assuming you don't increase your caloric intake, that's about a pound every three to four days of work, or two pounds a week. For someone working a forty hour week, that's about five pounds a month, or sixty pounds a year without additional exercise or dieting. There's a lot of health benefits that go along with losing extra weight, also. Lower blood pressure, lower cholesterol, lower incidence of several types of cancer.&lt;br /&gt;&lt;br /&gt;If you work more than forty hours a week, the benefits can be even greater, assuming you don't eat more to make up for the extra calories you burn.&lt;br /&gt;&lt;br /&gt;I've talked to a number of people who are using treadmill desks, and the feedback was universally positive. Everybody lost weight – several of them a considerable amount – and all were in better health than when they started. And almost everyone said the following word-for-word phrase to me: "I would never go back to a normal desk".&lt;br /&gt;&lt;br /&gt;After about the third person gave me the same basic story, I was sold. Sign me up! I can do this.&lt;br /&gt;&lt;br /&gt;But there was a problem.&lt;br /&gt;&lt;br /&gt;There are lots of plans for treadmill desks around the Internet and you can actually buy treadmill desks now. But, here's the thing: My primary machine is a Mac Pro with two 27" ACD monitors along with a crap-ton of accessories. I couldn't find any desk for under $5,000 that looked sturdy enough to safely and securely hold the weight of all my gear, and all the plans I found for building one seemed to assume the use of a laptop or small computer with small monitor. &lt;br /&gt;&lt;br /&gt;Because of that big sheet of glass, Apple's monitors are &lt;em&gt;heavy&lt;/em&gt;. Because of that big aluminum case, the Mac Pro is also very heavy. My computer and monitors alone weigh well over a hundred pounds, and I wasn't about to trust that much weight worth that much money to something that looked flimsy or was designed to hold a laptop.&lt;br /&gt;&lt;br /&gt;I experimented for a week using a makeshift treadmill desk with my MacBook Air, and I found the walking and working quite easy to do, but also found myself constantly pining to move back to my desk to use my more powerful machine and bigger monitors. I usually abandoned the treadmill after about two hours when I'd start getting into more hardcore coding, not because of the treadmill, but because of the computer.&lt;br /&gt;&lt;br /&gt;But, that week was enough to convince me that this was a good way to reverse the slow but persistent upward trend in my weight that's marked the last several years of my life. Unfortunately, it also convinced me that I could only make it work if I could find a way to use &lt;em&gt;&lt;strong&gt;my computer&lt;/strong&gt;&lt;/em&gt; while walking. &lt;br /&gt;&lt;br /&gt;So, I decided to build my own desk. Building a sturdy desk this tall (over four feet tall in my case, since I'm 6'3" and will be standing on a treadmill desk that's about 6" high) turned out to be an interesting, but not-entirely-trivial engineering exercise. It took a couple of re-designs and a lot of swearing, but my desk is now done and I've been happily using it for a couple of days now.&lt;br /&gt;&lt;br /&gt;Here's my rig on my desk (excuse the messy office):&lt;br /&gt;&lt;br /&gt;&lt;img alt="Finished 1" border="0" height="557" src="http://lh3.ggpht.com/-EKOCDfwrQEw/TvDQD9jPxEI/AAAAAAAAAzc/qu6cKOTky5g/Finished_1.jpg?imgmax=800" style="display: block; margin-left: auto; margin-right: auto;" title="Finished_1.jpg" width="600" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;i&gt;(Yes, there's a beer bottle in the background. That was my reward for finishing the desk.)&lt;/i&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;After I've been using it for longer and am convinced the design is good, I'll share how I made the desk for anyone who might wish to build one for themselves. &lt;br /&gt;&lt;br /&gt;So far, so good, though. The desk seems to be solid, has no perceptible wobble, and the monitors and computer don't seem to be putting any noticeable strain on it. Yesterday, I walked nearly nine miles at an average of 1.6 mile per hour and had a productive work day. Today's about half over and I've burned a little over 600 calories while fixing two pretty gnarly bugs in client apps. These two days have been enough to convince me that this is going to work. &lt;br /&gt;&lt;br /&gt;By having my good computer on the treadmill desk and my MacBook Air at my regular desk, there's a built-in incentive for me to walk, or at least stand, rather than sit at my desk. I'm simply more productive when I have more screen real estate and a more powerful computer.&lt;br /&gt;&lt;br /&gt;In a week or so, I'll put together a parts list and basic instructions, but the design is pretty basic. 1¼" galvanized pipe makes up the main frame of the desk with ⅛" wire rope and turnbuckles as guy wires to provide additional lateral stability.&lt;br /&gt;&lt;br /&gt;This is &lt;a href="http://www.amazon.com/gp/product/B003X5J1S6" target="_blank"&gt;the treadmill I use:&lt;br /&gt;&lt;img alt="NewImage" border="0" height="300" src="http://lh3.ggpht.com/-W2RnpQteWB8/TvDTqSptzUI/AAAAAAAAAzo/ddeoNm_BfkY/NewImage.png?imgmax=800" style="display: block; margin-left: auto; margin-right: auto;" title="NewImage.png" width="300" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It's designed only for walking, will hold up to 400 pounds, and it's shorter than most treadmills, so it takes up less room. It's not cheap, but it's fairly reasonable for a treadmill at $400, and it can fold up out of the way if you need to. I've been very happy with it so far. While it's not whisper quiet, it's nowhere near as loud as most treadmills I've used, and it has a full set of controls on the handle where you can reach them easily while using it as part of a treadmill desk, which is much nicer than having to awkwardly reach over the desk to the treadmill's console.&lt;br /&gt;&lt;br /&gt;The desk plans (when I post them them) are intended to work with this treadmill, you will probably need to make minor adjustments to use it with other models, as well as account for any height difference.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-8671717511264490927?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/8671717511264490927'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/8671717511264490927'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/12/brilliantly-simple-idea-treadmill-desk.html' title='Brilliantly Simple Idea: the Treadmill Desk'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/-EKOCDfwrQEw/TvDQD9jPxEI/AAAAAAAAAzc/qu6cKOTky5g/s72-c/Finished_1.jpg?imgmax=800' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-8627206652413401011</id><published>2011-11-14T07:30:00.000-08:00</published><updated>2011-11-14T07:30:48.226-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='comments'/><category scheme='http://www.blogger.com/atom/ns#' term='spam'/><title type='text'>Comments Gone</title><content type='html'>I regret to inform you that I've had to completely disable comments on the blog. I had to switch to moderation a while back since the spam detectors were failing to catch anything meaningful. Unfortunately, the rate of spam comments has been accelerating recently to the point where I simply don't have the time to search for the few actual and valid comments in the proverbial haystack of spam.&lt;br /&gt;&lt;br /&gt;I wish I didn't have to do this. I like comments. I like hearing other peoples' takes on things and love it when somebody catches a mistake or proposes a better solution. But, comment moderation has been sucking away what little time I have for the block lately.&lt;br /&gt;&lt;br /&gt;Maybe at some point I'll have the time to transition to software that can handle spam comments better, but I don't right now.&lt;br /&gt;&lt;br /&gt;Sorry it had to be this way. It sucks that there are people in the world who do this shit and ruin things for everyone else.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-8627206652413401011?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/8627206652413401011'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/8627206652413401011'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/11/comments-gone.html' title='Comments Gone'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-3726938798574642525</id><published>2011-11-09T06:20:00.000-08:00</published><updated>2011-11-09T06:20:11.255-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='Flash'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><title type='text'>Flash is Dead. No, Really this Time</title><content type='html'>It appears that &lt;a href="http://www.zdnet.com/blog/perlow/exclusive-adobe-ceases-development-on-mobile-browser-flash-refocuses-efforts-on-html5/19226"&gt;Adobe is going to cease development of mobile Flash&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I'm not ordinarily one to gloat or dwell on I-told-you-sos, but I'm going to make an exception in this one instance. I took an awful lot of heat for those blog rants &lt;a href="http://iphonedevelopment.blogspot.com/2009/08/flash-post-mortem.html"&gt;back&lt;/a&gt;in &lt;a href="http://iphonedevelopment.blogspot.com/2009/08/flash-is-dead-long-live-flash.html"&gt;2009&lt;/a&gt; for saying things like&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;I hate to break it to you, but Flash, as it currently exists, is dead. Oh, it's not going to die quickly, it's going to die a slow painful death precisely because there has been such a large investment of time and money into using it by so many large corporations like Disney. Flash's roots run way too deep for it to disappear quickly.&lt;br /&gt;&lt;br /&gt;Here's the thing, though: Flash is a product of a different generation of computing. It's a product of a world where 90% of the people used one platform, and the bulk of the remaining used another. There was Windows, and there was the Mac. &lt;br /&gt;&lt;br /&gt;[…]&lt;br /&gt;&lt;br /&gt;And now, the world is changing. People are increasingly browsing the web from mobile devices, and unlike the computer world of a decade ago, the mobile computing landscape is not anything like a monoculture or monopoly. There are several viable mobile platforms all competing in that space. We have the iPhone, Blackberry, Palm Pre, Windows Mobile, Android, Symbian and probably others that have slipped my mind. All of these are operating systems currently shipping on phones and all come with browsers. None of them, except a solitary model of Android phone, has Flash.&lt;/i&gt;&lt;/blockquote&gt;&lt;br /&gt;But before I get too smug, you know what? I missed a huge factor in the demise of Flash. I assumed the performance issues they were having back then were simply technical hurdles that would be overcome by Adobe's engineers before long. In the end, the lack of a monoculture was certainly a significant factor in the demise of mobile Flash, but the real nail in the coffin was that Adobe &lt;em&gt;never even got mobile Flash working demonstrably well on a single model on a single platform, let alone working well on the "billions of mobile phones" they were shooting for with the Flash Consortium.&lt;/em&gt; I completely overestimated Adobe's ability to deliver, technically.&lt;br /&gt;&lt;br /&gt;But all is not lost for Flash developers. Adobe has stated that they are going to "refocus" their efforts on allowing Flash to create HTML5 compliant web apps. What a brilliant idea! &lt;br /&gt;&lt;br /&gt;If I may… one last quote from my much-reviled Flash rants:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;But, that doesn't mean there's no hope. There are many ways that Adobe could save Flash/Flex for the mobile world. One way would be to create something like Google's GWT - an environment where some or all of the code gets translated into HTML and Javascript to be run on the client, leaving to a VM only those tasks that can't reasonably be handled that way.&lt;/i&gt;&lt;/blockquote&gt;&lt;br /&gt;I said that back in August 2009 and, frankly, I was kind of stating the obvious. Maybe Adobe should have made me CEO. I doubt I would've done much worse than the current management given the recent &lt;a href="http://www.reuters.com/article/2011/11/09/us-adobe-idUSTRE7A77R220111109"&gt;layoff announcements&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I know people think of me as an Adobe hater. I'm not. More accurately, I'm a disgruntled fan. In the nineties I held Adobe in higher regard than I held Apple (at least Apple before Jobs' return). I adored Photoshop, which I had started using around version 1.5 and which enabled me to make a living for a couple of years. Somehow, in the span of fifteen years, Adobe went from being a company that made amazing things to being a company that made mediocre things that they marketed as amazing. A company that had no focus. A company that churned out new versions of software in order to generate new income, not to meet honest customer demand. I watched a great company become a company that didn't care about being great as long as quarterly profit sheets looked good.&lt;br /&gt;&lt;br /&gt;I, for one, am hoping for a Phoenix-like rise from the ashes on the order of Apple's comeback. Hoping… but not expecting.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-3726938798574642525?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3726938798574642525'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3726938798574642525'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/11/flash-is-dead-no-really-this-time.html' title='Flash is Dead. No, Really this Time'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-7246518721707354835</id><published>2011-10-20T08:26:00.001-07:00</published><updated>2011-10-20T08:26:34.049-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Other blogs'/><title type='text'>Objective-C 2.0 Compiler Directives</title><content type='html'>Steffen Itterheim has posted a &lt;a href="http://www.learn-cocos2d.com/2011/10/complete-list-objectivec-20-compiler-directives/?%2BMaster%2Bcocos2d%2Bfor%2BiPhone%2BGame%2BDevelopment)=#encode"&gt;really nice list of all the Objective-C 2.0 compiler directives&lt;/a&gt; along with examples of how to use them.&lt;br /&gt;&lt;br /&gt;Nice!&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-7246518721707354835?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/7246518721707354835'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/7246518721707354835'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/10/objective-c-20-compiler-directives.html' title='Objective-C 2.0 Compiler Directives'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-2045962082778123155</id><published>2011-10-19T10:32:00.001-07:00</published><updated>2011-10-19T10:32:32.966-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Sample Code'/><category scheme='http://www.blogger.com/atom/ns#' term='GLKit'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL ES'/><title type='text'>GLKit Examples</title><content type='html'>I've added three new projects to my &lt;a href="https://github.com/jlamarche/iOS-OpenGLES-Stuff"&gt;iOS OpenGL ES repository&lt;/a&gt; on GitHub. They are fairly simple examples of how to use &lt;font face="monospace"&gt;GLKit&lt;/font&gt; and &lt;font face="monospace"&gt;GLKBaseEffect&lt;/font&gt;. You can find them in the &lt;a href="https://github.com/jlamarche/iOS-OpenGLES-Stuff/tree/master/GLKit%20Stuff"&gt;GLKit Stuff directory&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;They're kind of rough, but they should be helpful to you if you're just getting started with GLKit and trying to figure out how to use it.&lt;br /&gt;&lt;br /&gt;Thanks to &lt;a href="http://twitter.com/#!/juolgon"&gt;Julián Oliver&lt;/a&gt; for tweeting the solution to a problem I was having getting textures to work with &lt;font face="monospace"&gt;GLKBaseEffect&lt;/font&gt;.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-2045962082778123155?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/2045962082778123155'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/2045962082778123155'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/10/glkit-examples.html' title='GLKit Examples'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-5551420576587177015</id><published>2011-10-18T09:41:00.001-07:00</published><updated>2011-10-18T09:57:44.013-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='free code'/><category scheme='http://www.blogger.com/atom/ns#' term='Objective-C'/><category scheme='http://www.blogger.com/atom/ns#' term='CGAffineTransform'/><title type='text'>CGAffineTransform Additions</title><content type='html'>As you probably know, Apple provides a bunch of functionality for manipulating objects in 2D space using &lt;font face="monospace"&gt;CGAffineTransform&lt;/font&gt;. Oddly, Apple doesn't provide you with a way to extract the scale, transform, and rotation information from a &lt;font face="monospace"&gt;CGAffineTransform&lt;/font&gt; and they don't provide any shearing functionality at all.&lt;br /&gt;&lt;br /&gt;Here are some additional inline functions that I use. This adds the ability to extract component values of the &lt;font face="monospace"&gt;CGAffineTransform&lt;/font&gt; and also adds the ability to create and extract shear information.&lt;br /&gt;&lt;br /&gt;As always, this code is free to use without restriction or limitation, but has no warranty whatsoever. If you fix a bug, feel free to let me know about the fix so I can incorporate the fix.&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source mac_classic"&gt;&lt;span class="source source_c"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_c"&gt;ifndef&lt;/span&gt; __MCP_AFFINE_TRANSFORM_ADDITIONS__&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_macro meta_preprocessor_macro_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_define keyword_control_import_define_c"&gt;define&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_preprocessor entity_name_function_preprocessor_c"&gt;__MCP_AFFINE_TRANSFORM_ADDITIONS__&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c"&gt;import&lt;/span&gt; &lt;span class="string string_quoted string_quoted_other string_quoted_other_lt-gt string_quoted_other_lt-gt_include string_quoted_other_lt-gt_include_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c"&gt;&amp;lt;&lt;/span&gt;CoreGraphics/CoreGraphics.h&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_c"&gt;ifdef&lt;/span&gt; __cplusplus&lt;/span&gt;&lt;br /&gt;&lt;span class="storage storage_modifier storage_modifier_c"&gt;extern&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c"&gt;"&lt;/span&gt;C&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;#endif&lt;br /&gt;&lt;br /&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_macro meta_preprocessor_macro_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_define keyword_control_import_define_c"&gt;define&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_preprocessor entity_name_function_preprocessor_c"&gt;degreesToRadian&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_preprocessor variable_parameter_preprocessor_c"&gt;x&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;)&lt;/span&gt; (M_PI * x / &lt;span class="constant constant_numeric constant_numeric_c"&gt;180.0&lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_macro meta_preprocessor_macro_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_define keyword_control_import_define_c"&gt;define&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_preprocessor entity_name_function_preprocessor_c"&gt;radiansToDegrees&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_preprocessor variable_parameter_preprocessor_c"&gt;x&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;)&lt;/span&gt; (&lt;span class="constant constant_numeric constant_numeric_c"&gt;180.0&lt;/span&gt; * x / M_PI)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="storage storage_modifier storage_modifier_c"&gt;static&lt;/span&gt; &lt;span class="storage storage_modifier storage_modifier_c"&gt;inline&lt;/span&gt; CGAffineTransform&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="variable variable_other variable_other_c"&gt;CGAffineTransformMakeShear&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;CGFloat shearX, CGFloat shearY)&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CGAffineTransformMake&lt;/span&gt;(&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;, shearY, shearX, &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;, &lt;span class="constant constant_numeric constant_numeric_c"&gt;0.f&lt;/span&gt;, &lt;span class="constant constant_numeric constant_numeric_c"&gt;0.f&lt;/span&gt;);&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="storage storage_modifier storage_modifier_c"&gt;static&lt;/span&gt; &lt;span class="storage storage_modifier storage_modifier_c"&gt;inline&lt;/span&gt; CGAffineTransform&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="variable variable_other variable_other_c"&gt;CGAffineTransformShear&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;CGAffineTransform transform, CGFloat shearX, CGFloat shearY)&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;    CGAffineTransform sheared =&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CGAffineTransformMakeShear&lt;/span&gt;(&lt;/span&gt;shearX, shearY);&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CGAffineTransformConcat&lt;/span&gt;(&lt;/span&gt;transform, sheared);&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="storage storage_modifier storage_modifier_c"&gt;static&lt;/span&gt; &lt;span class="storage storage_modifier storage_modifier_c"&gt;inline&lt;/span&gt; CGFloat&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="variable variable_other variable_other_c"&gt;CGAffineTransformGetDeltaX&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;CGAffineTransform transform) &lt;span class="meta meta_block meta_block_c"&gt;{&lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; transform&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.tx&lt;/span&gt;;}&lt;/span&gt;;&lt;br /&gt;&lt;span class="storage storage_modifier storage_modifier_c"&gt;static&lt;/span&gt; &lt;span class="storage storage_modifier storage_modifier_c"&gt;inline&lt;/span&gt; CGFloat&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="variable variable_other variable_other_c"&gt;CGAffineTransformGetDeltaY&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;CGAffineTransform transform) &lt;span class="meta meta_block meta_block_c"&gt;{&lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; transform&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.ty&lt;/span&gt;;}&lt;/span&gt;;&lt;br /&gt;&lt;span class="storage storage_modifier storage_modifier_c"&gt;static&lt;/span&gt; &lt;span class="storage storage_modifier storage_modifier_c"&gt;inline&lt;/span&gt; CGFloat&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="variable variable_other variable_other_c"&gt;CGAffineTransformGetScaleX&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;CGAffineTransform transform) &lt;span class="meta meta_block meta_block_c"&gt;{&lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_support punctuation_whitespace_support_function punctuation_whitespace_support_function_leading punctuation_whitespace_support_function_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_C99 support_function_C99_c"&gt;sqrtf&lt;/span&gt;( (transform&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.a&lt;/span&gt; * transform&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.a&lt;/span&gt;) + (transform&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.c&lt;/span&gt; * transform&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.c&lt;/span&gt;) );}&lt;/span&gt;;&lt;br /&gt;&lt;span class="storage storage_modifier storage_modifier_c"&gt;static&lt;/span&gt; &lt;span class="storage storage_modifier storage_modifier_c"&gt;inline&lt;/span&gt; CGFloat&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="variable variable_other variable_other_c"&gt;CGAffineTransformGetScaleY&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;CGAffineTransform transform) &lt;span class="meta meta_block meta_block_c"&gt;{&lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_support punctuation_whitespace_support_function punctuation_whitespace_support_function_leading punctuation_whitespace_support_function_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_C99 support_function_C99_c"&gt;sqrtf&lt;/span&gt;( (transform&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.b&lt;/span&gt; * transform&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.b&lt;/span&gt;) + (transform&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.d&lt;/span&gt; * transform&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.d&lt;/span&gt;) );}&lt;/span&gt;;&lt;br /&gt;&lt;span class="storage storage_modifier storage_modifier_c"&gt;static&lt;/span&gt; &lt;span class="storage storage_modifier storage_modifier_c"&gt;inline&lt;/span&gt; CGFloat&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="variable variable_other variable_other_c"&gt;CGAffineTransformGetShearX&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;CGAffineTransform transform) &lt;span class="meta meta_block meta_block_c"&gt;{&lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; transform&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.b&lt;/span&gt;;}&lt;/span&gt;;&lt;br /&gt;&lt;span class="storage storage_modifier storage_modifier_c"&gt;static&lt;/span&gt; &lt;span class="storage storage_modifier storage_modifier_c"&gt;inline&lt;/span&gt; CGFloat&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="variable variable_other variable_other_c"&gt;CGAffineTransformGetShearY&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;CGAffineTransform transform) &lt;span class="meta meta_block meta_block_c"&gt;{&lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; transform&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.c&lt;/span&gt;;}&lt;/span&gt;;&lt;br /&gt;&lt;span class="storage storage_modifier storage_modifier_c"&gt;static&lt;/span&gt; &lt;span class="storage storage_modifier storage_modifier_c"&gt;inline&lt;/span&gt; CGFloat&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="variable variable_other variable_other_c"&gt;CGPointAngleBetweenPoints&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;CGPoint first, CGPoint second) &lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;    CGFloat dy = second&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.y&lt;/span&gt; - first&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.y&lt;/span&gt;;&lt;br /&gt;    CGFloat dx = second&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.x&lt;/span&gt; - first&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.x&lt;/span&gt;;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_support punctuation_whitespace_support_function punctuation_whitespace_support_function_leading punctuation_whitespace_support_function_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_C99 support_function_C99_c"&gt;atan2f&lt;/span&gt;(dy, dx);&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="storage storage_modifier storage_modifier_c"&gt;static&lt;/span&gt; &lt;span class="storage storage_modifier storage_modifier_c"&gt;inline&lt;/span&gt; CGFloat&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="variable variable_other variable_other_c"&gt;CGAffineTransformGetRotation&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;CGAffineTransform transform)&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; No exact way to get rotation out without knowing order of all previous operations&lt;br /&gt;&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; So, we'll cheat. We'll apply the transformation to two points and then determine the&lt;br /&gt;&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; angle betwen those two points&lt;br /&gt;&lt;/span&gt;    &lt;br /&gt;    CGPoint testPoint1 =&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CGPointMake&lt;/span&gt;(&lt;/span&gt;-&lt;span class="constant constant_numeric constant_numeric_c"&gt;100.f&lt;/span&gt;, &lt;span class="constant constant_numeric constant_numeric_c"&gt;0.f&lt;/span&gt;);&lt;br /&gt;    CGPoint testPoint2 =&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CGPointMake&lt;/span&gt;(&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_c"&gt;100.f&lt;/span&gt;, &lt;span class="constant constant_numeric constant_numeric_c"&gt;0.f&lt;/span&gt;);&lt;br /&gt;    CGPoint transformed1 =&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CGPointApplyAffineTransform&lt;/span&gt;(&lt;/span&gt;testPoint1, transform);&lt;br /&gt;    CGPoint transformed2 =&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CGPointApplyAffineTransform&lt;/span&gt;(&lt;/span&gt;testPoint2, transform);&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CGPointAngleBetweenPoints&lt;/span&gt;(&lt;/span&gt;transformed1, transformed2);&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_c"&gt;ifdef&lt;/span&gt; __cplusplus&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_c"&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;#endif&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-5551420576587177015?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/5551420576587177015'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/5551420576587177015'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/10/cgaffinetransform-additions.html' title='CGAffineTransform Additions'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-153461112844359866</id><published>2011-10-15T08:08:00.000-07:00</published><updated>2011-10-15T08:26:15.999-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Other blogs'/><title type='text'>Long Live the King</title><content type='html'>Jeff Atwood of Coding Horror has an interesting post today about &lt;a href="http://www.codinghorror.com/blog/2011/10/serving-at-the-pleasure-of-the-king.html"&gt;being a developer for Apple's ecosystem&lt;/a&gt;. We'll leave aside for now the fact that Jeff isn't and has never been an Apple developer and is, in fact, a strong proponent of Microsoft's developer stack. Despite that flaw, I usually enjoy reading Coding Horror. I think Jeff's a smart guy with a lot to offer the world in terms of insight about software development.&lt;br /&gt;&lt;br /&gt;But…&lt;br /&gt;&lt;br /&gt;Jeff's premise today is that third party Apple developers "serve at the pleasure of the king", which is absolutely true. But, he finishes his post by saying he would never develop for Apple's app stores because of the chance of "being thrown under a bus" by Apple. Fair enough, we all have different tolerance levels for things, and his assumption here is essentially correct. Apple developers run a risk of having Apple compete directly with us if our product is successful enough. It happens, perhaps, to .01% of us, but it does happen.&lt;br /&gt;&lt;br /&gt;I want to run with Jeff's metaphor a bit, but first, I need to address a couple of points in his article.&lt;br /&gt;&lt;br /&gt;The first point I want to talk about is his claim that if Microsoft were to ever do something as audacious as release a product with the same features as one of their third party developers&lt;br /&gt;&lt;blockquote&gt;&lt;strong&gt;…developers would be screaming bloody murder&lt;/strong&gt; and rioting in the, er, blogs and web forums.&lt;/blockquote&gt;&lt;br /&gt;Wait… what? Excuse me? What the hell kind of fantasy world does one have to live in to think that Microsoft doesn't, wouldn't, and hasn't competed with their own third-party developers. Microsoft practically made a sport of it in the nineties, and has continued to do it since then, albeit less obnoxiously. I mean, have we forgotten that Microsoft was convicted by both the US and the EU of abusing their monopoly power to compete unfairly. Microsoft used to routinely use their market power to put smaller software companies out of business in order to gain control of a particular niche of the software industry.&lt;br /&gt;&lt;br /&gt;And what were the third party Microsoft developers doing back then? Screaming bloody murder? &lt;br /&gt;&lt;br /&gt;Nope. &lt;br /&gt;&lt;br /&gt;They were defending Microsoft, and understandably so. The hand that feeds and all that. Those developers knew that being assimilated by Microsoft, or being unfairly competed against by Microsoft, were risks of doing business in that particular market and they deemed it worth the risk, much the way that iOS developers do today with Apple.&lt;br /&gt;&lt;br /&gt;The second point that I think needs to be made is Atwood's implied assumption that because Marco Arment isn't up in arms over Safari's &lt;i&gt;Reading List&lt;/i&gt; feature (which duplicates many of &lt;a href="http://www.instapaper.com/"&gt;Instapaper&lt;/a&gt;'s features), and isn't ranting to anybody who will listen, that it means he's "a loyal subject of the king". The implication being that Marco will put up with any treatment that Apple chooses to dish out, no matter how unfair, because he's a good whipping boy.&lt;br /&gt;&lt;br /&gt;Which is a completely inaccurate characterization.&lt;br /&gt;&lt;br /&gt;I don't know Marco personally, but he's one of the very few people I follow on the Internet who has consistently come across like a grown-up. Marco knew that &lt;a href="http://www.cocoanetics.com/2011/06/on-getting-sherlocked/"&gt;getting sherlocked&lt;/a&gt; was a risk he faced by participating in Apple's ecosystem and decided that it was worth the risk. When that risk turned into reality, he accepted the consequences like a grown up. Anyone who could condemn a man for acting maturely should be called out for it, and that's exactly what Jeff is doing here. Marco's response to the Reading List feature was nothing less than admirable.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Virtual Geography&lt;/h3&gt;&lt;br /&gt;Now, back to Jeff's original metaphor of App ecosystems as countries. Let's talk a little bit about the Apple Kingdom and also about the neighboring countries where, as a merchant, you might choose to peddle your wares if the King's terms aren't acceptable to you.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;The Apple Kingdom&lt;/h4&gt;&lt;br /&gt;As Atwood noted, the Apple Kingdom is a monarchy, ruled by a King. By Jeff's own admission, this king is a benign king, making decisions that he feels are best for his citizenry (consumers). He's not perfect, but generally his decisions have served the populace well, and they are happy and prosperous. The Apple Kingdom has beautiful paved roads and a great system of railways, and state-run stores within walking distance of every single citizen in the country. The king has invited even the smallest merchants to use this infrastructure to sell goods in exchange for a small percentage of their income and so long as those merchants follow some guidelines that the King has set (and, admittedly, may periodically change) in order to make sure his citizens have a good experience in his stores.&lt;br /&gt;&lt;br /&gt;The Apple Kingdom is large, and its citizens are fairly affluent. They regularly shop at the King's stores and enjoy buying things there. Even tiny merchants are finding ways to make a comfortable living by being able to reach all the citizens of the country. Sure, not all merchants are succeeding. Even the best roads and stores aren't going to make a poorly run business profitable or get people to buy spoiled produce, but the opportunity is there for any one who wishes to sell goods to do so with minimal overhead and startup costs.&lt;br /&gt;&lt;br /&gt;The King, however, is also something of a merchant himself, and sometimes he will sell at his own stores. He doesn't sell much, but when he does, sometimes he's selling the same types of products as some of the merchants in his kingdom. The King, of course, doesn't have to pay a percentage of his income to use the trains, roads, or stores, though. In even rarer cases, he'll find a product in the stores he likes so much that he wants to provide it to all of his citizens for free, which basically makes it impossible for the original merchant to sell that product any longer.&lt;br /&gt;&lt;br /&gt;Now, the Apple Kingdom is not the only country in the world, and the King doesn't prevent anybody from emigrating or, in fact, even from exporting products to other countries. When deciding whether to pack up and go to another country, you need to make sure that your destination is going to be better than where you are now, so let's look at these other countries.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Androidistan&lt;/H4&gt;The largest neighboring country is an enormous country called Androidistan. Androidistan doesn't have a king, but instead has dozens of local and municipal governments of varying types and quality. Their national system of government is probably best described as anarchy. Androidistan's infrastructure varies greatly from province to province, with some roads and trains being free for anybody to use, and others requiring payment. Many provinces have their own stores where anybody can sell, but it's hard to find what you want and the quality of the goods is generally kind of poor, though there are exceptional products if you're willing to look for them. Unfortunately, there are also dangerous products sitting on the shelves as well. Poisoned produce and other deadly items disguised as legitimate goods.&lt;br /&gt;&lt;br /&gt;Although there's a lot of people in Androidistan, most of them don't really like to buy goods at the government stores. They like to go in and make a meal of the free samples, but most don't really like to actually buy anything and shoplifting is rampant in these stores. In fact, it's often considerably easier to steal a product than to buy it legitimately because many of the stores aren't very well run.&lt;br /&gt;&lt;br /&gt;Most merchants have found they can't make enough money selling their goods in Androidistan's markets, so they've tried placing stickers on their goods advertising other products. Some merchants are making a really good living doing this, but many more aren't even covering their costs.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Windowsland&lt;/h4&gt;&lt;br /&gt;On the other side of the Apple Kingdom is the relatively large country of Windowsland. Windowsland was once prosperous and has a huge amount of industry, but the country has been stagnating somewhat during the recent move toward smaller merchants. The government has recently started updating their infrastructure and building stores modeled after the ones in the Apple Kingdom. Windowsland has started a heavy advertising campaign trying to get merchants to sell their goods there.&lt;br /&gt;&lt;br /&gt;Despite a great infrastructure and clean, brightly-lit stores, Windowsland has been having limited success in moving to the modern age of small merchants. Their large industry is still going strong, though, and in the long run, likely their stores will start to do a good business. Someday.&lt;br /&gt;&lt;br /&gt;Oh, did we mention that Windowsland is also run by a King? He charges the same percent of income to use his railways, roads, and stores, but has placed fewer restrictions on his merchants in an attempt to lure them to sell in his country. Windowsland is a pleasant enough place, but there's just not all that many people going into their stores yet.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;The Democratic Republic of WebOS&lt;/h4&gt;&lt;br /&gt;This small country had huge potential, but recent mismanagement and ineptitude have basically shut the government down. There are a few citizens roaming the streets still in a bit of a daze, but most have left for better-run countries.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;The Blackberry Oligarchy&lt;/h4&gt;&lt;br /&gt;The Blackberry Oligarchy, which actually has two kings, has gone in one generation from prosperous world power to third world country due to its inability to change its ways. Citizens have been leaving this country at an alarming rate and the remaining citizens have little faith that their pair of kings will be able to fix the problems given the frequent power outages and decaying infrastructure.&lt;br /&gt;&lt;br /&gt;There are several other small outlying countries in MobileWorld, but these five pretty much cover the major markets that merchants would want to sell into. &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Epilogue&lt;/h3&gt;&lt;br /&gt;Metaphors are easy to stretch to a point that they become meaningless, and I probably crossed the line a few paragraphs back, but the point is this: all ecosystems have their benefits and their downsides. In the old days of boxed software, instead of a single benign king, you had to deal with a dozen tyrants (software chains) to get your goods on the shelf, and they took more than half the sale price in exchange. If you didn't want to deal with them, you could instead choose to work through a distributor who took another large chunk of your gross income in exchange for dealing with the tyrants on your behalf.&lt;br /&gt;&lt;br /&gt;In every market at every time the risk of competition from a bigger, richer competitor has existed.&lt;br /&gt;&lt;br /&gt;Part of Atwood's argument is that even good Monarchies can go bad. Sure they can. So can good democracies. Let's take what Apple might be someday off the table. We can't fault people for not staging a revolution before there's an actual reason to revolt. &lt;br /&gt;&lt;br /&gt;Whether you do it explicitly or not, going into business means you're accepting certain risks in order to obtain certain rewards. When bad things happen in business — when risks (anticipated or otherwise) turn into actual problems — acting like a twelve year-old and whining to the Internets doesn't make things better. You buck up, find a way to fix it, or move on to something else.&lt;br /&gt;&lt;br /&gt;So, yeah. We Apple developers serve at the pleasure of our King, and we know it. In exchange, we get access to millions of citizens who want to buy our products. A tiny percentage of us will end up competing directly with our king at times, but overall, life is pretty good in the Apple Kingdom for us merchants.&lt;br /&gt;&lt;br /&gt;And, while we'd be glad to have you among our ranks, Jeff, you're more than welcome to pack up your gear and move to a neighboring country if you think life would be better for you there.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-153461112844359866?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/153461112844359866'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/153461112844359866'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/10/long-live-king.html' title='Long Live the King'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-7497954518488122714</id><published>2011-10-10T08:26:00.001-07:00</published><updated>2011-10-10T08:28:44.294-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iPhone 4s'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><category scheme='http://www.blogger.com/atom/ns#' term='iPHone'/><title type='text'>Disappointing</title><content type='html'>So, &lt;a href="http://daringfireball.net/2011/10/thoughts_and_observations_iphone_4s"&gt;like others&lt;/a&gt;, I was tempted to write a defense of the iPhone 4S after all the pundits and naysayers came out last week calling the iPhone 4S "disappointing". I'm glad I never found the time. As it turns out the &lt;a href="http://gigaom.com/apple/apple-more-than-1-million-iphone-4s-sold-in-first-day/"&gt;iPhone 4s doesn't need anybody to stand up for it.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;1,000,000 phones sold on the first day of pre-orders. That's 400,000 more than the iPhone 4. &lt;br /&gt;&lt;br /&gt;And, that's not counting the number that will sell on October 14th when they arrive at the Apple Stores in 7 countries. &lt;br /&gt;&lt;br /&gt;There's also a large batch of countries that don't get the phone until October 28, and a whopping 40 more countries (including China, where new Apple Stores have been shattering sales records lately) that won't get the iPhone 4s until some time in December.&lt;br /&gt;&lt;br /&gt;Yeah. Disappointing. You guys in the media &lt;a href="http://www.bgr.com/2011/10/05/apples-fall-from-grace/"&gt;sure nailed that one&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-7497954518488122714?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/7497954518488122714'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/7497954518488122714'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/10/disappointing.html' title='Disappointing'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-1141822257789513074</id><published>2011-10-06T21:43:00.001-07:00</published><updated>2011-10-06T22:19:38.598-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Steve Jobs'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><title type='text'>Respect &amp; Shame</title><content type='html'>It's been fascinating seeing how many people have responded to the death of Steve Jobs exactly the way I did. It's truly amazing how many people who never met the man feel not just that the world has lost somebody significant but that they themselves have lost a friend.&lt;br /&gt;&lt;br /&gt;Hearing others express exactly what I'm feeling? It helps. And, for the most part, the media has been right there with us, responding to Steve's death by focusing on his impact and the good he has done. &lt;br /&gt;&lt;br /&gt;I really hope seeing how many peoples' lives he has touched is helping Steve's family and friends get through this.&lt;br /&gt;&lt;br /&gt;But not all of the media has chosen to focus on the good. I won't link to any of the actual articles, but Gawker and the New York Times top a short list of media outlets that have chosen to focus on Steve's flaws and to stand up and shout out to anybody who will listen that Steve was… well… human. Imperfect. Flawed.&lt;br /&gt;&lt;br /&gt;There's a custom in modern society that's often called "respect for the dead". It has nothing whatsoever to do with the dead. The dead don't care what you say about them. It's about the living who cared about the dead, and they &lt;b&gt;do&lt;/b&gt;. It's because they care that mourning is such a difficult process. Painful. Sad. It's not a time when you want reminders of the flaws of the person whose absence you are trying to come to terms with.&lt;br /&gt;&lt;br /&gt;No human with with a shred of empathy or decency chooses to publicly criticize the recently departed, famous or otherwise, regardless of how they felt about them. Doing so is an act of cruelty. It's hurtful. Little. It's kicking people hard when they are already as low as they can be.&lt;br /&gt;&lt;br /&gt;For those, like me, who care, but didn't know Steve Jobs personally, people like this are an annoyance. They're just another crass, classless obnoxious Internet loudmouth that we have to make an effort to ignore. &lt;br /&gt;&lt;br /&gt;But for Steve's family, friends, and coworkers… the people who &lt;i&gt;really&lt;/i&gt; knew him, it's a hell of a lot more than that. It breaks my heart to think that they might read those articles.&lt;br /&gt;&lt;br /&gt;Shame on you, New York Times. You're better than that. Shame on you, Gawker. You &lt;i&gt;should&lt;/i&gt; be better than that.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-1141822257789513074?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/1141822257789513074'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/1141822257789513074'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/10/respect-shame.html' title='Respect &amp;amp; Shame'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-3508684072817940247</id><published>2011-10-05T18:16:00.001-07:00</published><updated>2011-10-05T18:16:38.667-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Steve Jobs'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><title type='text'>Sad Mac</title><content type='html'>&lt;img style="display:block; margin-left:auto; margin-right:auto;" src="http://lh3.ggpht.com/-iUeFAjStFaM/Toz8NtsQzTI/AAAAAAAAAzU/dAVEwL45qak/sad-mac.jpg?imgmax=800" alt="Sad mac" title="sad-mac.jpg" border="0" width="157" height="180" /&gt;&lt;br /&gt;&lt;br /&gt;I haven't had much time for blogging lately. I have about a half-dozen unfinished blog posts in my queue, but have been too busy to finish any of them. &lt;br /&gt;&lt;br /&gt;One of the things keeping me busy right now is work for Apple through MartianCraft. This work, in many ways, is a dream come true for me, as I wanted to work for Apple for years and never managed it. &lt;br /&gt;&lt;br /&gt;I started programming on an Apple ][+ in 1980 and Apple has been a part of my life ever since then. I don't need to look much further than the desk I'm sitting at to realize just how much my life has been impacted by this company called Apple started in a garage by two guys named Steve. I make a living using Apple's products and developing for Apple's products, but more importantly, my life is better because of their products.&lt;br /&gt;&lt;br /&gt;I took a few hours away from my desk this evening and returned to the news of Steve Jobs' death. I came back to news that quite literally felt like a kick in the stomach. And I mean literally. My stomach hurts.&lt;br /&gt;&lt;br /&gt;It seems odd to feel this way about a man I never met. I've only once been closer to Steve Jobs than the front section of Moscone West or North, and that was when I accidentally knocked into him on the show floor at MacWorld one year. But I feel like an old friend has died. I'm fighting back tears, and maybe I should be ashamed of that. &lt;br /&gt;&lt;br /&gt;But I'm not.&lt;br /&gt;&lt;br /&gt;Steve died far too young. I think a few tears are in order.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-3508684072817940247?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3508684072817940247'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3508684072817940247'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/10/sad-mac.html' title='Sad Mac'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/-iUeFAjStFaM/Toz8NtsQzTI/AAAAAAAAAzU/dAVEwL45qak/s72-c/sad-mac.jpg?imgmax=800' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-5075815702835646316</id><published>2011-08-12T06:55:00.000-07:00</published><updated>2011-08-12T06:58:42.604-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Sample Code'/><category scheme='http://www.blogger.com/atom/ns#' term='Objective-C'/><category scheme='http://www.blogger.com/atom/ns#' term='Book project'/><category scheme='http://www.blogger.com/atom/ns#' term='New Category'/><title type='text'>Online Session Code for Big Objects (Plus a Warning)</title><content type='html'>In Chapter 9 of &lt;em&gt;More iPhone Development&lt;/em&gt;, we wrote a set of classes that mimicked the behavior of GameKit's peer-to-peer connectivity, but for regular network connections (GameKit's only works with BlueTooth and local network connections). Basically, we wrote a class that lets you send and receive anything that can be packaged into an instance of &lt;font face="monospace"&gt;NSData&lt;/font&gt;. Since it's relatively trivial to implement &lt;font face="monospace"&gt;NSCoding&lt;/font&gt; for most classes, this means passing objects between two iOS apps (or an iOS and a Mac app) becomes pretty easy. You don't have to poll for the data, or worry about chunking out the data. You just make a method call and pass an &lt;font face="monospace"&gt;NSData&lt;/font&gt; instance to send data, and then implement a delegate method for receiving data back from the other end. Life is good, right?&lt;br /&gt;&lt;br /&gt;Hmm...&lt;br /&gt;&lt;br /&gt;Maybe not. There's a pretty big limitation in the book's implementation. That implementation, designed for passing tiny packets of data (TicTacToe game moves), kept everything in memory. If you try to send a good size image to the other connection, likely you'd run out of memory fairly quickly.&lt;br /&gt;&lt;br /&gt;A while back, I faced exactly that situation. For a kiosk app that MartianCraft was writing for a client, I needed to send large images shot with a DSLR camera from a Mac Cocoa program to an iPad program and also needed to send pictures taken with the iPad's camera back to the Mac Cocoa app. These images, compressed, ranged from about one to about five megs. I grabbed the &lt;font face="monospace"&gt;OnlineSession&lt;/font&gt; class from &lt;em&gt;More&lt;/em&gt;, figuring I had the network code basically done, and watched my application go down in a blaze of… well… not glory, that's for sure. Not only did the iPad run out of memory, it ran out of memory &lt;strong&gt;FAST&lt;/strong&gt;… much faster than I expected. Even sending the smaller iPad camera images often caused low-memory crashes.&lt;br /&gt;&lt;br /&gt;There were two basic problems with the &lt;font face="monospace"&gt;OnlineSession&lt;/font&gt; class when you try to use it for sending larger volumes of data. First, as I said, was that it relied only on physical memory. Given that the physical limitations of the original iPad, this was problematic. But there was another, much bigger problem. &lt;br /&gt;&lt;br /&gt;The second issue was that during the process of chunking up the data to send, the code kept making unnecessary copies of the data. Put simply, I made a n00b mistake. The mistake didn't impact the TicTacToe application because the game moves would easily fit into the send buffer, but it's a mistake I've made before and definitely should've known better. &lt;br /&gt;&lt;br /&gt;So, what, specifically, was this mistake, you ask?&lt;br /&gt;&lt;br /&gt;Using &lt;font face="monospace"&gt;NSData&lt;/font&gt;'s regular convenience constructor &lt;font face="monospace"&gt;dataWithBytes:length:&lt;/font&gt; when creating the new &lt;font face="monospace"&gt;NSData&lt;/font&gt; instance to store the portion of the image that won't fit into the send buffer. If you read the description of &lt;font face="monospace"&gt;dataWithBytes:length:&lt;/font&gt;, it very clearly says that it makes a copy of the data you provide. So, every time a packet was sent, the code would create a new &lt;font face="monospace"&gt;NSData&lt;/font&gt; instance to hold the remainder that wouldn't fit in the buffer, &lt;em&gt;and it would copy all the remaining unsent data for every packet.&lt;/em&gt; Ouch.&lt;br /&gt;&lt;br /&gt;So, as a simple example, if we were sending a 5 meg image, and the send buffer was set to 128k, the code would make a 4.825 meg copy after the first packet was sent, then a 4.75 meg copy after the second packet was sent, a 4.265 meg copy after the third packet, and so on. After every packet, another slightly smaller copy of the data was made. A descending progression that would eat up memory fast.&lt;br /&gt;&lt;br /&gt;After a lot of swearing at myself, I made some modifications to the class to do two things. &lt;br /&gt;&lt;br /&gt;First, I switched to using &lt;font face="monospace"&gt;NSData&lt;/font&gt;'s &lt;font face="monospace"&gt;dataWithBytes:NoCopy:length:&lt;/font&gt;, which uses the provided data in place without making a copy. This kept the memory footprint a lot smaller. In some instances, because the DSLR images were so large and our app needed to send so many, I still hit memory problems. So, the second thing I did was to add filesystem caching of the outbound queue so that all the encoded objects waiting to be sent didn't have to fit in memory for the application to function properly.&lt;br /&gt;&lt;br /&gt;The new version of the class functions exactly as the one from the book, so you should be able to just drop-in replace the &lt;font face="monospace"&gt;OnlineSession&lt;/font&gt; from Chapter 9 with this one without making any changes to your application code.&lt;br /&gt;&lt;br /&gt;You can download the new version &lt;a href="http://innerloop.biz/code/New%20OnlineSession.zip"&gt;right here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-5075815702835646316?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/5075815702835646316'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/5075815702835646316'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/08/online-session-code-for-big-objects.html' title='Online Session Code for Big Objects (Plus a Warning)'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-3197556901130196505</id><published>2011-07-26T14:25:00.001-07:00</published><updated>2011-07-26T14:25:17.133-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MartianCraft'/><title type='text'>Working for MartianCraft</title><content type='html'>In case you missed my tweets earlier this week, MartianCraft is looking to add a few developers. We're looking for a couple of experienced developers, and are also thinking about bringing in one or two entry-level devs without significant experience to be trained up.&lt;br /&gt;&lt;br /&gt;Initially, the work would be project-based contracting and would start in late August. Conversion to full-time employment is a possibility, but not right away. &lt;br /&gt;&lt;br /&gt;If you're interested in being considered, send an e-mail with relevant work experience and/or résumé/CV to &lt;a href="mailto:work@martiancraft.com"&gt;work@martiancraft.com&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-3197556901130196505?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3197556901130196505'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3197556901130196505'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/07/working-for-martiancraft.html' title='Working for MartianCraft'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-6590563171955180205</id><published>2011-07-14T06:16:00.000-07:00</published><updated>2011-07-14T07:28:03.159-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tips'/><category scheme='http://www.blogger.com/atom/ns#' term='Xcode 4'/><title type='text'>Auto-Incrementing Build Numbers for Release Builds in Xcode</title><content type='html'>I use the wonderful &lt;a href="http://testflightapp.com/"&gt;Test Flight&lt;/a&gt; to distribute builds. One thing that Test Flight is a little picky about is build numbers. When you upload a build, it uses the build number to see if you're uploading a replacement or a new build. It will let you create a new build even if you don't remember to increment the build number, but it's an extra manual step, and then you end up with two builds with the same build number.&lt;br /&gt;&lt;br /&gt;Because I'm forgetful, I wanted to automated this process. Basically, I wanted to increment the version short string any time we do an Archive and increment the bundle build ID any time we do a Release configuration build, but leave the version numbers alone on Debug builds.&lt;br /&gt;&lt;br /&gt;Unfortunately, several of our projects are ones that we inherited or took over, so not every project uses the same version numbering scheme. How we increment 1.0b5 is different from how we increment 1.0.12, or a simple build number like 1058.&lt;br /&gt;&lt;br /&gt;The way I deal with this is a Run Script Build Phase in my application's executable target that runs the following Ruby script (make sure you set the "shell" field to &lt;span style="font-family: monospace;"&gt;/usr/bin/ruby&lt;/span&gt;, and make sure the script is the last build phase in the application). Feel free to use this script if you wish and modify it to meet your needs. If you improve it, I'd be glad to incorporate improvements back into it. One item of note: the way that I differentiate between Archive builds and other Release configuration builds might be a bit fragile since I'm relying on an undocumented naming pattern in an environment variable. &lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;b&gt;Note&lt;/b&gt;: I'm aware of &lt;span style="font-family: monospace;"&gt;agvtool&lt;/span&gt;. I avoided it for two reasons. First, I wanted more control over the numbering schemes, and second, I tried using &lt;span style="font-family: monospace;"&gt;agvtool&lt;/span&gt; in a build script a few years back, but at that time, there were issues when you bumped the version numbers of a project that was currently open. Those issues may have been resolved, but I didn't want to fight that battle again.&lt;/blockquote&gt;&lt;br /&gt;&lt;pre class="textmate-source mac_classic"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;get_file_as_string&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;(&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby"&gt;filename&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    data &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    f &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;File&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;open&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;filename&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;r&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;br /&gt;    f&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;each_line &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;line&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;br /&gt;        data &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby"&gt;+=&lt;/span&gt; line&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_pseudo-method keyword_control_pseudo-method_ruby"&gt;return&lt;/span&gt; data&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;handle_alpha_beta&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;(&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby"&gt;old_value&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; letter&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; infoplist&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; start_of_value&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; end_of_value&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    parts &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; old_value&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;split&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;letter&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;    version_num &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; parts&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;0&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;br /&gt;    alpha_num &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; parts&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_i&lt;br /&gt;&lt;br /&gt;    alpha_num &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; alpha_num &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;&lt;br /&gt;    new_version &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; version_num&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_s &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; letter &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; alpha_num&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_s&lt;br /&gt;    print &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;Assigning new version: &lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; new_version &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;&lt;span class="constant constant_character constant_character_escape constant_character_escape_ruby"&gt;\n&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    new_key &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;&amp;lt;string&amp;gt;&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;new_version&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&amp;lt;/string&amp;gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    part_1 &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; infoplist&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;0&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; start_of_value &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;-&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;&amp;lt;string&amp;gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;length&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_statement punctuation_separator_statement_ruby"&gt;;&lt;/span&gt;&lt;br /&gt;    part_2 &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; new_key &lt;br /&gt;    part_3 &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; infoplist&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;end_of_value &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;&amp;lt;/string&amp;gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;length&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; infoplist&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;length &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;-&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;end_of_value &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;-&lt;/span&gt; start_of_value &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;new_key&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;length &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;-&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;))&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;    &lt;br /&gt;&lt;br /&gt;    new_info_plist &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; part_1 &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; part_2 &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; part_3&lt;br /&gt;    new_info_plist&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;find_and_increment_version_number_with_key&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;(&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby"&gt;key&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; infoplist&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    start_of_key &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; infoplist&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;index&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;key&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;    start_of_value &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; infoplist&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;index&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;&amp;lt;string&amp;gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; start_of_key&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;&amp;lt;string&amp;gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;length&lt;br /&gt;    end_of_value &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; infoplist&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;index&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;&amp;lt;/string&amp;gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; start_of_value&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;    old_value &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; infoplist&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;start_of_value&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; end_of_value &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;-&lt;/span&gt; start_of_value&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    print &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;Old version for &lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; key &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;: &lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; old_value &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;&lt;span class="constant constant_character constant_character_escape constant_character_escape_ruby"&gt;\n&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    print old_value&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;class&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_s &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;&lt;span class="constant constant_character constant_character_escape constant_character_escape_ruby"&gt;\n&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    old_value_int &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; old_value&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_i&lt;br /&gt;    print old_value_int&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;class&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_s &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;&lt;span class="constant constant_character constant_character_escape constant_character_escape_ruby"&gt;\n&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;if&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;old_value&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;index&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;a&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;!=&lt;/span&gt; &lt;span class="constant constant_language constant_language_ruby"&gt;nil&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; alpha&lt;br /&gt;&lt;/span&gt;        infoplist &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; handle_alpha_beta&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;old_value&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;a&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; infoplist&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; start_of_value&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; end_of_value&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;elsif&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;old_value&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;index&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;b&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;!=&lt;/span&gt; &lt;span class="constant constant_language constant_language_ruby"&gt;nil&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; beta&lt;br /&gt;&lt;/span&gt;        infoplist &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; handle_alpha_beta&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;old_value&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;b&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; infoplist&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; start_of_value&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; end_of_value&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;elsif&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;old_value&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;index&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;.&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;!=&lt;/span&gt; &lt;span class="constant constant_language constant_language_ruby"&gt;nil&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; release dot version&lt;br /&gt;&lt;/span&gt;        parts &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; old_value&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;split&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;.&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;        last_part &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; parts&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;last&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_i&lt;br /&gt;        last_part &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; last_part &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;&lt;br /&gt;        parts&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;delete&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;parts&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;last&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        new_version &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        first &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="constant constant_language constant_language_ruby"&gt;true&lt;/span&gt;&lt;br /&gt;        parts&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;each &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;one_part&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;br /&gt;            &lt;span class="keyword keyword_control keyword_control_ruby"&gt;if&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;first&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;                first &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="constant constant_language constant_language_ruby"&gt;false&lt;/span&gt;&lt;br /&gt;            &lt;span class="keyword keyword_control keyword_control_ruby"&gt;else&lt;/span&gt;&lt;br /&gt;                new_version &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; new_version &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;.&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;            new_version &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; new_version &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; one_part&lt;br /&gt;        &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;        new_version &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; new_version&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_s &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;.&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; last_part&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_s&lt;br /&gt;        print &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;New version: &lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; new_version&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_s &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;&lt;span class="constant constant_character constant_character_escape constant_character_escape_ruby"&gt;\n&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        new_key &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;&amp;lt;string&amp;gt;&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;new_version&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&amp;lt;/string&amp;gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        infoplist &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;infoplist&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;0&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; start_of_value &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;-&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;&amp;lt;string&amp;gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;length&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}#{&lt;/span&gt;new_key&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}#{&lt;/span&gt;infoplist&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;end_of_value &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;&amp;lt;/string&amp;gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;length&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; infoplist&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;length &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;-&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;end_of_value&lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;elsif&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;old_value&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_i &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;!=&lt;/span&gt; &lt;span class="constant constant_language constant_language_ruby"&gt;nil&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; straight integer build number&lt;br /&gt;&lt;/span&gt;        new_version &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; old_value&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_i &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;&lt;br /&gt;        print &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;New version: &lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; new_version&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_s &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;&lt;span class="constant constant_character constant_character_escape constant_character_escape_ruby"&gt;\n&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        new_key &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;&amp;lt;string&amp;gt;&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;new_version&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&amp;lt;/string&amp;gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        part_1 &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; infoplist&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;0&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; start_of_value &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;-&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;&amp;lt;string&amp;gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;length&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;br /&gt;        part_2 &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; new_key&lt;br /&gt;        part_3 &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; infoplist&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;end_of_value &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;&amp;lt;/string&amp;gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;length&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; infoplist&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;length &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;-&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;end_of_value&lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;br /&gt;        infoplist &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; part_1 &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; part_2 &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; part_3&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt; &lt;br /&gt;    infoplist&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;config &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="meta meta_environment-variable meta_environment-variable_ruby"&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;ENV&lt;/span&gt;[&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;CONFIGURATION&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;upcase&lt;br /&gt;config_build_dir &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="meta meta_environment-variable meta_environment-variable_ruby"&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;ENV&lt;/span&gt;[&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;CONFIGURATION_BUILD_DIR&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;archive_action &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="constant constant_language constant_language_ruby"&gt;false&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;if&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;config_build_dir&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;include?&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;ArchiveIntermediates&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;))&lt;/span&gt;&lt;br /&gt;    archive_action &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="constant constant_language constant_language_ruby"&gt;true&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;print &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;Archive: &lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; archive_action&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_s &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;&lt;span class="constant constant_character constant_character_escape constant_character_escape_ruby"&gt;\n&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;print config&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;if&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;config &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;==&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;RELEASE&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;    print &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt; incrementing build numbers&lt;span class="constant constant_character constant_character_escape constant_character_escape_ruby"&gt;\n&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    project_dir &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="meta meta_environment-variable meta_environment-variable_ruby"&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;ENV&lt;/span&gt;[&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;PROJECT_DIR&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;]&lt;/span&gt;&lt;br /&gt;    infoplist_file &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="meta meta_environment-variable meta_environment-variable_ruby"&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;ENV&lt;/span&gt;[&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;INFOPLIST_FILE&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;]&lt;/span&gt;&lt;br /&gt;    plist_filename &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;project_dir&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;/&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;infoplist_file&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    infoplist &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; get_file_as_string&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;plist_filename&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;    infoplist &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; find_and_increment_version_number_with_key&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;CFBundleVersion&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; infoplist&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;if&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;archive_action&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;        infoplist &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; find_and_increment_version_number_with_key&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;CFBundleShortVersionString&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; infoplist&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class="support support_class support_class_ruby"&gt;File&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;open&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;plist_filename&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;w&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;f&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt; f&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;write&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;infoplist&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;else&lt;/span&gt;&lt;br /&gt;    print &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt; not incrementing build numbers&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-6590563171955180205?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/6590563171955180205'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/6590563171955180205'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/07/auto-incrementing-build-numbers-for.html' title='Auto-Incrementing Build Numbers for Release Builds in Xcode'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-1146873698521217431</id><published>2011-07-07T10:08:00.000-07:00</published><updated>2011-07-07T10:08:40.545-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Book project'/><title type='text'>Happenings and Prospects</title><content type='html'>I apologize for the relative dearth of posts here since WWDC. That week in San Francisco always tends to backlog me pretty badly (I returned from WWDC at inbox 1138 - and that's after spending the return flight answering e-mails), so I've been pretty much heads down on work-related stuff ever since. I've also, at the same time, been consciously trying to back away from the 12-15 hour days, 7 days a week schedule that I'd fallen into trying to help get MartianCraft off the ground. Those two have conspired to give me very little time for writing lately, but I think things are under control now.&lt;br /&gt;&lt;br /&gt;I've got my&amp;nbsp;semi-mythical OpenGL ES from the Ground Up 10th installment on skeletal animation nearly finished and hope to have it posted within the next couple of weeks, and it's bit of a doozy. My goal with this post is to make one of the more intimidating topics in graphics programming approachable. Fingers crossed, it's been a challenge making this topic approachable, but I think I'm getting there.&lt;br /&gt;&lt;br /&gt;A few other bits of news.&lt;br /&gt;&lt;br /&gt;First, work has officially started on &lt;i&gt;Beginning iPhone 5 Development&lt;/i&gt;. Yes, I know it probably should be called &lt;i&gt;Beginning iOS 5 Development&lt;/i&gt;, but as of right now, we're sticking with the naming sequence Apress established with the first book. Dave, Jack, and I have already started updating the book for Xcode 4, ARC, Storyboards, and all the other cool new stuff and are hoping to have the book ready to go to press when the GM version of iOS 5 ships this fall.&lt;br /&gt;&lt;br /&gt;Second, I purchased a new domain today. There's nothing there yet, but&amp;nbsp;&lt;a href="http://OpenGLESBook.com/"&gt;OpenGLESBook.com&lt;/a&gt; is now mine, and I have big plans for it. Once &lt;i&gt;Beginning iPhone 5 Development&lt;/i&gt;&amp;nbsp;is in the can, I'm going to revisit my partially written OpenGL ES 2.0 book. I plan to revise it to use GLKit and to add material about the very cool new OpenGL ES tools we're getting with iOS 5.&lt;br /&gt;&lt;br /&gt;As of right now, my plan is to self-publish. I'm still researching the exact process, tools, and services that I'll use, but my plan is to sell the book without DRM and at a reasonable price. I'd like to have an early access program, however since a lot of the material I'll be covering will be under NDA until iOS 5 goes GM, I can't promise that at this time.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-1146873698521217431?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/1146873698521217431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/1146873698521217431'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/07/happenings-and-prospects.html' title='Happenings and Prospects'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-6939132122090505432</id><published>2011-07-07T05:51:00.001-07:00</published><updated>2011-07-07T05:52:28.100-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL ES'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Update on UpdateConf</title><content type='html'>Just wanted to let you know that I'm speaking at another conference. I'll be speaking at the inaugural &lt;a href="http://updateconf.com/"&gt;UpdateConf&lt;/a&gt; in &lt;a href="http://en.wikipedia.org/wiki/Brighton"&gt;Brighton&lt;/a&gt;, UK on September 5th.&lt;br /&gt;&lt;br /&gt;As part of the conference, I'm also giving a two-day intensive workshop on OpenGL ES. The workshop assumes no prior experience with graphics program, but will be fairly fast-paced and will cover a lot of ground because there's a lot of new ground to cover. I'll be going over the new GLKit and the incredible new OpenGL debugger as well as the updated OpenGL ES Instruments templates.&lt;br /&gt;&lt;br /&gt;&amp;nbsp;Not interested in OpenGL ES? There are four other two-day workshops going on with some really awesome instructors. &lt;a href="http://twitter.com/#!/mzarra/"&gt;Marcus Zarra&lt;/a&gt; is doing a two-day workshop on Core Data, &lt;a href="http://twitter.com/#!/drewmccormack/"&gt;Drew McCormack&lt;/a&gt; is doing a workshop on Core Animation, &lt;a href="http://twitter.com/#!/sazzy/"&gt;Sarah Parmenter&lt;/a&gt; is doing one on iOS UI design, and &lt;a href="http://twitter.com/#!/rem"&gt;Remy Sharp&lt;/a&gt; is doing one on HTML5 for mobile. The worst thing about giving this workshop is that doing so will prevent me from going to one of the other great workshops.&lt;br /&gt;&lt;br /&gt;The conference proper has a number of speakers, including the workshop instructors and it's really shaping up to to be quite a conference, and also quite a steal at £99 for early bird tickets to the conference (the workshops are extra). You can sign up for the conference &lt;a href="http://www.eventbrite.com/event/1423476657"&gt;on EventBrite&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&amp;nbsp;Hope to see you there!&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-6939132122090505432?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/6939132122090505432'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/6939132122090505432'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/07/update-on-updateconf.html' title='Update on UpdateConf'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-8405776836987716114</id><published>2011-06-04T04:16:00.000-07:00</published><updated>2011-06-04T04:18:05.645-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Other blogs'/><title type='text'>On Being Excellent to Each Other</title><content type='html'>Marcus Zarra has &lt;a href="http://www.cimgf.com/2011/06/03/why-so-serious/"&gt;a somewhat depressing post today&lt;/a&gt; on the excellent &lt;a href="http://www.cimgf.com/"&gt;Cocoa is My Girlfriend&lt;/a&gt; blog. It's about the release of &lt;a href="http://www.thedaily.com/"&gt;The Daily&lt;/a&gt;. Because of all the secrecy around The Daily prior to its official launch, I think not a lot of people knew Marcus was not just involved with it, but was actually leading much of the development effort.&lt;br /&gt;&lt;br /&gt;I knew.&lt;br /&gt;&lt;br /&gt;I wasn't on the main development team for The Daily, but I did most of implementation work on a single component (the 360° panorama). I wasn't in NYC every day the way Marcus was, but I went down there enough to know the conditions under which the application was written. I saw the endless late nights (actually, it was usually early mornings) and the stress and difficulties under which the app was written. &lt;br /&gt;&lt;br /&gt;A personal stake always makes it harder to watch negative publicity. The Daily's launch was especially hard because I was in a position where I couldn't really come to Marcus' team's defense, since my involvement with the project wasn't yet public knowledge. If it had been, I would have been written off as biased.&lt;br /&gt;&lt;br /&gt;So, I had to just sit back and watch it the way you'd watch a trainwreck. It was painful watching the snark. It was painful watching Loren Brichter, a well-respected member of our community put together a carousel demo in a complete vacuum and post a video of it as if it proved something about performance in an incredibly large and complex application. It was even more painful seeing John Gruber link to that video, spreading a false impression to a far wider audience.&lt;br /&gt;&lt;br /&gt;They both enough about software development that they should have known better. There's almost no part of The Daily that can't be re-implemented in a few hours as a standalone application using static data and with great performance. &lt;br /&gt;&lt;br /&gt;Doing the same thing as part of a large development application developed by a large team, working with a larger management team and a huge content and production teams under an unreasonable deadline and constant pressure? That takes more than being a competent developer. A lot more. It takes patience and diplomacy and a very high tolerance for frustration. I don't think I would've survived in Marcus' shoes all those months. I would've walked out or been escorted out long before the launch ever happened. It was honestly that tough.&lt;br /&gt;&lt;br /&gt;I'm not sure that our community is getting quite as bad as it appears to Marcus at the moment, but there is no doubt that we are capable of producing our share of snark. And let's be honest… &lt;strong&gt;I&lt;/strong&gt; am capable of producing more than my individual share. I don't think we think about being mean when we fire off a smug comment. I think it's usually just a side effect of expressing a myopic, partially informed opinion. I'm sure Loren honestly believes he could have done better with the carousel had he been working on The Daily. But he's wrong. He just doesn't know enough about the situation to realize it.&lt;br /&gt;&lt;br /&gt;But it's not my intention to point fingers here. I'm been just as guilty at times. Last year, during the WWDC keynote, I was extraordinarily snarky about the Farmville demo, completely forgetting that I know people who worked on it. I wasn't intending to shit on their work, but I did, and I'm sincerely sorry about it. There have been other examples. I hope there won't be more in the future, but only time will tell.&lt;br /&gt;&lt;br /&gt;I think Marcus' post should be read and taken to heart by all of us. I think it should serve as a reminder that real people — very often our friends and colleagues — are behind the software and hardware that we express opinions on. We should keep in mind that a lot of work went into it. We should also keep in mind that in most cases, we have no idea the circumstances under which the application was written. &lt;br /&gt;&lt;br /&gt;Being critical is not only fine, but a necessary part of driving each other to be better developers. But we should try and avoid being a dick about it. It can be done respectfully, and should be. &lt;br /&gt;&lt;br /&gt;I promise to try if you will.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-8405776836987716114?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/8405776836987716114'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/8405776836987716114'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/06/on-being-excellent-to-each-other.html' title='On Being Excellent to Each Other'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-2636155082582779260</id><published>2011-06-03T12:26:00.000-07:00</published><updated>2011-06-03T12:26:58.621-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Game Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL ES'/><title type='text'>Thoughts on Unity3D</title><content type='html'>As I stated in my &lt;a href="http://iphonedevelopment.blogspot.com/2011/05/3d-game-and-graphics-engines.html"&gt;previous post on 3D engines&lt;/a&gt;, I'm going to do four blog posts giving my thoughts on each of the four engines that I looked into using for a project recently. Those four engines are &lt;a href="http://unity3d.com/"&gt;Unity3D&lt;/a&gt;, &lt;a href="http://sio2interactive.com/"&gt;Sio2&lt;/a&gt;, &lt;a href="http://www.ogre3d.org/"&gt;Ogre3D&lt;/a&gt;, and &lt;a href="http://brenwill.com/cocos3d/"&gt;Cocos3D&lt;/a&gt;. I'm starting with Unity3D, which we selected for one of our recent projects.&lt;br /&gt;&lt;br /&gt;Now, let me state up front, that all four of these are competent engines and I could see situations where I would recommend three of the four engines for client projects and could easily imagine situations where all four of them would be good choices.These four do not make an exhaustive list; there are other engines out there, including some really good ones, but these were the four that we looked at for this specific project. As much as I like the &lt;a href="http://www.udk.com/"&gt;UDK&lt;/a&gt;, for example, I don't like it enough to spend quality time in Windows, so that one is off the table for me until the fine folks at Epic decide to port their dev and content tools to the Mac.&lt;br /&gt;&lt;h3&gt;Unity Overview&lt;/h3&gt;Unity3D actually predates the iPhone, and of the four engines, it's the one that feels the most mature and has the most robust developer tools. It also has one of the most active developer communities. Unity3D is a closed-source commercial product that you must pay for, which might be a turn-off for some, but it is worth every penny of the license fee.&lt;br /&gt;&lt;h4&gt;Unity Pros&lt;/h4&gt;Unity is actually fairly easy to learn, yet has a feature set that is  compares favorably to most other engines. Unity's asset pipeline is really robust and their tools give you the ability to very quickly make changes and test those changes.&lt;br /&gt;&lt;br /&gt;One of the best things about Unity3D is the fact that it supports both Windows and Mac OS equally as development platforms. Regardless of which platform you develop on, you can generate games that runs on every platform Unity supports (assuming you're licensed for it). You can even have part of your team developing on Macs and the other part on Windows with no problems.&lt;br /&gt;&lt;br /&gt;At the time I'm writing this, it is possible to generate games from Unity that run on Mac OS X and Windows (both native apps as well as games playable through a web plug-in), iOS, Android, Wii, Xbox 360, and PS3. The Unity folks are also actively working on adding Linux support. Console licenses are negotiated on an individual basis and are likely quite expensive, but it's nice to have the option to take a successful game to so many platforms without having to do a full port each time.&lt;br /&gt;&lt;br /&gt;Having had to port OpenGL ES apps from iOS to Android more than once (which is no fun), I can honestly state that the Android support should be a huge selling point you're giving any thought to supporting both iOS and Android.&lt;br /&gt;&lt;h4&gt;Unity Cons&lt;/h4&gt;The downsides to Unity3D are relatively few, actually.It is the most expensive of the engines I looked at, and the costs are completely front-loaded. You pay a flat per-developer license per platform up front, but then you can create as many games as you want for the platforms you're licensed for. For the basic iOS license, it's $400 per seat (one developer using up to two machines), for the Pro license, you're looking at $3,000 (because the $1,500 iOS Pro requires the $1,500 Unity Pro), which might sound like a lot of money, but it's really a pittance compared to the amount of development time it can save you. The "Basic" version of Unity, which allows you to generate Mac, Windows, and Web games (though excludes some of the more advanced features) is available completely free of charge.&lt;br /&gt;&lt;br /&gt;The other potential downside in some situations is that the underlying C++ source code is not available. You work primarily in either JavaScript or C# (MonoScript) and at a higher level of abstraction. Unity supports a few other languages besides Javascript and C#, but only those two languages work for mobile development.&lt;br /&gt;&lt;br /&gt;After about two weeks of spending my evenings with Unity, I actually came to the conclusion that not having access to the source isn't really much of a drawback, and for many developers, working this way will be &lt;em&gt;better&lt;/em&gt; than working in C++. The engine takes care of almost all the low-level stuff you'd need to do, but even if it doesn't, Unity has a shader language that lets you write code that runs on the GPU and anything that needs to run on the CPU can be done by scripting inside Unity.&lt;br /&gt;&lt;br /&gt;Although the programming in Unity3D is done with scripting languages, the scripts you write are actually compiled, so there's not a huge performance overhead to using them. In the exceedingly rare situation where C# or Javascript isn't sufficient, it is possible to send messages into and out of Unity from your application's C or Objective-C code.&lt;br /&gt;&lt;h3&gt;Learning Curve&lt;/h3&gt;I found Unity surprisingly easy to learn. There are some really good resources out there, including lots of tutorials and instructional videos. I actually had a game functioning after about two hours of playing. It was ugly and the game mechanics were simple, but it was playable. Unity also has a fairly active developer community forum where you can go and get help when you get stuck.&lt;br /&gt;&lt;br /&gt;If you don't already know something about graphics programming, you still don't need to be too scared or intimidated. Most of the gnarly stuff is squirreled away where you won't see it until you need it, and you can do a surprising amount by just configuring things in the development GUI. You can create, for example, a fairly full-featured physics simulations without ever writing a line of code. Want to stack up a bunch of crates and roll a ball into them and watch them all fall? You can do it without ever opening a text editor. Heck, you can even do that without opening a 3D program.&lt;br /&gt;&lt;h3&gt;Complexity&lt;/h3&gt;I was scared of one thing going into learning Unity: I was concerned that because it was so easy (at least I had &lt;em&gt;heard&lt;/em&gt; it was), that it was going to be a dumbed down game maker that sacrificed more advanced features for the sake of lowering the obstacles to entry. My fears were completely misplaced, though. That's not the case at all. The Unity folks have done a really great job of making their tools easy to use while still giving you the ability to do most anything you'd ever need to do. It's even possible (though the process is a bit convoluted) to integrate UIKit and Unity3D within the same application.&lt;br /&gt;&lt;h3&gt;Asset Pipeline&lt;/h3&gt;The thing that actually impressed me most about Unity is what they call their "asset pipeline", which is the process by which you get 3d models, textures, and other assets into your game. If you've ever developed a game or game mod for the UDK, a Valve Source game, or other commercial engine, usually there's kind of a convoluted process you have to go through to get your game assets including characters, textures, props, and environments, into the game. You usually have to use separate applications to specify shaders and physics options, sometimes write a compile script or other text document to define certain trains, and then compile the object and package it all up into some kind of bundle or package. While developing a single mod, you typically iterate through this process many, many times. It can be a bit tedious and hard to learn and usually requires the use of multiple tools and lots of trial and error.&lt;br /&gt;&lt;br /&gt;Unity bypasses almost all of this tedium. When you save your assets from your 3D program or Photoshop, you simply save them in your Unity project's &lt;em&gt;Assets&lt;/em&gt; folder. When you launch Unity, or navigate back to it if it's already open, Unity detects the new file, or any changes you've made to an existing file. It imports it and adds it to the list of available assets.Anything you need to do that can't be done in your 3D program, such as specify a shader or identify the physics engine properties for the object, you do right in Unity, and most of that can be done without writing code (though everything you can configure without code can also be changed from code).&lt;br /&gt;&lt;br /&gt;Which 3D program do you need to use? Pretty much any one you're comfortable with. Unity3D has direct import support for the native file formats from several programs including Blender , but any package that can export to Autodesk FBX or Collada can be used with full support for all features like bones, textures, animations, etc.It also supports native Photoshop files (.psd) for textures, flattening layers in a non-destructive manner when you build your app.Assets can even be given different characteristics for different platforms. You could have, for example, a 2048x2048 texture asset for the desktop version of your game but tell Unity to use a 1024x1024 version for game consoles and a 512x512 version on iOS and Android.&lt;br /&gt;&lt;h3&gt;The Bottom Line&lt;/h3&gt;As I stated earlier, there are situations where I could see any of the four engines I looked at being a good choice, as could many of the other engines I didn't look at. But, honestly, if I had to make an engine decision without detailed information, Unity3D would be my first recommendation. The tools are solid, the company and community support is awesome, it supports many platforms, and getting assets into your game couldn't be easier. It's relatively easy to start using for both experienced developers and those who aren't.&lt;br /&gt;&lt;br /&gt;A good, experienced graphics programmer working in mobile right now can easily ask $200 per hour or more because the demand far outstrips the supply. Figure it out. Unity's full iOS license is basically the equivalent of 15 hours of a graphics programmer's time. Yet, Unity will easily cut five times that many hours off of any decent size software game project's schedule, probably a lot more.&lt;br /&gt;&lt;br /&gt;I'm giving Unity3D two big thumbs up. I'm using it on a project now and hope to use it on many more in the future because it's fun to use and removes much of the tedium associated with 3D programming without removing power.&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;span style="font-size: x-small;"&gt;&lt;b&gt;1&lt;/b&gt; Many of the more advanced features require the more expensive "Pro" license, however, and really cutting edge features from the latest games generally take a little while to show up in the tools&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-2636155082582779260?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/2636155082582779260'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/2636155082582779260'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/06/thoughts-on-unity3d.html' title='Thoughts on Unity3D'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-7023397326676172547</id><published>2011-05-25T15:27:00.000-07:00</published><updated>2011-05-25T15:28:47.854-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WWDC'/><category scheme='http://www.blogger.com/atom/ns#' term='Pilgrimage'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><title type='text'>A Few Seats Left</title><content type='html'>There are a few seats left for the afternoon trip to Cupertino on June 6th. If you're interested, &lt;a href="http://goo.gl/4gWHh" target="_blank"&gt;go here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;As I write this, there are less than 15 seats, though, so if you want one, I suggest you hurry.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-7023397326676172547?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/7023397326676172547'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/7023397326676172547'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/05/few-seats-left.html' title='A Few Seats Left'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-3845495105319256844</id><published>2011-05-21T09:52:00.001-07:00</published><updated>2011-05-21T09:52:43.573-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WWDC'/><category scheme='http://www.blogger.com/atom/ns#' term='Pilgrimage'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><title type='text'>Bus Update</title><content type='html'>Just to let you all know, we're down to eleven remaining available seats on the third and last bus, and they're about equally split between morning and afternoon. If you missed getting a seat on the first two buses, and haven't filled out the interest form for the third, there probably won't be a seat.So, &lt;a href="https://spreadsheets.google.com/embeddedform?formkey=dEd6d2JTTnNQcWFsc3g4eDVtS0dWLUE6MQ"&gt;go here now&lt;/a&gt; to tell us you're interested in one of the remaining seats. Speak now or forever hold your peace.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-3845495105319256844?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3845495105319256844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3845495105319256844'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/05/bus-update.html' title='Bus Update'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-9144725513866262922</id><published>2011-05-19T15:54:00.001-07:00</published><updated>2011-05-19T16:04:17.685-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WWDC'/><category scheme='http://www.blogger.com/atom/ns#' term='Pilgrimage'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><title type='text'>Pre-WWDC Schedule Update</title><content type='html'>The good news:&lt;br /&gt;&lt;br /&gt;The additional bus is a go! We'll be opening up payment for those seats this weekend to people who signed the interest form, and then opening it up to the public 24 hours later until seats are gone. The third bus will leave Moscone a bit later than the other two (11:30 and 3:45), &lt;strike&gt;but will not stop at SFO. If you're interested in the additional bus, but need to be picked up at SFO, drop me an e-mail (jeff at martiancraft dot com) or send me a tweet, and we'll see if we can find a way to accommodate you by shuffling a few seats&lt;/strike&gt;. &lt;b&gt;Update&lt;/b&gt;: The third bus &lt;b&gt;will&lt;/b&gt; stop at SFO!.&lt;br /&gt;&lt;br /&gt;The bad news:&lt;br /&gt;&lt;br /&gt;There will not be another bus once we fill this one. We're already threatening to overflow both The Company Store and BJ's, a fourth bus would be overkill even if we were sure we could fill it, which I'm not at all sure we could do anyway.As of right now, there are approximately 25 spaces left on the third and final bus. &lt;br /&gt;&lt;br /&gt;The &lt;a href="https://spreadsheets.google.com/embeddedform?formkey=dEd6d2JTTnNQcWFsc3g4eDVtS0dWLUE6MQ"&gt;interest form&lt;/a&gt; will remain open until we either run out of seats, or we open up the reservation payment again. People who signed up on interest form get dibs on the remaining seats.One final note: last year, we had some people show up without signing up in advance. Please don't do that this year. Simply put, we won't have any place to put you. The bus company won't let people stand while the bus is driving, so if you're interested in going, you've got to reverse a seat in advance.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-9144725513866262922?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/9144725513866262922'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/9144725513866262922'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/05/pre-wwdc-schedule-update.html' title='Pre-WWDC Schedule Update'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-9194129848819054566</id><published>2011-05-18T10:37:00.001-07:00</published><updated>2011-05-18T10:37:59.985-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WWDC'/><category scheme='http://www.blogger.com/atom/ns#' term='Pilgrimage'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><title type='text'>Pre-WWDC 2011 Pilgrimage Additional Buses</title><content type='html'>Okay, here's the deal folks. We're trying to find out from the bus company what are options are. In the meantime, we need to know how many of you are interested in a seat on the bus. If you want to go, and didn't get a seat, you need to &lt;a href="https://spreadsheets.google.com/embeddedform?formkey=dEd6d2JTTnNQcWFsc3g4eDVtS0dWLUE6MQ"&gt;go fill out this form right now.&lt;/a&gt;If we get enough interest to cover the cost of another bus, we'll then send you all information on how to pay for your seats. Spread the word, because we really don't want anybody to get left behind if at all possible.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-9194129848819054566?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/9194129848819054566'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/9194129848819054566'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/05/pre-wwdc-2011-pilgrimage-additional.html' title='Pre-WWDC 2011 Pilgrimage Additional Buses'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-203341052795522156</id><published>2011-05-17T22:47:00.001-07:00</published><updated>2011-05-17T22:47:12.328-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WWDC'/><category scheme='http://www.blogger.com/atom/ns#' term='Pilgrimage'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><title type='text'>Sold Out</title><content type='html'>Okay, I'm just about to head to bed, but wanted to let you know that we've officially sold out all four bus trips for the June 5 pilgrimage. Scott and I are going to regroup in the morning and see what our options are for adding capacity.Because we have to pay for buses &lt;em&gt;by the day&lt;/em&gt; and not per trip, we have to be sure we can fill two more bus trips in order to cover the cost of adding an additional bus. We're also going to see if adding a smaller bus is a possibility and how that would impact the per-seat price.Whatever we do, I'll post about it here and also tweet it. But not until tomorrow.G'night.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-203341052795522156?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/203341052795522156'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/203341052795522156'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/05/sold-out.html' title='Sold Out'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-8019348138963845693</id><published>2011-05-17T13:46:00.001-07:00</published><updated>2011-05-17T13:46:28.803-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WWDC'/><category scheme='http://www.blogger.com/atom/ns#' term='Pilgrimage'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Pre-WWDC Pilgrimage 2011 Update</title><content type='html'>If you signed the interest form, you should have received an e-mail telling you how to reserve seats on the pilgrimage buses. If you did sign the earlier form but didn't get an e-mail, let me know.If you didn't sign the interest sheet, don't worry, we'll be opening registration up to the public tomorrow. We thought it only fair to give the people who signed up in advance a bit of a head start.We should have enough room for everybody, as we're able to add additional buses if we need more capacity. We just have to make sure that we have enough additional people to cover the cost of another bus.Keep an eye here or &lt;a href="http://twitter.com/#!/jeff_lamarche"&gt;follow me on twitter&lt;/a&gt; to find out when we open registration up to everyone else.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-8019348138963845693?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/8019348138963845693'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/8019348138963845693'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/05/pre-wwdc-pilgrimage-2011-update.html' title='Pre-WWDC Pilgrimage 2011 Update'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-2964891785620743937</id><published>2011-05-14T07:44:00.001-07:00</published><updated>2011-05-14T08:01:46.592-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Game development'/><category scheme='http://www.blogger.com/atom/ns#' term='Graphics Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL ES'/><category scheme='http://www.blogger.com/atom/ns#' term='iOS'/><category scheme='http://www.blogger.com/atom/ns#' term='iPHone'/><title type='text'>3D Game and Graphics Engines</title><content type='html'>One thing that I get asked about a lot is whether you should use a game or graphics engine instead of learning OpenGL ES. Often, these emails are prefaced by a statement about how hard graphics programming. I've had to answer this question enough times now that it seems like a good topic for a blog post.&lt;br /&gt;&lt;br /&gt;Honestly, I find it kind of hard to answer, because I don't see the "using an engine" and "learning graphics programming" as being distinct or mutually exclusive approaches. While a good game or graphics engine will handle a lot of the more gnarly programming tasks for you and shorten your development time, you still need to understand the underlying concepts to build anything of any complexity.&lt;br /&gt;&lt;br /&gt;All of these engines are built on top of OpenGL (and/or DirectX if they support Windows), and are subject to the same limitations and strengths. Not understanding, at least at some level, how these lower-level graphics libraries work and the basic maths of 3D programming will eventually hold you back.&lt;br /&gt;&lt;br /&gt;But… that doesn't necessarily mean you need to learn OpenGL before you can start using these tools effectively. You don't. It's just that some of the difficult, sticky math and concepts that might be scaring you away from OpenGL are still there (though better hidden), and you may well still have to deal with them at some point if you're doing the coding on the game (as opposed to just creating assets or doing level design).&lt;br /&gt;&lt;br /&gt;Here's kind of a simple nutshell rule:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;If you love graphics programming or are fascinated by it, then study OpenGL ES and the underlying maths and forget about using the engines at first (though studying their source is a great way to learn). There's always going to be work for good graphics programmers and you can't put a price tag on doing what you love.&lt;br /&gt;&lt;br /&gt;If, on the other hand, your goal is to make a game or other graphics-heavy application, and graphics programming is just a means to that end, then use an engine, because it will shorten the amount of work you have to do tremendously, which inherently increases your chances of making money because time is money and there's never enough of it.&lt;/blockquote&gt;&lt;br /&gt;So, when shouldn't you use an existing engine if your goal is to make a game and not to try and be the next John Carmack? Almost never. Rolling your own game engine should be a labor of love. It's got to be an itch you can't scratch; the kind of desire that I probably couldn't talk you out of anyway. Otherwise, it's just a waste of your time.&lt;br /&gt;&lt;br /&gt;What about when there just isn't an engine that works for what you want to do? &lt;br /&gt;&lt;br /&gt;Honestly, that's not all that likely in this day and age, but even if it is, you're far better off starting with an existing engine and then modifying it to meet your needs.&lt;br /&gt;&lt;br /&gt;From a business and financial perspective, it's almost never better to start from scratch. Even many of the AAA commercial game engines are derivatives of other engines. To give an example: Valve's &lt;a href="http://en.wikipedia.org/wiki/Source_engine"&gt;Source Engine&lt;/a&gt;, is derived from their older &lt;a href="http://en.wikipedia.org/wiki/GoldSrc"&gt;Goldsource Engine&lt;/a&gt;, which itself was forked from the &lt;a href="http://en.wikipedia.org/wiki/Quake_engine"&gt;Quake Engine&lt;/a&gt; back around 1996.&lt;br /&gt;&lt;br /&gt;Though there are &lt;a href="http://en.wikipedia.org/wiki/List_of_game_engines"&gt;quite a few game engines around&lt;/a&gt;, a very large percentage of high-end commercial games, both console and PC, are based on either the Unreal engine or the Quake engine or one of their derivatives. If you throw in a handful of other engines, like the &lt;a href="http://www.crytek.com/cryengine"&gt;CryEngine&lt;/a&gt;, you've probably covered all but a few outliers.&lt;br /&gt;&lt;br /&gt;If it's not cost effective for large, multi-person development teams with multi-million dollar budgets to develop their own game engines, it's probably not the best choice for individual indie developers or small shops.&lt;br /&gt;&lt;br /&gt;So, don't reinvent the wheel. Use an engine and stand on the shoulders of &lt;a href="http://en.wikipedia.org/wiki/John_D._Carmack"&gt;John Carmack&lt;/a&gt; and others like him. Don't spend your time trying to solve problems that are long-solved. Just be aware that using an engine can't completely eliminate the need to learn a little math or to understand the underlying concepts.&lt;br /&gt;&lt;h4&gt;Engines&lt;/h4&gt;It just so happens that for a number of proposals I've done lately, I've been looking at game engines in some depth. I'm not going to do "reviews" per se, but over the next few weeks, I will try and post my thoughts about several of the engines available for iOS, including &lt;a href="http://unity3d.com/"&gt;Unity3D&lt;/a&gt;, &lt;a href="http://sio2interactive.com/"&gt;Sio2&lt;/a&gt;, &lt;a href="http://www.ogre3d.org/"&gt;Ogre3D&lt;/a&gt;, and &lt;a href="http://brenwill.com/cocos3d/"&gt;Cocos3D&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;I won't be discussing the &lt;a href="http://www.udk.com/"&gt;UDK&lt;/a&gt;, even though it's a phenomenal engine, because it requires using Windows for many tasks, and I don't want to spend time in Windows. If you've got both a Mac and a Windows machine, however, and don't mind splitting time between OS X and Windows, you might want to check it out. A lot of time and brainpower has gone into getting the UDK to have incredible performance on iOS and the license terms have been changed to be much more friendly to small indie shops ($99 plus 25% of royalties after the first $50,000).&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-2964891785620743937?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/2964891785620743937'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/2964891785620743937'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/05/3d-game-and-graphics-engines.html' title='3D Game and Graphics Engines'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-4382747376597418805</id><published>2011-05-04T11:18:00.001-07:00</published><updated>2011-05-04T11:18:35.087-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL ES'/><category scheme='http://www.blogger.com/atom/ns#' term='Xcode 4'/><title type='text'>Empty OpenGL ES Application Xcode 4 Template</title><content type='html'>Jacques De Schepper sent in an updated version of my &lt;a href="http://iphonedevelopment.blogspot.com/2008/12/updated-opengl-es-xcode-project.html"&gt;old Empty OpenGL ES Application Template&lt;/a&gt;, updated to use Xcode 4's completely revamped templating mechanism. You can download the new Xcode 4 version of the &lt;a href="http://www.innerloop.biz/code/Empty%20OpenGL%20ES%20Application.xctemplate.zip"&gt;template right here.&lt;/a&gt; I haven't had a chance yet to test this out, but once I do, I'll also add it to GitHub.Thanks, Jacques!&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-4382747376597418805?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/4382747376597418805'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/4382747376597418805'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/05/empty-opengl-es-application-xcode-4.html' title='Empty OpenGL ES Application Xcode 4 Template'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-5354662616296683738</id><published>2011-05-03T07:18:00.001-07:00</published><updated>2011-05-03T08:19:16.571-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WWDC'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple HQ'/><title type='text'>Bus Trip Update</title><content type='html'>Just wanted to give you all an update on the bus pilgrimage to Cupertino on June 5th. We had a tremendous show of interest. Approximately 300 people expressed an interest, plus several people tweeted and e-mailed after the interest form was closed down. Last year, we took 100 people. &lt;br /&gt;&lt;br /&gt;Scott Knaster is investigating bus options, including a possible bus directly from SFO to the Apple Store and then up to WWDC for people who wouldn't be able to get up to San Francisco in time for the bus.&lt;br /&gt;&lt;br /&gt;We'll start the official signups the middle of this month, once all the arrangements are squared away and we know how many seats there will be. Once the arrangements are made, the seats will be made available on a first-come, first-served basis. If you filled out the interest form, you'll get an e-mail with details of how to reserve your seat and pay for it as soon as signup opens. If you didn't fill out the interest form, you probably want to follow &lt;a href="http://twitter.com/#!/jeff_lamarche" target="_blank"&gt;me&lt;/a&gt; or &lt;a href="http://twitter.com/#!/scottknaster" target="_blank"&gt;Scott&lt;/a&gt; on Twitter, as we'll tweet when the signups start and then periodically re-tweet until the seats are gone.&lt;br /&gt;&lt;br /&gt;I want to set expectations, especially for first timers. The only thing open at Apple HQ will be The Company Store, which is similar to an Apple Store, but with a lot of Apple schwag and paraphernalia (t-shirts, pens, mugs, sweatshirts, etc). Being not just a Sunday, but the Sunday before WWDC, don't expect to see many Apple employees coming and going, and you will definitely &lt;strong&gt;not&lt;/strong&gt; be able to get into the quad (the inside portion of One Infinite Loop). There is no official Apple recognition of this trip, and we don't have any expectation that there will be. &lt;br /&gt;&lt;br /&gt;In the parking lot near The Company Store, there is a restaurant called BJ's, affectionately referred to as "IL7" by Apple employees (the buildings at One Infinite Loop are named IL1 through IL6), which is fairly good for what it is. You can have lunch or a drink there, but if you do, I advise you to order quickly and have your check brought with your food. Since the same bus will be used for multiple trips, we won't be able to wait for stragglers. The bus will leave at the scheduled departure time with or without you. We didn't leave anybody behind last year, but we had one table that cut it awfully, awfully close. It's an awfully long damn walk back to San Francisco, and they get pretty busy on Sundays even without a bus full of additional customers.&lt;br /&gt;&lt;br /&gt;Lastly, if you see Scott on Sunday, make sure to say a big thank you to him. Scott has done nearly all of the legwork again this year and the trip is happening very much because of him, so thanks Scott!&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-5354662616296683738?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/5354662616296683738'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/5354662616296683738'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/05/bus-trip-update.html' title='Bus Trip Update'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-8023080040453230034</id><published>2011-04-22T16:28:00.001-07:00</published><updated>2011-04-22T16:28:43.973-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Appsterdam'/><category scheme='http://www.blogger.com/atom/ns#' term='Ohter Blogs'/><category scheme='http://www.blogger.com/atom/ns#' term='Community'/><title type='text'>Appsterdam</title><content type='html'>You may have been hearing some rumors and jokes around Twitter concerning something called "Appsterdam". If you've been wondering what that's all about, &lt;a href="http://mur.mu.rs/" target="_blank"&gt;wonder no longer, Mike Lee lays it all out for you.&lt;/a&gt; It's an interesting idea, and I must admit I'm intrigued and would love to go. For a handful of personal reasons, I simply can't expatriate to Amsterdam at this point in my life, but I am seriously considering going over a few times per year to soak up the community, and if things take off, who knows? My reasons for not going are relatively temporary. &lt;br /&gt;&lt;br /&gt;The nice thing about what we all do is that it really doesn't matter where we do it, so I can work from Amsterdam just as easily as from my house.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-8023080040453230034?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/8023080040453230034'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/8023080040453230034'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/04/appsterdam.html' title='Appsterdam'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-8844853029974269109</id><published>2011-04-16T09:28:00.001-07:00</published><updated>2011-04-16T09:46:14.527-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WWDC'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>WWDC Mothership Pilgrimage 2011</title><content type='html'>Okay, after telling many people I wasn't going to organize a trip to the Mothership on the Sunday before WWDC, I may have had a change of heart. Scott Knaster, who did most of the hard leg work on arranging the buses last year, has offered to take the same role this year, and a lot of people have expressed interest, so we're thinking about running the bus trip again this year.&lt;br /&gt;&lt;br /&gt;If you're interested in taking the bus trip down to One Infinite Loop, &lt;a href="https://spreadsheets.google.com/viewform?formkey=dE02Njg1cVA1ak50aTUwMkNpbDFtNkE6MQ"&gt;go here and fill out the short form&lt;/a&gt;. This will help us gauge how many buses we'll need to arrange.&lt;br /&gt;&lt;br /&gt;If anybody's interested in sponsoring all or part of the trip, do let me know.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-8844853029974269109?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/8844853029974269109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/8844853029974269109'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/04/wwdc-mothership-pilgrimage-2011.html' title='WWDC Mothership Pilgrimage 2011'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-4660063655586816062</id><published>2011-04-12T09:37:00.001-07:00</published><updated>2011-04-12T10:37:30.063-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MacBook Air'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>MacBook Air 11" as Dev Machine</title><content type='html'>I just got back home from Seattle, where I went to attend and speak at &lt;a href="http://www.voicesthatmatter.com/" target="_blank"&gt;Voices that Matter&lt;/a&gt;. The VTM folks put on a great conference, as always, and I'll have more to say about that in future blog posts. But, I wanted to quickly address a question I've been asked numerous times this weekend both over Twitter and in real life. That question was "how productive were you able to be with just an 11" MacBook Air?"&lt;br /&gt;&lt;br /&gt;If you follow me on Twitter, you know that after years of using Apple's biggest and most powerful laptops (17" MacBooks and 17" PowerBooks before that), I bought Apple's smallest, least powerful one. This weekend, I decided to experiment by traveling very light. Besides the MacBook Air, my computer bag had an iPad2, &lt;a href="http://www.clearwirelessinternet4g.com/" target="_blank"&gt;a Clear 4G+&lt;/a&gt;, the various cables and power cords for those devices, and a mechanical pencil, nothing more. My entire bag weighed 6 pounds, which was quite a change from the monstrosity I usually have with me when I travel to conferences. With a larger computer comes a larger bag with more room for storage that inevitably gets filled with things I might maybe possibly need.&lt;br /&gt;&lt;br /&gt;So, how'd it work out?&lt;br /&gt;&lt;br /&gt;Absolutely perfectly. Despite being considerably less powerful, the 11" MacBook Air rarely feels slow thanks to the SSD. Certain things take noticeably longer (compiling large applications), but the vast majority of day-to-day tasks feel downright snappy.&lt;br /&gt;&lt;br /&gt;The screen is small, but it's a pretty high pixel density, so it's not quite as confining as you might expect. With a few changes to my coding habits, which included going from Menlo-10 to Menlo-9 as my coding font, and committing the Xcode key commands to to hide and show panes to memory, I quickly settled into a workflow that worked really, really well for me.&lt;br /&gt;&lt;br /&gt;There may have been a very slight hit to productivity, but it wasn't bad, and it was more than offset by the fact that I could use the laptop anywhere, even sitting in coach. My 17" MacBook Pro is basically unusable in coach if the person in front of me reclines their seat. And the person in front of me always reclines their seat. I got a solid 4 or 5 hours of coding in yesterday that I wouldn't have gotten with my bigger laptop.&lt;br /&gt;&lt;br /&gt;So, yeah. It worked out great. &lt;br /&gt;&lt;br /&gt;A couple of times this weekend, I was also asked a related question, which is "could you use it as your main development machine?".&lt;br /&gt;&lt;br /&gt;The answer to that is "I could, but probably wouldn't want to". However, that's because of factors that probably don't impact most developers. The nature of several of our clients (sorry I can't be more specific than that) means that a lot of our mockups and images come to us as very, very, very large Photoshop files with lots of layers. I regularly have to deal with Photoshop files that are a gigabyte in size or larger. &lt;br /&gt;&lt;br /&gt;If it weren't for that, and my occasional dabbling in 3D graphics programming, I definitely could use this machine full time. In fact, an 11" MacBook Air with a 27" Apple display, would be a very capable iPhone dev machine for most developers, though I would definitely buy the "ultimate configuration" if you are looking at getting one.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-4660063655586816062?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/4660063655586816062'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/4660063655586816062'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/04/macbook-air-11-as-dev-machine.html' title='MacBook Air 11&amp;quot; as Dev Machine'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-3255607627475830303</id><published>2011-04-05T11:42:00.001-07:00</published><updated>2011-04-05T12:55:07.895-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='3D'/><category scheme='http://www.blogger.com/atom/ns#' term='Open Source'/><category scheme='http://www.blogger.com/atom/ns#' term='Blender'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL ES'/><title type='text'>Blender 2.57 Objective-C Export Script</title><content type='html'>A few days ago, the &lt;a href="http://blender.org/" target="_blank"&gt;Blender Foundation&lt;/a&gt; put out the first &lt;a href="http://download.blender.org/release/Blender2.57/" target="_blank"&gt;release candidate of Blender 2.5&lt;/a&gt;. This release unexpectedly broke compatibility with most existing 2.5 python scripts, including my Objective-C header Export Script.&lt;br /&gt;&lt;br /&gt;Which was great timing, since I needed to use the script today. I could've just gone back to an older version of Blender, but decided instead to re-write the script to work. I just added &lt;a href="https://github.com/jlamarche/iOS-OpenGLES-Stuff/tree/master/Blender%20Export/objc_blend_2.57%20(RC1)" target="_blank"&gt;to GitHub, the new 2.57 compatible version of the export script&lt;/a&gt;. This version is back to being an add-on that you can add through the User Preferences.&lt;br /&gt;&lt;br /&gt;I've also added a few options that you can select when exporting (they're on the left side of the file selection screen, underneath the volumes and recently visited locations). You can see the new options in the following screen grab:&lt;br /&gt;&lt;br /&gt;&lt;img style="display:block; margin-left:auto; margin-right:auto;" src="http://lh3.ggpht.com/_QLwms0mVa4w/TZtgXKYrxCI/AAAAAAAAAyM/h16ueouRGyc/Screen%20shot%202011-04-05%20at%202.32.44%20PM.png?imgmax=800" alt="Screen shot 2011 04 05 at 2 32 44 PM" border="0" width="227" height="115" /&gt;&lt;br /&gt;&lt;br /&gt;The first option lets you specify whether modifiers are applied before exporting the mesh. If you uncheck this, the script will strip the modifiers before exporting, otherwise, it will apply them to the mesh before exporting. &lt;br /&gt;&lt;br /&gt;The second option will rotate the object 90° along the X axis, which converts the object from Blender's Z-up coordinate space to OpenGL's Y-up coordinate space. I've made this the default, but I could foresee situations where people would want to skip the conversion. &lt;br /&gt;&lt;br /&gt;The final option will move the export the object using its world space coordinates rather than exporting it using object space coordinates. This option will, for example, preserve relative distance between multiple objects exported from the same file into different headers. Or, to put it another way, objects exported will normally have use their coordinates as they relate to the object's origin, regardless of where the object is in the Blender scene. If this is checked, the vertex coordinates will be exported relative to the scene's origin.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;NB:&lt;/b&gt; There was a problem with the triangulation code in the version posted earlier. If you're having problems, pull again from GitHub.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-3255607627475830303?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3255607627475830303'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3255607627475830303'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/04/blender-257-objective-c-export-script.html' title='Blender 2.57 Objective-C Export Script'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_QLwms0mVa4w/TZtgXKYrxCI/AAAAAAAAAyM/h16ueouRGyc/s72-c/Screen%20shot%202011-04-05%20at%202.32.44%20PM.png?imgmax=800' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-2288191760186340461</id><published>2011-04-05T09:53:00.001-07:00</published><updated>2011-04-05T09:53:02.790-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='App Store'/><category scheme='http://www.blogger.com/atom/ns#' term='iOS'/><title type='text'>App Store Review Times by Shiny Development</title><content type='html'>&lt;a href="https://twitter.com/#!/daveverwer/" target="_blank"&gt;Dave Verwer&lt;/a&gt; of &lt;a href="http://shinydevelopment.com/" target="_blank"&gt;Shiny Development&lt;/a&gt; has created a web bot that trolls Twitter for tweets about App Store review times and maintains a running average of both iOS and Mac review times. &lt;a href="http://reviewtimes.shinydevelopment.com/" target="_blank"&gt;The results are continuously available at this website&lt;/a&gt;. The more people who contribute, the better the data will be, so if you want to contribute, just tweet your review time using the &lt;strong&gt;#iosreviewtime&lt;/strong&gt; or &lt;strong&gt;#macreviewtime&lt;/strong&gt; hash tags like &lt;a href="https://twitter.com/daveverwer/status/44772212561027072" target="_blank"&gt;the example tweet&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-2288191760186340461?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/2288191760186340461'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/2288191760186340461'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/04/app-store-review-times-by-shiny.html' title='App Store Review Times by Shiny Development'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-3389477455887614064</id><published>2011-04-03T07:04:00.001-07:00</published><updated>2011-04-03T07:04:00.845-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Speaking'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Voices that Matter Seattle</title><content type='html'>This is just a reminder that &lt;a href="http://iphonespring2011.crowdvine.com/" target="_blank"&gt;Voices that Matter Seattle&lt;/a&gt; is this coming weekend. I'll be presenting on iOS Multitasking on Sunday morning. I'm really looking forward to it. It looks like there's still space available if you're free this weekend.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-3389477455887614064?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3389477455887614064'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3389477455887614064'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/04/voices-that-matter-seattle.html' title='Voices that Matter Seattle'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-254161271384214752</id><published>2011-03-29T07:00:00.001-07:00</published><updated>2011-03-29T07:03:41.502-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='App Store'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><title type='text'>Briefs is Dead, Long Live the Briefs</title><content type='html'>&lt;a href="http://www.twitter.com/capttaco" target="_blank"&gt;Rob&lt;/a&gt;, one of my MartianCraft partners-in-crime,  decided to &lt;a href="http://blog.robrhyne.com/post/4179305832/always-a-bridesmaid" target="_blank"&gt;throw in the towel last night on Briefs.app&lt;/a&gt;. After a solid year of fighting with Apple's app review team, implementing changes that were suggested &lt;em&gt;might&lt;/em&gt; clear the path for getting Briefs.app on the App Store, and trying to just get a straight answer from Apple about what the real problem was, he's finally decided it's just not worth the hassle any more.&lt;br /&gt;&lt;br /&gt;There were several lights at the end of the tunnel over the course of the year, each one a bigger and faster freight train. Despite the changes to the license agreement that seemed to imply Apple was going to become more reasonable on this subject, they continued to insist that Briefs allowed users to download and run executable code and is dangerous.&lt;br /&gt;&lt;br /&gt;I don't like that answer, but if that was the answer, they should have manned up and told him that a year ago rather than stringing him along, giving him false hope, and enticing him to invest more time he doesn't have on a fruitless endeavor. &lt;br /&gt;&lt;br /&gt;This was no way to treat a third party dev, and Rob has been way too nice about the whole damn situation.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-254161271384214752?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/254161271384214752'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/254161271384214752'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/03/briefs-is-dead-long-live-briefs.html' title='Briefs is Dead, Long Live the Briefs'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-3353385370849339450</id><published>2011-03-28T19:32:00.001-07:00</published><updated>2011-03-28T19:42:04.988-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WWDC'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>On WWDC Now Being "Broken"</title><content type='html'>Over at TUAW, fellow author Erica Sadun &lt;a href="http://www.tuaw.com/2011/03/28/hey-apple-wwdc-is-broken/" target="_blank"&gt;opines that WWDC is broken&lt;/a&gt; because it sold out fast. And she's right. It's so horribly broken that more people want to attend than they've got room for. Th… wait, what? Where I come from, that's called "success", and it usually indicates that you're doing something right. It's not usually a big red flag that you need to make a complete about face in your approach. &lt;br /&gt;&lt;br /&gt;But that's exactly what Erica is suggesting Apple do.&lt;br /&gt;&lt;br /&gt;I used to work in the Enterprise software world and know all about these large conferences that Erica is referencing. I was a developer at PeopleSoft (now part of Oracle), and I've been to (and have even spoken at) mega Enterprise conferences like the old PeopleSoft conferences (20k attendees at its peak) and OracleWorld (which is now, I guess, called Oracle OpenWorld because Oracle is so… open).&lt;br /&gt;&lt;br /&gt;Making WWDC more like these giant, soulless, "enterprise" conferences is not the answer. Scaling WWDC to 10k, 20k or 40k is fixing the problem by shooting the golden goose. Trying to scale up WWDC like that would utterly destroy everything that is wonderful about it.&lt;br /&gt;&lt;br /&gt;WWDC is community. WWDC is actually being able to talk with the engineers who wrote the software you're having problems using. WWDC is a chance to get on a first name basis with people in our community, including (if you're lucky) some of the awesome people who make the APIs we use to make our living. It's a time for learning, absolutely, but it's also for making friendships, making business connections, and looking for future employees/employers/subcontractors. The current size of WWDC is part of what makes it great and is part of why so many people want to attend. In fact, the past few years, it's bordered on being too big, with lab slots becoming harder to get and many sessions having long lines and being standing room only.&lt;br /&gt;&lt;br /&gt;What WWDC is, is not what giant corporate conferences like OracleWorld are. If anything, they're the polar opposite. Which is not to knock what those big conferences are - they serve a particular market, and they serve it well, but &lt;em&gt;we are not their market and our needs cannot be met by adopting their model.&lt;/em&gt; Conferences like Oracle World are places where groups of people from the same large company or government entity go together, hang out together, and then leave together. They're places that people go because their employer is paying for them to go and has instructed them to go. They're places where people wander through large convention halls picking up swag they don't really want while being sold on the merits of various products their employers don't really need. They're vendor fair as much as a place to learn. In fact, they're usually more like one big fucking advertisement that your company pays for you to attend.&lt;br /&gt;&lt;br /&gt;They are not events (by and large) that people save up and do without in order to attend. They're not events that people make sacrifices in order to find a way to go. &lt;br /&gt;&lt;br /&gt;But that's &lt;strong&gt;exactly&lt;/strong&gt; what WWDC is. WWDC is a conference that people want to go to even if they have to pay money out of their own pocket. It's something people look forward to attending and talk about having attended for months afterwards. It's a conference where a great many people pay their own way to attend and are thrilled to do so.&lt;br /&gt;&lt;br /&gt;Monstrous mega-conferences don't develop community. That's simply not what they're there for. Forty thousand people isn't a community: It's a city. Forty thousand people is so far beyond anybody's &lt;a href="http://en.wikipedia.org/wiki/Dunbar's_number" target="_blank"&gt;monkeysphere&lt;/a&gt; as to make the concept of "community" meaningless. Wandering around conferences like OpenWorld no more engenders a sense of community than does walking through Times Square.&lt;br /&gt;&lt;br /&gt;I don't want WWDC to become that. You don't want WWDC to become that. I honestly don't even think Erica &lt;em&gt;really&lt;/em&gt; wants WWDC to become that. I think what she wants is a &lt;a href="http://en.wikipedia.org/wiki/Utopia" target="_blank"&gt;perfectly egalitarian world where everybody gets what they want&lt;/a&gt;. But that only exists in fiction. In real life, everything involves tradeoffs, and the tradeoffs with her suggested solution would be disastrous for our community.&lt;br /&gt;&lt;br /&gt;Scarcity always increases value. Apple could have chosen to jack up the WWDC ticket price until they stopped selling out, but they didn't do that. In fact, the price hasn't increased in years. Yes, they did get rid of the early-bird pricing and group rates, but the base ticket price for WWDC has remained unchanged for quite some time (8 years maybe? Anyone know?). Apple could gouge us and many of us would pay the inflated price happily. But they don't do that. In fact, they charge us less than the early bird prices at big mega-conferences like Oracle OpenWorld, Tech Ed, and PDC, despite the fact that WWDC has no sponsors or advertisers and no vendor floor.&lt;br /&gt;&lt;br /&gt;The simple fact of the matter is that any mechanism that Apple might implement to "level the playing field" for tickets would result in somebody feeling like they didn't get a fair chance to purchase. The more complex the scheme and the more advance notice Apple were to give, the more opportunities there would be for people to game the system and create true inequity in the process. &lt;br /&gt;&lt;br /&gt;What Apple did do was put WWDC tickets on sale without advance notice and sold them on a first come, first served basis. That's not perfect, but it is about as close to a level playing field as you can get. Yes, some people were on planes, and some people were sleeping (including people in Silicon Valley, it should be noted), and some just weren't paying attention to the Internet when the tickets went on sale. But those tickets were available for over ten hours and everybody should have known they were going to sell out quickly. Yes, people got left out, and it sucks. That's the nature of scarcity. &lt;br /&gt;&lt;br /&gt;This is not an artificial scarcity, however. WWDC tickets are like money, you can't just solve the scarcity by printing more tickets. Every additional ticket reduces the value of the conference to the rest of the attendees. Letting everybody have what they want means nobody gets what they really want, or need. &lt;br /&gt;&lt;br /&gt;I'll take scarcity and a once-a-year scramble to buy tickets before they sell out over a soulless commodity conference like OpenWorld any day, thank you.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-3353385370849339450?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3353385370849339450'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3353385370849339450'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/03/on-wwdc-now-being.html' title='On WWDC Now Being &amp;quot;Broken&amp;quot;'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-8063110589836215654</id><published>2011-03-28T15:55:00.001-07:00</published><updated>2011-03-28T15:55:42.801-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WWDC'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>WWDC 2011 is Sold Out.</title><content type='html'>I told you they'd go fast.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-8063110589836215654?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/8063110589836215654'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/8063110589836215654'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/03/wwdc-2011-is-sold-out.html' title='WWDC 2011 is Sold Out.'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-5818223694549946266</id><published>2011-03-28T07:49:00.001-07:00</published><updated>2011-03-28T09:29:21.873-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WWDC'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>WWDC First Timer's Survival Guide, 2011 Edition</title><content type='html'>Today, WWDC was announced. This is the earliest they've announced WWDC during the iPhone epoch, so there's a little more time to prepare than we've had the last few years. Given how popular it's been the past few years, I thought it was worth updating and re-posting my &lt;a href="http://iphonedevelopment.blogspot.com/2010/04/wwdc-first-time-guide-2010-edition.html" target="_blank"&gt;WWDC First Time Guide from last year&lt;/a&gt; and &lt;a href="http://iphonedevelopment.blogspot.com/2009/03/wwdc-first-time-guide.html"&gt;the previous year&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Again, WWDC is different every year, so don't take anything written here as gospel, but hopefully these hints and suggestions will help some of you.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;Arrive on Sunday or Earlier&lt;/b&gt;. Registration is usually open most of the day on Sunday. You really, really want to get your badge and related swag (bag, shirt, jacket, etc) on Sunday. The line for the keynote will start forming many hours before the doors to Moscone West open up on Monday (the past three years, people started lining up before midnight Sunday). If you do not have your badge when you get to Moscone on Monday morning, you will almost certainly end up in an overflow room for the Keynote and may even miss part of it. Even if you don't care about being in the main room, there's still a lot going on on Sunday and it's a good time to meet new people and catch up with old friends. You really don't want to deal with the badge process on Monday.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Do &lt;strong&gt;not&lt;/strong&gt; lose your badge&lt;/b&gt;. If you lose it, you are done. You will spend your time crying on the short steps in front of Moscone West while you watch everyone else go in to get schooled. Sure, you'll still be able to attend the unofficial  after-hours goings-on (but not the Thursday night party, which is usually a blast), but you'll miss out on the really important stuff. No amount of begging or pleading will get you a replacement badge, and since they're likely to sell out, no amount of money will get you another one, either. And that would suck. Treat it like gold. When I'm not in Moscone West or somewhere else where I need the badge, I put it in my backpack, clipped to my backpack's keyper (the little hook designed to hold your keys so they don't get lost in the bottom of your bag). Yes, there have been isolated stories of people managing to convince a sympathetic conference worker to print them a new badge, but don't expect it, those are exceptions. The employees are not supposed to print new badges, and most won't.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Eat your fill&lt;/b&gt;. They will feed you two meals a day; you're on your own for dinner. Breakfast starts a half-hour before the first session, and it's most likely going to be a continental breakfast - fruit, pastries, juice, coffee, donuts, toast, and those round dinner rolls that Californians think are bagels, but really aren't. If you're diabetic, need to eat gluten-free, or are an early riser, you'll probably want to eat before-hand. Lunch used to be (IIRC) a hot lunch, but three or four years ago they switched to boxed lunches. They are pretty good as far as boxed lunches go, but they are boxed lunches. A lot of people complain (loudly) about them and choose to go to a nearby restaurant during the lunch break, which is pretty long - at least 90 minutes.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Party hard&lt;/b&gt; (not that you have a choice). There are lots of official and unofficial events in the evening. There's often a CocoaHeads meeting at the Apple Store. It fills up crazy fast, so go early if you go. It's usually competing with several other parties, but it starts earlier than most events and finishes early enough for people to go to other parties when it's done.  Best bet is to follow as many iPhone and Mac devs on Twitter that you can - the unofficial gatherings happen at various places downtown, often starting with a few "seed crystal" developers stopping for a drink and tweeting their whereabouts. The unofficial, spontaneous gatherings can be really fun and a great opportunity. The parties often start before WWDC - there are usually a few on Sunday, and there have been ones as early as Saturday before. Pretty much any other bar within stumbling distance of Moscone West will be used for planned and informal gatherings. As we get closer, there will be lists and calendars devoted to all the events and parties. Some are invite-only, but many are first-come, first-serve. Although there's a lot of drinking going on, these are worth attending even if you don't drink. Great people, great conversations... good times.&lt;br /&gt;&lt;br /&gt;At some point, one or more lists will pop up to track the official parties, gatherings, meet-ups, and BOF (birds of a feather meetings - meet-ups for people interested in a particular subject).&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Take good notes&lt;/b&gt;. You are going to be drinking knowledge from a firehose there. The information will come at you fast and furious. As an attendee, you will get all the session videos on ADC on iTunes. It used to take some time before the videos were available, but hopefully they'll continue to get them out quickly. Even so, make sure you write down the information you need immediately.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Collaborative note taking&lt;/b&gt; A few years ago, people started taking communal notes using &lt;a href="http://www.subethaedit.net/"&gt;SubEthaEdit&lt;/a&gt; and &lt;a href="http://www.panic.com/coda/" target="_blank"&gt;Panic's Coda&lt;/a&gt; (they are compatible with each other). That worked out really, really well. My notes from the past few years are ten times better than from previous years. With SubEthaEdit, you don't have to type fast enough to catch every detail. Instead, the audience works as a team and everybody gets great notes. The license fee pays for itself in one WWDC, especially considering you can see notes being taken in other sessions, not just your own.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Labs rule&lt;/b&gt;. If you're having a problem, find an appropriate lab. One of the concierges at any of the labs can tell you exactly which teams and/or which Apple employees will be at which labs when. If you're having an audio problem, you can easily stalk the Core Audio team until they beat the information into your skull, for example. It's unstructured, hands-on time with the people who write the frameworks and applications we use every day. People start remembering the labs later in the week it seems, but early on, you can often get an engineer all to yourself, though people have started to catch on. Every year the labs fill up earlier in the week.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Buddy up, divide and conquer&lt;/b&gt; There will be at least a few times when you want to be at more than one presentation at the same time. Find someone who's attending one and go to the other (Twitter is a good way to find people), then share your notes.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Make sure to sleep on the plane&lt;/b&gt;. You won't get many other chances once you get there. Everybody is ragged by Friday, some of us even earlier. Everyone remains surprisingly polite given how sleep-deprived and/or hungover people are.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Thank your hosts.&lt;/b&gt; The folks at Apple - the engineers and evangelists who give the presentations and staff the labs, kill themselves for months to make WWDC such a great event. So, do your mother proud and remember your manners. Say thank you when someone helps you, or even if they try and don't. And if you see one of them at an after hours event, it's quite alright to buy them a beer to say thanks.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Remember you're under NDA&lt;/b&gt;. This one is hard, especially for me. We see so much exciting amazing stuff that week that it's natural to want to tweet it, blog it, or even tell the guy handing out advertisements for strip joints on the corner all about it. Don't. Everything, from morning to night except the Keynote and the Thursday night party are under NDA.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Brown Bag it&lt;/b&gt;. Most days there are "brown bag" sessions. These are speakers not from Apple who give entertaining, enlightening, or inspiring talks at lunchtime. Check the schedule, some of them are bound to be well worth your time.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Monday, Monday&lt;/b&gt; I don't know what to say about Monday. The last few years, people started lining up before midnight the night before. I'm typically on East coast time and usually walk over around 4:15 to see what's going on. I've done the line, and I've done the have-a-leisurely-breakfast route, and both have their merits. If you straggle too much, they may start before you get in the room, however (happened to me two years ago).&lt;br /&gt;&lt;br /&gt;Waiting in line is not really my thing, but you do get to talk to a lot of very cool people while waiting in line, and there is a sense of camaraderie that develops when you do something silly with other people like that. Some people probably want me to suggest what time to get in line. I have no idea. Most people will get into the main room to see the Keynote. There will be some people diverted to an overflow room, but because the number of attendees is relatively low and the Presidio (the keynote room) is so big, it's a tiny percentage who have to go to the overflow rooms (maybe the last 1,000 to 1,500 or so, depending on number of VIPs in attendance). On the other hand, you'll actually get a better view in the overflow rooms unless you get in line crazy early - you'll get to watch it in real time on huge screens and you'll get to see what's happening better than the people at the back of the Presidio. So, go when you want to. If you want to get up early and go be one of the "crazy ones", cool! If you want to get up later, you'll still get to see the keynote sitting in a comfy room with other geeks.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Turn off your MiFi/Clear/other wireless router&lt;/b&gt;. I'm so totally not kidding on this one. People will punch you if they find out you've got one on. Last year, so many people had MiFis and other mobile hotspots running during the keynote that it interfered with the conference center's (very good) WiFi network and disrupted some of the tech demos. Once you're in the building, you don't need it. They have crazy fast pipe in the building, so just use the provided WiFi and turn your wireless router off. Seriously.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Park it once in a while&lt;/b&gt; There will be time between sessions, and maybe even one or two slots that have nothing you're interested in. Or, you might find yourself just too tired to take in the inner workings of some technology. In that case, there are several lounges around where you can crash in a bean bag chair, comfy chair, moderately-comfy chair, or patch of floor. There is good wi-fi throughout the building and crazy-fast wired connections and outlets in various spots on all floors. So, find a spot, tweet your location, and zone out for a little while or do some coding. You never know who you might end up talking with. If you move around too much, well, let's just say a moving target is harder to hit than a stationary one.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Twitter is invaluable, but don't expect it to stay up during the keynote&lt;/b&gt;. There's really no better way to hook up with people you didn't travel with than Twitter. Two years ago, we completely overwhelmed twitter during the keynote. Last year it fared okay, though there were some delays and hiccups.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;It's okay to leave&lt;/b&gt;. Don't worry if a few minutes into a session you decide that you've made a horrible mistake and it's too boring/advanced/simple/etc, or you're just too hungover. Just get up and leave quietly and wander to a different session. Nobody is going to be offended if you leave politely and without causing a disturbance.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Bring proof of age on Thursday night&lt;/b&gt;. The official party is always on Thursday night, and it's always a blast. There's good food, good drink, great company, and usually a pretty good band. The last three years featured OK, Go, Cake, and the Bare Naked Ladies. They are pretty strict about making sure only people who are over 21 get alcohol. So, if you want to have a drink or five on Thursday, don't leave your license or passport in your hotel room, even if you're 70 years old.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;It's okay to take breaks&lt;/b&gt;. Your first time, you're going to be tempted to go to every session you possibly can. Somewhere around Wednesday or Thursday, though, that effort combined with lack of sleep, is going to take its toll on you. If you're too tired or overwhelmed to process information, it's okay to hole up on a couch or at a table instead of going to a session, or even to go back to your hotel (you did get a close one, right?). In fact, it's a darn good idea to map out a few "sacrificial" time slots that won't feel bad about missing just in case you need a break. You don't want to burn out and then miss something you are really interested in. And some of the best, more advanced sessions fall at the end of the week, so don't shoot your wad early in the week.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Get a close hotel&lt;/b&gt; If at all possible, try and get a hotel within two blocks and definitely not more than five blocks from Moscone West. Five blocks doesn't seem like a lot, but it can become quite a hassle, especially if you're North of Moscone West because you'll be climbing up a pretty decent hill in one direction.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Official Evening Events&lt;/b&gt; In addition to the Thursday night Beer Bash, there are other official activities in the evening that are very entertaining and usually happen in the early evening before the parties really get going. The two stalwarts are the Apple Design Awards and Stump the Chumps (it's actually called "Stump the Experts", but most of the participants refer to it as "Stump the Chumps"). Stump the Experts is an Apple trivia game-show like event with notable tech luminaries and former Apple employees. Lots of sharp wits and deep knowledge of Apple make for some good entertainment. There used to also be a Monday night reception and cocktail hour, but if memory serves, it hasn't happened in a few years.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Take the BART&lt;/b&gt; If you're flying into either SFO or OAK and are staying near Moscone West (or near any BART station) there's really no reason to bother with renting a car or taking a cab from the airport. Just take BART and get off at the Powell Street station and walk up 4th street (South). Moscone West will be about four blocks on your right.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Bring a Sweatshirt or Jacket&lt;/b&gt; A lot of first-timers assume that it's California in the summer so it's going to be hot. Well, it could be, during the middle of the day, but look up Mark Twain's quote about San Francisco in the summer. It can be downright cool in San Francisco in the summer time, especially in the evenings and early morning. Bring a sweatshirt or light jacket, and wear layers because the temperature differential over the course of the day can be forty or fifty degrees.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Sample Code&lt;/b&gt; Many sessions will have sample code, usually downloadable from the schedule or class descriptions web pages. The sample code will stay up for a while, but may not stay around forever, so it's a good idea to download any code samples you want as soon as you can. &lt;b&gt;Edit:&lt;/b&gt; It looks like starting with 2009, you &lt;b&gt;can&lt;/b&gt; get to the old source code for years you attended by &lt;a href="http://developer.apple.com/itunes/" target="_blank"&gt;logging in to ADC on iTunes&lt;/a&gt;, however I always save off a copy just in case.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Get a Battery Pack&lt;/b&gt; You might want to consider a battery pack for your iPhone. You'll be in for some very long days, and it's not uncommon for your phone to be bone dry by early evening if you don't remember to charge it during the day. AT&amp;T reception in San Francisco is notoriously bad, and that takes a toll on battery life.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;Don't Sound Like a N00b&lt;/b&gt; It's technically called the "World Wide Developer's Conference", so logically, you'd expect people to refer to it as "&lt;b&gt;the&lt;/b&gt; WWDC" (e.g. "I'm going to head over to the WWDC")… only nobody does. It's just "WWDC" ("are you gong to WWDC this year?). Less commonly, it's also called the "Dubdub", with or without the "the": ("Man, what an awesome Dubdub that was", or "What time are you heading over to the Dubdub?").&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;Have more suggestions for first-timers? Add them to the comments.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-5818223694549946266?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/5818223694549946266'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/5818223694549946266'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/03/wwdc-first-timer-survival-guide-2011.html' title='WWDC First Timer&amp;#39;s Survival Guide, 2011 Edition'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-7517264643174918245</id><published>2011-03-28T06:31:00.001-07:00</published><updated>2011-03-28T06:31:19.733-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WWDC'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>WWDC 2011 Announced</title><content type='html'>&lt;a href="http://developer.apple.com/wwdc/" target="_blank"&gt;June 6-10 at Moscone West&lt;/a&gt;. You should go. If you're going to go, don't wait, they will sell out.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-7517264643174918245?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/7517264643174918245'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/7517264643174918245'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/03/wwdc-2011-announced.html' title='WWDC 2011 Announced'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-7972809909446194582</id><published>2011-03-10T15:11:00.001-08:00</published><updated>2011-03-12T05:45:26.957-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Sample Code'/><category scheme='http://www.blogger.com/atom/ns#' term='iOS SDK'/><category scheme='http://www.blogger.com/atom/ns#' term='iPhone SDK'/><title type='text'>Attributed Strings in iOS</title><content type='html'>Ten months ago when the original iPad shipped, Apple released iOS 3.2, and for the first time, iOS developers had access to &lt;font face="monospace"&gt;NSAttributedString&lt;/font&gt; and &lt;font face="monospace"&gt;NSMutableAttributedString&lt;/font&gt;, objects designed to hold strings along with font, paragraph, and style information. We no longer had to resort to using heavy  &lt;font face="monospace"&gt;UIWebView&lt;/font&gt;s or complex Core Graphics calls to draw styled text.&lt;br /&gt;&lt;br /&gt;Well, sort of…&lt;br /&gt;&lt;br /&gt;On the Mac side of things, &lt;font face="monospace"&gt;NSAttributedString&lt;/font&gt; and its counterpart &lt;font face="monospace"&gt;NSMutableAttributedString&lt;/font&gt; have been around for a long, long time, as part of Foundation. But, there's also been, for nearly as long, categories on both of these classes in App Kit called the &lt;em&gt;Application Kit Additions&lt;/em&gt; which have all sorts of useful additional methods.&lt;br /&gt;&lt;br /&gt;These categories provide ways to create attributed strings from various sorts of formatted text documents (RTF, HTML), to create attributed strings by specifying multiple specified attributes, to tweak existing attributes, to draw the attributed string, and to determine the size of an attributed string if it were to be drawn.&lt;br /&gt;&lt;br /&gt;In fact, most of the really useful methods for these two classes are contained in these App Kit categories and not in the base classes. Unfortunately, we don't have those categories in the iOS SDK, or even a scaled back version of them. We just have the base classes. That means we have a whopping thirteen methods on &lt;font face="monospace"&gt;NSAttributedString&lt;/font&gt;, and another thirteen on &lt;font face="monospace"&gt;NSMutableAttributedString&lt;/font&gt;. &lt;br /&gt;&lt;br /&gt;Cocoa has luxury-brand attributed strings; Cocoa touch has store-brand generic  ones. &lt;br /&gt;&lt;br /&gt;Even weirder, &lt;font face="monospace"&gt;NSAttributedString&lt;/font&gt; has an init method that takes a dictionary of string attributes, but the key constants for using that method aren't even included in iOS in either the public headers or the documentation. The description of the methods that take these attributes state that the constants are in the &lt;strong&gt;Overview&lt;/strong&gt; section of the documentation, but that's actually only true in the Mac OS X documentation, not the iOS documentation.&lt;br /&gt;&lt;br /&gt;In other words, you can't create an &lt;font face="monospace"&gt;NSAttributedString&lt;/font&gt; or &lt;font face="monospace"&gt;NSMutableAttributedString&lt;/font&gt; using &lt;font face="monospace"&gt;initWithString:attributes:&lt;/font&gt; because you don't have the constants you need in order to specify the various attributes. That's not entirely true; you actually are able to use the Core Text counterparts of the &lt;font face="monospace"&gt;NSAttributedString&lt;/font&gt; constants , such as &lt;font face="monospace"&gt;kCTForegroundColorAttributeName&lt;/font&gt; in place of &lt;font face="monospace"&gt;NSForegroundColorAttributeName&lt;/font&gt;, however this isn't actually documented anywhere, and there isn't an exact 1:1 correlation between the &lt;font face="monospace"&gt;NS&lt;/font&gt; and &lt;font face="monospace"&gt;CT&lt;/font&gt; string attributes (though it's close).&lt;br /&gt;&lt;br /&gt;This situation is really odd. Apple went through great efforts to give us all the low-level pieces need to do complex text rendering, but didn't give us higher-level objects to handle most that functionality elegantly. We have the lion's share of all of the low-level Core Text and Core Graphics calls that are available on Mac OS X (still no Core Image, though). Yet, we have to write low-level Core Text and Core Graphics code to do the bulk of even the most common typesetting tasks using attributed strings.&lt;br /&gt;&lt;br /&gt;Fortunately, &lt;font face="monospace"&gt;NSAttributedString&lt;/font&gt; and &lt;font face="monospace"&gt;NSMutableAttributedString&lt;/font&gt; are both &lt;font face="monospace"&gt;toll-free bridged&lt;/font&gt; to their Core Foundation counterparts &lt;font face="monospace"&gt;CFAttributedStringRef&lt;/font&gt; and &lt;font face="monospace"&gt;CFMutableAttributedStringRef&lt;/font&gt; respectively. That means you can create, for example, a &lt;font face="monospace"&gt;CFAttributedStringRef&lt;/font&gt; and simply cast it to an &lt;font face="monospace"&gt;NSAttributedString&lt;/font&gt; pointer, and then calling &lt;font face="monospace"&gt;NSAttributedString&lt;/font&gt; methods on it will work.&lt;br /&gt;&lt;br /&gt;Mostly.&lt;br /&gt;&lt;br /&gt;There's one gotcha here. On iOS, &lt;font face="monospace"&gt;UIFont&lt;/font&gt; and &lt;font face="monospace"&gt;CTFont&lt;/font&gt; are &lt;strong&gt;not&lt;/strong&gt; toll-free bridged, even though &lt;font face="monospace"&gt;NSFont&lt;/font&gt; and &lt;font face="monospace"&gt;CTFont&lt;/font&gt; on the Mac are. You cannot pass a &lt;font face="monospace"&gt;UIFont&lt;/font&gt; into a function that expects a &lt;font face="monospace"&gt;CTFont&lt;/font&gt; and vice versa.&lt;br /&gt;&lt;br /&gt;To get a &lt;font face="monospace"&gt;CTFont&lt;/font&gt; from a &lt;font face="monospace"&gt;UIFont&lt;/font&gt;, you can do this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source mac_classic"&gt;&lt;span class="source source_objc source_objc_iphone"&gt;CTFontRef&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;CTFontCreateFromUIFont&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(UIFont *font)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;    CTFontRef ctFont =&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CTFontCreateWithName&lt;/span&gt;(&lt;/span&gt;(CFStringRef)font&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.fontName&lt;/span&gt;, &lt;br /&gt;                                            font&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.pointSize&lt;/span&gt;, &lt;br /&gt;                                            &lt;span class="constant constant_language constant_language_c"&gt;NULL&lt;/span&gt;);&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; ctFont;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Notice the name of this method - the word "create" in the function name indicates that the returned &lt;font face="monospace"&gt;CTFont&lt;/font&gt; object has been retained for you, and you are responsible for calling &lt;font face="monospace"&gt;CFRelease()&lt;/font&gt; on it when you're done with it, to avoid leaking.&lt;br /&gt;&lt;br /&gt;Going the other way, from a &lt;font face="monospace"&gt;CTFont&lt;/font&gt; to a &lt;font face="monospace"&gt;UIFont&lt;/font&gt; is only a little more involved. Here's a category method on &lt;font face="monospace"&gt;UIFont&lt;/font&gt; that will create an instance of &lt;font face="monospace"&gt;UIFont&lt;/font&gt; based on a &lt;font face="monospace"&gt;CTFontRef&lt;/font&gt; pointer&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source mac_classic"&gt;&lt;span class="source source_objc source_objc_iphone"&gt;&lt;span class="meta meta_implementation meta_implementation_objc"&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;implementation&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_objc"&gt;UIFont&lt;/span&gt;&lt;span class="meta meta_scope meta_scope_implementation meta_scope_implementation_objc"&gt;(MCUtilities)&lt;br /&gt;&lt;span class="meta meta_function-with-body meta_function-with-body_objc"&gt;&lt;span class="meta meta_function meta_function_objc"&gt;+ &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_id storage_type_id_objc"&gt;id&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;fontWithCTFont&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;CTFontRef&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;ctFont&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;    CFStringRef fontName =&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CTFontCopyFullName&lt;/span&gt;(&lt;/span&gt;ctFont);&lt;br /&gt;    &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; fontSize =&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CTFontGetSize&lt;/span&gt;(&lt;/span&gt;ctFont);&lt;br /&gt;    &lt;br /&gt;    UIFont *ret = &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;UIFont &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;fontWithName&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;(&lt;span class="support support_class support_class_cocoa"&gt;NSString&lt;/span&gt; *)fontName &lt;span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc"&gt;size&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;fontSize&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CFRelease&lt;/span&gt;(&lt;/span&gt;fontName);&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; ret;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Once you have the ability to convert the two font objects into each other, creating attributed strings really isn't that bad. Here's an example category method on &lt;font face="monospace"&gt;NSMutableAttributedString&lt;/font&gt; that will create an instance by taking an &lt;font face="monospace"&gt;NSString&lt;/font&gt; plus a font, a font size, and a constant representing the desired text justification. It will return an autoreleased attributed string with the text attributes applied to the entire string:&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source mac_classic"&gt;&lt;span class="source source_objc source_objc_iphone"&gt;+ (&lt;span class="storage storage_type storage_type_id storage_type_id_objc"&gt;id&lt;/span&gt;)mutableAttributedStringWithString:(&lt;span class="support support_class support_class_cocoa"&gt;NSString&lt;/span&gt; *)string font:(UIFont *)font color:(UIColor *)color alignment:(CTTextAlignment)alignment&lt;br /&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;    CFMutableAttributedStringRef attrString =&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CFAttributedStringCreateMutable&lt;/span&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_variable constant_other_variable_mac-classic constant_other_variable_mac-classic_c"&gt;kCFAllocatorDefault&lt;/span&gt;, &lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;);&lt;br /&gt;    &lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;string != &lt;span class="constant constant_language constant_language_objc"&gt;nil&lt;/span&gt;)&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;        &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CFAttributedStringReplaceString&lt;/span&gt; (&lt;/span&gt;attrString,&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CFRangeMake&lt;/span&gt;(&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;, &lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;), (CFStringRef)string);&lt;br /&gt;    &lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CFAttributedStringSetAttribute&lt;/span&gt;(&lt;/span&gt;attrString,&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CFRangeMake&lt;/span&gt;(&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;,&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CFAttributedStringGetLength&lt;/span&gt;(&lt;/span&gt;attrString)), &lt;span class="constant constant_other constant_other_variable constant_other_variable_mac-classic constant_other_variable_mac-classic_c"&gt;kCTForegroundColorAttributeName&lt;/span&gt;, color&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.CGColor&lt;/span&gt;);&lt;br /&gt;    CTFontRef theFont =&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CTFontCreateFromUIFont&lt;/span&gt;(&lt;/span&gt;font);&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CFAttributedStringSetAttribute&lt;/span&gt;(&lt;/span&gt;attrString,&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CFRangeMake&lt;/span&gt;(&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;,&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CFAttributedStringGetLength&lt;/span&gt;(&lt;/span&gt;attrString)), &lt;span class="constant constant_other constant_other_variable constant_other_variable_mac-classic constant_other_variable_mac-classic_c"&gt;kCTFontAttributeName&lt;/span&gt;, theFont);&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CFRelease&lt;/span&gt;(&lt;/span&gt;theFont);&lt;br /&gt;    &lt;br /&gt;    CTParagraphStyleSetting settings&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt; = &lt;span class="meta meta_block meta_block_c"&gt;{&lt;span class="constant constant_other constant_other_variable constant_other_variable_mac-classic constant_other_variable_mac-classic_c"&gt;kCTParagraphStyleSpecifierAlignment&lt;/span&gt;,&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;sizeof&lt;/span&gt;(&lt;/span&gt;alignment), &amp;amp;alignment}&lt;/span&gt;;&lt;br /&gt;    CTParagraphStyleRef paragraphStyle =&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CTParagraphStyleCreate&lt;/span&gt;(&lt;/span&gt;settings,&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;sizeof&lt;/span&gt;(&lt;/span&gt;settings) /&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;sizeof&lt;/span&gt;(&lt;/span&gt;settings&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;));&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CFAttributedStringSetAttribute&lt;/span&gt;(&lt;/span&gt;attrString,&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CFRangeMake&lt;/span&gt;(&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;,&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CFAttributedStringGetLength&lt;/span&gt;(&lt;/span&gt;attrString)), &lt;span class="constant constant_other constant_other_variable constant_other_variable_mac-classic constant_other_variable_mac-classic_c"&gt;kCTParagraphStyleAttributeName&lt;/span&gt;, paragraphStyle);    &lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CFRelease&lt;/span&gt;(&lt;/span&gt;paragraphStyle);&lt;br /&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class="support support_class support_class_cocoa"&gt;NSMutableAttributedString&lt;/span&gt; *ret = (&lt;span class="support support_class support_class_cocoa"&gt;NSMutableAttributedString&lt;/span&gt; *)attrString;&lt;br /&gt;    &lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;ret &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;autorelease&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What about calculating the space needed to draw an attributable string? That's a little more involved, but it can be done. Here are two category methods on &lt;font face="monospace"&gt;NSAttributedString&lt;/font&gt;that will tell you how much space an attributed string will require when drawn at a specified width or height, which is a useful thing to know when laying out text:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;NB(1):&lt;/b&gt; This is a new version that's both shorter, and fixes a bug with the original version.&lt;br /&gt;&lt;br /&gt;&lt;b/&gt;NB(2):&lt;/b&gt; A couple of people on Twitter have commented that you should save a reference to your &lt;font face="monospace"&gt;CTFrameSetterRef&lt;/font&gt; when calculating height or width and re-use it, because the framesetter will cache those calculations. If you use a new one, you not only have the overhead of a new object, you  will also be doing the size calculation twice. I'm planning a future post where I show how to draw attributed strings, and I need to give some thought about how to re-architect the code for that post based on that feedback.&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source mac_classic"&gt;&lt;span class="source source_objc source_objc_iphone"&gt;- (&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt;)boundingWidthForHeight:(&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt;)inHeight&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;    CTFramesetterRef framesetter =&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CTFramesetterCreateWithAttributedString&lt;/span&gt;(&lt;/span&gt; (CFMutableAttributedStringRef) self); &lt;br /&gt;    &lt;span class="support support_type support_type_quartz"&gt;CGSize&lt;/span&gt; suggestedSize =&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CTFramesetterSuggestFrameSizeWithConstraints&lt;/span&gt;(&lt;/span&gt;framesetter,&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CFRangeMake&lt;/span&gt;(&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;, &lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;), &lt;span class="constant constant_language constant_language_c"&gt;NULL&lt;/span&gt;,&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CGSizeMake&lt;/span&gt;(&lt;/span&gt;CGFLOAT_MAX, inHeight), &lt;span class="constant constant_language constant_language_c"&gt;NULL&lt;/span&gt;);&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CFRelease&lt;/span&gt;(&lt;/span&gt;framesetter);&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; suggestedSize&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.width&lt;/span&gt;;   &lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;- (&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt;)boundingHeightForWidth:(&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt;)inWidth&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;    CTFramesetterRef framesetter =&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CTFramesetterCreateWithAttributedString&lt;/span&gt;(&lt;/span&gt; (CFMutableAttributedStringRef) self); &lt;br /&gt;    &lt;span class="support support_type support_type_quartz"&gt;CGSize&lt;/span&gt; suggestedSize =&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CTFramesetterSuggestFrameSizeWithConstraints&lt;/span&gt;(&lt;/span&gt;framesetter,&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CFRangeMake&lt;/span&gt;(&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;, &lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;), &lt;span class="constant constant_language constant_language_c"&gt;NULL&lt;/span&gt;,&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CGSizeMake&lt;/span&gt;(&lt;/span&gt;inWidth, CGFLOAT_MAX), &lt;span class="constant constant_language constant_language_c"&gt;NULL&lt;/span&gt;);&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CFRelease&lt;/span&gt;(&lt;/span&gt;framesetter);&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; suggestedSize&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.height&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I assume it's only a matter of time before Apple gives us the &lt;font face="monospace"&gt;NSAttributedString&lt;/font&gt; &lt;em&gt;UIKit Additions&lt;/em&gt; category, or some similar higher-level functionality. In the meantime, any time you have to deal with attributed strings, the best bet is to figure out how to do what you need to do in Core Text and/or Core Graphics (Apple's Programming Guides actually show exactly how to do the most common tasks using both of these frameworks), then wrap a generic version of that code into a category method on &lt;font face="monospace"&gt;NSAttributedString&lt;/font&gt; or &lt;font face="monospace"&gt;NSMutableAttributableString&lt;/font&gt;.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-7972809909446194582?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/7972809909446194582'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/7972809909446194582'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/03/attributed-strings-in-ios.html' title='Attributed Strings in iOS'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-770956279605048884</id><published>2011-03-10T05:54:00.001-08:00</published><updated>2011-03-10T05:54:57.311-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mac App Store'/><title type='text'>Building for the MAS</title><content type='html'>If you have any thought of making the jump from iOS to the Mac App Store, &lt;a href="http://furbo.org/2011/03/09/mac-app-store-guide/" target="_blank"&gt;bookmark this post by Craig Hockenberry right now&lt;/a&gt;. It's a brilliant and detailed guide to everything you need to do to get your application on the Mac App Store from somebody who's been there.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-770956279605048884?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/770956279605048884'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/770956279605048884'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/03/building-for-mas.html' title='Building for the MAS'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-3217779342206491027</id><published>2011-03-07T10:41:00.001-08:00</published><updated>2011-03-07T10:41:02.722-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iOS SDK'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorials'/><category scheme='http://www.blogger.com/atom/ns#' term='iPhone SDK'/><category scheme='http://www.blogger.com/atom/ns#' term='Other blogs'/><title type='text'>Design Then Code</title><content type='html'>&lt;a href="http://twitter.com/#!/flyosity" target="_blank"&gt;Mike Rundle&lt;/a&gt; just put up &lt;a href="http://designthencode.com/scratch/" target="_blank"&gt;a really nice beginner's tutorial on program iOS SDK applications from scratch&lt;/a&gt;. Although I disagree with him pretty violently about whether you should use Interface Builder (no, really, you should use it), it's otherwise a brilliant introduction; one of the best I've seen on the web for beginners.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-3217779342206491027?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3217779342206491027'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3217779342206491027'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/03/design-then-code.html' title='Design Then Code'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-4787839659169996608</id><published>2011-03-04T14:02:00.001-08:00</published><updated>2011-03-04T14:17:38.647-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iPad'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='iOS'/><title type='text'>The iPad 2 Rant</title><content type='html'>MartianCraft has a fair amount of Android work right now. Personally, I try to focus on the iOS work whenever possible, but we're a small company, so nobody gets to play the primadonna. As a result, I spend a good chunk of my time on Android projects and have to stay abreast of both the Android and iOS worlds from both a hardware and a software perspective.&lt;br /&gt;&lt;br /&gt;Last week, I found myself grudgingly admitting to myself that the Motorola Xoom is not a bad tablet. It feels incomplete in many ways. It has rough edges, some definite hardware and software CBBs&amp;sup1;, and a general dearth of good, native-resolution apps. But, it had potential and I definitely saw how certain demographics might be attracted to it over the iPad. I saw a tablet that normal people could use with some frustration, but not an insurmountable amount… much like Windows, post Windows-95.&lt;br /&gt;&lt;br /&gt;The thing that I haven't seen in any of the Android tablets, however, is a compelling reason to buy them instead of the iPad. The only people I know who've bought Android tablets also own iPads. Other than a strong aversion to Apple's products or Apple as a company, what would compel somebody to pay $800 for a Xoom or Tab rather than going out and getting an iPad? Maybe there's a reason, but I can't see it. While both the Xoom and Tab had some specs that were better than the original iPad, neither offered a comparable experience let alone a better one, and neither could do anything that the iPad can't&amp;sup2;, despite higher price tags.&lt;br /&gt;&lt;br /&gt;Then came yesterday.&lt;br /&gt;&lt;br /&gt;Two days ago, the Xoom looked like a decent, almost finished and slightly overpriced tablet. Two days ago, it had a couple of quantifiable advantages, including native CDMA support and a better GPU. Two days ago, you could make the Xoom look better than the iPad on paper. Though marketing based on tech specs hasn't proven to be a very effective strategy in mobile computing space, at least they did have that for them. They had grounds for claiming you should buy the Xoom instead of an iPad. The arguments were thin, but two days ago they existed.&lt;br /&gt;&lt;br /&gt;Today, simply put: The Xoom is fucked. So, I suspect, is the unreleased Samsung Tab 10.1 and the RIM Playbook. I can only imagine the discussions that are going on inside those companies today.&lt;br /&gt;&lt;br /&gt;Only the staunchest Apple haters and self-deluded "openness" ideologues are going to pony up that kind of dough for a tablet that can't offer a comparable experience and doesn't have better tech specs. The Xoom doesn't even have the advantage of working with a carrier that Apple's tablet doesn't. In seven days, there will be both native CDMA and GSM models of the iPad 2.&lt;br /&gt;&lt;br /&gt;Think about this: yesterday when I checked, the Android Marketplace had sixteen Honeycomb tablet-resolution apps. &lt;em&gt;Sixteen&lt;/em&gt;. And you know what's not included in that sixteen? That space game that they show the guy playing in the Xoom commercials. In other words, they had to put a fake game in the commercial. Would they have done that if they had even &lt;em&gt;one&lt;/em&gt; compelling application that could make the Xoom look better than the iPad?&lt;br /&gt;&lt;br /&gt;As a tablet platform, Android has two big challenges.&lt;br /&gt;&lt;br /&gt;First, it has a chicken-and-egg problem with software. Developers are waiting for people to buy Android tablets in sufficient quantity to support the platform, and many consumers are waiting for good apps to buy Android. In the phone world, Android seems to be past that hump. While the app situation is nowhere near as good as on iOS yet, there are apps — including some good ones — for the platform.&lt;br /&gt;&lt;br /&gt;But, even if the Xoom were every bit as amazing of a piece of hardware as the iPad 2, it would still have the problem that &lt;em&gt;it does less cool things&lt;/em&gt;. There's nothing comparable to Garage Band or iMovies, or any of the hundreds of jaw-dropping iPad apps that have been created in the last year like Infinity Blade, The Elements, or Alice. There's just no "wow" app you can put on your Xoom and show people that's going to make them want to run out and buy one. There's nothing you can do and confidently say "your iPad can't do that shit right there, bitch".&lt;br /&gt;&lt;br /&gt;The second, and much larger problem is simply one of price. I see people constantly comparing the Android/iOS situation to the Windows/Mac situation of the eighties and nineties. I usually see this claim by people laughably arguing that Apple's failure is imminent. &lt;br /&gt;&lt;br /&gt;In the nineties, Apple kept insane profit margins on their products while dozens of manufacturers created inexpensive commodity PCs running Windows. There was a margin war on the PC side, and PCs became noticeably cheaper (despite paying hefty licensing fees to Microsoft), and that price difference, combined with Microsoft closing some of the usability gap with the Mac, is what lead to the dominance of Wintel machines.  In the nineties, Macs simply cost more. You could argue that Macs were cheaper based on TOC or employee efficiency, but in the quantifiable terms that bean counters understand, the Mac was a lot more expensive and didn't do noticeably more, especially once Adobe jumped ship and become cross-platform.&lt;br /&gt;&lt;br /&gt;That's not where things are now, however. For typical consumers - people who don't have a dog in the technology race, so to speak, are going to buy based largely on price, &lt;em&gt;Apple's mobile "post-PC devices" aren't just better than their competitors, they're cheaper than comparable competitors.&lt;/em&gt; &lt;br /&gt;&lt;br /&gt;We don't have a situation where commodity resellers can easily assemble components into a working, desirable mobile device. Mobile devices are all about form factor, design, and ease of use. They don't sit on a desk, they go where you go. They need to be well engineered, light, get good battery life, and be easy to use. They can't require IT support staff, an instruction manual, or training. A large beige box on a desk is one thing, but in your pocket it's another thing altogether.&lt;br /&gt;&lt;br /&gt;Why is this the case, though? Why can't these companies compete with Apple on price in the tablet space?&lt;br /&gt;&lt;br /&gt;The prices Apple can offer is a result of two things. First, is plain and simple buying power. Apple sells a lot of devices, so they buy a lot of screens, flash memory, etc. As a result, they can get quantity discounts. Apple got to the 10 inch form factor first and cornered the market, driving up the price for 10" screen components for any competitors coming after them.&lt;br /&gt;&lt;br /&gt;The second, however, is that they have gobs of cash on hand. A lot of market watchers say Apple is foolhardy to keep so much cash on hand. On the contrary! Apple understands psychology, and not just consumer psychology. When they go to a vendor or hardware partner and ask for exclusive arrangements, priority fulfillment, or better prices, do you know what bargaining chip they have that few other companies have? &lt;br /&gt;&lt;br /&gt;The corporate equivalent of a suitcase full of cash. &lt;br /&gt;&lt;br /&gt;When a vendor needs to retool for a new manufacturing process Apple has developed or needs to increase their output capacity, Apple shows up with a wad of cash in hand. They don't have to liquidate any assets or get a loan or seek permission of shareholders. They just play Daddy Warbucks and pull out a wad of million dollar bills. Apple's partners, in addition to getting large-volume contracts, can get working capital as part of their arrangment with Apple without taking out loans. A definite part of the reason you were able to buy an iPad for only $499 is because Apple didn't follow conventional wisdom about cash on hand.&lt;br /&gt;&lt;br /&gt;Arguing that Apple would be doing better by doing what everybody else is doing isn't usually very convincing to me.&lt;br /&gt;&lt;br /&gt;Motorola and Samsung… they're both large companies with a lot of buying power and strong brand recognition. The problem is, they don't understand the game that Apple's playing in the mobile space, so they're playing it wrong. They're so caught up in catching up that they're not even trying to innovate in this space. Maybe HP or Rim will figure it out, but I'm not going to hold my breath.&lt;br /&gt;&lt;br /&gt;Which is unfortunate. If Apple's doing this kind of amazing stuff without any viable competition, can you imagine what they'd be doing with strong, viable competitors nipping at their heels?&lt;br /&gt;&lt;br /&gt;&lt;hr/&gt;&lt;font size="2"&gt;&lt;i&gt;&lt;b&gt;1&lt;/b&gt; "Could Be Betters"&lt;/i&gt;&lt;/font&gt;&lt;br/&gt;&lt;font size="2"&gt;&lt;i&gt;&lt;b&gt;2&lt;/b&gt; From a consumer perspective, not from the perspective of a geek who likes to take things apart and put them back together. The Xoom, with its more powerful processor and GPU had the &lt;b&gt;potential&lt;/b&gt; to do things the original iPad couldn't, but didn't ship with any application that proved it. Consumers believe what they see, not what the tech specs say.&lt;/i&gt;&lt;/font&gt;&lt;/br&gt;&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-4787839659169996608?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/4787839659169996608'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/4787839659169996608'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/03/ipad-2-rant.html' title='The iPad 2 Rant'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-6734008856189847096</id><published>2011-02-24T18:36:00.001-08:00</published><updated>2011-02-24T18:36:47.391-08:00</updated><title type='text'>QuickBoot</title><content type='html'>If you're going to install the 10.7 preview on a separate hard drive or partition, it's definitely worth knowing about &lt;a href="http://buttered-cat.com/products/QuickBoot" target="_blank"&gt;Buttered Cat Software's QuickBoot&lt;/a&gt;, which allows you to change startup disks and reboot from your menu bar.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-6734008856189847096?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/6734008856189847096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/6734008856189847096'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/02/quickboot.html' title='QuickBoot'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-3891643600319389109</id><published>2011-02-24T07:52:00.001-08:00</published><updated>2011-02-24T07:57:42.388-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><category scheme='http://www.blogger.com/atom/ns#' term='Mac OS X'/><title type='text'>Lion in the House</title><content type='html'>Today, Apple released a preview version of &lt;a href="http://www.apple.com/macosx/lion/" target="_blank"&gt;Mac OS X Lion&lt;/a&gt;, but only for registered Mac developers. This is a big release, not just in terms of front-end experience, but also under the hood. A lot of the changes are influenced by UIKit and iOS, hence the moniker "Back to the Mac", but there's also a fair amount of completely new goodness, some of which will likely roll down to iOS at some point.&lt;br /&gt;&lt;br /&gt;If you're an iOS developer, but not a Mac developer, it's probably worth $99 to get access to &lt;strike&gt;Tiger&lt;/strike&gt; Lion. It'll give you a better idea of where Apple is taking things.&lt;br /&gt;&lt;br /&gt;Plus, there's just a lot of really cool stuff in there.&lt;br /&gt;&lt;br /&gt;Interestingly, the OS preview is being delivered via the Mac App Store, which might be a hint at how paid OS upgrades will be handled in the future.&lt;br /&gt;&lt;br /&gt;Members of the Mac developer program can log into the &lt;a href="http://developer.apple.com/devcenter/mac/index.action" target="_blank"&gt;Mac Developer site&lt;/a&gt; to download Lion, the release notes, and a new version of Xcode 4.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-3891643600319389109?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3891643600319389109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3891643600319389109'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/02/lion-in-house.html' title='Lion in the House'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-2779129654423770654</id><published>2011-02-23T09:11:00.001-08:00</published><updated>2011-02-23T09:11:14.382-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Speaking'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Voices that Matter Seattle</title><content type='html'>So far, 2011 has been pretty light for me in terms of speaking. I do, however, have one speaking engagement lined up for this year: I'll be speaking at &lt;a href="http://iphonespring2011.crowdvine.com/" target="_blank"&gt;Voices that Matter &lt;/a&gt;in &lt;strike&gt;the land of Mordor&lt;/strike&gt; Seattle on April 9th and 10th. If you're interested in going, early bird pricing ends on February 25.&lt;br /&gt;&lt;br /&gt;You can use the speaker code &lt;strong&gt;SEASPK2&lt;/strong&gt; to get $100 off.&lt;br /&gt;&lt;br /&gt;There's a great &lt;a href="http://iphonespring2011.crowdvine.com/speakers" target="_blank"&gt;speaker lineup&lt;/a&gt; for this conference, including &lt;a href="http://ihnatko.com/" target="_blank"&gt;Andy Ihnatko&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-2779129654423770654?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/2779129654423770654'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/2779129654423770654'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/02/voices-that-matter-seattle.html' title='Voices that Matter Seattle'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-2198350498529329223</id><published>2011-02-22T11:16:00.001-08:00</published><updated>2011-02-22T11:16:36.191-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Open Source'/><category scheme='http://www.blogger.com/atom/ns#' term='Blender'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL ES'/><title type='text'>Blender 2.5 beta 6 Objective-C Export</title><content type='html'>A kind reader updated my Objective-C export script for Blender to work with the 2.5 beta 6 version of Blender. You can find the new version &lt;a href="https://github.com/jlamarche/iOS-OpenGLES-Stuff/tree/master/Blender%20Export/objc-export-2.5/objc_blend_2.5.6" target="_blank"&gt;on GitHub&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;On a related note, if you make a change to your clone of any of my public repositories on Github, you can send me a pull request. I'm happy to take additions, bug fixes, and other updates back into the master repository.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Thanks to John Becker for updating the script!&lt;/em&gt;&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-2198350498529329223?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/2198350498529329223'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/2198350498529329223'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/02/blender-25-beta-6-objective-c-export.html' title='Blender 2.5 beta 6 Objective-C Export'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-314450034967498889</id><published>2011-02-22T11:10:00.001-08:00</published><updated>2011-02-22T11:10:51.247-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='App Store'/><category scheme='http://www.blogger.com/atom/ns#' term='Other blogs'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><title type='text'>Apple Outsider on the Subscription "Hubbub"</title><content type='html'>I have a very short list of "must-read" blogs. While I have a much bigger list of blogs I read as time permits, the list of ones that I check every morning before I buckle down to work consists of only about a half-dozen blogs by people in our industry who really know their stuff. One of those blogs is &lt;a href="http://www.appleoutsider.com" target="_blank"&gt;Apple Outside&lt;/a&gt;, written by former Apple Evangelist, Cocoa Guru, and all-around nice guy &lt;a href="http://twitter.com/#!/drance" target="_blank"&gt;Matt Drance&lt;/a&gt; (not to be confused with the more intimidating &lt;a href="http://twitter.com/#!/batdrance" target="_blank"&gt;BatDrance&lt;/a&gt; who is most definitely &lt;em&gt;&lt;strong&gt;not&lt;/strong&gt;&lt;/em&gt; Matt's alter-ego). &lt;br /&gt;&lt;br /&gt;I've been keeping my head low on the whole subscription kerfuffle that's been happening in the iOS dev world. Partially that's just because I'm busy and don't have time to pen a long blog-rant, but it's also because it's a complex situation on which I don't have a fully-formed opinion yet. Matt's &lt;a href="http://www.appleoutsider.com/2011/02/22/omgiapbbq/" target="_blank"&gt;even-handed take on the situation&lt;/a&gt; does a great job of articulating the situation and is well worth reading.&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-314450034967498889?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/314450034967498889'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/314450034967498889'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/02/apple-outsider-on-subscription.html' title='Apple Outsider on the Subscription &amp;quot;Hubbub&amp;quot;'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-6840146683971979344</id><published>2011-02-15T17:52:00.001-08:00</published><updated>2011-02-15T17:55:09.700-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iPhone SDK'/><category scheme='http://www.blogger.com/atom/ns#' term='Objective-C'/><category scheme='http://www.blogger.com/atom/ns#' term='CGAffineTransform'/><title type='text'>A Couple CGAffineTransform Goodies</title><content type='html'>Thanks to Core Animation, we iOS programmers tend to use &lt;a href="http://en.wikipedia.org/wiki/Affine_transformation" target="_blank"&gt;affine transformations&lt;/a&gt; (by way of &lt;font face="monospace"&gt;CGAffineTransform&lt;/font&gt;) a lot. By being able to combine multiple 2D transformations into a single matrix, we have the ability to do a lot of cool animation effects with only a few lines of code.&lt;br /&gt;&lt;br /&gt;Take the following example, which is fairly typical:&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source mac_classic"&gt;&lt;span class="source source_objc source_objc_iphone"&gt;    CGAffineTransform transform = CGAffineTransformMakeTranslation(&lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;, -translation);&lt;br /&gt;    transform = CGAffineTransformScale(transform, scaleFactor, scaleFactor);&lt;br /&gt;    view.transform = transform;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Not bad, right? In just three lines of code, we're able to both scale and translate a view or layer. But in reality, there's actually quite a few operations going on behind these three lines of code. The &lt;em&gt;CGAffineTransformScale()&lt;/em&gt; function calls &lt;em&gt;CGAffineTransformConcat()&lt;/em&gt; to perform a matrix multiplication operation between two affine matrices. But, as you probably know, you can't multiply a 2x3 matrix by another 2x3 matrix. To multiply affine transformations, they have to be converted back to 3x3 vector matrices first.&lt;br /&gt;&lt;br /&gt;On today's devices (even mobile devices), this all takes a trivial amount of processing power. But sometimes, when you're doing a lot of these transformations — say thousand or tens of thousands a second — it can be valuable to be able to avoid that conversion and matrix multiplication.&lt;br /&gt;&lt;br /&gt;It just so happens that with certain commonly used &lt;font face="monospace"&gt;CGAffineTransform&lt;/font&gt;s, you can cheat. Certain matrices can be joined together without performing matrix multiplication. For example, here are the matrices created by &lt;font face="monospace"&gt;CGAffineTransformMakeScale()&lt;/font&gt; and &lt;font face="monospace"&gt;CGAffineTransformMakeTranslation()&lt;/font&gt;, respectively:&lt;br /&gt;&lt;center&gt;&lt;br /&gt;&lt;img src="http://lh4.ggpht.com/_QLwms0mVa4w/TVsnFX0P1eI/AAAAAAAAAxo/Ekww_8YICng/equation08.gif?imgmax=800" alt="Equation08" border="0" width="79" height="69" /&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;img src="http://lh3.ggpht.com/_QLwms0mVa4w/TVsnfc-OFnI/AAAAAAAAAxs/F8GaqRXkIcs/equation06.gif?imgmax=800" alt="Equation06" border="0" width="76" height="74" /&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;Go ahead and multiply those two together. Plug in any number for &lt;em&gt;tx&lt;/em&gt;, &lt;em&gt;ty&lt;/em&gt;, &lt;em&gt;sx&lt;/em&gt;, and &lt;em&gt;sy&lt;/em&gt; and run the numbers. I'll wait. Okay, you don't have to. This is what you'll get:&lt;br /&gt;&lt;img style="display:block; margin-left:auto; margin-right:auto;" src="http://lh4.ggpht.com/_QLwms0mVa4w/TVsoLUvbgcI/AAAAAAAAAxw/7-unArIq-Ew/equation0x.gif?imgmax=800" alt="Equation0x" border="0" width="76" height="74" /&gt;&lt;br /&gt;&lt;br /&gt;So, if that's the result we're going to get, why bother going through the matrix multiplication in the first place? Why not just populate the matrix with both the scale and translate values right from the get-go? Well, we can. We can also do the same thing with translate and rotate.&lt;br /&gt;&lt;br /&gt;This is all there is to it:&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source mac_classic"&gt;&lt;span class="source source_objc source_objc_iphone"&gt;&lt;span class="storage storage_modifier storage_modifier_c"&gt;static&lt;/span&gt; &lt;span class="storage storage_modifier storage_modifier_c"&gt;inline&lt;/span&gt; CGAffineTransform&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;CGAffineTransformMakeRotateTranslate&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; angle, &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; dx, &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; dy)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CGAffineTransformMake&lt;/span&gt;(&lt;/span&gt;&lt;span class="support support_function support_function_C99 support_function_C99_c"&gt;cosf&lt;/span&gt;(angle),&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_support punctuation_whitespace_support_function punctuation_whitespace_support_function_leading punctuation_whitespace_support_function_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_C99 support_function_C99_c"&gt;sinf&lt;/span&gt;(angle), -&lt;span class="support support_function support_function_C99 support_function_C99_c"&gt;sinf&lt;/span&gt;(angle),&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_support punctuation_whitespace_support_function punctuation_whitespace_support_function_leading punctuation_whitespace_support_function_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_C99 support_function_C99_c"&gt;cosf&lt;/span&gt;(angle), dx, dy);&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="storage storage_modifier storage_modifier_c"&gt;static&lt;/span&gt; &lt;span class="storage storage_modifier storage_modifier_c"&gt;inline&lt;/span&gt; CGAffineTransform&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;CGAffineTransformMakeScaleTranslate&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; sx, &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; sy, &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; dx, &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; dy)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CGAffineTransformMake&lt;/span&gt;(&lt;/span&gt;sx, &lt;span class="constant constant_numeric constant_numeric_c"&gt;0.f&lt;/span&gt;, &lt;span class="constant constant_numeric constant_numeric_c"&gt;0.f&lt;/span&gt;, sy, dx, dy);&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That's it. It only saves you two lines of code:&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source mac_classic"&gt;&lt;span class="source source_objc source_objc_iphone"&gt;    view.transform = CGAffineTransformMakeScaleTranslate(scaleFactor, scaleFactor, &lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;, -translation);&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;But, your stack allocation is considerably smaller (one &lt;font face="monospace"&gt;CGAffineTransform&lt;/font&gt; instead of two &lt;font face="monospace"&gt;CGAffineTransform&lt;/font&gt;s and an intermediate 3x3 array. It also saves you eighteen floating point multiplications and nine floating point additions. 99.9% of the time, that number of operations is going to have no noticeable affect on your application - it's a trivial amount of both memory and &lt;a href="http://en.wikipedia.org/wiki/FLOPS" target="_blank"&gt;FLOPS&lt;/a&gt; under most normal situations.&lt;br /&gt;&lt;br /&gt;But… if you're doing a lot per second, they can add up and it's nice to know there's a way that you can save yourself a little overhead in some situations.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-6840146683971979344?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/6840146683971979344'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/6840146683971979344'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/02/couple-cgaffinetransform-goodies.html' title='A Couple CGAffineTransform Goodies'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_QLwms0mVa4w/TVsnFX0P1eI/AAAAAAAAAxo/Ekww_8YICng/s72-c/equation08.gif?imgmax=800' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-8523810502745047284</id><published>2011-02-13T11:22:00.001-08:00</published><updated>2011-02-13T11:22:42.891-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Xcode'/><category scheme='http://www.blogger.com/atom/ns#' term='Xcode 4'/><title type='text'>Xcode 4 Icons</title><content type='html'>Well, now that Xcode 4 is GM, it has the same icon as Xcode 3.25. Ordinarily, this wouldn't be an issue, since a GM release means you can throw out the old one and use it full-time.&lt;br /&gt;&lt;br /&gt;Only, you may not be able to with all of your projects. Xcode 4 GM has a few issues that make it hard to go full-time with it, &lt;a href="https://devforums.apple.com/message/374029" target="_blank"&gt;including a linker error that can only be worked around by turning some level of code optimization&lt;/a&gt;, a change that makes it hard to debug. A few of these problems impact projects I'm working on, so as a result, I have to grudgingly use Xcode 3.25 for some tasks.&lt;br /&gt;&lt;br /&gt;Despite a small handful of problems, though, Xcode 4 is where I want to be whenever possible. Having multiple identical icons in your Dock can be a bit of a pain.&lt;br /&gt;&lt;br /&gt;Unfortunately, I didn't save the old Xcode 4 installers. If I had, I would have just gone and stolen the old preview icon and continued using that. Since I didn't, &lt;a href="http://iphonedevelopment.blogspot.com/2009/03/multiple-developer-tool-installs.html" target="_blank"&gt;I did the same thing I did for beta iOS releases&lt;/a&gt; and made a customized version of the app icon for Xcode 4. &lt;a href="http://innerloop.biz/images/Xcode4.icns.zip" target="_blank"&gt;If you want to use it, you can download it here&lt;/a&gt;. To install, you just copy the .icns file into Xcode 4's app bundle, replacing the existing one. And, no, replacing the icon file with a new one doesn't cause problems with Xcode 4 due to code signing, though I feared it might.&lt;br /&gt;&lt;br /&gt;This is what it looks like:&lt;br /&gt;&lt;br /&gt;&lt;img style="display:block; margin-left:auto; margin-right:auto;" src="http://lh5.ggpht.com/_QLwms0mVa4w/TVgtWhKy3TI/AAAAAAAAAxg/Wg3WAf0tf-U/Xcode.png?imgmax=800" alt="Xcode" border="0" width="512" height="512" /&gt; &lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-8523810502745047284?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/8523810502745047284'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/8523810502745047284'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/02/xcode-4-icons.html' title='Xcode 4 Icons'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_QLwms0mVa4w/TVgtWhKy3TI/AAAAAAAAAxg/Wg3WAf0tf-U/s72-c/Xcode.png?imgmax=800' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-4612588836483561241</id><published>2011-02-08T09:42:00.001-08:00</published><updated>2011-02-09T15:42:45.128-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Open Source'/><category scheme='http://www.blogger.com/atom/ns#' term='source code'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL ES'/><title type='text'>MC3D - Platform Agnostic 3D Foundation</title><content type='html'>Sorry for the lack of posts recently. Things have been, well… you know. Same old story. Super busy. Which is good, but it's murder on blog post frequency.&lt;br /&gt;&lt;br /&gt;I've recently had to port some OpenGL ES work I did from iOS to Android. It used to be that doing so would have been insanely painful (as opposed to just painful). I would have had to convert the Objective-C code to Java, and then maintain completely distinct sets of code that do the same exact thing. Fortunately, the &lt;a href="http://developer.android.com/sdk/ndk/index.html" target="_blank"&gt;Android NDK&lt;/a&gt; (Native Development Kit) allows you to write code for Android in C/C++. The version of the NDK supported on 2.2 still requires part of the Activity (Android's counterpart to an iOS view controller) to be written in Java, but does allow you to call C/C++ code using JNI. In 2.3 and 3.0, you can do entire activities in C or C++.&lt;br /&gt;&lt;br /&gt;This is a huge step forward for Android for those of us who do performance-critical work on multiple platforms, but it's not without some pain. Debugging across the JNI bridge is… less than easy. But, being able to share code across platforms is a huge win, and being able to get native speeds in the process is teh awseome.&lt;br /&gt;&lt;br /&gt;During these projects, I've been taking a lot of my 3D-related code and creating a new set of platform-agnostic C functions and types. I've been cleaning up and making names consistent, and placing appropriate pre-compiler macros to make sure the code compiles correctly everywhere. On iOS, the library will take advantage of the Accelerate Framework in places, but doesn't require Accelerate to function.&lt;br /&gt;&lt;br /&gt;I've chosen C because I don't like mixing C++ and Objective-C. The object models are too different for my tastes. But I've also made sure to include proper ifdef'd extern statements so that you can import the MC3D header files from C++ without hassle.&lt;br /&gt;&lt;br /&gt;I've dubbed this set of functions &lt;a href="https://github.com/jlamarche/MC3D" target="_blank"&gt;&lt;strong&gt;MC3D&lt;/strong&gt;&lt;/a&gt;, and I'm making it open source under a simplified version of the simplified BSD license (&lt;em&gt;simplified simplified BSD license?&lt;/em&gt;). I've taken out the attribution requirement, so the only requirement is that if you re-distribute the source code, you have to leave the copyright and license text intact. That's it. Otherwise, you can use it for free in any project, commercial or otherwise, without paying anything, without attributing, and without asking (no really, you don't need to ask).&lt;br /&gt;&lt;br /&gt;MC3D is still very much a work in progress, and I'm only adding code to the repository that I feel is ready for public consumption. Much of what's in MC3D has been posted here before, sometimes with different names or in slightly different form. &lt;br /&gt;&lt;br /&gt;I have other code that I plan to add in the future, including higher-level functionality like model loading, scene management, and skeletal animation, but I won't add anything until its both solid and platform agnostic.&lt;br /&gt;&lt;br /&gt;Currently, documentation is very sparse, and I currently can't offer any support or help with using it, so &lt;em&gt;caveat emptor&lt;/em&gt;! I will gladly accept contributions, bug fixes, and new functionality back into the MC3D codeline.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://github.com/jlamarche/MC3D" target="_blank"&gt;&lt;strong&gt;MC3D on GitHub.&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;B&gt;Link fixed, sorry about that&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-4612588836483561241?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/4612588836483561241'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/4612588836483561241'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/02/mc3d-platform-agnostic-3d-foundation.html' title='MC3D - Platform Agnostic 3D Foundation'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-1823344147404984984</id><published>2011-01-27T17:14:00.001-08:00</published><updated>2011-01-27T17:14:29.111-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Other blogs'/><title type='text'>Complete Friday Q&amp;A</title><content type='html'>Mike Ash &lt;a href="http://www.mikeash.com/pyblog/complete-friday-qa-now-available.html" target="_blank"&gt;just announced the availability of his &lt;em&gt;Complete Friday Q&amp;A&lt;/em&gt; book.&lt;/a&gt; Mike's weekly blog posting is a must read for any Cocoa developer. Mike's knowledge of the language and system internals is amazing, and having all his weekly posts available in one place formatted like a book is a great resource. Go check it out on &lt;a href="http://itunes.apple.com/us/book/the-complete-friday-q-a-volume/id417272297" target="_blank"&gt;iTunes&lt;/a&gt; or &lt;a href="http://www.amazon.com/Complete-Friday-ebook/dp/B004KZQ0LO/ref=sr_1_14?ie=UTF8&amp;qid=1296154100&amp;sr=8-14" target="_blank"&gt;Amazon&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-1823344147404984984?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/1823344147404984984'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/1823344147404984984'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/01/complete-friday-q.html' title='Complete Friday Q&amp;amp;A'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-7383525547219527122</id><published>2011-01-27T08:40:00.001-08:00</published><updated>2011-02-08T11:24:10.420-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Game Programming'/><title type='text'>Garage Games</title><content type='html'>I noticed that Garage Games, the makers of the Torque game engine have recently had a near-death experience. As of the end of last year, it looked like they were shutting down operations. However, they appear to be in the midst of a phoenix-like return to life with, perhaps, some changes in focus and priority. The bad news for iOS folks, is that they've removed the mobile version of their 3D engine from their product list. I don't know if this means it's abandoned, or that they're just not ready to announce/release it. They are actively hiring developers and designers, and from the &lt;a href="http://www.garagegames.com/company/employment" target="_blank"&gt;job descriptions they've posted&lt;/a&gt;, it sounds to me like they've got their sights set firmly on mobile.&lt;br /&gt;&lt;br /&gt;To celebrate their revival, they're having a sale on all their products - you can get any of their engines, including a full source license for $99.&lt;br /&gt;&lt;br /&gt;Now, I honestly don't know how Torque compares to, say, &lt;a href="http://unity3d.com/" target="_blank"&gt;Unity&lt;/a&gt;, &lt;a href="http://sio2interactive.com/" target="_blank"&gt;Sio2&lt;/a&gt;, or the &lt;a href="http://www.udk.com/download" target="_blank"&gt;UDK&lt;/a&gt; in terms of features or ease of development, but there have been a lot of very solid games created with Torque over the years and the demos show the engine is versatile and fairly powerful. &lt;br /&gt;&lt;br /&gt;What I do know that $99 is a hell of a price for a source license to a game engine of this size and complexity. For me, it's worth that much money to get to peek around their code. There's a lot to be learned from looking at other people's code.&lt;br /&gt;&lt;br /&gt;No word on how long the sale is for, but &lt;a href="http://www.garagegames.com/" target="_blank"&gt;you can check it out here.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Note:&lt;/b&gt; I had an e-mail conversation with Garage Games' community manager about iTorque 3D. Unfortunately, right now the official word is that the product is off their roadmap. They have no announced plans to release it, so if you're targeting the iPhone or mobile devices in general, you're out of luck for now and should probably look at another engine. &lt;br /&gt;&lt;br /&gt;That being said, they didn't rule out the possibility of re-introducing iTorque 3D at some future point. Frankly, if you're interested in writing games, I still think it's well worth dropping $99 for a license to be able to see the choices they've made in designing their engine as well as how they've implemented them. It's a pretty good example of a complex cross-platform project.&lt;br /&gt;&lt;br /&gt;I have to say, I like the new public face of Garage Games. Their responses to my questions were prompt and candid. I think the new management knows exactly what they want to do and I'm looking forward to seeing where they take things.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-7383525547219527122?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/7383525547219527122'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/7383525547219527122'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2011/01/garage-games.html' title='Garage Games'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-4357429790463925454</id><published>2010-12-31T06:55:00.001-08:00</published><updated>2010-12-31T06:55:32.111-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><category scheme='http://www.blogger.com/atom/ns#' term='Apple'/><title type='text'>On Seven Inches</title><content type='html'>&lt;a href="http://twitter.com/#!/timbray" target="_blank"&gt;Tim Bray&lt;/a&gt; has &lt;a href="http://www.tbray.org/ongoing/When/201x/2010/12/28/Mobile-Market" target="_blank"&gt;a year-end blog post up that's worth a read.&lt;/a&gt; In case you don't know, Tim Bray is Google's Android Evangelist. As you might expect from someone who would take that job, he's as enthusiastic about the Android platform as I am about iOS. Although his perspective colors his view (as does mine), his analysis is usually pretty good.&lt;br /&gt;&lt;br /&gt;He's got one assertion in this most recent post, however, that doesn't seem to ring true to my ear.&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;Apple will totally do a 7" device. Anyone who’s spent quality time reading books or playing games on the Galaxy Tab knows; there’s a great big hole in the ecosystem that needs something bigger than a handset but that still fits in one hand and you can use for four hours in a row sitting up. This argument is over.&lt;/i&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;John Gruber seems similarly skeptical, opining yesterday that:&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;The problem is that it’s nice, for certain tasks, to be able to hold a tablet in one hand, but you can’t do that with the current iPad. I think Bray’s mistake is assuming that using a 7-inch display is the only way to solve that problem.&lt;/i&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;The argument is far from over, and it's silly to even make the assertion. I have, within arm's reach, the very 7" tablet Tim refers to - a &lt;a href="http://galaxytab.samsungmobile.com/" target="_blank"&gt;Samsung Galaxy Tab&lt;/a&gt;. I have spent quality time with the Tab, and think I definitely count as part of the set known as "anyone", yet I don't see this glaring hole that Tim thinks is so obvious. Personally, I found the Tab awkward for text reading, though part of that is due to Android's abysmal text rendering engine. The only way the Tab is better than the iPad for reading is that it's lighter and more portable. As for games, I'll admit that the Tab's form factor is pretty much ideal for driving games. All other types of games I've tried, it's either no better or worse than the iPad and, of course, there's no comparison in the selection of available games yet.&lt;br /&gt;&lt;br /&gt;The Tab is a 16:9 tablet running Android 2.2. For watching 16:9 video content like movies and HD television shows, the end result is that you get roughly the same size image video as you do on the iPad in a package that's lighter and easier to hold, which sounds like a winner, right? There are downsides, however. The smaller form factor means less room for batteries and thus shorter battery life. The energy requirements for a 7" tablet are not considerably less than those of a 10" device, but there's a lot less room for batteries. As a result, while battery life is almost never an issue on my iPad, it's often one on the Tab. If you've seen the inside of an iPad, you know that most of the heft of the iPad comes from batteries. Apple made the design decision that they'd rather have a slightly heavier device that could run all day long on a single charge with normal usage. Based on sales and reviews, I think it's safe to say that was a good decision.&lt;br /&gt;&lt;br /&gt;Batteries are getting more efficient every year, as are processors, so at some point, a 7" device with iPad-like battery life is completely feasible, however when that happens, a 10" device will have even better battery life. But battery life is far from the only downside to this form factor.&lt;br /&gt;&lt;br /&gt;With the exception of video, some types of games (e.g. car driving games), and likely a handful of other tasks, the smaller form factor is simply not as good as the iPad for most things you'd want to do. It sits in an uncomfortable middle ground between phone-size devices and 10" tablets like the iPad and the… well, like the iPad. The Tab does nothing considerably better than either an iPhone or an iPad. It's "as good" at a handful of tasks. &lt;br /&gt;&lt;br /&gt;What it boils down to is that the main advantage of the 7" form factor is that it's easier to carry around with you and is lighter to hold. I'm just unconvinced that's enough of a reason to make a 7" iPad inevitable.&lt;br /&gt;&lt;br /&gt;Personally, If I were going to buy something to fit between my iPhone 4 and my iPad, I'd buy a Kindle, and recent sales numbers seem to indicate that many people are making that choice. The Kindle does less than the Tab, but it's even lighter and it &lt;strong&gt;does&lt;/strong&gt; do something better than the iPad, iPhone, and Tab: it's a better ebook reader. It gets great battery life, it's easy on your eyes, has nice text, it's easy to carry, can be held comfortably in one hand, and it's much, much cheaper. &lt;br /&gt;&lt;br /&gt;When Apple introduced the iPad, it looked like it was going to compete, and probably kill, the burgeoning ebook reader market. Instead, it pushed those special-purpose devices into a lower price bracket where they no longer compete directly with the iPad. Looking at how the sales numbers have jumped recently, the iPad may just be the best thing that ever happened to the Kindle. The Kindle and Nook are almost down into the "impulse buy" category, and as a result, they're selling like hotcakes, often to people who already own iPads.&lt;br /&gt;&lt;br /&gt;But where does a seven inch tablet fit into the market? What would compel someone who owns an iPad to buy one, or would compel someone to buy one instead of an iPad? There isn't really a huge unmet demand for this product to fill. There's no pressing, burning need that would cause people to buy yet another device. A seven inch tablet has to compete with products that are already on the market and that are well-established. It can't compete with the Kindle on price, size, weight, or as an ebook reader. It's not noticeably cheaper than the iPad, yet has shorter batter life. It doesn't do anything that the iPad or iPhone can't. It's only compelling advantages are that it's lighter and smaller. Well, for a small segment of the market, it has another advantage: it's not from Apple. &lt;br /&gt;&lt;br /&gt;The Galaxy Tab has been selling pretty well, but it's got novelty working for it, and it's really the only viable non-Apple tablet on the market right now. That will not be the case for long, however. The way the iPad has sold, you can expect every computer hardware manufacturer to try to claim a piece of the tablet market.  Microsoft has already announced that, for them, CES would be about "slates" yet again this year (oh, boy!).&lt;br /&gt;&lt;br /&gt;For seven inch tablets to gain traction in the long run, they will have to provide a compelling advantage over the iPad, the iPhone, and the Kindle. If they're not going to compete on price, maybe there's some feature or ability where seven inch tablets can distinguish themselves and establish a long-term foothold, but I haven't thought of it yet, and apparently neither have the current tablet manufacturers like Samsung. &lt;br /&gt;&lt;br /&gt;The only way Apple will release a 7" tablet is if they think of some compelling reason for such a product to exist. It's possible that the reason would be price - making a more affordable and smaller iPad available to people who can't afford a $500+ device but want something bigger than an iPod touch. That's not impossible given Apple's drive for competitive pricing in their consumer products the last few years, but it's far from a foregone conclusion.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-4357429790463925454?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/4357429790463925454'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/4357429790463925454'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2010/12/on-seven-inches.html' title='On Seven Inches'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-8924613439962227748</id><published>2010-12-22T11:07:00.001-08:00</published><updated>2010-12-22T11:56:03.721-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Sample Code'/><category scheme='http://www.blogger.com/atom/ns#' term='Animation'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL ES'/><category scheme='http://www.blogger.com/atom/ns#' term='Core Animation'/><title type='text'>More Animation Curves than You Can Shake a Stick at</title><content type='html'>&lt;a href="http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreAnimation_guide/Introduction/Introduction.html" target="_blank"&gt;Core Animation&lt;/a&gt; is awesome. It makes doing a lot of complex, fancy animations downright easy. One of the really nice built-in features of Core Animation is the ability to use &lt;em&gt;animation curves&lt;/em&gt;. These curves let you specify whether the animation happens linearly (at the same pace throughout the animation), or whether the animation eases in, eases out, or does both.&lt;br /&gt;&lt;br /&gt;When you have to go closer to the metal and use OpenGL ES, you're not so lucky. We don't have animation curves provided for us in OpenGL ES. We have to interpolate ourselves. Fortunately, the math behind animation curves is straightforward. Plus, there are far more curves than just the four Apple offers. &lt;br /&gt;&lt;br /&gt;I haven't run across a good library for generating animation curves, so I've decided to release my animation curve functions as public domain (no attribute required, no rights reserved). Here is a graph of all the different animation curves I'm releasing:&lt;br /&gt;&lt;img style="display:block; margin-left:auto; margin-right:auto;" src="http://lh5.ggpht.com/_QLwms0mVa4w/TRJIc-C_KKI/AAAAAAAAAxA/U2p2-uS_68Q/Ease.jpg?imgmax=800" alt="Ease.png" border="0" width="450" height="600" /&gt;&lt;br /&gt;&lt;br /&gt;Here is the &lt;a href="http://www.innerloop.biz/code/Quadratic%20Check.numbers.zip" target="_blank"&gt;original Numbers.app document that generated the graph&lt;/a&gt;, and here is the &lt;a href="http://www.innerloop.biz/code/quadratic-test.zip" target="_blank"&gt;Xcode project that generated the data&lt;/a&gt;. The project also contains all the functions needed to plot these curves.&lt;br /&gt;&lt;br /&gt;Apple doesn't document which calculations they use for easing, but my guess is that they're quadratic.  I'm not sure, though, since many of the curves yield similar results.&lt;br /&gt;&lt;br /&gt;All of the interpolation functions included in the Xcode project above take three inputs and return a &lt;font face="monospace"&gt;GLfloat&lt;/font&gt; containing the interpolated value. The first parameter, &lt;font face="monospace"&gt;t&lt;/font&gt;, is the percent of the way through the animation you want a value calculated for. This is a clamped float that should be in the range &lt;font face="monospace"&gt;0.0&lt;/font&gt; to &lt;font face="monospace"&gt;1.0&lt;/font&gt;. Values above &lt;font face="monospace"&gt;1.0&lt;/font&gt; will be treated as 1.0 and values below &lt;font face="monospace"&gt;0.0&lt;/font&gt; are treated as &lt;font face="monospace"&gt;0.0&lt;/font&gt;. The second parameter, &lt;font face="monospace"&gt;start&lt;/font&gt;, is the value when the animation starts. The third parameter, &lt;font face="monospace"&gt;end&lt;/font&gt;, is the final value to be animated toward. &lt;br /&gt;&lt;br /&gt;If you want to apply a curve to a &lt;font face="monospace"&gt;CGPoint&lt;/font&gt; or &lt;font face="monospace"&gt;Vector3D&lt;/font&gt;, you have to call the function multiple times for each component (x/y or x/y/z).&lt;br /&gt;&lt;br /&gt;Have fun!&lt;br /&gt;&lt;br /&gt;Here are the functions included in the project above:&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source mac_classic"&gt;&lt;span class="source source_c"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c"&gt;include&lt;/span&gt; &lt;span class="string string_quoted string_quoted_other string_quoted_other_lt-gt string_quoted_other_lt-gt_include string_quoted_other_lt-gt_include_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c"&gt;&amp;lt;&lt;/span&gt;OpenGLES/ES2/gl.h&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c"&gt;include&lt;/span&gt; &lt;span class="string string_quoted string_quoted_other string_quoted_other_lt-gt string_quoted_other_lt-gt_include string_quoted_other_lt-gt_include_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c"&gt;&amp;lt;&lt;/span&gt;OpenGLES/ES2/glext.h&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c"&gt;include&lt;/span&gt; &lt;span class="string string_quoted string_quoted_other string_quoted_other_lt-gt string_quoted_other_lt-gt_include string_quoted_other_lt-gt_include_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c"&gt;&amp;lt;&lt;/span&gt;math.h&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_macro meta_preprocessor_macro_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_define keyword_control_import_define_c"&gt;define&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_preprocessor entity_name_function_preprocessor_c"&gt;BoundsCheck&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_preprocessor variable_parameter_preprocessor_c"&gt;t, start&lt;span class="punctuation punctuation_separator punctuation_separator_parameters punctuation_separator_parameters_c"&gt;,&lt;/span&gt; end&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;)&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_continuation punctuation_separator_continuation_c"&gt;\&lt;br /&gt;&lt;/span&gt;&lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt; (t &amp;lt;= &lt;span class="constant constant_numeric constant_numeric_c"&gt;0.f&lt;/span&gt;) &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; start;        &lt;span class="punctuation punctuation_separator punctuation_separator_continuation punctuation_separator_continuation_c"&gt;\&lt;br /&gt;&lt;/span&gt;&lt;span class="keyword keyword_control keyword_control_c"&gt;else&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt; (t &amp;gt;= &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;) &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; end;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;GLfloat&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;LinearInterpolation&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(GLclampf t, GLfloat start, GLfloat end)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;BoundsCheck&lt;/span&gt;(&lt;/span&gt;t, start, end);&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; t * end + (&lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt; - t) * start;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_section"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_pragma keyword_control_import_pragma_c"&gt;pragma mark&lt;/span&gt; &lt;span class="meta meta_toc-list meta_toc-list_pragma-mark meta_toc-list_pragma-mark_c"&gt;-&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_section"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_pragma keyword_control_import_pragma_c"&gt;pragma mark&lt;/span&gt; &lt;span class="meta meta_toc-list meta_toc-list_pragma-mark meta_toc-list_pragma-mark_c"&gt;Quadratic&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;GLfloat&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;QuadraticEaseOut&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(GLclampf t, GLfloat start, GLfloat end)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;BoundsCheck&lt;/span&gt;(&lt;/span&gt;t, start, end);&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt;   -end * t * (t - &lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt;) -&lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;GLfloat&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;QuadraticEaseIn&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(GLclampf t, GLfloat start, GLfloat end)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;BoundsCheck&lt;/span&gt;(&lt;/span&gt;t, start, end);&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; end * t * t + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;GLfloat&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;QuadraticEaseInOut&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(GLclampf t, GLfloat start, GLfloat end)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;BoundsCheck&lt;/span&gt;(&lt;/span&gt;t, start, end);&lt;br /&gt;    t *= &lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt;;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;t &amp;lt; &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;) &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; end/&lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt; * t * t + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;    t--;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; -end/&lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt; * (t*(t-&lt;span class="constant constant_numeric constant_numeric_c"&gt;2&lt;/span&gt;) - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1&lt;/span&gt;) + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_section"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_pragma keyword_control_import_pragma_c"&gt;pragma mark&lt;/span&gt; &lt;span class="meta meta_toc-list meta_toc-list_pragma-mark meta_toc-list_pragma-mark_c"&gt;-&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_section"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_pragma keyword_control_import_pragma_c"&gt;pragma mark&lt;/span&gt; &lt;span class="meta meta_toc-list meta_toc-list_pragma-mark meta_toc-list_pragma-mark_c"&gt;Cubic&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;GLfloat&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;CubicEaseOut&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(GLclampf t, GLfloat start, GLfloat end)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;BoundsCheck&lt;/span&gt;(&lt;/span&gt;t, start, end);&lt;br /&gt;    t--;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; end*(t * t * t + &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;) + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;GLfloat&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;CubicEaseIn&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(GLclampf t, GLfloat start, GLfloat end)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;BoundsCheck&lt;/span&gt;(&lt;/span&gt;t, start, end);&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; end * t * t * t+ start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;GLfloat&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;CubicEaseInOut&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(GLclampf t, GLfloat start, GLfloat end)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;BoundsCheck&lt;/span&gt;(&lt;/span&gt;t, start, end);&lt;br /&gt;    t *= &lt;span class="constant constant_numeric constant_numeric_c"&gt;2&lt;/span&gt;.;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;t &amp;lt; &lt;span class="constant constant_numeric constant_numeric_c"&gt;1&lt;/span&gt;.) &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; end/&lt;span class="constant constant_numeric constant_numeric_c"&gt;2&lt;/span&gt; * t * t * t + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;    t -= &lt;span class="constant constant_numeric constant_numeric_c"&gt;2&lt;/span&gt;;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; end/&lt;span class="constant constant_numeric constant_numeric_c"&gt;2&lt;/span&gt;*(t * t * t + &lt;span class="constant constant_numeric constant_numeric_c"&gt;2&lt;/span&gt;) + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_section"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_pragma keyword_control_import_pragma_c"&gt;pragma mark&lt;/span&gt; &lt;span class="meta meta_toc-list meta_toc-list_pragma-mark meta_toc-list_pragma-mark_c"&gt;-&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_section"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_pragma keyword_control_import_pragma_c"&gt;pragma mark&lt;/span&gt; &lt;span class="meta meta_toc-list meta_toc-list_pragma-mark meta_toc-list_pragma-mark_c"&gt;Quintic&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;GLfloat&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;QuarticEaseOut&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(GLclampf t, GLfloat start, GLfloat end)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;BoundsCheck&lt;/span&gt;(&lt;/span&gt;t, start, end);&lt;br /&gt;    t--;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; -end * (t * t * t * t - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1&lt;/span&gt;) + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;GLfloat&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;QuarticEaseIn&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(GLclampf t, GLfloat start, GLfloat end)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;BoundsCheck&lt;/span&gt;(&lt;/span&gt;t, start, end);&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; end * t * t * t * t + start;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;GLfloat&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;QuarticEaseInOut&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(GLclampf t, GLfloat start, GLfloat end)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;BoundsCheck&lt;/span&gt;(&lt;/span&gt;t, start, end);&lt;br /&gt;    t *= &lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt;;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;t &amp;lt; &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;) &lt;br /&gt;        &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; end/&lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt; * t * t * t * t + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;    t -= &lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt;;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; -end/&lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt; * (t * t * t * t - &lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt;) + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_section"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_pragma keyword_control_import_pragma_c"&gt;pragma mark&lt;/span&gt; &lt;span class="meta meta_toc-list meta_toc-list_pragma-mark meta_toc-list_pragma-mark_c"&gt;-&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_section"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_pragma keyword_control_import_pragma_c"&gt;pragma mark&lt;/span&gt; &lt;span class="meta meta_toc-list meta_toc-list_pragma-mark meta_toc-list_pragma-mark_c"&gt;Quintic&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;GLfloat&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;QuinticEaseOut&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(GLclampf t, GLfloat start, GLfloat end)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;BoundsCheck&lt;/span&gt;(&lt;/span&gt;t, start, end);&lt;br /&gt;    t--;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; end * (t * t * t * t * t + &lt;span class="constant constant_numeric constant_numeric_c"&gt;1&lt;/span&gt;) + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;GLfloat&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;QuinticEaseIn&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(GLclampf t, GLfloat start, GLfloat end)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;BoundsCheck&lt;/span&gt;(&lt;/span&gt;t, start, end);&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; end * t * t * t * t * t + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;GLfloat&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;QuinticEaseInOut&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(GLclampf t, GLfloat start, GLfloat end)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;BoundsCheck&lt;/span&gt;(&lt;/span&gt;t, start, end);&lt;br /&gt;    t *= &lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt;;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;t &amp;lt; &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;) &lt;br /&gt;        &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; end/&lt;span class="constant constant_numeric constant_numeric_c"&gt;2&lt;/span&gt; * t * t * t * t * t + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;    t -= &lt;span class="constant constant_numeric constant_numeric_c"&gt;2&lt;/span&gt;;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; end/&lt;span class="constant constant_numeric constant_numeric_c"&gt;2&lt;/span&gt; * ( t * t * t * t * t + &lt;span class="constant constant_numeric constant_numeric_c"&gt;2&lt;/span&gt;) + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_section"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_pragma keyword_control_import_pragma_c"&gt;pragma mark&lt;/span&gt; &lt;span class="meta meta_toc-list meta_toc-list_pragma-mark meta_toc-list_pragma-mark_c"&gt;-&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_section"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_pragma keyword_control_import_pragma_c"&gt;pragma mark&lt;/span&gt; &lt;span class="meta meta_toc-list meta_toc-list_pragma-mark meta_toc-list_pragma-mark_c"&gt;Sinusoidal&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;GLfloat&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;SinusoidalEaseOut&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(GLclampf t, GLfloat start, GLfloat end)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;BoundsCheck&lt;/span&gt;(&lt;/span&gt;t, start, end);&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; end *&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_support punctuation_whitespace_support_function punctuation_whitespace_support_function_leading punctuation_whitespace_support_function_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_C99 support_function_C99_c"&gt;sinf&lt;/span&gt;(t * (M_PI/&lt;span class="constant constant_numeric constant_numeric_c"&gt;2&lt;/span&gt;)) + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;GLfloat&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;SinusoidalEaseIn&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(GLclampf t, GLfloat start, GLfloat end)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;BoundsCheck&lt;/span&gt;(&lt;/span&gt;t, start, end);&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; -end *&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_support punctuation_whitespace_support_function punctuation_whitespace_support_function_leading punctuation_whitespace_support_function_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_C99 support_function_C99_c"&gt;cosf&lt;/span&gt;(t * (M_PI/&lt;span class="constant constant_numeric constant_numeric_c"&gt;2&lt;/span&gt;)) + end + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;GLfloat&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;SinusoidalEaseInOut&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(GLclampf t, GLfloat start, GLfloat end)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;BoundsCheck&lt;/span&gt;(&lt;/span&gt;t, start, end);&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; -end/&lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt; * (&lt;span class="support support_function support_function_C99 support_function_C99_c"&gt;cosf&lt;/span&gt;(M_PI*t) - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;) + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_section"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_pragma keyword_control_import_pragma_c"&gt;pragma mark&lt;/span&gt; &lt;span class="meta meta_toc-list meta_toc-list_pragma-mark meta_toc-list_pragma-mark_c"&gt;-&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_section"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_pragma keyword_control_import_pragma_c"&gt;pragma mark&lt;/span&gt; &lt;span class="meta meta_toc-list meta_toc-list_pragma-mark meta_toc-list_pragma-mark_c"&gt;Exponential&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;GLfloat&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;ExponentialEaseOut&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(GLclampf t, GLfloat start, GLfloat end)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;BoundsCheck&lt;/span&gt;(&lt;/span&gt;t, start, end);&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; end * (-&lt;span class="support support_function support_function_C99 support_function_C99_c"&gt;powf&lt;/span&gt;(&lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt;, -&lt;span class="constant constant_numeric constant_numeric_c"&gt;10.f&lt;/span&gt; * t) + &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt; ) + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;GLfloat&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;ExponentialEaseIn&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(GLclampf t, GLfloat start, GLfloat end)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;BoundsCheck&lt;/span&gt;(&lt;/span&gt;t, start, end);&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; end *&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_support punctuation_whitespace_support_function punctuation_whitespace_support_function_leading punctuation_whitespace_support_function_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_C99 support_function_C99_c"&gt;powf&lt;/span&gt;(&lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt;, &lt;span class="constant constant_numeric constant_numeric_c"&gt;10.f&lt;/span&gt; * (t - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;) ) + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;GLfloat&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;ExponentialEaseInOut&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(GLclampf t, GLfloat start, GLfloat end)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;BoundsCheck&lt;/span&gt;(&lt;/span&gt;t, start, end);&lt;br /&gt;    t *= &lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt;;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;t &amp;lt; &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;) &lt;br /&gt;        &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; end/&lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt; *&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_support punctuation_whitespace_support_function punctuation_whitespace_support_function_leading punctuation_whitespace_support_function_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_C99 support_function_C99_c"&gt;powf&lt;/span&gt;(&lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt;, &lt;span class="constant constant_numeric constant_numeric_c"&gt;10.f&lt;/span&gt; * (t - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;) ) + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;    t--;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; end/&lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt; * ( -&lt;span class="support support_function support_function_C99 support_function_C99_c"&gt;powf&lt;/span&gt;(&lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt;, -&lt;span class="constant constant_numeric constant_numeric_c"&gt;10.f&lt;/span&gt; * t) + &lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt; ) + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_section"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_pragma keyword_control_import_pragma_c"&gt;pragma mark&lt;/span&gt; &lt;span class="meta meta_toc-list meta_toc-list_pragma-mark meta_toc-list_pragma-mark_c"&gt;-&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_section"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_pragma keyword_control_import_pragma_c"&gt;pragma mark&lt;/span&gt; &lt;span class="meta meta_toc-list meta_toc-list_pragma-mark meta_toc-list_pragma-mark_c"&gt;Circular&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;GLfloat&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;CircularEaseOut&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(GLclampf t, GLfloat start, GLfloat end)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;BoundsCheck&lt;/span&gt;(&lt;/span&gt;t, start, end);&lt;br /&gt;    t--;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; end *&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_support punctuation_whitespace_support_function punctuation_whitespace_support_function_leading punctuation_whitespace_support_function_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_C99 support_function_C99_c"&gt;sqrtf&lt;/span&gt;(&lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt; - t * t) + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;GLfloat&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;CircularEaseIn&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(GLclampf t, GLfloat start, GLfloat end)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;BoundsCheck&lt;/span&gt;(&lt;/span&gt;t, start, end);&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; -end * (&lt;span class="support support_function support_function_C99 support_function_C99_c"&gt;sqrtf&lt;/span&gt;(&lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt; - t * t) - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;) + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;GLfloat&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;CircularEaseInOut&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(GLclampf t, GLfloat start, GLfloat end)&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;    &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;BoundsCheck&lt;/span&gt;(&lt;/span&gt;t, start, end);&lt;br /&gt;    t *= &lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt;;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;t &amp;lt; &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;) &lt;br /&gt;        &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; -end/&lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt; * (&lt;span class="support support_function support_function_C99 support_function_C99_c"&gt;sqrtf&lt;/span&gt;(&lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt; - t * t) - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;) + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;    t -= &lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt;;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; end/&lt;span class="constant constant_numeric constant_numeric_c"&gt;2.f&lt;/span&gt; * (&lt;span class="support support_function support_function_C99 support_function_C99_c"&gt;sqrtf&lt;/span&gt;(&lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt; - t * t) + &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;) + start - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.f&lt;/span&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-8924613439962227748?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/8924613439962227748'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/8924613439962227748'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2010/12/more-animation-curves-than-you-can.html' title='More Animation Curves than You Can Shake a Stick at'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_QLwms0mVa4w/TRJIc-C_KKI/AAAAAAAAAxA/U2p2-uS_68Q/s72-c/Ease.jpg?imgmax=800' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-5428426871699661756</id><published>2010-12-21T13:55:00.001-08:00</published><updated>2010-12-21T13:55:00.909-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL ES'/><category scheme='http://www.blogger.com/atom/ns#' term='Other blogs'/><title type='text'>The Little Grashopper Blog</title><content type='html'>Well, I'm not sure how I never ran across it before, but &lt;a href="" target="_blank"&gt;Philip Rideout&lt;/a&gt;, author of O'Reilly's &lt;a href="http://amzn.to/do1nHZ" target="_blank"&gt;iPhone 3D&lt;/a&gt; (a book I recommended last week), &lt;a href="http://prideout.net/blog/" target="_blank"&gt;has a hell of a blog&lt;/a&gt; for people interested in OpenGL. A lot of the posts are specific to desktop OpenGL (and recent versions of OpenGL at that!), but there's tons of great information that applies to OpenGL ES as well. It's a veritable treasure trove of advanced graphics goodness from a guy who's been doing it for years.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-5428426871699661756?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/5428426871699661756'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/5428426871699661756'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2010/12/little-grashopper-blog.html' title='The Little Grashopper Blog'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-7146151356945946717</id><published>2010-12-21T13:37:00.001-08:00</published><updated>2010-12-21T13:37:41.979-08:00</updated><title type='text'>More Math Resources</title><content type='html'>After posting about the free Linear Algebra book, I was told about another resource for learning math &lt;a href="http://twitter.com/jasonbogd/status/17330718334001152" target="_blank"&gt;via Twitter&lt;/a&gt;. The &lt;a href="http://www.khanacademy.org/" target="_blank"&gt;Khan Academy&lt;/a&gt; is a not-for-profit website providing online video courses on a number of topics. They don't just cover math, but they do cover math extensively. They have well over 100 video lessons on linear algebra alone. Definitely a great resource I'm happy to pass along!&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-7146151356945946717?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/7146151356945946717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/7146151356945946717'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2010/12/more-math-resources.html' title='More Math Resources'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-8625522447051584779</id><published>2010-12-21T10:21:00.001-08:00</published><updated>2010-12-21T10:21:06.889-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Developers'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Contracting'/><title type='text'>Non-Deterministic Problems aka Finding Talent</title><content type='html'>As programmers, we usually deal with &lt;a href="http://en.wikipedia.org/wiki/Deterministic_system_(philosophy)" target="_blank"&gt;deterministic systems&lt;/a&gt;. To state it simplistically, deterministic systems are systems where the same inputs always results in the same output. Unless we intentionally introduce randomness&amp;sup1; or have a relatively &lt;a href="http://en.wikipedia.org/wiki/Unusual_software_bug" target="_blank"&gt;rare kind of bug&lt;/a&gt; in our code, the same inputs to our programs will always yield the same output. It could very well be the wrong result if our algorithm is bad, but it should be the same wrong result every time, which is a trait we rely on heavily.&lt;br /&gt;&lt;br /&gt;In the real world, most things we encounter are non-deterministic. There are always factors we can't control or measure, and most systems have a human element. We are at the mercy of whim and emotion, and that's hard for a lot of programmers to deal with. Our fellow humans's decisions are decidedly non-deterministic and hard to predict, as are ours (though we usually don't notice this trait quite as much in ourselves).&lt;br /&gt;&lt;br /&gt;You may have noticed that I haven't had much time to write lately. I've been exceedingly busy of late, even by my own standards. Although a lot of my time is being spent writing and debugging software, I've also been involved with some very non-deterministic problems as a result of my involvement with some large, complex development projects.&lt;br /&gt;&lt;br /&gt;Probably the biggest non-programming problem that I've had to deal with lately, which most of my industry peers and nearly all of our clients are dealing with also, is finding good, experienced, reliable developers to staff projects. In short, there aren't enough experienced mobile software developers to go around. There simply aren't as many developers with multiple successful projects under their belt as there are companies who need the services of such people. I know of one large company that currently has ten open requisitions for mobile developers - five iOS and five Android - and no viable prospects at the moment. I helped one client recently bring aboard a good iOS developer, which took several months, and then I very quickly regretted it, because MartianCraft could really use that developer's services now.&lt;br /&gt;&lt;br /&gt;Yet, on the other hand, whenever I blog about just how much work there is right now, I inevitably get several e-mails or comments from developers wanting to know how to find all this work. I make it sound like it's raining work, and they're not getting wet.&lt;br /&gt;&lt;br /&gt;Given that, I thought it worth a few minutes to write about both sides of the equation: how to find developers, and how to find work as a developer. This isn't an exhaustive treatment, just a summary of recent observations.&lt;br /&gt;&lt;br /&gt;&lt;H3&gt;For Developers: Finding Work&lt;/H3&gt;&lt;br /&gt;&lt;br /&gt;Unfortunately, I've got no silver bullet for aspiring developers. Overnight success is often indistinguishable from years of hard work. There are countless issues around getting that are not mobile development-specific that I'm not going to touch, such as a willingness to relocate ("go where the work is").&lt;br /&gt;&lt;br /&gt;As with any industry, a large part of finding work is establishing a reputation and getting to know as many people in the industry as you can. Though it's expensive, you really need to go to WWDC, and probably a couple other conferences as well. About half, maybe even more, of MartianCraft work has come directly or indirectly as a result of one of us attending a conference. Conferences are where we meet our peers and where we develop and maintain our relationships with them. You should also attend &lt;a href="http://cocoaheads.org/" target="_blank"&gt;CocoaHeads&lt;/a&gt; and/or &lt;a href="http://nscodernight.com/" target="_blank"&gt;NSCoder Night&lt;/a&gt; if you have one near you. This is where you can meet and get to know local iOS and Mac developers. On the Android side, there are similar meet-ups that you can attend.&lt;br /&gt;&lt;br /&gt;When going to hire or subcontract a developer, most people I know will automatically prefer someone they've met, talked with, and maybe shared a drink with over a stranger, no matter how good the stranger's resume looks. Confidence in someone's ability to get a job done comes more rapidly from personal interaction. Resumes are sterile, but sitting down and working through a tough bug with somebody gives you a real feel for the other person's character and technical chops in a way you can never get from a resume.&lt;br /&gt;&lt;br /&gt;At conferences, don't worry about going to every session. Everybody tries to at their first DubDub, but don't. Really. Pace yourself so you can socialize in the evenings. That may sound like bad, or even frivolous advice - as if I'm telling you to play hooky, but the information in the sessions can be found again. Most conferences videotape their sessions, and usually some of the attendees do joint note-taking using SubEthaEdit and make those notes available. But socializing with industry peers is vital if you want to do this full time, especially as an Indie. These are the people who can give you work (and accept work when you're too busy to take on new work yourself), and they are the people who can help you when you're stuck on a gnarly technical problem. These are the people who can give you a different perspective on something you've been staring at for far too long and are the people who can help you become a smarter, better developer.&lt;br /&gt;&lt;br /&gt;Though not perfect, the iOS and Mac developer community is incredibly giving and helpful. It's not uncommon for direct competitors to help each other out and consider each other friends. Most of us realize that it's not a zero-sum game, and helping out others in our community usually comes back with interest. Scratch that. Not usually. Always.&lt;br /&gt;&lt;br /&gt;Getting ongoing work requires more than being liked by other developers, however. You have to give people a reason to have confidence in your abilities. Creating or contributing to open source projects can show huge (if not immediate) returns. In the early days of iOS, before Core Data was available, my SQLitePersistentObjects project brought me nearly as much recognition as having my name on the cover of iPhone programming books. &lt;br /&gt;&lt;br /&gt;Regular blogging is also a huge opportunity. Not only does it give people an idea of the depth of your knowledge, it gives you a chance to learn and improve. I don't think I've posted more than a couple technical blog posts where there wasn't either a correction or improvement sent to me by a reader, and often there were many. Just remember not to get defensive or depressed when it happens. You don't stop making mistakes until you stop living, but if you keep learning, you can avoid making the same mistake too many times. Readers who care enough to point out your mistakes are valuable beyond belief. Tame your ego and cherish them. Nobody's going to think less of you as a developer for occasional mistakes or less-than-perfect code.&lt;br /&gt;&lt;br /&gt;But, no matter how much of the above you do, there is one absolute prerequisite to getting work on an ongoing basis: you have to have the technical chops. This is probably the hardest thing to figure out. I've met many great developers who lacked confidence in their abilities and I've met some who've had far too much confidence in them. It's really hard to gauge your own ability and it's almost always sobering to revisit older code you've written. No matter how good you get, there's always room to get better and if you're doing it right, you will. As developers, we're paid as much for our ability to quickly assimilate new knowledge as we are for the things we already know.&lt;br /&gt;&lt;br /&gt;Don't worry too much about your whether you have a specific degree, or a college degree at all. You don't have to have a computer science or computer engineering degree to be a good programmer. There are many, many great programmers (including inside Apple) without those degrees and, in fact, without degrees at all. College is one way to get the information and some of the experience you need to be a good programmer, but it's not the only way, and it's possible (though probably not common) to get through school with a CS or CE degree and completely suck. Some of the worst iOS programmers I've encountered have both degrees and programming experience. Objective-C is a bit of a weird beast, and overconfidence is a big problem for experienced developers coming from C++, Java, and C# background. They look at Objective-C, see familiar aspects, and think they know what they're doing, sometimes completely oblivious to the differences between a static, strongly-typed language and a dynamic, weakly-typed one or the differences between a garbage-collected language and a reference-counted one.&lt;br /&gt;&lt;br /&gt;In a perfect world, nobody would ever be able to offer their services as an iOS developer without perfectly understanding the rules around memory management. I'm not suggesting you should, but everything else, you could learn on the job, but you have to really grok the way retain counting and memory management work to be a professional iOS developer. You can really fuck up a code base trying to fix EXC_BAD_ACCESS bugs if you don't know what you're doing and can create an awful lot of work for somebody else in the process. You can also get away with an awful lot of leaks if you're developing on the simulator that will cause significant problems later. The stakes get much higher when you're working on the same code at the same time other developers are.&lt;br /&gt;&lt;br /&gt;One thing to seriously consider, even if you have a few apps under your belt, is to take a class or workshop. There are some excellent ones out there, including (but certainly not limited to) the &lt;a href="http://www.bignerdranch.com/" target="_blank"&gt;Big Nerd Ranch&lt;/a&gt; and the &lt;a href="http://pragmaticstudio.com/iphone/" target="_blank"&gt;Pragmatic Studio&lt;/a&gt;. A few thousand dollars may seem like a lot of money, but it's a hell of an investment given the work opportunities available right now. A good workshop will beat into your head the important stuff. They'll strap a firehose of information onto your face and open the spout. They will make your brain hurt, but you will come out knowing memory management and the fundamentals, and that will put you in the running.&lt;br /&gt;&lt;br /&gt;Another key skill is debugging. Being able to fix your bugs and those you find in other people's code is vital. Plus, the more bugs you encounter, the more things you know not to do in the future. Want to test yourself? Try &lt;a href="http://www.innerloop.biz/code/DebugMe.zip" target="_blank"&gt;downloading this.&lt;/a&gt; It's an Xcode project — a modified version of one of the Beginning iPhone 3 Development projects — that has a number of common bugs introduced into it. You should be able to get this to compile clean (no errors or warnings), then be able to navigate into every view in the application without it crashing and with something being displayed on every view. Once you've done that, you should then be able to fix any leaks in the app using Instruments. How long it takes is going to depend on a lot of factors, but I'd say that a typical, experienced, professional iOS developer should be able to fix this in between a half hour and an hour and a half. Regardless of how long it takes, if you can fix them all without help, you've gone a long way down the path to becoming a great developer.&lt;br /&gt;&lt;br /&gt;Don't worry if you can't find them all that quickly. The first time you encounter a particular class of bug, it takes more time. Persistence is as important as speed, and debugging this project is a good exercise. Once you see a type of bug once, it's much easier to find and fix it when you encounter it again. &lt;br /&gt;&lt;br /&gt;If I find time over the holiday, I might do a screencast showing how to find and fix all the bugs in the project. I can't promise I'll find the time to do that given my current workload, but if I can, I will.&lt;br /&gt;&lt;br /&gt;Lastly, if you're looking for full-time iOS or Android employment, or for contract development work, &lt;a href="mailto:jeff@martiancraft.com" target="_blank"&gt;send me your resume&lt;/a&gt;. MartianCraft isn't hiring full-time employees at the moment, but we do often need subs, and I know of many, many open requisitions for full-time jobs and I'm always happy to pass resumes along to hiring managers.&lt;br /&gt;&lt;br /&gt;&lt;H3&gt;For Companies: Finding Mobile Developers&lt;/H3&gt;&lt;br /&gt;&lt;br /&gt;The other side of the equation is, how do you staff a mobile development project right now? Many experienced mobile developers were attracted to the space because it offered them the ability to make a living creating what they want to create. Mobile, and especially iOS development offer opportunities for small teams without a lot of funding to make a decent living. Many of those indie developers are doing exactly what they want to be doing and it's going to be hard, if not impossible, to attract them away from that life, if they're good at what they do.&lt;br /&gt;&lt;br /&gt;Hell, many contract developers have app ideas they'd love to be working on themselves. A friend of mine who owns a development shop stated the problem fairly succinctly recently by saying: "We've got several app ideas we'd like to build, but clients keep throwing money at us."&lt;br /&gt;&lt;br /&gt;I don't know exactly how many contract iOS developers there are with Objective-C experience that pre-dates the release of the iPhone SDK and/or who have several successful projects under their belt, but it's less than are needed. Big businesses are finally catching on to the importance of mobile and that's making a shallow talent pool even shallower. The situation for Android is similar. Though there are more people who already know the underlying language (Java), the platform has only relatively recently hit critical mass, so there aren't a lot of people who have been involved with successful Android software projects yet compared to the work available, and even less who have successfully shipped multiple Android projects.&lt;br /&gt;&lt;br /&gt;In all reality, you're either going to need to offer crazy rates to lure the cream of the crop to your project (and that is no guarantee you're going to get the cream) or you're going to need to invest time and money into developing internal talent. I would advise at least having one really good, experienced tech lead on any decent size project, though. As many App Store success stories can attest, it is absolutely possible to ship good software using only inexperienced developers. But, doing so increases your risk substantially. Having at least one mentor who can guide and help and solve the really icky problems is gold.&lt;br /&gt;&lt;br /&gt;In most places, you can train developers more cheaply and more quickly than you can find existing ones, at least if you're looking for full-time employees. It's not a perfect plan - your newly trained people will be learning on the job and making mistakes and may, at times, hit problems that are beyond their ken. But, with the proper training and support, they can handle the bulk of the work, and over time, will gain the experience to handle anything. Of course, you'll have to take steps to keep them from leaving. Arming an employee with a highly marketable skill always incurs a risk of losing that employee.&lt;br /&gt;&lt;br /&gt;You can deal with that using contract terms requiring payback of training expenses or other similar ideas, but it's far more effective (albeit harder) to create an environment where people want to work. Job satisfaction is a bigger motivator for many developers than the size of their paycheck, assuming they're making enough to be comfortable and to feel valued. We're one of the few growth industries in this economy, and there's always another paycheck somewhere if you have these skills, so if you're create a hostile environment, no amount of money is going to keep the good people around long term.&lt;br /&gt;&lt;br /&gt;There's another option you might be considering: offshoring. Go ahead. I mean, anything I say against the practice is going to seem biased given what I do for a living, and it's true that you can get considerably lower rates by doing it. I've seen shops in other countries offering iOS development services for about what you can make working at Burger King here in the states. And there are actually success stories from offshoring to cheap development body shops. Unfortunately, there are even more horror stories. In the few cases where I've been brought in to fix&amp;sup2; projects of this nature, it's always been a waste of time and we ended up just throwing out the old code and starting over. Let me tell you, "start over" is a suggestion that strikes fear into the hearts of project managers.&lt;br /&gt;&lt;br /&gt;To put it as fairly as possible: Offshoring increases risk. If you're comfortable with more risk, then it might be a good choice for you. There's a chance you'll come in way under budget and be a hero. Just recognize that there's a larger chance you'll end up six months down the line starting over completely. Any way you cut it, you're likely to have language barriers, cultural differences, and a hard time enforcing accountability. The simple fact of the matter is, even in countries with considerably lower cost of living, opportunities for good mobile developers are legion, so the only way those shops can maintain those excessively low rates is with a constant stream of new, inexperienced bodies. Call me crazy, but it seems to me, that if you're going to have inexperienced bodies working on your project, you'd be better off with ones closer to home that you can train and guide and have some idea of what they're doing.&lt;br /&gt;&lt;br /&gt;I'll be blunt. If you're looking to build a team of iOS or Android developers in-house, you've got a tough road ahead of you at the moment. At some point, we'll hit equilibrium and it will get easier, but right now, it's hard. Just as I suggested to aspiring developers, I'd encourage you to get involved with the community. Send somebody, preferably somebody with some authority to hire developers and whose day-to-day job is working with the technology, to conferences, &lt;a href="http://cocoaheads.org/" target="_blank"&gt;CocoaHeads&lt;/a&gt; meetings, and &lt;a href="http://nscodernight.com/" target="_blank"&gt;NSCoder Nights&lt;/a&gt;, or the Android equivalents (&lt;a href="http://www.meetup.com/" target="_blank"&gt;Meetup.com&lt;/a&gt; is a good place to find both iOS and Android groups in your area).&lt;br /&gt;&lt;br /&gt;I'm always happy to &lt;a href="mailto:jeff@martiancraft.com" target="_blank"&gt;hear from&lt;/a&gt; companies that need iOS or Android development resources. I'm thrilled to refer potential employees your way if you're looking for in-house talent, and MartianCraft is always open to &lt;a href="mailto:sales@martiancraft.com" target="_blank"&gt;talking with with&lt;/a&gt; you about your development needs, whether it's for a little strategic consulting and guidance, or to fully staff a development project. And if MartianCraft isn't a good fit for your situation or doesn't have the resources available to do a great job, there's a pretty good chance we know somebody who is and does. If we do, we'll connect you with them.&lt;br /&gt;&lt;br /&gt;&lt;hr/&gt;&lt;br /&gt;&lt;font size="2"&gt;&lt;b&gt;1&lt;/b&gt; Technically speaking, without external input of some sort, computers are not capable of true randomness, and using a pseudorandom function doesn't make a computer non-deterministic. Pseudorandomness does make the computer pretend to be non-deterministic, though, and you will appear to get different output from the same input on successive runs of the program.&lt;/font&gt;&lt;br /&gt;&lt;font size="2"&gt;&lt;b&gt;2&lt;/b&gt; The term that we professionals in the industry use to refer to this process is "unfucking". Surprisingly, most dictionaries have not picked up this term yet.&lt;/font&gt;&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-8625522447051584779?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/8625522447051584779'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/8625522447051584779'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2010/12/non-deterministic-problems-aka-finding.html' title='Non-Deterministic Problems aka Finding Talent'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-4967298030115024872</id><published>2010-12-20T19:14:00.001-08:00</published><updated>2010-12-21T06:47:18.257-08:00</updated><title type='text'>Free Course in Linear Algebra</title><content type='html'>Computer graphics programming uses &lt;a href="http://en.wikipedia.org/wiki/Linear_algebra" target="_blank"&gt;linear algebra&lt;/a&gt; so heavily, you could basically say it's based on it. Yet, many people — perhaps most — who develop an interest in graphics programming don't have a background in Linear Algebra. At most universities, it is taught as an upper-level (300 or 400) mathematics course, which means that the majority of students who aren't majoring or minoring in math or certain hard sciences, typically don't take them. Even if you have studied it, if you've gone a period of time without using it, you very likely have forgotten it.&lt;br /&gt;&lt;br /&gt;Yet, if you want to go beyond a certain level in graphics programming, you need to understand it.&lt;br /&gt;&lt;br /&gt;Today, I stumbled across a &lt;a href="http://linear.ups.edu/" target="_blank"&gt;free course in Linear Algebra&lt;/a&gt;, and it looks to be quite good. It's dense but, hey, this is higher math we're talking about here, so there's not much that can be done to simplify it without making it incorrect. But the price is right, the content is good, and what's even better is that the course doesn't assume much in the way of specific prior knowledge.&lt;br /&gt;&lt;br /&gt;Make no bones about it, this is hard stuff to learn, but if you've got a &lt;em&gt;reason&lt;/em&gt; to learn it (like a drive to create computer graphics), it helps a lot. Linear algebra in the classroom taught in an abstract manner bored me to tears. Having a real reason and being able to do things with it makes it much more rewarding and fun.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-4967298030115024872?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/4967298030115024872'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/4967298030115024872'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2010/12/free-course-in-linear-algebra.html' title='Free Course in Linear Algebra'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-5479616990810020019</id><published>2010-12-12T14:28:00.001-08:00</published><updated>2010-12-12T15:40:19.194-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Books'/><category scheme='http://www.blogger.com/atom/ns#' term='Book project'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL ES'/><title type='text'>OpenGL ES Book Recommendation</title><content type='html'>Since canceling my OpenGL ES 2.0 for iOS 4 book, I've had several people request book recommendations to use instead of my book. Honestly, I didn't really have one to give before today, partially because I intentionally avoided reading competing books while working on mine.&lt;br /&gt;&lt;br /&gt;Today, while stuck on a train, I checked out Philip Rideout's &lt;a href="http://oreilly.com/catalog/9780596804831" target="_blank"&gt;iPhone 3D Programming&lt;/a&gt; by O'Reilly. Now, it's never easy to give an objective opinion on a book that competes with one you're writing, and even though my book is currently not on a production schedule and I have no time to work on it, I tend to still think of myself as working on an OpenGL ES book. Although there are several things that I would have done differently, I also know it's unfair to judge a book that way. Deciding what to include and what not to include in a book is a horribly difficult thing with an expansive topic like OpenGL ES and no two authors are going to make the same exact decision in that regard, so I'm not going to criticize Philip Rideout for, well, for not being me. Hell, normally not being me is taken as a bit of a compliment anyway.&lt;br /&gt;&lt;br /&gt;Yet, though it's not the book I would have written, I can wholeheartedly recommend it. The information is solid and useful and it's presented in a way that doesn't assume or require a Ph.D in math. One thing that Rideout does do that I opted not to even attempt, is to give both the OpenGL ES 1.1 and OpenGL ES 2.0 approach to tasks that can be done in both environments, which is actually interesting on multiple grounds. One, it's a great transition for people who know 1.1 but not 2.0, but also, it shows the interesting ways people have figured out to work around the limitations of the fixed pipeline. These kinds of solutions fascinate me because they're the result of people refusing to accept technical limitations.&lt;br /&gt;&lt;br /&gt;Much (all?) of the material from this book is available &lt;a href="http://iphone-3d-programming.labs.oreilly.com/" target="_blank"&gt;free online&lt;/a&gt;, but I'd recommend buying the book, which gives you access to the book's source code and also will also help an angel get his wings. Well, I'm not 100% sure on the latter, but it seems likely this time of year.&lt;br /&gt;&lt;br /&gt;If you're floundering a bit with OpenGL ES, this book is well worth your time.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-5479616990810020019?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/5479616990810020019'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/5479616990810020019'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2010/12/opengl-es-book-recommendation.html' title='OpenGL ES Book Recommendation'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-3731903264082028893</id><published>2010-11-29T14:16:00.001-08:00</published><updated>2010-11-29T14:16:04.138-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UIImage'/><category scheme='http://www.blogger.com/atom/ns#' term='source code'/><category scheme='http://www.blogger.com/atom/ns#' term='Categories'/><title type='text'>Drawing Part of a UIImage</title><content type='html'>Happy Thanksgiving, and sorry for the relative lack of posts here lately. Things are crazier than ever and it's been a challenge finding time to shower, let alone blog.&lt;br /&gt;&lt;br /&gt;I do have something to share, today, though. No, it's not the next chapter of OpenGL ES 2.0 for iOS. It's a category that some of you may find useful: a method that allows you to draw only part of a &lt;font face="monospace"&gt;UIImage&lt;/font&gt; rather than the entire thing.&lt;br /&gt;&lt;br /&gt;On the Mac, &lt;em&gt;NSImage&lt;/em&gt; has a handy instance method called &lt;font face="monospace"&gt;drawInRect:fromRect:operation:fraction:&lt;/font&gt; that lets you specify exactly which part of an image to draw. On &lt;font face="monospace"&gt;UIImage&lt;/font&gt;, we've only got the ability to draw the entire image either unless we drop down to Core Graphics calls. We don't have a nice, easy, convenient way using just UIImage to draw a portion of the image it represents.&lt;br /&gt;&lt;br /&gt;I needed this ability in an application I'm working on, so I hacked out the following category. At first glance, this may look to be inefficient, since we're making a copy of the instance's backing &lt;font face="monospace"&gt;CGImage&lt;/font&gt; in order to create the sub-image, however I believe that &lt;font face="monospace"&gt;CGImageCreateWithImageInRect()&lt;/font&gt; references the original image's bitmap data. I haven't confirmed that it doesn't make a copy of the bitmap data, but the documentation certainly seems to imply it. Anyone know?&lt;br /&gt;&lt;br /&gt;Anyway, here is the category; I've even commented the code more pedantically than is normal for me in case anyone might be confused about what's going on. Improvements and bug fixes are, as always, welcome.&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source mac_classic"&gt;&lt;span class="source source_objc"&gt;&lt;span class="meta meta_implementation meta_implementation_objc"&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;implementation&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_objc"&gt;UIImage&lt;/span&gt;&lt;span class="meta meta_scope meta_scope_implementation meta_scope_implementation_objc"&gt;(MCDrawSubImage)&lt;br /&gt;&lt;span class="meta meta_function-with-body meta_function-with-body_objc"&gt;&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;drawInRect&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_type support_type_quartz"&gt;CGRect&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;drawRect&lt;/span&gt;&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;fromRect&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_type support_type_quartz"&gt;CGRect&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;fromRect&lt;/span&gt;&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;blendMode&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;CGBlendMode&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;blendMode&lt;/span&gt;&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;alpha&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;alpha&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;    CGImageRef drawImage =&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CGImageCreateWithImageInRect&lt;/span&gt;(&lt;/span&gt;self&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.CGImage&lt;/span&gt;, fromRect); &lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;drawImage != &lt;span class="constant constant_language constant_language_c"&gt;NULL&lt;/span&gt;)&lt;br /&gt;    &lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;        CGContextRef context =&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;UIGraphicsGetCurrentContext&lt;/span&gt;(&lt;/span&gt;);&lt;br /&gt;        &lt;br /&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Push current graphics state so we can restore later&lt;br /&gt;&lt;/span&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;        &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CGContextSaveGState&lt;/span&gt;(&lt;/span&gt;context);   &lt;br /&gt;        &lt;br /&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Set the alpha and blend based on passed in settings&lt;br /&gt;&lt;/span&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;        &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CGContextSetBlendMode&lt;/span&gt;(&lt;/span&gt;context, blendMode);&lt;br /&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;        &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CGContextSetAlpha&lt;/span&gt;(&lt;/span&gt;context, alpha);&lt;br /&gt;        &lt;br /&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Take care of Y-axis inversion problem by translating the context on the y axis&lt;br /&gt;&lt;/span&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;        &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CGContextTranslateCTM&lt;/span&gt;(&lt;/span&gt;context, &lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;, drawRect&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.origin.y&lt;/span&gt; + fromRect&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.size.height&lt;/span&gt;);  &lt;br /&gt;        &lt;br /&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Scaling -1.0 on y-axis to flip&lt;br /&gt;&lt;/span&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;        &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CGContextScaleCTM&lt;/span&gt;(&lt;/span&gt;context, &lt;span class="constant constant_numeric constant_numeric_c"&gt;1.0&lt;/span&gt;, -&lt;span class="constant constant_numeric constant_numeric_c"&gt;1.0&lt;/span&gt;);&lt;br /&gt;        &lt;br /&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Then accommodate the translate by adjusting the draw rect&lt;br /&gt;&lt;/span&gt;        drawRect&lt;span class="variable variable_other variable_other_dot-access variable_other_dot-access_c"&gt;.origin.y&lt;/span&gt; = &lt;span class="constant constant_numeric constant_numeric_c"&gt;0.0f&lt;/span&gt;;&lt;br /&gt;        &lt;br /&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Draw the image&lt;br /&gt;&lt;/span&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;        &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CGContextDrawImage&lt;/span&gt;(&lt;/span&gt;context, drawRect, drawImage);&lt;br /&gt;        &lt;br /&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Clean up memory and restore previous state&lt;br /&gt;&lt;/span&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;        &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CGImageRelease&lt;/span&gt;(&lt;/span&gt;drawImage);&lt;br /&gt;        &lt;br /&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Restore previous graphics state to what it was before we tweaked it&lt;br /&gt;&lt;/span&gt;&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;        &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;CGContextRestoreGState&lt;/span&gt;(&lt;/span&gt;context); &lt;br /&gt;    }&lt;/span&gt;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;end&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-3731903264082028893?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3731903264082028893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3731903264082028893'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2010/11/drawing-part-of-uiimage.html' title='Drawing Part of a UIImage'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-3612977178535658837</id><published>2010-11-19T08:53:00.001-08:00</published><updated>2010-11-19T08:53:31.811-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tutorials'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL ES'/><title type='text'>OpenGL ES Course on iTunes University</title><content type='html'>Those of you waiting for the next chapter of OpenGL ES 2.0 for iOS can do yourselves a favor by checking out &lt;a href="http://deimos.apple.com/WebObjects/Core.woa/Browse/matcmadison.edu.3989485784.04638434143" target="_blank"&gt;this course on iTunes University&lt;/a&gt;. It's an Advanced iOS Development course taught by Brad Larsson at the &lt;a href="http://matcmadison.edu/" target="_blank"&gt;Madison Area Technical College&lt;/a&gt;, and the most recent lesson is on OpenGL ES. You can also find the course notes &lt;a href="http://www.sunsetlakesoftware.com/sites/default/files/AdvancediOSDevelopmentFall2010.zip" target="_blank"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-3612977178535658837?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3612977178535658837'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/3612977178535658837'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2010/11/opengl-es-course-on-itunes-university.html' title='OpenGL ES Course on iTunes University'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-9130789234573123276</id><published>2010-11-17T12:18:00.001-08:00</published><updated>2010-11-17T12:18:50.793-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL ES'/><category scheme='http://www.blogger.com/atom/ns#' term='Power VR'/><title type='text'>OpenGL ES Update</title><content type='html'>Sorry for the silence around here lately.&lt;br /&gt;&lt;br /&gt;Unfortunately, the next chapter of OpenGL ES 2.0 I plan to release contains detailed, step-by-step instructions based on Xcode 4 (mostly written around the time of DP2) which is still under NDA. As a result, this chapter is going to take a little longer to scrub, and I haven't had much time to scrub lately. &lt;br /&gt;&lt;br /&gt;In the meantime, I realized that I've never linked to the &lt;a href="http://www.imgtec.com/powervr/insider/powervr-sdk.asp" target="_blank"&gt;PowerVR Insider SDK&lt;/a&gt;, so I'm rectifying that. The company that makes the GPU in all iOS devices has an SDK you can download - in fact, they have several versions of it for different platforms, including iOS. Most of the code is fairly generic C++ with just enough Objective-C around them to work, but there's a metric buttload of good code there for doing all sorts of things. Definitely worth signing and downloading, because they show you how to do a lot of common tasks. It's not very beginner-friendly, granted, but still a great resource you should know about. Most of the code is general OpenGL ES and not actually specific to their hardware, though some of the texture-related tools and optimizations are designed for best performance on their hardware and in some cases use vendor-specific extensions. If you're an iOS-only dev, that's not a problem at all unless Apple changes their GPU vendor.&lt;div class="blogger-post-footer"&gt;&lt;BR/&gt;&lt;font size="2"&gt;&lt;center&gt;&amp;copy;2008-2010 Jeff LaMarche. &lt;br/&gt;
http://iphonedevelopment.blogspot.com&lt;/center&gt;&lt;/font&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2947441758360063609-9130789234573123276?l=iphonedevelopment.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/9130789234573123276'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2947441758360063609/posts/default/9130789234573123276'/><link rel='alternate' type='text/html' href='http://iphonedevelopment.blogspot.com/2010/11/opengl-es-update.html' title='OpenGL ES Update'/><author><name>Jeff LaMarche</name><uri>http://www.blogger.com/profile/01594901246790283587</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_QLwms0mVa4w/R2NT6g94HMI/AAAAAAAAAAM/ZgLQQ30Rem4/S220/Photo+1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-2947441758360063609.post-2032039240470223055</id><published>2010-11-04T08:29:00.001-07:00</published><updated>2010-11-04T09:00:06.414-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='NSPreciate'/><category scheme='http://www.blogger.com/atom/ns#' term='Sample Code'/><category scheme='http://www.blogger.com/atom/ns#' term='category'/><category scheme='http://www.blogger.com/atom/ns#' term='NSExpression'/><category scheme='http://www.blogger.com/atom/ns#' term='Core Data'/><title type='text'>NSExpression</title><content type='html'>The relatively new &lt;font face="monospace"&gt;NSExpression&lt;/font&gt; class is incredibly powerful, yet not really used very often. Part of that is that it's not very well documented. Although the API documentation for &lt;font face="monospace"&gt;NSExpression&lt;/font&gt; is fairly well detailed, the listed "companion guide" (&lt;a href="http://developer.apple.com/library/ios/documentation/cocoa/Conceptual/Predicates/" target="_blank"&gt;Introduction to Predicates Programming&lt;/a&gt;) has very little information about how to actually use &lt;font face="monospace"&gt;NSExpression&lt;/font&gt;.&lt;br /&gt;&lt;br /&gt;&lt;font face="monospace"&gt;NSExpression&lt;/font&gt; deserves to be better documented, because it brings to predicate programming (including Core Data), a lot of features from the relational database world that people often complain are missing, like unioning, intersecting, and subtracting resultsets and performing aggregate operations without loading managed objects or faults into memory.&lt;br /&gt;&lt;br /&gt;The aggregates functionality is especially important on iOS given the limited memory on most iOS devices. If you've got a large dataset, and you want to get a count of objects, or calculate an average or sum for one of the attributes, you really don't want to have to pull the entire dataset into memory. Even if they're just faults, they're going to eat up memory you don't need to use because the underlying SQLite persistent store can figure that stuff out without the object overhead.&lt;br /&gt;&lt;br /&gt;I don't have time to do a full &lt;font face="monospace"&gt;NSExpression&lt;/font&gt; tutorial, but I thought it at least worth posting a category on &lt;font face="monospace"&gt;NSManagedObject&lt;/font&gt; that lets you take advantage of some of its more useful features.&lt;br /&gt;&lt;br /&gt;With this category, to get a sum of the attribute &lt;em&gt;bar&lt;/em&gt; on entity &lt;em&gt;Foo&lt;/em&gt;, you would do this:&lt;br /&gt;&lt;pre class="textmate-source mac_classic"&gt;&lt;span class="source source_objc source_objc_iphone"&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSNumber&lt;/span&gt; *fooSum = &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;Foo &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;aggregateOperation&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc"&gt;@"&lt;/span&gt;sum:&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc"&gt;onAttribute&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc"&gt;@"&lt;/span&gt;bar&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc"&gt;withPredicate&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="constant constant_language constant_language_objc"&gt;nil&lt;/span&gt; &lt;span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc"&gt;inManagedObjectContext&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;context&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This will calculate it for you using the database features, NOT by loading all the managed objects into memory. Much more memory and processor efficient than doing it manually.&lt;br /&gt;&lt;br /&gt;Cheers. Category follows:&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Header File:&lt;/strong&gt;&lt;br /&gt;&lt;pre class="textmate-source mac_classic"&gt;&lt;span class="source source_objc source_objc_iphone"&gt;&lt;span class="meta meta_interface-or-protocol meta_interface-or-protocol_objc"&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;interface&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_objc"&gt;NSManagedObject&lt;/span&gt;&lt;span class="meta meta_scope meta_scope_interface meta_scope_interface_objc"&gt;(MCAggregate)&lt;br /&gt;&lt;span class="meta meta_function meta_function_objc"&gt;+&lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSNumber&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;aggregateOperation&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSString&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;function&lt;/span&gt;&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;onAttribute&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSString&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;attributeName&lt;/span&gt;&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;withPredicate&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSPredicate&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;predicate&lt;/span&gt;&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;inManagedObjectContext&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;NSManagedObjectContext *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;context&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;@end&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Implementation File:&lt;/strong&gt;&lt;br /&gt;&lt;pre class="textmate-source mac_classic"&gt;&lt;span class="source source_objc source_objc_iphone"&gt;+(&lt;span class="support support_class support_class_cocoa"&gt;NSNumber&lt;/span&gt; *)aggregateOperation:(&lt;span class="support support_class support_class_cocoa"&gt;NSString&lt;/span&gt; *)function onAttribute:(&lt;span class="support support_class support_class_cocoa"&gt;NSString&lt;/span&gt; *)attributeName withPredicate:(&lt;span class="support support_class support_class_cocoa"&gt;NSPredicate&lt;/span&gt; *)predicate inManagedObjectContext:(NSManagedObjectContext *)context&lt;br /&gt;&lt;span class="meta meta_block meta_block_c"&gt;{&lt;br /&gt;    &lt;span class="support support_class support_class_cocoa"&gt;NSExpression&lt;/span&gt; *ex = &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSExpression&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;expressionForFunction&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;function &lt;br /&gt;        &lt;span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc"&gt;arguments&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSArray&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;arrayWithObject&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSExpression&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;expressionForKeyPath&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;attributeName&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;    NSExpressionDescription *ed = &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;NSExpressionDescription &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;alloc&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;init&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;&lt;br /&gt;    &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;ed &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;setName&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc"&gt;@"&lt;/span&gt;result&lt;span class="punctuation punctuation_definition punctuation_defi
