<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" xml:lang="en-US">
  <title>Intridea - Company Blog</title>
  <id>tag:www.intridea.com,2009:company</id>
  
  <link href="http://www.intridea.com/blog/company" rel="alternate" type="text/html" />
  <updated>2009-11-12T10:07:31-05:00</updated>
  <link rel="self" href="http://feeds.feedburner.com/intridea" type="application/atom+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><entry xml:base="http://www.intridea.com">
    <author>
      <name>Michael Bleigh</name>
    </author>
    <id>tag:www.intridea.com,2009-11-12:209</id>
    <published>2009-11-12T09:13:00-05:00</published>
    <updated>2009-11-12T09:13:00-05:00</updated>
    <category term="announcements" />
    <category term="gems" />
    <category term="open-source" />
    <category term="hashie" />
    <category term="mash" />
    <link href="http://feedproxy.google.com/~r/intridea/~3/FClsZyfoLj8/hashie-the-hash-toolkit" rel="alternate" type="text/html" />
    <title>Hashie: The Hash Toolkit</title>
    <content type="html">&lt;p&gt;One of my earliest gems was &lt;a href="http://intridea.com/2008/4/12/mash-mocking-hash-for-total-poser-objects?blog=company"&gt;Mash&lt;/a&gt;, a useful tool for creating mocking objects as a Hash. One of the most common problems people had with Mash was a simple one: it conflicted with another class of the same name in extlib! To address this problem as well as give the project some room to grow, Mash is now part of a new toolkit called &lt;strong&gt;Hashie&lt;/strong&gt;. Hashie is available now via Gemcutter and the source, as always, is &lt;a href="http://github.com/intridea/hashie"&gt;available on GitHub&lt;/a&gt;. To install:&lt;/p&gt;


&lt;pre name='code'&gt;gem install hashie&lt;/pre&gt;

	&lt;h3&gt;Hello, Hashie&lt;/h3&gt;


	&lt;p&gt;Hashie is, right now, simply the former Mash code along with a new extended Hash called a Dash. A Dash is a &amp;#8220;discrete hash&amp;#8221; that has pre-defined properties. It can be used as a dead-simple data object when even something like DataMapper is too heavy, but a Struct is too light (Dash gives you the ability to set per-property defaults as well as initialize from an attributes Hash). For example:&lt;/p&gt;


&lt;pre name='code' class='ruby'&gt;class Person &amp;lt; Hashie::Dash
  property :name
  property :email
  property :occupation, :default =&amp;gt; 'Rubyist'
end

p = Person.new
p.name # =&amp;gt; nil
p.occupation # =&amp;gt; 'Rubyist'
p.email = 'abc@def.com'
p.email # =&amp;gt; 'abc@def.com'
p['awesome'] # =&amp;gt; NoMethodError

p = Person.new(:name =&amp;gt; "Awesome Guy")
p.name # =&amp;gt; "Awesome Guy" 
p.occupation # =&amp;gt; "Rubyist"&lt;/pre&gt;

	&lt;p&gt;The other advantage Hashie has over Mash is that it&amp;#8217;s built from the ground up to avoid conflicts. Instead of adding &lt;code&gt;stringify_keys&lt;/code&gt; methods to the Hash class, it&amp;#8217;s instead added to a Hashie::Hash subclass. You can, however, get Hashie&amp;#8217;s few Hash extensions in the Hash class by including the HashExtensions:&lt;/p&gt;


&lt;pre name='code' class='ruby'&gt;Hash.send :include, Hashie::HashExtensions&lt;/pre&gt;

	&lt;p&gt;Hopefully the move will make it easier for everyone to use it in their projects without fear of running into conflicts, and hopefully you&amp;#8217;ll also find the Dash useful. Over time the functionality of Hashie may grow to encompass additional simple and useful extensions of Hash. So install Hashie, your friendly neighborhood Hash toolkit, today!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/intridea/~4/FClsZyfoLj8" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.intridea.com/posts/hashie-the-hash-toolkit</feedburner:origLink></entry>
  <entry xml:base="http://www.intridea.com">
    <author>
      <name>Brendan Lim</name>
    </author>
    <id>tag:www.intridea.com,2009-11-11:208</id>
    <published>2009-11-11T16:02:00-05:00</published>
    <updated>2009-11-11T16:02:00-05:00</updated>
    <category term="carfinder" />
    <category term="augmented" />
    <category term="reality" />
    <category term="mobile" />
    <category term="iphone" />
    <link href="http://feedproxy.google.com/~r/intridea/~3/Ny6IbqC1igE/car-finder-becomes-a-hit-application-for-iphone" rel="alternate" type="text/html" />
    <title>Car Finder Becomes a Hit Application for iPhone</title>
    <content type="html">&lt;p&gt;
We released &lt;a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=335295621&amp;#38;mt=8"&gt;Car Finder&lt;/a&gt; just over a week ago and the amount of attention we&amp;#8217;ve received is much more than we could have ever anticipated.  For those of you who don&amp;#8217;t know, &lt;a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=335295621&amp;#38;mt=8"&gt;Car Finder&lt;/a&gt; is an iPhone application that utilizes augmented reality to help you find where you parked your car.  
&lt;/p&gt;
&lt;p align='center'&gt;
&lt;img src="http://img.skitch.com/20091111-xby9ge456nyrqgpmc7ba4fcpq7.png" alt="thugfinder"/&gt;&lt;br/&gt;
&lt;span style='font-size: 10px'&gt;&lt;strong&gt;Note:&lt;/strong&gt; Car Finder developer &lt;a href="http://intridea.com/about/people/brendan"&gt;Brendan Lim&lt;/a&gt; and his brother (with the dollar) sold separately&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
Throughout this whole process we&amp;#8217;ve noticed that the Twitter mentions that came after these news articles proved to play a huge part in &lt;a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=335295621&amp;#38;mt=8"&gt;Car Finder&amp;#8217;s&lt;/a&gt; success.  Below are a list of a few articles that covered the release of &lt;a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=335295621&amp;#38;mt=8"&gt;Car Finder&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Wired UK&lt;/strong&gt;&lt;br/&gt;
&lt;a href="http://www.wired.co.uk/news/archive/2009-11/06/save-face-with-the-car-finder-augmented-reality-app.aspx"&gt;Save face with the Car Finder augmented reality app&lt;/a&gt;
&lt;br/&gt;&lt;br/&gt;
&lt;strong&gt;The Unofficial Apple Weblog&lt;/strong&gt;&lt;br/&gt;
&lt;a href="http://www.tuaw.com/2009/11/03/use-augmented-reality-to-find-your-car/"&gt;Use Augmented Reality to Find Your Car&lt;/a&gt;
&lt;br/&gt;&lt;br/&gt;
&lt;strong&gt;Autoblog&lt;/strong&gt;&lt;br/&gt;
&lt;a href="http://www.autoblog.com/2009/11/06/latest-auto-iphone-app-augmented-reality-parked-car-finder/"&gt;Latest auto iPhone app: Augmented reality parked car finder&lt;/a&gt;
&lt;br/&gt;&lt;br/&gt;
&lt;strong&gt;Holy Kaw!&lt;/strong&gt;&lt;br/&gt;
&lt;a href="http://holykaw.alltop.com/cant-find-your-car-theres-an-app-for-that"&gt;Can’t find your car? There’s an app for that. &amp;#8211; Holy Kaw!&lt;/a&gt;
&lt;br/&gt;&lt;br/&gt;
&lt;strong&gt;Cult of Mac&lt;/strong&gt;&lt;br/&gt;
&lt;a href="http://www.cultofmac.com/car-finder-iphone-app-uses-augmented-reality-to-find-your-wheels/20478"&gt;Car Finder iPhone App Uses Augmented Reality To Find Your Wheels&lt;/a&gt;
&lt;br/&gt;&lt;br/&gt;
&lt;strong&gt;Boing Boing&lt;/strong&gt;&lt;br/&gt;
&lt;a href="http://www.boingboing.net/2009/11/04/car-finder-app-for-i.html"&gt;Car Finder app for iPhone&lt;/a&gt;
&lt;br/&gt;&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=335295621&amp;#38;mt=8" target="_new"&gt;Car Finder&lt;/a&gt; is available now on the App Store for $0.99.  Intridea offers services for application development on all major mobile platforms, which include iPhone, Android, BlackBerry, and Palm webOS.  If you need help with your mobile application feel free to &lt;a href="/contact"&gt;contact us&lt;/a&gt; for a quote.
&lt;/p&gt;

&lt;p align="center"&gt;
&lt;a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=335295621&amp;#38;mt=8"&gt;&lt;img src="https://presentlyapp.com/images/avail_on_app_store.png?1253891834"&gt;&lt;/a&gt;
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/intridea/~4/Ny6IbqC1igE" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.intridea.com/posts/car-finder-becomes-a-hit-application-for-iphone</feedburner:origLink></entry>
  <entry xml:base="http://www.intridea.com">
    <author>
      <name>Michael Bleigh</name>
    </author>
    <id>tag:www.intridea.com,2009-11-03:207</id>
    <published>2009-11-03T08:57:00-05:00</published>
    <updated>2009-11-03T08:57:00-05:00</updated>
    <category term="ruby" />
    <category term="rails" />
    <category term="quick tip" />
    <category term="validations" />
    <category term="with_options" />
    <category term="ActiveRecord" />
    <link href="http://feedproxy.google.com/~r/intridea/~3/xNS5GpePfsM/rails-quick-tip-readable-conditional-validations" rel="alternate" type="text/html" />
    <title>Quick Tip: Readable Conditional Validations in Rails</title>
    <content type="html">&lt;p&gt;This is something that many may already use as a best practice, but if not it&amp;#8217;s something simple and convenient to add to your repertoire. Sometimes you may have a model that requires additional information if a certain condition is met. For example, I may require a user to add more information about themselves if they wish to be listed publicly, whereas I would not if they do not wish to be listed. By combining ActiveSupport&amp;#8217;s &lt;code&gt;Object#with_options&lt;/code&gt; and ActiveRecord&amp;#8217;s conditional validations, we can implement this behavior in a straightforward and readable manner (assuming here that there is a boolean field called &amp;#8220;listed&amp;#8221; in the database that is exposed as a checkbox or similar to the user):&lt;/p&gt;


&lt;pre name='code' class='ruby'&gt;class User &amp;lt; ActiveRecord::Base
  # Our standard validations
  validates_presence_of :login
  validates_uniqueness_of :login

  # Validations for listed users
  with_options :if =&amp;gt; :listed? do |l|
    l.validates_presence_of :email
    l.validates_length_of :description, :minimum =&amp;gt; 100
  end
end&lt;/pre&gt;

	&lt;p&gt;It&amp;#8217;s a simple technique that piggybacks off of Rails&amp;#8217;s automatic construction of existence query methods (in this case, &lt;code&gt;listed?&lt;/code&gt;) for fields in the database combined with the mapping power of &lt;code&gt;with_options&lt;/code&gt; and standard conditional validations.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/intridea/~4/xNS5GpePfsM" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.intridea.com/posts/rails-quick-tip-readable-conditional-validations</feedburner:origLink></entry>
  <entry xml:base="http://www.intridea.com">
    <author>
      <name>Brendan Lim</name>
    </author>
    <id>tag:www.intridea.com,2009-11-02:206</id>
    <published>2009-11-02T16:47:00-05:00</published>
    <updated>2009-11-02T16:47:00-05:00</updated>
    <category term="mobile" />
    <category term="augmented reality" />
    <category term="iphone" />
    <link href="http://feedproxy.google.com/~r/intridea/~3/R6qZR51DjjQ/use-augmented-reality-to-find-your-vehicle-with-car-finder-for-iphone" rel="alternate" type="text/html" />
    <title>Use Augmented Reality to Find Your Vehicle With Car Finder for iPhone</title>
    <content type="html">&lt;p&gt;
If you&amp;#8217;ve ever parked your vehicle in a large parking lot you&amp;#8217;ve realized that it would be great to have something help you memorize where your car was.  Intridea&amp;#8217;s latest iPhone application, &lt;a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=335295621&amp;#38;mt=8" target="_new"&gt;Car Finder&lt;/a&gt;, helps you do just that.  Unlike the cookie-cutter car finding applications in the App Store, &lt;a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=335295621&amp;#38;mt=8" target="_new"&gt;Car Finder&lt;/a&gt; helps you find your car using &lt;i&gt;augmented reality&lt;/i&gt;.  
&lt;/p&gt;

&lt;p&gt;
Using the camera, A-GPS and the compass built into the iPhone 3GS, &lt;a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=335295621&amp;#38;mt=8" target="_new"&gt;Car Finder&lt;/a&gt; allows you to find your car by positioning an overlay on top of a live view of what&amp;#8217;s in front of you.  Also, when you mark your car &lt;a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=335295621&amp;#38;mt=8" target="_new"&gt;Car Finder&lt;/a&gt; allows you to set a note for your parking spot.  This is particularly useful if you know what section you&amp;#8217;re parked in or if the &lt;span class="caps"&gt;GPS&lt;/span&gt; is spotty in the location that your car is currently parked in.  
&lt;/p&gt;
&lt;p align="center"&gt;
&lt;img src="http://img.skitch.com/20091102-tnhg9qmaadbrdtsce74xk2xm1g.png"&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=335295621&amp;#38;mt=8" target="_new"&gt;Car Finder&lt;/a&gt; is available now on the App Store for $0.99.  Intridea offers services for application development on all major mobile platforms, which include iPhone, Android, BlackBerry, and Palm webOS.  If you need help with your mobile application feel free to &lt;a href="/contact"&gt;contact us&lt;/a&gt; for a quote.
&lt;/p&gt;

&lt;p align="center"&gt;
&lt;a href="http://appsto.re/carfinder"&gt;&lt;img src="https://presentlyapp.com/images/avail_on_app_store.png?1253891834"&gt;&lt;/a&gt;
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/intridea/~4/R6qZR51DjjQ" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.intridea.com/posts/use-augmented-reality-to-find-your-vehicle-with-car-finder-for-iphone</feedburner:origLink></entry>
  <entry xml:base="http://www.intridea.com">
    <author>
      <name>Michael Bleigh</name>
    </author>
    <id>tag:www.intridea.com,2009-10-29:205</id>
    <published>2009-10-29T17:47:00-04:00</published>
    <updated>2009-10-29T17:47:00-04:00</updated>
    <category term="presently" />
    <category term="announcements" />
    <category term="feature" />
    <category term="sharepoint" />
    <category term="oss" />
    <link href="http://feedproxy.google.com/~r/intridea/~3/Dh0I-dmHbe0/presently-adds-sharepoint-integration" rel="alternate" type="text/html" />
    <title>Presently Adds SharePoint Integration</title>
    <content type="html">&lt;p&gt;We&amp;#8217;re always looking for ways to make it easier to integrate Presently into your day-to-day workflow. Today, we&amp;#8217;re happy to announce something that will make it much easier for businesses using &lt;a href="http://sharepoint.microsoft.com/Pages/Default.aspx"&gt;Microsoft&amp;#8217;s SharePoint&lt;/a&gt; to integrate Presently. Starting today businesses can use the &lt;strong&gt;Presently SharePoint Web Part&lt;/strong&gt;.&lt;/p&gt;


&lt;p align='center'&gt;&lt;a href="http://img.skitch.com/20091027-t7gcgqa9uee32hgmuxdjmtnmug.jpg" target="_blank"&gt;&lt;img src='http://img.skitch.com/20091027-pbpfgbusqggmxadmj8hah6nd4t.jpg'/&gt;&lt;/a&gt;&lt;/p&gt;

	&lt;p&gt;The Presently Web Part will allow you to view and post updates to your company&amp;#8217;s Presently account from directly inside your Microsoft SharePoint portal. For more information on the installation and usage of the Web Part, you can visit &lt;a href="http://presentlyapp.com/sharepoint"&gt;the SharePoint application page&lt;/a&gt;.&lt;/p&gt;


&lt;p align='center'&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/Ib0fKZchBl4&amp;#38;hl=en&amp;#38;fs=1&amp;#38;"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/Ib0fKZchBl4&amp;#38;hl=en&amp;#38;fs=1&amp;#38;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/p&gt;

	&lt;p&gt;We have also released the source code to the web part, it&amp;#8217;s &lt;a href="http://github.com/presently/presently-sharepoint"&gt;available on GitHub&lt;/a&gt;. Please feel free to &lt;a href="http://support.presentlyapp.com/"&gt;contact support&lt;/a&gt; with any additional questions.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/intridea/~4/Dh0I-dmHbe0" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.intridea.com/posts/presently-adds-sharepoint-integration</feedburner:origLink></entry>
  <entry xml:base="http://www.intridea.com">
    <author>
      <name>Brendan Lim</name>
    </author>
    <id>tag:www.intridea.com,2009-10-29:204</id>
    <published>2009-10-29T13:58:00-04:00</published>
    <updated>2009-10-29T13:58:00-04:00</updated>
    <category term="mobile" />
    <category term="sushime" />
    <category term="iphone" />
    <link href="http://feedproxy.google.com/~r/intridea/~3/3IZuZ4TKk9w/find-great-sushi-with-sushime-on-iphone" rel="alternate" type="text/html" />
    <title>Find Great Sushi Anywhere with SushiMe on iPhone</title>
    <content type="html">&lt;p&gt;Adding to Intridea&amp;#8217;s collection of great food finding applications for the iPhone, like &lt;a href="http://appsto.re/ipho" target="_new"&gt;iPho&lt;/a&gt; and &lt;a href="http://appsto.re/icurry" target="_new"&gt;iCurry&lt;/a&gt;, comes &lt;a href="http://appsto.re/sushime" target="_new"&gt;SushiMe&lt;/a&gt;.  SushiMe allows you to find great sushi restaurants around you using your current location or any location that you specify.  You can sort through a list of restaurants by their rating (provided by &lt;a href="http://yelp.com" target="_new"&gt;Yelp&lt;/a&gt;) or by their distance.  With SushiMe you can also view a map of all of the restaurants around you and even call them directly from your iPhone to make reservations.
&lt;/p&gt;
&lt;p align="center"&gt;
&lt;img src="http://img.skitch.com/20091029-erhmbmi7qqskd8acj7icytr88j.png"&gt;
&lt;/p&gt;
&lt;p&gt;
SushiMe is a free application and is available right now in the App Store.  Intridea offers services for application development on all major mobile platforms, which include iPhone, Android, BlackBerry, and Palm webOS.  If you need help with your mobile application feel free to &lt;a href="/contact"&gt;contact us&lt;/a&gt; for a quote.
&lt;/p&gt;
&lt;p align="center"&gt;
&lt;a href="http://appsto.re/sushime"&gt;&lt;img src="https://presentlyapp.com/images/avail_on_app_store.png?1253891834"&gt;&lt;/a&gt;
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/intridea/~4/3IZuZ4TKk9w" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.intridea.com/posts/find-great-sushi-with-sushime-on-iphone</feedburner:origLink></entry>
  <entry xml:base="http://www.intridea.com">
    <author>
      <name>Brendan Lim</name>
    </author>
    <id>tag:www.intridea.com,2009-10-08:203</id>
    <published>2009-10-08T12:02:00-04:00</published>
    <updated>2009-10-08T12:02:00-04:00</updated>
    <category term="presently" />
    <category term="iphone" />
    <category term="mobile" />
    <link href="http://feedproxy.google.com/~r/intridea/~3/JblaRSo9A6A/presently-updates-iphone-app-with-camera-and-attachment-integration" rel="alternate" type="text/html" />
    <title>Present.ly Updates iPhone App With Camera and Attachment Integration</title>
    <content type="html">&lt;p&gt;
Present.ly, our enterprise microblogging platform, which is used daily by many large corporations and government organizations, offers native versions of the application on all major mobile platforms.  Today, Apple has approved the latest version of Present.ly for iPhone.
&lt;/p&gt;
&lt;p align="center" style="white-space: nowrap;"&gt;
&lt;img src="http://img.skitch.com/20091008-tkykthwhmgj2grnxc68ax896yn.png"&gt;
&lt;/p&gt;
&lt;p&gt;
Included in this latest version is an updated user interface.  The new user interface ditches the previous dark theme and replaces it with a look that is more familiar to iPhone users and is easier on the eyes.  Uploaded attachments can be viewed directly from the phone.  Updates with one or more attached files are indicated by a small paperclip icon within your feed.  &lt;/p&gt;
&lt;p&gt;
In addition to attaching files, photos from your photo library or the iPhone camera can be added to your updates&amp;#8212;a highly anticipated feature.  This version of the app provides a more robust user experience by enabling many of the most useful features of the web client.  Present.ly is a free application available in the App Store.  To get Present.ly for your iPhone click on the link below.
&lt;/p&gt;

&lt;p align="center"&gt;
&lt;a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=302924106&amp;#38;mt=8"&gt;&lt;img src="https://presentlyapp.com/images/avail_on_app_store.png?1253891834"&gt;&lt;/a&gt;
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/intridea/~4/JblaRSo9A6A" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.intridea.com/posts/presently-updates-iphone-app-with-camera-and-attachment-integration</feedburner:origLink></entry>
  <entry xml:base="http://www.intridea.com">
    <author>
      <name>Brendan Lim</name>
    </author>
    <id>tag:www.intridea.com,2009-10-01:202</id>
    <published>2009-10-01T17:41:00-04:00</published>
    <updated>2009-10-01T17:41:00-04:00</updated>
    <category term="iphone" />
    <category term="apps" />
    <category term="mobile" />
    <link href="http://feedproxy.google.com/~r/intridea/~3/ZJELV0iXA7E/intridea-kicks-off-mobile-development-services-with-two-free-iphone-apps-for-foodies" rel="alternate" type="text/html" />
    <title>Intridea Kicks off Mobile Development Services With Two Free iPhone Apps for Foodies</title>
    <content type="html">&lt;p&gt;
&lt;img src="http://img.skitch.com/20091001-m8tnru6gh7cuy93c7ern8bwdk1.png" align="right" style='padding: 5px;'&gt; &lt;img src="http://img.skitch.com/20091001-7xpmhcphnyq7tk8xispti9u1f.png" align="right"  style='padding: 5px;'&gt; Sometimes you just want an application that gets something done quick and gets it done right -- especially if your stomach's calling.  That's why we've decided to create iPho and iCurry for the iPhone. 
&lt;/p&gt;
&lt;p&gt;iPho will help you find the best phở around you using your current location or any address you use using the built-in search.  iCurry does the same but allows you to search through the best Indian food around.  &lt;/p&gt;
&lt;p&gt;Both of these applications will show you a list of restaurants sorted by their average rating or their distance relative to you or the address you search from.  You can also drill down into each restaurant so that you can get their address, get directions, give them a call, and even see if they are open.  There's even a map view which overlays all of the restaurants around you.  Ratings and listings are provided using the &lt;a href="http://yelp.com" target="_new"&gt;Yelp&lt;/a&gt; API.  Both iCurry and iPho are free applications and are available now on the App Store.
&lt;/p&gt;
&lt;p&gt;
Along with the announcement of these two great applications, we at Intridea are kicking off our mobile development services for our clients.  We are offering services for application development on all major mobile platforms, which include iPhone, Android, BlackBerry, and Palm webOS.  We've built a great team of talented mobile developers that can help bring your product or service to the mobile market.  Expect to see more mobile related announcements soon.  
&lt;/p&gt;
&lt;p&gt;
Need help with your mobile app? &lt;a href="/contact"&gt;Contact us&lt;/a&gt; for a quote.
&lt;/p&gt;
&lt;div style='float: left; text-align: center; width: 50%; color: #444;'&gt;
&lt;strong&gt;Download iPho&lt;/strong&gt;&lt;br/&gt;&lt;br/&gt;
&lt;a href="http://appsto.re/ipho"&gt;&lt;img src="https://presentlyapp.com/images/avail_on_app_store.png?1253891834"&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div style='float: left; text-align: center; width: 50%; color: #444;'&gt;
&lt;strong&gt;Download iCurry&lt;/strong&gt;&lt;br/&gt;&lt;br/&gt;
&lt;a href="http://appsto.re/icurry"&gt;&lt;img src="https://presentlyapp.com/images/avail_on_app_store.png?1253891834"&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div style="clear: both"&gt;&lt;/div&gt;

&lt;br/&gt;
&lt;p align="center" style="white-space: no-wrap"&gt;
&lt;img src="http://img.skitch.com/20091001-cxk8h2k27w3gy2xn96ppuqywdg.png"&gt; &lt;img src="http://img.skitch.com/20091001-mucnxf9466ms3spb171hcastkp.png"&gt; &lt;img src="http://img.skitch.com/20091001-r2nghefrt84u79m2k3ex6daheq.png"&gt;
&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/intridea/~4/ZJELV0iXA7E" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.intridea.com/posts/intridea-kicks-off-mobile-development-services-with-two-free-iphone-apps-for-foodies</feedburner:origLink></entry>
  <entry xml:base="http://www.intridea.com">
    <author>
      <name>Michael Bleigh</name>
    </author>
    <id>tag:www.intridea.com,2009-09-22:201</id>
    <published>2009-09-22T17:02:00-04:00</published>
    <updated>2009-09-22T17:02:00-04:00</updated>
    <category term="open-source" />
    <category term="twitter" />
    <category term="streaming api" />
    <category term="release" />
    <category term="announcement" />
    <link href="http://feedproxy.google.com/~r/intridea/~3/hp2RgICi9g0/tweetstream-ruby-access-to-the-twitter-streaming-api" rel="alternate" type="text/html" />
    <title>TweetStream: Ruby Access to the Twitter Streaming API</title>
    <content type="html">&lt;p&gt;Twitter&amp;#8217;s &lt;a href="http://apiwiki.twitter.com/Streaming-API-Documentation"&gt;Streaming &lt;span class="caps"&gt;API&lt;/span&gt;&lt;/a&gt; is one of the most exciting developments in the Twitter &lt;span class="caps"&gt;API&lt;/span&gt; in some time. It gives you the ability to create a long-standing connection to Twitter that receives &amp;#8220;push&amp;#8221; updates when new tweets matching certain criteria arrive, obviating the need to constantly poll for updates. &lt;a href="http://github.com/intridea/tweetstream"&gt;TweetStream&lt;/a&gt; is a Ruby library to access the new &lt;span class="caps"&gt;API&lt;/span&gt;.&lt;/p&gt;


	&lt;h3&gt;Installation&lt;/h3&gt;


	&lt;p&gt;Installation of TweetStream is simple, it&amp;#8217;s available as a gem on GitHub and &lt;a href="http://gemcutter.org/"&gt;Gemcutter.org&lt;/a&gt;. To install it from GitHub:&lt;/p&gt;


&lt;pre&gt;gem sources -a http://gems.github.com
gem install intridea-tweetstream&lt;/pre&gt;

	&lt;p&gt;To install it from Gemcutter:&lt;/p&gt;


&lt;pre&gt;gem sources -a http://gemcutter.org
gem install tweetstream&lt;/pre&gt;

	&lt;h3&gt;Usage&lt;/h3&gt;


	&lt;p&gt;TweetStream creates a long-standing &lt;span class="caps"&gt;HTTP&lt;/span&gt; connection to Twitter, so unlike other Twitter libraries you don&amp;#8217;t simply run it once and deal with the results. Instead, you provide a block that will be yielded to with each new status that arrives. The most basic example is:&lt;/p&gt;


&lt;pre name='code' class='ruby'&gt;require 'rubygems'
require 'tweetstream'

TweetStream::Client.new('user','pass').sample do |status|
  puts "[#{status.user.screen_name}] #{status.text}" 
end&lt;/pre&gt;

	&lt;p&gt;This will provide you with a small sample snapshot of all of the updates being posted to Twitter at this moment and print them to the screen. There are also methods available to track single-word keywords as well as the updates of a specified list of user ids (integers, not screen names). You can do that like so:&lt;/p&gt;


&lt;pre name='code' class='ruby'&gt;# Track the terms 'keyword1' and 'keyword2'
TweetStream::Client.new('user','pass').track('keyword1', 'keyword2') do |status|
  puts "[#{status.user.screen_name}] #{status.text}" 
end

# Track users with IDs 123 and 456
TweetStream::Client.new('user','pass').follow(123, 456) do |status|
  puts "[#{status.user.screen_name}] #{status.text}" 
end&lt;/pre&gt;

	&lt;h3&gt;Handling Deletion/Limit Notices (Updated in 0.1.4)&lt;/h3&gt;


	&lt;p&gt;Sometimes the Streaming &lt;span class="caps"&gt;API&lt;/span&gt; will send messages other than statuses.
Specifically, it does so when a status is deleted or rate limitations
have caused some tweets not to appear in the stream. To handle these, you can use the on_delete and on_limit methods. Example:&lt;/p&gt;


&lt;pre name='code' class='ruby'&gt;TweetStream::Client.new('user','pass').on_delete{ |status_id, user_id|
  Tweet.delete(status_id)
}.on_limit { |skip_count|
  # do something
}.track('intridea') do |status|
  # do something with the status like normal
end&lt;/pre&gt;

	&lt;h3&gt;Daemonization&lt;/h3&gt;


	&lt;p&gt;One of the most useful features of TweetStream is its built-in daemonization functionality. This allows you to create scripts that run in the background of your machine rather than taking up an active process. To create a daemon script, you simply use &lt;code&gt;TweetStream::Daemon&lt;/code&gt; instead of &lt;code&gt;TweetStream::Client&lt;/code&gt;. Here&amp;#8217;s an example:&lt;/p&gt;


&lt;pre name='code' class='ruby'&gt;require 'rubygems'
require 'tweetstream'

# The third argument is an optional process name.
TweetStream::Daemon.new('user','pass','tracker').track('keyword1','keyword2') do |status|
  # Do something like dump the status to ActiveRecord
  # or anything else you want.
end&lt;/pre&gt;

	&lt;p&gt;If you were to place the above code in a file called &lt;code&gt;tracker.rb&lt;/code&gt; you could then run &lt;code&gt;ruby tracker.rb&lt;/code&gt; to see a list of daemonization commands such as start, stop, or run.&lt;/p&gt;


	&lt;p&gt;TweetStream is a simple wrapper on the Streaming &lt;span class="caps"&gt;API&lt;/span&gt;, but with built-in daemonization provides powerfully flexible means of accessing the Twitter Streaming &lt;span class="caps"&gt;API&lt;/span&gt; using familiar Ruby tools. More complete code documentation is &lt;a href="http://rdoc.info/projects/intridea/tweetstream"&gt;available at rdoc.info&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; I overlooked the deletion and rate limit notices when I wrote the initial version of the gem. As of version 0.1.4 these are handled properly.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/intridea/~4/hp2RgICi9g0" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.intridea.com/posts/tweetstream-ruby-access-to-the-twitter-streaming-api</feedburner:origLink></entry>
  <entry xml:base="http://www.intridea.com">
    <author>
      <name>Michael Bleigh</name>
    </author>
    <id>tag:www.intridea.com,2009-09-21:200</id>
    <published>2009-09-21T02:59:00-04:00</published>
    <updated>2009-09-21T02:59:00-04:00</updated>
    <category term="couchdb" />
    <category term="lucene" />
    <category term="couchdb-lucene" />
    <category term="couchrest" />
    <category term="ruby" />
    <link href="http://feedproxy.google.com/~r/intridea/~3/PsF2kTAs25k/couchdb-lucene-couchdbx-and-couchrest" rel="alternate" type="text/html" />
    <title>CouchDB-Lucene, CouchDBX, and CouchRest</title>
    <content type="html">&lt;p&gt;I&amp;#8217;ve been playing a lot with &lt;a href="http://couchdb.apache.org/"&gt;CouchDB&lt;/a&gt; lately and if you&amp;#8217;re on &lt;span class="caps"&gt;OS X&lt;/span&gt; there&amp;#8217;s really no easier way to do so than by using &lt;a href="http://janl.github.com/couchdbx/"&gt;CouchDBX&lt;/a&gt;, a self-contained application that includes CouchDB, Erlang, and all of the dependencies you need to run Couch.&lt;/p&gt;


	&lt;p&gt;However, recently I wanted to try the power and functionality of &lt;a href="http://github.com/rnewson/couchdb-lucene"&gt;couchdb-lucene&lt;/a&gt; for full-text indexing of a CouchDB application on which I was working. It wasn&amp;#8217;t immediately obvious to me how to make that happen, so I thought I&amp;#8217;d share how I got it working for those who might want to do the same. For the record, I am using the following versions of things:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Mac &lt;span class="caps"&gt;OS X 10&lt;/span&gt;.6 (Snow Leopard)&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://cloud.github.com/downloads/janl/couchdbx-core/CouchDBX-0.9.1-R13B-pl2.zip"&gt;CouchDBX 0.9.1 &lt;span class="caps"&gt;R13B&lt;/span&gt; pl2&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://cloud.github.com/downloads/rnewson/couchdb-lucene/couchdb-lucene-0.4-jar-with-dependencies.jar.gz"&gt;CouchDB Lucene v0.4&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h3&gt;Unpacking CouchDB Lucene&lt;/h3&gt;


	&lt;p&gt;You will need to place CouchDB Lucene in a convenient location, but first you&amp;#8217;ll need to unpack the gZip file. Note that, at least for me, &lt;strong&gt;the default Mac unarchiver did not provide a suitable .jar file&lt;/strong&gt;. Instead, follow the &lt;a href="http://cloud.github.com/downloads/rnewson/couchdb-lucene/README"&gt;&lt;span class="caps"&gt;README&lt;/span&gt; instructions&lt;/a&gt; and extract it using the following command:&lt;/p&gt;


&lt;pre&gt;unpack200 couchdb-lucene-0.4-jar-with-dependencies.jar.gz couchdb-lucene-0.4-jar-with-dependencies.jar&lt;/pre&gt;

	&lt;p&gt;It doesn&amp;#8217;t particularly matter where you put it (I put mine in &lt;code&gt;/usr/local/etc&lt;/code&gt;) so long as you remember the location.&lt;/p&gt;


	&lt;h3&gt;Editing the CouchDBX .ini File&lt;/h3&gt;


	&lt;p&gt;Next you will need to edit the CouchDBX &lt;code&gt;local.ini&lt;/code&gt; file to add the external for full-text indexing. To access the file, right-click CouchDBX and select &amp;#8220;Show Package Contents&amp;#8221; then navigate to &lt;code&gt;Contents/Resources/couchdbx-core/couchdb/etc/couchdb/local.ini&lt;/code&gt; and open it up in your favorite text editor. You will need to add the following lines to this file, taking note to change the directory to match where you stored your Lucene .jar file.&lt;/p&gt;


&lt;pre name='code' class='ini'&gt;[couchdb]
os_process_timeout=60000 ; increase the timeout from 5 seconds.

[external]
fti=/usr/bin/java -server -Xmx1g -jar /path/to/couchdb-lucene-0.4-jar-with-dependencies.jar -search

[update_notification]
indexer=/usr/bin/java -server -Xmx1g -jar  /path/to/couchdb-lucene-0.4-jar-with-dependencies.jar -index

[httpd_db_handlers]
_fti = {couch_httpd_external, handle_external_req, &amp;lt;&amp;lt;"fti"&amp;gt;&amp;gt;}&lt;/pre&gt;

	&lt;p&gt;All right, that&amp;#8217;s all the setup you need to be running CouchDB Lucene! Now you can start up CouchDBX and set up your first search indexes.&lt;/p&gt;


	&lt;h3&gt;Creating a Full-Text Index View&lt;/h3&gt;


	&lt;p&gt;To create a full-text index view, you simply need to add a &amp;#8220;fulltext&amp;#8221; field to one of your design documents. The &lt;span class="caps"&gt;URL&lt;/span&gt; structure for accessing CouchDB Lucene searches is as follows:&lt;/p&gt;


&lt;pre&gt;http://localhost:5984/database_name/_fti/design_doc_name/index_name?q=your+query+here&lt;/pre&gt;

	&lt;p&gt;Where &lt;code&gt;database_name&lt;/code&gt; is any database you have on your system, &lt;code&gt;design_doc_name&lt;/code&gt; is any design document in your database, and &lt;code&gt;index_name&lt;/code&gt; is a fulltext index you defined. For instance, if I had a &lt;a href="http://github.com/couchrest/couchrest"&gt;CouchRest&lt;/a&gt; generated design doc for a bunch of music, I might have a design document that looks something like this:&lt;/p&gt;


&lt;pre name='code' class='js'&gt;{
  "_id":"_design/Song",
  "_rev":"af12a4b12af1b24afbf244f1",
  "fulltext":{
    "my_search":{
      "index":"function(doc) { if (!doc['couchrest-type'] == 'Song') return null; var ret = new Document(); ret.add(doc.title); ret.add(doc.artist); return ret; }" 
    }
  }
}&lt;/pre&gt;

	&lt;p&gt;I would then be able to access the search results with this &lt;span class="caps"&gt;URL&lt;/span&gt;:&lt;/p&gt;


&lt;pre&gt;http://localhost:5984/myapp/_fti/Song/my_search?q=Ben+Folds&lt;/pre&gt;

	&lt;p&gt;Awesome! We now have full-text indexing up and running on CouchDBX!&lt;/p&gt;


	&lt;h3&gt;Bonus: CouchRest Lucene&lt;/h3&gt;


	&lt;p&gt;I use CouchRest extensively in my Ruby CouchDB projects, and I wanted to be able to integrate the new Lucene searches easily. I found &lt;a href="http://zdzolton.wordpress.com/2009/05/04/quick-tip-couchdb-with-lucene-search/"&gt;this post&lt;/a&gt; that added a bit of functionality, but I wanted to be able to integrate with ExtendedDocument (and the snippet was also slightly outdated), so I&amp;#8217;ve updated it. Just add this sometime after you include CouchRest:&lt;/p&gt;


&lt;pre name='code' class='ruby'&gt;class CouchRest::Database
  def search(design, index, query, options={})
    CouchRest.get CouchRest.paramify_url("#{@root}/_fti/#{design}/#{index}", options.merge(:q =&amp;gt; query))
  end
end

class CouchRest::ExtendedDocument
  def self.search(index, query, options={})
    options[:include_docs] = true
    ret = self.database.search(self.to_s, index, query, options)
    ret['rows'].collect!{|r| self.new(r['doc'])}
    ret
  end
end&lt;/pre&gt;

	&lt;p&gt;What this snippet does is allows you to perform searches on a database directly or by calling a search method on an extended document. Let&amp;#8217;s look at a couple examples to see how it would work:&lt;/p&gt;


&lt;pre name='code' class='ruby'&gt;@db = CouchRest.database!("http://localhost:5984/myapp")

@db.search('Song','my_search', 'Ben Folds', :include_docs =&amp;gt; true)

# The following is equivalent to the above, but will automatically
# include the docs and cast the result rows into ExtendedDocuments
Song.search('my_search', 'Ben Folds')&lt;/pre&gt;

	&lt;p&gt;Now that we have this set up, we&amp;#8217;re ready to go forth and build full-text search into our CouchDB apps. I hope this is helpful to some who have become somewhat familiar with CouchDB but are looking to push it a little further and try out some of the more advanced usages of CouchDB in their applications.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/intridea/~4/PsF2kTAs25k" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.intridea.com/posts/couchdb-lucene-couchdbx-and-couchrest</feedburner:origLink></entry>
  <entry xml:base="http://www.intridea.com">
    <author>
      <name>Michael Bleigh</name>
    </author>
    <id>tag:www.intridea.com,2009-08-24:199</id>
    <published>2009-08-24T12:52:00-04:00</published>
    <updated>2009-08-24T12:52:00-04:00</updated>
    <category term="rails" />
    <category term="rumble" />
    <category term="thingivore" />
    <link href="http://feedproxy.google.com/~r/intridea/~3/UDiqqVuTbYE/thingivore-rails-rumble-post-mortem" rel="alternate" type="text/html" />
    <title>Good Idea, Bad Idea: Thingivore's Rails Rumble Post-Mortem</title>
    <content type="html">&lt;div style='float:right; margin: 0 0 10px 10px;'&gt;&lt;img src='http://img.skitch.com/20090824-eefjcq11tdka135rgmqkn8wcbu.jpg' alt='Thingivore.com'/&gt;&lt;/div&gt;

	&lt;p&gt;The time has come and gone: the 2009 Rails Rumble is over (from a code perspective, anyway). This year myself and the other members of my team (Brent Collier, Dave Naffis, and Ping Yu) put together &lt;a href="http://www.thingivore.com/"&gt;Thingivore&lt;/a&gt;, a place to show off your collection of movies, games, and books online. As one might expect from a 48-hour marathon application development experience, it was a mixed bag of elation, frustration, fist-pumping and head-hanging as the hours drew to a close. I wanted to take some time to document some of my &amp;#8220;lessons learned&amp;#8221; so to speak for future Rumblers and app developers in general.&lt;/p&gt;


	&lt;h3&gt;Good Idea: Have a Server Configuration Guru&lt;/h3&gt;


	&lt;p&gt;While the Rumble is primarily a coding contest, it&amp;#8217;s important to note that &lt;strong&gt;someone&lt;/strong&gt; on your team needs to be able to get that Linode server up and running. By having someone who can configure centos servers in their sleep on your team, you don&amp;#8217;t have to sweat bullets at the prospect of &amp;#8220;just getting it running.&amp;#8221; In fact, Dave Naffis (Intridea co-founder and Rails deployment genius) came in and 45 minutes later said &amp;#8220;OK, just hit &lt;code&gt;cap deploy deploy:migrate&lt;/code&gt;&amp;#8221; whenever you want to update the server. This is including setting up &lt;span class="caps"&gt;DNS&lt;/span&gt; for &lt;code&gt;thingivore.com&lt;/code&gt;, getting Ruby, Rails, Apache, Passenger, MySQL, and CouchDB all running and probably all other manner of dark magic I can&amp;#8217;t comprehend.&lt;/p&gt;


	&lt;p&gt;Maybe it&amp;#8217;s because I&amp;#8217;m not a server configuration guy, but that&amp;#8217;s exactly the point: I didn&amp;#8217;t have to worry about it and could focus on the design and development instead of worrying about whether or not we were going to get it running on the competition machines.&lt;/p&gt;


	&lt;h3&gt;Bad Idea: &amp;#8220;Let&amp;#8217;s Try Something New!&amp;#8221;&lt;/h3&gt;


	&lt;p&gt;For some crazy reason, I decided that I wanted to use the Rumble as a way to experiment with new technologies (primarily CouchDB). &lt;strong&gt;Do not do this.&lt;/strong&gt; The Rumble is a time to take the skills you know like the back of your hand and apply them with laser-beam focus to build something awesome and complete in 48 hours. While I&amp;#8217;m happy with our product, there are reams of features that were cut while I scrambled to understand some of the complexities of complex sorts and other issues with CouchRest and CouchDB.&lt;/p&gt;


	&lt;p&gt;Of course, it was also fun to learn a new technology and use it in a &amp;#8220;trial by fire&amp;#8221; circumstance, but ultimately if you want to build something that can win the competition it&amp;#8217;s probably better to stick to your guns.&lt;/p&gt;


	&lt;h3&gt;Good Idea: As Many Plugins As You Can Actually Use&lt;/h3&gt;


	&lt;p&gt;Ruby and Rails provide some of the most powerful collections of reliable code that you could hope for. We were originally planning to go 100% with CouchDB for the project, but when it became apparent that we would have to roll our own OpenID authentication we decided to slap MySQL in as well (only for user models) so that we could make use of &lt;a href="http://github.com/binarylogic/authlogic"&gt;AuthLogic&lt;/a&gt; and its OpenID extension. This saved us who-knows-how-many hours of work.&lt;/p&gt;


	&lt;p&gt;We also used some powerful Javascript libraries to achieve some impressive visual effects quickly and without too much pain. When planning your app, think about what technologies you&amp;#8217;re using and make sure that there is sufficient library support to get you where you need to be in 48 hours.&lt;/p&gt;


	&lt;h3&gt;Bad Idea: Plans Are For Sissies&lt;/h3&gt;


	&lt;p&gt;This one is somewhat obvious, but it&amp;#8217;s a good idea to have a strong game plan heading into something as time-limited as the Rumble. It was unavoidable in our case as I was on my honeymoon in Paris until (literally) the day before the competition, but planning in advance would have meant that every team member was utilized every moment they were available instead of spending time figuring out who should be doing what.&lt;/p&gt;


	&lt;p&gt;That being said, I think there is also value in not planning &lt;strong&gt;too&lt;/strong&gt; much. During the competition there will be times when you see things that work and you need to let the application grow organically instead of mechanistically sticking to your original gameplan.&lt;/p&gt;


	&lt;h3&gt;Good Idea: Hang Out In &lt;span class="caps"&gt;IRC&lt;/span&gt;&lt;/h3&gt;


	&lt;p&gt;The &lt;code&gt;#railsrumble&lt;/code&gt; IRC channel was a good place to be throughout the competition. You get direct access to a couple hundred other competitors as well as the organizers of the competition. If GitHub goes down, if there&amp;#8217;s confusion about the rules, you&amp;#8217;ll get your answers in a couple minutes.&lt;/p&gt;


	&lt;p&gt;It&amp;#8217;s also just fun to feel the energy of the competition and everything from &amp;#8220;Got it deployed!&amp;#8221; to &amp;#8220;so much left to do and so little time zomg&amp;#8221;. I wasn&amp;#8217;t able to physically be in the same area as any Rumblers, but I still had a great time and lots of comraderie on the &lt;span class="caps"&gt;IRC&lt;/span&gt; channel.&lt;/p&gt;


	&lt;h3&gt;Bad Idea: Last-Minute Anything&lt;/h3&gt;


	&lt;p&gt;You will have things to do until the last minute. &lt;strong&gt;Do not do them.&lt;/strong&gt; You will have features you want to implement in the last 2 hours. &lt;strong&gt;Do not implement them.&lt;/strong&gt; You will want to tweak the style, tweak a view, tweak something that seems important (but isn&amp;#8217;t app-crashing) in the last 20 minutes. &lt;strong&gt;Do not do it.&lt;/strong&gt; Last-minute changes that aren&amp;#8217;t to address specific, serious bugs are a terrible idea when you won&amp;#8217;t have a chance to fix new problems you introduce.&lt;/p&gt;


	&lt;p&gt;Next year I am going to try to force myself to spend the last 2-3 hours of the competition doing nothing but finding showstoppers on the production site and fixing only those things. Our OpenID flow was damaged in the last hour of the competition (for registration, not login) and we didn&amp;#8217;t catch it until after pencils down. Never again!&lt;/p&gt;


	&lt;h3&gt;Best Idea: Compete in the Rumble!&lt;/h3&gt;


	&lt;p&gt;All in all, you can&amp;#8217;t go wrong joining in the Rails Rumble. While your family and non-developer friends probably won&amp;#8217;t quite understand what&amp;#8217;s wrong with you (&amp;#8220;You work 40 hours, over a weekend, and don&amp;#8217;t get paid?&amp;#8221;) you will have a blast and will learn a lot about how to build things inside a pressure cooker. I know that I plan to be back for next year&amp;#8217;s Rumble, and my thanks go out to my team and everyone who made it possible!&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; I forgot one more bad idea because I didn&amp;#8217;t realize it until later&amp;#8230;&lt;strong&gt;Bad Idea: Forget to Add Google Analytics to Your Site&lt;/strong&gt;. You know that you will be curious about your visitors as the judging spins up, but if you forget to add analytics (as I did) you won&amp;#8217;t have much information at your disposal!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/intridea/~4/UDiqqVuTbYE" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.intridea.com/posts/thingivore-rails-rumble-post-mortem</feedburner:origLink></entry>
  <entry xml:base="http://www.intridea.com">
    <author>
      <name>Brent Collier</name>
    </author>
    <id>tag:www.intridea.com,2009-08-14:198</id>
    <published>2009-08-14T10:00:00-04:00</published>
    <updated>2009-08-14T10:00:00-04:00</updated>
    <category term="iphone" />
    <category term="mobile" />
    <link href="http://feedproxy.google.com/~r/intridea/~3/tP8g_m6TE9M/iphone-hack-day-at-viget-labs" rel="alternate" type="text/html" />
    <title>iPhone Hack Day at Viget Labs</title>
    <content type="html">&lt;p&gt;&lt;a href="http://s3.amazonaws.com/brentmc79-prod/files/10/original.jpg?1250189401"&gt;&lt;img style="margin:0px 0px 5px 5px" src="http://s3.amazonaws.com/brentmc79-prod/files/10/medium.jpg?1250189401" alt="photo.jpg" width="300" height="225" align="right" /&gt;&lt;/a&gt;I recently spent a day hanging out with a few of the guys at &lt;a title="Viget Labs homepage" href="http://www.viget.com" target="_blank"&gt;Viget Labs&lt;/a&gt; hacking on the iPhone.&amp;nbsp; &lt;a title="Ben Scofield's professional blog" href="http://benscofield.com/" target="_blank"&gt;Ben Scofield&lt;/a&gt;, the Technology Director at Viget Labs, was leading an iPhone development primer for a few of Viget's finest, and they were nice enough to let a handful of "outsiders" join the fun.&lt;/p&gt;
&lt;p&gt;My iPhone development experience at that point was very minimal.&amp;nbsp; I had done a few online tutorials and walk-throughs, but nowhere near enough to really understand what I was doing.&amp;nbsp; On top of that, my Objective-C knowledge was pretty much non-existant.&amp;nbsp; Fortunately, none of this was a problem.&lt;/p&gt;
&lt;p&gt;We spent the first half of the day going over the basics.&amp;nbsp; Ben walked us through Xcode and Interface Builder, and we talked about basic project layout, the different types of iPhone apps (list, view, and navigation-based, etc).&lt;/p&gt;
&lt;p&gt;We then broke off into small groups, pairs mostly, to do a little hacking.&amp;nbsp; &lt;a title="David's professional blog" href="http://davideisinger.com/"&gt;David Eisinger &lt;/a&gt;and myself put our heads together on something amazing.&amp;nbsp; The Text-EmBIGiner, we called it (or something like that).&amp;nbsp; Picture this, a text field, a button, and a label.&amp;nbsp; You enter your text, hit the buttom, and BAM -- the label is updated with your text.&amp;nbsp; It was amazing.&amp;nbsp; We thought so at least.&amp;nbsp; Many high-fives were had.&lt;/p&gt;
&lt;p&gt;Lunch was provided in the form of &lt;a href="http://www.amantepizza.com/"&gt;Amante Pizza&lt;/a&gt;.&amp;nbsp; Thanks Viget!&lt;/p&gt;
&lt;p&gt;In the afternoon we moved on to talk about ways of making iPhone development less painful.&amp;nbsp; In other words, removing the Objective-C.&amp;nbsp; We briefly talked about &lt;a href="http://rhomobile.com/home"&gt;Rhomobile&lt;/a&gt;, an open source framwork for building cross-platform mobile apps.&lt;/p&gt;
&lt;p&gt;The remainder of the day was spent talking about and playing with two other frameworks, Appcelerator's &lt;a href="http://www.appcelerator.com/products/titanium-mobile/" target="_blank"&gt;Titanium&lt;/a&gt; and the open source &lt;a href="http://phonegap.com" target="_blank"&gt;PhoneGap&lt;/a&gt;.&amp;nbsp; Both frameworks allow you to build your app using primarily HTML and javascript, but they still give you access to the iPhone native controls and features.&amp;nbsp; They were very cool and I could definitely see myself playing with these more in the future.&lt;/p&gt;
&lt;p&gt;Overall it was a really fun day, and I'm looking forward to putting my new knowledge to good use.&lt;/p&gt;
&lt;p&gt;Thanks again Viget!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/intridea/~4/tP8g_m6TE9M" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.intridea.com/posts/iphone-hack-day-at-viget-labs</feedburner:origLink></entry>
  <entry xml:base="http://www.intridea.com">
    <author>
      <name>Brendan Lim</name>
    </author>
    <id>tag:www.intridea.com,2009-08-13:197</id>
    <published>2009-08-13T17:12:00-04:00</published>
    <updated>2009-08-13T17:12:00-04:00</updated>
    <category term="iphonedevcamp" />
    <category term="iphone" />
    <category term="mobile" />
    <link href="http://feedproxy.google.com/~r/intridea/~3/d4yjiCvV9NE/looking-back-at-iphonedevcamp-3" rel="alternate" type="text/html" />
    <title>Looking Back at iPhoneDevCamp 3 at Yahoo!</title>
    <content type="html">&lt;p&gt;
&lt;img style="margin: 0px 0px 5px 15px" src="http://farm3.static.flickr.com/2441/3818224733_2de432c7b5.jpg" align='right' width="250px" height="333px"&gt;
Our Director of Research &amp; Development, Pradeep Elankumaran, and I attended &lt;a href="http://iphonedevcamp.org" target="new"&gt;iPhoneDevCamp 3&lt;/a&gt; during the first week of this month.  For those of you who haven't heard of iPhoneDevCamp, it is supposed to be setup as an "unconference", sort of a "Barcamp" type of an event, featuring content from the attendees and dedicated time for hacking on your own applications.  Last year's iPhoneDevCamp was hosted by Adobe Systems in San Francisco.  This year's iPhoneDevCamp was kindly hosted by the good guys at Yahoo! in Sunnyvale, California.  
&lt;/p&gt;
&lt;p&gt;
Yahoo! has an amazing campus that was more than capable of hosting the large amount of iPhone developers there for the event.  There were also many "satellite" events going on in different cities around the world at the same time.   One really interesting feature that they had at the event was a live stream of presenters of developers hacking away that could be viewed on any iPhone thanks to the new HTTP live streaming available in OS 3.0.
&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;
&lt;a href="http://www.flickr.com/photos/intridea/3819008564/in/set-72157621907538845" target="new"&gt;&lt;img src="http://farm3.static.flickr.com/2457/3819008564_881404f48f_m.jpg"&gt;&lt;/a&gt; &amp;nbsp;

&lt;a href="http://www.flickr.com/photos/intridea/3819033470/in/set-72157621907538845/" target="new"&gt;&lt;img src="http://farm4.static.flickr.com/3469/3819033470_42097a9de8_m.jpg"&gt;&lt;/a&gt; &amp;nbsp;

&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;
The event kicked off on the first day with a mixer, which allowed everybody to walk around and introduce themselves to other developers and vendors that were at the event.    &lt;a href="http://www.kpcb.com/team/index.php?Chi-Hua%20Chien" target="new"&gt;Chi-Hua Chien&lt;/a&gt; gave the keynote and talked about the general growth of mobile and the &lt;a href="http://www.kpcb.com/initiatives/ifund/" target="new"&gt;Kleiner Perkins iFund&lt;/a&gt;.  After his keynote was another chance to meet others, followed by a musical performance by &lt;a href="http://en.wikipedia.org/wiki/BT" target="new"&gt;BT&lt;/a&gt;.  Pradeep and I "accidentally" had a chance to walk on stage and check out BT setting up his equipment.  
&lt;/p&gt;
&lt;p&gt;
&lt;center&gt;

&lt;a href="http://www.flickr.com/photos/intridea/3819022530/in/set-72157621907538845" target="new"&gt;&lt;img src="http://farm4.static.flickr.com/3519/3819022530_0204105f81_m.jpg"&gt;&lt;/a&gt; &amp;nbsp; 
&lt;a href="http://www.flickr.com/photos/intridea/3818215867/in/set-72157621907538845" target="new"&gt;&lt;img src="http://farm3.static.flickr.com/2571/3818215867_606ecfe887_m.jpg"&gt;&lt;/a&gt; &amp;nbsp; 
&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;
The rest of the event on the following two days consisted of teams hacking on different iPhone applications, which could be entered in to win a bunch of prizes for many different categories.  Other keynotes from these days were by &lt;a href="http://www.stone.com/" target="new"&gt;Andrew Stone&lt;/a&gt; of &lt;a href="http://www.stone.com/Twittelator/" target="new"&gt;Twittelator&lt;/a&gt; fame and &lt;a href="http://demiforce.blogspot.com/" target="new"&gt;Steve Demeter&lt;/a&gt;, developer of &lt;a href="http://www.demiforce.com/games.html" target="new"&gt;Trism&lt;/a&gt;. There were also various talks held within different classrooms.  Of those in attendance, the majority were experienced iPhone developers, but many others were not.  People who didn't have any Objective-C experience helped out web interfaces, graphics, etc.  I'm pretty comfortable with Objective-C but Pradeep hasn't had much experience with it at the time.  For our project, which we weren't planning on submitting at the end of the event, Pradeep worked on the Rails back end and I worked on the iPhone interface.  
&lt;/p&gt;

&lt;p&gt;
&lt;center&gt;
&lt;a href="http://www.flickr.com/photos/intridea/3819017882/in/set-72157621907538845" target="new"&gt;&lt;img src="http://farm3.static.flickr.com/2504/3819017882_d64834fd8a_m.jpg"&gt;&lt;/a&gt; &amp;nbsp; 
&lt;a href="http://www.flickr.com/photos/intridea/3819031174/in/set-72157621907538845/" target="new"&gt;&lt;img src="http://farm3.static.flickr.com/2470/3819031174_4bb8d34204_m.jpg"&gt;&lt;/a&gt; &amp;nbsp; 
&lt;/center&gt;
&lt;/p&gt;


&lt;p&gt;
There were some really interesting applications that won awards at the event.  Some of those that stood out to us were AR Kit (Best iPhone Open Source App), Nurse Brain (Highest Potential Startup Idea), and iSign (Best iPhone App for Accessibility).  AR Kit is an  open source augmented reality UI library for displaying location based data in spherical coordinate systems mirroring UI Kit on the phone.  Nurse Brain allows nurses to hand-off important data about patients during shift change.  iSign opens up people accessibility on the iPhone by introducing a gesture based sign language.  There were many other great applications that received awards.  You can see the complete list of the winners &lt;a href="http://www.iphonedevcamp.org/2009/08/02/iphonedevcamp-3-hackathon-winners/" target="new"&gt;here&lt;/a&gt;.
&lt;/p&gt;


&lt;p&gt;
&lt;center&gt;
&lt;img src="http://farm4.static.flickr.com/3287/3779708084_1585b618d8.jpg"&gt;
&lt;/center&gt;
&lt;/p&gt;

&lt;p&gt;
We had a great time at iPhoneDevCamp 3 and hope that we can have the chance to participate again next year.  Thanks again to everyone who organized the great event, BT for performing (and not getting your security to throw us off stage), and Yahoo! for allowing the event to be hosted at a great campus.  Hopefully, we'll soon be able to reveal what we were working on at the event! 
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/intridea/~4/d4yjiCvV9NE" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.intridea.com/posts/looking-back-at-iphonedevcamp-3</feedburner:origLink></entry>
  <entry xml:base="http://www.intridea.com">
    <author>
      <name>Brendan Lim</name>
    </author>
    <id>tag:www.intridea.com,2009-08-03:195</id>
    <published>2009-08-03T18:26:00-04:00</published>
    <updated>2009-08-03T18:26:00-04:00</updated>
    <category term="conference" />
    <category term="rails" />
    <category term="railsunderground" />
    <category term="mobile" />
    <link href="http://feedproxy.google.com/~r/intridea/~3/hc-kyw-njQU/rails-underground-recap" rel="alternate" type="text/html" />
    <title>Rails Underground Recap</title>
    <content type="html">&lt;p&gt;I finally had the time to write up a recap of &lt;a href="http://railsunderground.com"&gt;Rails Underground&lt;/a&gt; in London, even though it&amp;#8217;s a little overdue.  I&amp;#8217;ve really come to enjoy smaller regional conferences.  Since it&amp;#8217;s such a smaller crowd than larger conferences, you get to meet and spend more time with the same people&amp;#8212;getting to know them better and pick each other&amp;#8217;s brain.  Rails Underground was great because of this reason, but not this reason alone.&lt;/p&gt;


	&lt;p style="text-align:center;"&gt;&lt;img src="http://farm3.static.flickr.com/2424/3779576818_3309684df0.jpg" alt="" /&gt;&lt;/p&gt;


	&lt;p&gt;I was attending Rails Underground to give my talk on &lt;a href="http://www.rails-underground.com/2009/06/talk-mobilize-your-rails-application-brendan-g-lim.html"&gt;Mobilizing Your Rails Application&lt;/a&gt;.  The point of my talk was to get developers more focused on the mobile web and other mobile technologies and explain how to use certain plugins and gems to accomplish this.  I believe my talk went well judging from the response afterwards&amp;#8212;and since it was recorded, you&amp;#8217;ll be able to judge it yourself as well.  If you&amp;#8217;re interested, feel free to view the slides &lt;a href="http://www.slideshare.net/brendanlim/mobilizing-your-rails-application"&gt;here&lt;/a&gt;.  I&amp;#8217;ll be adding a link to the video of the talk as soon as it&amp;#8217;s posted.&lt;/p&gt;


	&lt;p style="text-align:center;"&gt;&lt;img src="http://farm4.static.flickr.com/3468/3778775803_950ba6324c.jpg" alt="" /&gt;&lt;/p&gt;


	&lt;p&gt;The conference was spread into two separate tracks for two full days. When I gave my talk, I was up against &lt;a href="http://skillsmatter.com/podcast/ajax-ria/pat-allan-from-the-keyboard-to-the-community"&gt;Pat Allen&amp;#8217;s  talk about the Community&lt;/a&gt;, which was another great talk also being presented at the same time in a different room.  I enjoyed all of the talks that I attended but some of the talks that stood out to me were &lt;a href="http://www.rails-underground.com/2009/06/talk-working-outsidein-with-cucumber-joseph-wilk.html"&gt;James Wilk&amp;#8217;s talk on Cucumber&lt;/a&gt;, &lt;a href="http://skillsmatter.com/podcast/ajax-ria/pat-allan-sphinx-beyond-the-basics"&gt;Pat Allan&amp;#8217;s talk on Thinking Sphinx&lt;/a&gt;, &lt;a href="http://www.rails-underground.com/2009/07/talk-dead-simple-javascript-unit-tests-in-rails-with-blue-ridge-and-screwunit-dr-nic.html"&gt;Dr. Nic&amp;#8217;s talk on Blue Ridge&lt;/a&gt;, and &lt;a href="http://skillsmatter.com/podcast/ajax-ria/jim-weirich-grand-unified-theory-of-software"&gt;Jim Weirich&amp;#8217;s talk on the Grand Unified Theory of Software&lt;/a&gt;.  One talk that was extremely creative and entertaining was &lt;a href="http://www.rails-underground.com/2009/06/talk-an-agile-workflow-with-rails-productive-rails-development-and-client-happiness-paul-campbell.html"&gt;Paul Campbell&amp;#8217;s talk, An Agile Workflow with Rails&lt;/a&gt;, which ended up being a hand-drawn story presentation. There were also keynotes on each day of the event.  The opening keynote was delivered by Fred George and by Yehuda Katz on the last day.&lt;/p&gt;


	&lt;p&gt;There&amp;#8217;s no doubt that the first Rails Underground was a success.  Everybody that I talked to had a great time and learned a great deal of information.  I met some new friends, learned some new things, had a great time and would love to attend again next year.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/intridea/~4/hc-kyw-njQU" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.intridea.com/posts/rails-underground-recap</feedburner:origLink></entry>
  <entry xml:base="http://www.intridea.com">
    <author>
      <name>Intridea</name>
    </author>
    <id>tag:www.intridea.com,2009-07-08:194</id>
    <published>2009-07-08T18:25:00-04:00</published>
    <updated>2009-07-08T18:25:00-04:00</updated>
    <category term="built_for_speed" />
    <category term="performance. amazon" />
    <category term="cloudfront" />
    <category term="s3" />
    <link href="http://feedproxy.google.com/~r/intridea/~3/-S19sBg7O_Q/amazon-cloudfront-preventing-stale-assets" rel="alternate" type="text/html" />
    <title>Built For Speed: Prevent Amazon CloudFront From Serving Stale Assets</title>
    <content type="html">&lt;p&gt;In the &lt;a href="http://intridea.com/2009/7/6/using-amazon-cloudfront-to-serve-assets"&gt;last Built For Speed post&lt;/a&gt;, I demonstrated how you can use the Amazon CloudFront Content Delivery Network (CDN) for images on your site. However, ideally we should be using CloudFront for &lt;em&gt;all&lt;/em&gt; static assets, not just images.&lt;/p&gt;


	&lt;p&gt;Before we jump into that, though, let&amp;#8217;s do a quick review of how CloudFront works. Like all CDNs, CloudFront consists of a number of edge servers all around the world, each of which has a connection back to a central asset server. When CloudFront receives a request for an asset, it calculates which edge server is geographically closest to the request location. For example, a user in England may request the asset &amp;#8216;dog.jpg&amp;#8217;. CloudFront will route that request to the London server, which will check if it has a cached version of &amp;#8216;dog.jpg&amp;#8217;. If it does, the edge server will return that cached version. If not, it will retrieve the image from the central asset, cache it locally and return it to the user. All subsequent requests in England for &amp;#8216;dog.jpg&amp;#8217; will get the cached version on the London edge server. This approach minimizes network latency.&lt;/p&gt;


	&lt;p&gt;There is one big gotcha with this approach: If the &amp;#8216;dog.jpg&amp;#8217; image changes from a poodle to a beagle, but keeps the same name, the edge server will keep serving the poodle image (assuming the expires headers are set far in the future as they should be). The edge server will not pick up the latest asset unless the name of the asset changes.&lt;/p&gt;


	&lt;p&gt;Okay, with that background out of the way, let&amp;#8217;s take a look at how we can get our &lt;span class="caps"&gt;CSS&lt;/span&gt; and JavaScripts served through CloudFront. The approach I&amp;#8217;ve taken is to create an initializer file that sets a &lt;span class="caps"&gt;REVISION&lt;/span&gt; constant. This could easily be created as part of a deployment process, copying the latest Git or Subversion revision into the initializer file, but for now I just created it manually. We&amp;#8217;ll append the &lt;span class="caps"&gt;REVISION&lt;/span&gt; constant to the names of your packaged &lt;span class="caps"&gt;CSS&lt;/span&gt; and JavaScripts, so that on each deploy, the files have a different name, thereby preventing CloudFront from serving stale assets.&lt;/p&gt;


	&lt;p&gt;I have also moved the S3 configuration parsing out of the Post model and into another initializer, which sets the S3_CONFIG hash constant. In addition, I added the bucket name to my amazon_s3.yml config file. (Remember, if you have any questions, you can always refer to the &lt;a href="http://github.com/dramsay/built_for_speed/tree/master"&gt;source code&lt;/a&gt;.)&lt;/p&gt;


&lt;pre name="code" class="ruby"&gt;
# /config/initializers/s3_config.rb
S3_CONFIG = YAML.load_file("#{RAILS_ROOT}/config/amazon_s3.yml")[RAILS_ENV]
&lt;/pre&gt;

	&lt;p&gt;See below for the Rake task I wrote to copy the packaged files to S3. Note that this should be run after you run the &amp;#8216;rake assets:packager:build_all&amp;#8217; task from AssetPackager (see the &lt;a href="http://intridea.com/2009/6/26/using-the-assetpackager-plugin?blog=company"&gt;first Built For Speed post&lt;/a&gt;).&lt;/p&gt;


&lt;pre name="code" class="ruby"&gt;
require 'right_aws'

namespace :s3 do
  namespace :assets do
    desc "Upload static assets to S3" 
    task :upload =&amp;gt; :environment do
      s3 = RightAws::S3.new(
        S3_CONFIG['access_key_id'], 
        S3_CONFIG['secret_access_key']
      )
      bucket = s3.bucket(S3_CONFIG['bucket'], true, 'public-read')

      files = Dir.glob(File.join(RAILS_ROOT, "public/**/*_packaged.{css,js}"))

      files.each do |file|
        filekey = file.gsub(/.*public\//, "").gsub(/_packaged/, "_packaged_#{REVISION}")
        key = bucket.key(filekey)
        begin
          File.open(file) do |f|
            key.data = f
            key.put(nil, 'public-read', {'Expires' =&amp;gt; 1.year.from_now})
          end
        rescue RightAws::AwsError =&amp;gt; e
          puts "Couldn't save #{key}" 
          puts e.message
          puts e.backtrace.join("\n")
        end
      end
    end
  end
end
&lt;/pre&gt;

	&lt;p&gt;Again, ideally this should be part of the deployment process &amp;#8211; first, run the AssetPackager task to create the packaged asssets, then run the S3 upload task to store them on S3. Notice that I&amp;#8217;m appending the &lt;span class="caps"&gt;REVISION&lt;/span&gt; string to the end of file names for each of the packaged &lt;span class="caps"&gt;CSS&lt;/span&gt; and JavaScript files before uploading to S3. Also notice that I&amp;#8217;m setting the Expires header to one year from now.&lt;/p&gt;


	&lt;p&gt;Hmm, we may have a couple problems here. First, by default, Rails expects &lt;span class="caps"&gt;CSS&lt;/span&gt; and JavaScript files to be in their proper places in the /public directory at the root of the application. That&amp;#8217;s easily fixed by adding the following line to the bottom of /config/environments/production.rb:&lt;/p&gt;


&lt;pre name="code" class="ruby"&gt;
ActionController::Base.asset_host = Proc.new { CLOUDFRONT_DISTRIBUTION }
&lt;/pre&gt;

	&lt;p&gt;The second problem is that the helpers provided by the AssetPackager plugin (&amp;#8216;stylesheet_link_merged&amp;#8217; and &amp;#8216;javascript_include_merged&amp;#8217;) don&amp;#8217;t know that you&amp;#8217;ve added a revision number to the end of the filenames. Not to worry &amp;#8211; we just need to update a couple lines in /vendor/plugins/asset_packager/lib/synthesis/asset_package.rb. Update the &amp;#8216;current_file&amp;#8217; method to look like this:&lt;/p&gt;


&lt;pre name="code" class="ruby"&gt;
def current_file
  build unless package_exists?

  path = @target_dir.gsub(/^(.+)$/, '\1/')
  name = "#{path}#{@target}_packaged" 
  name += "_#{REVISION}" if defined? REVISION
end
&lt;/pre&gt;

	&lt;p&gt;Try making those updates, then running &amp;#8216;rake s3:assets:upload &lt;span class="caps"&gt;RAILS&lt;/span&gt;_ENV=production&amp;#8221; (remember we&amp;#8217;re running in production mode for all the Built For Speed examples). After restarting your application, inspect the source and you should see that your stylesheets and scripts are being served by CloudFront, with the revision number at the end of the file names.&lt;/p&gt;


	&lt;p&gt;Now let&amp;#8217;s return to our images. After the last post, we already have them delivered by CloudFront. The problem is, if you decide to update your image, Paperclip will give it the same style names as before (&amp;#8216;original&amp;#8217;, &amp;#8216;large&amp;#8217;, &amp;#8216;medium&amp;#8217;, &amp;#8216;thumb&amp;#8217;). Uh-oh. Because the files have the same names, the CloudFront edge servers won&amp;#8217;t update from the central asset server to use the latest image, and your users will continue to see the stale, old image.&lt;/p&gt;


	&lt;p&gt;Go ahead and give it a try by updating an image for an existing post. Whoops! The old image is still displayed.&lt;/p&gt;


	&lt;p&gt;Here&amp;#8217;s how we solve that problem. First of all, let&amp;#8217;s update the Post model to use the new S3_CONFIG constant. While we&amp;#8217;re at it, let&amp;#8217;s add a timestamp to our image path so that each time you update the image, it will have a different name.&lt;/p&gt;


&lt;pre name="code" class="ruby"&gt;
# in /app/models/post.rb
has_attached_file :image, 
                :styles =&amp;gt; {:large =&amp;gt; "500x500", :medium =&amp;gt; "250x250", :thumb =&amp;gt; "100x100"}, 
                :storage =&amp;gt; 's3', 
                :s3_credentials =&amp;gt; S3_CONFIG, 
                :bucket =&amp;gt; S3_CONFIG['bucket'], 
                :path =&amp;gt; ":class/:id/:style_:timestamp.:extension" 
&lt;/pre&gt; 

	&lt;p&gt;One small issue: For some reason the Paperclip plugin uses a string representation for its &amp;#8216;timestamp&amp;#8217; method, so you end up with values like &amp;#8220;2009-06-26 15:25:44 &lt;span class="caps"&gt;UTC&lt;/span&gt;&amp;#8221;. This isn&amp;#8217;t very practical for timestamping file names, so I&amp;#8217;ve changed it:&lt;/p&gt;


&lt;pre name="code" class="ruby"&gt;
# /vendor/plugins/paperclip/lib/paperclip/interpolations.rb
def timestamp attachment, style
  attachment.instance_read(:updated_at).to_i
end
&lt;/pre&gt;

	&lt;p&gt;With that change, now each time we store an attached image, it will have a timestamp affixed to the end of the filename. Thus, the CloudFront edge server will go back to the central asset server and retrieve the new image rather than serving up the old image. Don&amp;#8217;t worry &amp;#8211; for each subsequent request, you&amp;#8217;ll get the benefit of having the new image on the edge server.&lt;/p&gt;


	&lt;p&gt;Restart your application, and try updating an image again. This time around, you&amp;#8217;ll see the image is updated correctly.&lt;/p&gt;


	&lt;p&gt;That wraps it up for our CloudFront review.  Now go forth and speed up your sites!&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;I realized I promised in my last post to show you how to make YSlow recognize that you were now using a &lt;span class="caps"&gt;CDN&lt;/span&gt;. Here&amp;#8217;s what you do:&lt;/p&gt;


	&lt;ol&gt;
	&lt;li&gt;Go to &amp;#8220;about:config&amp;#8221; in Firefox&lt;/li&gt;
		&lt;li&gt;Right-click on the page, and select &amp;#8220;New&amp;#8221; &amp;gt; &amp;#8220;String&amp;#8221; &lt;/li&gt;
		&lt;li&gt;Enter &amp;#8220;extensions.yslow.cdnHostnames&amp;#8221; as the preference name&lt;/li&gt;
		&lt;li&gt;Enter &amp;#8220;cloudfront.net&amp;#8221; as your &lt;span class="caps"&gt;CDN&lt;/span&gt; host name&lt;/li&gt;
		&lt;li&gt;Restart Firefox and run YSlow on your application again &amp;#8211; you should now see that you get an &amp;#8220;A&amp;#8221; for using a &lt;span class="caps"&gt;CDN&lt;/span&gt;&lt;/li&gt;
	&lt;/ol&gt;


	&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;RESOURCES&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://github.com/dramsay/built_for_speed/tree/master"&gt;Built For Speed source code&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/intridea/~4/-S19sBg7O_Q" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.intridea.com/posts/amazon-cloudfront-preventing-stale-assets</feedburner:origLink></entry>
  <entry xml:base="http://www.intridea.com">
    <author>
      <name>Intridea</name>
    </author>
    <id>tag:www.intridea.com,2009-07-06:193</id>
    <published>2009-07-06T18:00:00-04:00</published>
    <updated>2009-07-06T18:00:00-04:00</updated>
    <category term="performance" />
    <category term="yslow" />
    <category term="built_for_speed" />
    <category term="amazon" />
    <category term="s3" />
    <category term="cloudfront" />
    <link href="http://feedproxy.google.com/~r/intridea/~3/NHXxMUkJ5ts/using-amazon-cloudfront-to-serve-assets" rel="alternate" type="text/html" />
    <title>Built For Speed: Using Amazon CloudFront To Serve Assets</title>
    <content type="html">&lt;p&gt;This is the second in a series of posts on improving your site&amp;#8217;s performance with the help of the YSlow Firefox plugin. In the &lt;a href="http://intridea.com/posts/using-the-assetpackager-plugin"&gt;last Built for Speed post&lt;/a&gt;, we took a look at YSlow&amp;#8217;s most important factor in page speed &amp;#8211; the number of &lt;span class="caps"&gt;HTTP&lt;/span&gt; requests. We demonstrated using the AssetPackager plugin to help reduce both the number of &lt;span class="caps"&gt;HTTP&lt;/span&gt; requests and the size of your &lt;span class="caps"&gt;CSS&lt;/span&gt; and JavaScript files. The &lt;a href="http://github.com/dramsay/built_for_speed/tree/master"&gt;source for the Built for Speed application&lt;/a&gt; is available on Github.&lt;/p&gt;


	&lt;p&gt;This week, we&amp;#8217;ll learn how to use a Content Delivery Network (CDN) to help users see our static content faster. Granted, this may be overkill for a lot of sites, but I think it&amp;#8217;s worth the time to see how it&amp;#8217;s done. There are a lot of CDNs out there, but I&amp;#8217;ve decided to use &lt;a href="http://aws.amazon.com/cloudfront/"&gt;Amazon&amp;#8217;s CloudFront&lt;/a&gt; because it&amp;#8217;s relatively cheap and easy to set up (not to mention it integrates seamlessly with S3). Before you get much further, you&amp;#8217;ll want to set up an account with &lt;a href="http://aws.amazon.com/s3/"&gt;S3&lt;/a&gt; and &lt;a href="http://aws.amazon.com/cloudfront/"&gt;CloudFront&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;First, let&amp;#8217;s install the Paperclip plugin so we can upload an image to go with our post.&lt;/p&gt;


&lt;pre name="code"&gt;
  script/plugin install git://github.com/thoughtbot/paperclip.git
&lt;/pre&gt;

	&lt;p&gt;Next, we need to add the Paperclip fields to the Post model:&lt;/p&gt;


&lt;pre name="code"&gt;
  script/generate migration AddPaperclipColumnsToPost 
&lt;/pre&gt;

&lt;pre name="code" class="ruby"&gt;
  # in the newly-created migration
  def self.up
    add_column(:posts, :image_file_name, :string)
    add_column(:posts, :image_content_type, :string)
    add_column(:posts, :image_file_size, :integer)
    add_column(:posts, :image_updated_at, :datetime)
  end

  def self.down
    remove_column(:posts, :image_file_name)
    remove_column(:posts, :image_content_type)
    remove_column(:posts, :image_file_size)
    remove_column(:posts, :image_updated_at)
  end
&lt;/pre&gt;

	&lt;p&gt;We also need to make the Paperclip declaration in the Post model:&lt;/p&gt;


&lt;pre name="code" class="ruby"&gt;
  class Post &amp;lt; ActiveRecord::Base
    has_attached_file :image, :styles =&amp;gt; {:large =&amp;gt; "500x500", :medium =&amp;gt; "250x250", :thumb =&amp;gt; "100x100"}
  end
&lt;/pre&gt;

	&lt;p&gt;And finally we make the updates to the views. First change the new and edit views, adding the file_field for the attachment and making sure the form is set to accept multipart data (see the &lt;a href="http://github.com/dramsay/built_for_speed/tree/master"&gt;source on Github&lt;/a&gt; if you have questions). Then update your show view to display the image:&lt;/p&gt;


&lt;pre name="code" class="rhtml"&gt;
  &amp;lt;%= image_tag @post.image.url(:large) %&amp;gt;
&lt;/pre&gt; 

	&lt;p&gt;Now let&amp;#8217;s take a look at our application in Firefox. Remember, we&amp;#8217;re running it in production mode to see the benefits of the AssetPackager plugin among other things. Create a new post with the image attachment of your choice.&lt;/p&gt;


	&lt;p&gt;One gotcha &amp;#8211; if you are running your application using Passenger, you may see an error something like this when you try to create a Paperclip attachment:&lt;/p&gt;


&lt;pre name="code"&gt;
  Image /tmp/passenger.621/var/stream.818.0 is not recognized by the 'identify' command.
&lt;/pre&gt;

	&lt;p&gt;In order to avoid this, create a file in /config/initializers to tell Paperclip where to find ImageMagick. I installed ImageMagick using MacPorts, so my file looks like:&lt;/p&gt;


&lt;pre name="code" class="ruby"&gt;
  Paperclip.options[:command_path] = "/opt/local/bin" 
&lt;/pre&gt;

	&lt;p&gt;Okay, now that we have a new post with an image, browse to the post detail page, open up the YSlow interface, click &amp;#8220;Run Test&amp;#8221; and take a look at the second grade, &amp;#8220;Use a Content Delivery Network (CDN)&amp;#8221;.&lt;/p&gt;


&lt;div class="thumbnail"&gt;&lt;a href="http://skitch.com/dramsay/bssxs/posts-show"&gt;&lt;img src="http://img.skitch.com/20090706-tyck79park6nb4yg3gpw3q2ddq.preview.jpg" alt="Posts: show" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family: Lucida Grande, Trebuchet, sans-serif, Helvetica, Arial; font-size: 10px; color: #808080"&gt;Uploaded with &lt;a href="http://plasq.com/"&gt;plasq&lt;/a&gt;&amp;#8217;s &lt;a href="http://skitch.com"&gt;Skitch&lt;/a&gt;!&lt;/span&gt;&lt;/div&gt;

	&lt;p&gt;Ugh, we got a &amp;#8220;D&amp;#8221;. Okay, let&amp;#8217;s see how we can implement Amazon CloudFront to make that grade an &amp;#8220;A&amp;#8221;.&lt;/p&gt;


	&lt;p&gt;Let&amp;#8217;s start by telling Paperclip to use S3 for our image storage. Go ahead and create a configuration file called amazon_s3.yml. Obviously, you&amp;#8217;ll need to replace the values here with your own keys:&lt;/p&gt;


&lt;pre name="code"&gt;
  # config/amazon_s3.yml
  development:
    access_key_id: 123...
    secret_access_key: 123...
  test:
    access_key_id: abc...
    secret_access_key: abc...
  production:
    access_key_id: 456...
    secret_access_key: 456...
&lt;/pre&gt;

	&lt;p&gt;Paperclip depends on the &amp;#8216;right_aws&amp;#8217; gem for its S3 storage, so make sure you add that to your config.gem list in /config/environment.rb and install it with:&lt;/p&gt;


&lt;pre name="code"&gt;
  rake gems:install
&lt;/pre&gt;

	&lt;p&gt;Next, update the Post model so it will use the new S3 configuration:&lt;/p&gt;


&lt;pre name="code" class="ruby"&gt;
  class Post &amp;lt; ActiveRecord::Base
    has_attached_file :image, 
                    :styles =&amp;gt; {:large =&amp;gt; "500x500", :medium =&amp;gt; "250x250", :thumb =&amp;gt; "100x100"}, 
                    :storage =&amp;gt; 's3', 
                    :s3_credentials =&amp;gt; YAML.load_file("#{RAILS_ROOT}/config/amazon_s3.yml")[RAILS_ENV], 
                    :bucket =&amp;gt; "built-for-speed", 
                    :path =&amp;gt; ":class/:id/:style.:extension" 
  end
&lt;/pre&gt;

	&lt;p&gt;Now restart your application and create a new post with an image. When you get to the post detail page, check out the source and you should see that your image is being served from your S3 bucket. That&amp;#8217;s great, but what we really want to do is serve the image from the CloudFront &lt;span class="caps"&gt;CDN&lt;/span&gt;. The easiest way to do this is to install the &lt;a href="http://www.s3fox.net/"&gt;S3 Firefox Organizer plugin&lt;/a&gt;). Once you enter your credentials, you should see your newly-created &amp;#8216;built-for-speed&amp;#8217; bucket. Right-click on the bucket name and click &amp;#8220;Manage Distributions&amp;#8221;, then optionally add a comment and click &amp;#8220;Create Distribution&amp;#8221; (we&amp;#8217;ll skip the &lt;span class="caps"&gt;CNAME&lt;/span&gt; option for now).&lt;/p&gt;


&lt;div class="thumbnail"&gt;&lt;a href="http://skitch.com/dramsay/bsaqy/s3-firefox-organizer"&gt;&lt;img src="http://img.skitch.com/20090706-b9fwuqr7cs6q4xxt55g7k6puyt.preview.jpg" alt="S3 Firefox Organizer" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family: Lucida Grande, Trebuchet, sans-serif, Helvetica, Arial; font-size: 10px; color: #808080"&gt;Uploaded with &lt;a href="http://plasq.com/"&gt;plasq&lt;/a&gt;&amp;#8217;s &lt;a href="http://skitch.com"&gt;Skitch&lt;/a&gt;!&lt;/span&gt;&lt;/div&gt;

	&lt;p&gt;This will generate a new resource &lt;span class="caps"&gt;URL&lt;/span&gt; for you to use in your application so you can take advantage of CloudFront. Now we have to go back and tell our application to use this resource &lt;span class="caps"&gt;URL&lt;/span&gt;:&lt;/p&gt;


&lt;pre name="code" class="ruby"&gt;
  # /config/initializers/cloudfront.rb
  # 
  # Note that your CloudFront resource URL will be different
  CLOUDFRONT_DISTRIBUTION = "http://d2qd39qqjqb9uw.cloudfront.net" 
&lt;/pre&gt;

&lt;pre name="code" class="ruby"&gt;
  # in /app/models/post.rb
  def cloudfront_url( variant = nil )
    image.url(variant).gsub( "http://s3.amazonaws.com/built-for-speed", CLOUDFRONT_DISTRIBUTION )
  end
&lt;/pre&gt;

&lt;pre name="code" class="rhtml"&gt;
  # in /app/views/posts/show.html.erb
  &amp;lt;%= image_tag @post.cloudfront_url(:large) %&amp;gt;
&lt;/pre&gt;

	&lt;p&gt;Restart the application and go back to the post detail page. Inspect the source and you&amp;#8217;ll see that your image is now being served from CloudFront.&lt;/p&gt;


	&lt;p&gt;Okay, I think that&amp;#8217;s enough for today. In the next post, I&amp;#8217;ll show you how to avoid CloudFront serving stale assets and how to make YSlow recognize that you are now using a &lt;span class="caps"&gt;CDN&lt;/span&gt;. Please leave any questions or comments below.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;CREDITS&lt;/span&gt;/RESOURCES:&lt;/strong&gt;&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://sdruby.com/podcast/63"&gt;Nick Zadrozny&amp;#8217;s YSlow presentation from SD Ruby&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://developer.amazonwebservices.com/connect/entry.jspa?externalID=2331"&gt;Managing Assets on Amazon CloudFront&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/intridea/~4/NHXxMUkJ5ts" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.intridea.com/posts/using-amazon-cloudfront-to-serve-assets</feedburner:origLink></entry>
  <entry xml:base="http://www.intridea.com">
    <author>
      <name>Dave Potsiadlo</name>
    </author>
    <id>tag:www.intridea.com,2009-07-01:192</id>
    <published>2009-07-01T09:20:00-04:00</published>
    <updated>2009-07-01T09:20:00-04:00</updated>
    <category term="sketchnotes" />
    <category term="user experience" />
    <link href="http://feedproxy.google.com/~r/intridea/~3/OSgUdpmhqfM/sketchnotes-uie-roadshow" rel="alternate" type="text/html" />
    <title>Sketchnotes from the UIE Roadshow</title>
    <content type="html">&lt;p&gt;I recently had the pleasure of attending the &lt;a href="http://www.uie.com/events/roadshow/"&gt;User Interface Engineering Roadshow&lt;/a&gt; in Washington, DC.  The day was chock-full of insight and wisdom from usability guru Jared Spool, founder of &lt;a href="http://www.uie.com/"&gt;UIE.com&lt;/a&gt;.  In taking notes during the workshop, I decided to take my first official shot at sketchnoting.  The results are as follows:&lt;/p&gt;&lt;p style="text-align: center;"&gt;&lt;a style="border: none;" href="http://www.skipvision.com/blog/wp-content/uploads/2009/07/20090630-uie-sketchnotes.gif"&gt;&lt;img class="size-full wp-image-97" style="border: none; padding: 0;" title="Sketchnotes from the UIE Roadshow" src="http://www.skipvision.com/blog/wp-content/uploads/2009/07/20090630-uie-sketchnotes-500.gif" alt="Sketchnotes from the UIE Roadshow" width="500" height="1075" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Overall, I found this experience to be wholly satisfying.  Putting key ideas into sketches required an interesting use of my attention span: in addition to listening intently to the ideas being communicated, I was simultaneously forced to employ creative sketching solutions that would properly embody the most important parts of the talks.&lt;/p&gt;
&lt;p&gt;Upon returning home from the Roadshow, I was quite surprised to find these sketches spanning 5 full pages of my notebook.  Upon scanning the notes and adding a bit of chronological organization, I&amp;#8217;m left with a sort of visual map of the workshop (as I experienced it).  I hope these notes might be of interest to others who attended.&lt;/p&gt;
&lt;p&gt;As for adventures in sketchnoting?  I look forward to continued exploration when the proper circumstances arise in the future.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/intridea/~4/OSgUdpmhqfM" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.intridea.com/posts/sketchnotes-uie-roadshow</feedburner:origLink></entry>
  <entry xml:base="http://www.intridea.com">
    <author>
      <name>Intridea</name>
    </author>
    <id>tag:www.intridea.com,2009-06-26:191</id>
    <published>2009-06-26T14:42:00-04:00</published>
    <updated>2009-06-26T14:42:00-04:00</updated>
    <category term="performance" />
    <category term="assetpackager" />
    <category term="yslow" />
    <category term="built_for_speed" />
    <link href="http://feedproxy.google.com/~r/intridea/~3/3eClZCy_VVY/using-the-assetpackager-plugin" rel="alternate" type="text/html" />
    <title>Built For Speed: Using the AssetPackager Plugin</title>
    <content type="html">&lt;p&gt;Inspired by the recent launch of &lt;a href="http://code.google.com/speed"&gt;code.google.com/speed&lt;/a&gt;, I decided to sit down and see how I could apply their guidelines. This is the first in a series of posts on improving front-end performance for your Rails applications.&lt;/p&gt;


	&lt;p&gt;First of all, we need to create our sample application. Recently, I&amp;#8217;ve been using &lt;a href="http://jackdempsey.github.com/beet"&gt;Beet&lt;/a&gt;, a gem for generating Ruby projects, but you can create your local version however works for you.  Using Beet, the following command tells the Rails generator to use MySQL, remove unused files (public/index.html, etc.) and initialize a Git repository:&lt;/p&gt;


&lt;pre name="code"&gt;
  beet -g built_for_speed -r="rails/db/mysql, rails/clean_files, rails/git" 
&lt;/pre&gt;

	&lt;p&gt;Next, let&amp;#8217;s create a Post resource:&lt;/p&gt;


&lt;pre name="code"&gt;
  script/generate scaffold Post title:string body:text
&lt;/pre&gt;

	&lt;p&gt;Make sure your databases are created, and run the migrations. Note that for the purposes of this tutorial, I&amp;#8217;m running the application in production mode (to better see the speed benefits), using Passenger on my MacBook Pro. By the way, I highly recommend the &lt;a href="http://www.fngtps.com/passenger-preference-pane"&gt;Fingertips Passenger preference pane&lt;/a&gt; for managing your sites locally.&lt;/p&gt;


&lt;pre name="code"&gt;
  RAILS_ENV=production rake db:migrate
&lt;/pre&gt;

	&lt;p&gt;Now let&amp;#8217;s add the Blueprint &lt;span class="caps"&gt;CSS&lt;/span&gt; framework. Download the latest version from &lt;a href="http://blueprintcss.org"&gt;blueprintcss.org&lt;/a&gt; and unpack it somewhere. Blueprint provides you with compressed versions of the &lt;span class="caps"&gt;CSS&lt;/span&gt; files, but humor me and add the uncompressed versions. From the unpacked directory, copy all the &lt;span class="caps"&gt;CSS&lt;/span&gt; files from /blueprint/src/ into /public/stylesheets/blueprint/ in your application.&lt;/p&gt;


	&lt;p&gt;Before we start up the application, let&amp;#8217;s add the &lt;span class="caps"&gt;CSS&lt;/span&gt; files as well as the default JavaScript files to the head of our posts layout (/app/views/layout/posts.html.erb). The head of your layout file should look something like this (note that I added my own base.css file):&lt;/p&gt;


&lt;pre class="rhtml" name="code"&gt;
  &amp;lt;head&amp;gt;
    ...
    &amp;lt;%= stylesheet_link_tag 'blueprint/reset', :media =&amp;gt; 'projection, screen' %&amp;gt;
    &amp;lt;%= stylesheet_link_tag 'blueprint/typography', :media =&amp;gt; 'projection, screen' %&amp;gt;
    &amp;lt;%= stylesheet_link_tag 'blueprint/forms', :media =&amp;gt; 'projection, screen' %&amp;gt;
    &amp;lt;%= stylesheet_link_tag 'blueprint/grid', :media =&amp;gt; 'projection, screen' %&amp;gt;
    &amp;lt;%= stylesheet_link_tag 'blueprint/print', :media =&amp;gt; 'print' %&amp;gt;
    &amp;lt;!--[if lt IE 8]&amp;gt;
        &amp;lt;%= stylesheet_link_tag 'blueprint/ie', :media =&amp;gt; "screen, projection" %&amp;gt;
    &amp;lt;![endif]--&amp;gt;
    &amp;lt;%= stylesheet_link_tag 'base', :media =&amp;gt; 'projection, screen' %&amp;gt;
    &amp;lt;%= javascript_include_tag :defaults %&amp;gt;
  &amp;lt;/head&amp;gt;
&lt;/pre&gt;

	&lt;p&gt;Okay, now let&amp;#8217;s fire up the application. I&amp;#8217;ll be using Firefox so we can profile the application using &lt;a href="http://developer.yahoo.com/yslow/"&gt;YSlow&lt;/a&gt;. Go ahead and create your first post. Once you&amp;#8217;re looking at the &amp;#8216;show&amp;#8217; page, let&amp;#8217;s open up Firebug and click on the &amp;#8220;YSlow&amp;#8221; tab. On the YSlow screen, click the &amp;#8220;Run Test&amp;#8221; button to get your page grade.&lt;/p&gt;


&lt;div class="thumbnail"&gt;&lt;a href="http://skitch.com/dramsay/biwa7/posts-show"&gt;&lt;img src="http://img.skitch.com/20090626-tmxf8kxp2m5a2nxbxxhwqeutu7.preview.jpg" alt="Posts: show" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family: Lucida Grande, Trebuchet, sans-serif, Helvetica, Arial; font-size: 10px; color: #808080"&gt;Uploaded with &lt;a href="http://plasq.com/"&gt;plasq&lt;/a&gt;&amp;#8217;s &lt;a href="http://skitch.com"&gt;Skitch&lt;/a&gt;!&lt;/span&gt;&lt;/div&gt;

	&lt;p&gt;Bummer, we got an overall D &amp;#8211; not so good. Let&amp;#8217;s take a look at what&amp;#8217;s going on. YSlow grades are listed in order of importance, so let&amp;#8217;s check out the first section: &amp;#8220;Make fewer &lt;span class="caps"&gt;HTTP&lt;/span&gt; requests&amp;#8221;. Looks like we got a C in that area. What can we do to improve our grade? YSlow gives us some tips: &amp;#8220;combine multiple scripts into one script, combine multiple &lt;span class="caps"&gt;CSS&lt;/span&gt; files into one style sheet&amp;#8221;. Before we get back to the application, take a look at the &amp;#8220;Components&amp;#8221; tab in the YSlow dialog.&lt;/p&gt;


&lt;div class="thumbnail"&gt;&lt;a href="http://skitch.com/dramsay/biw5p/posts-show"&gt;&lt;img src="http://img.skitch.com/20090626-kq6mqmw9g9g2kkxeh8j5u28924.preview.jpg" alt="Posts: show" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family: Lucida Grande, Trebuchet, sans-serif, Helvetica, Arial; font-size: 10px; color: #808080"&gt;Uploaded with &lt;a href="http://plasq.com/"&gt;plasq&lt;/a&gt;&amp;#8217;s &lt;a href="http://skitch.com"&gt;Skitch&lt;/a&gt;!&lt;/span&gt;&lt;/div&gt;

	&lt;p&gt;Hmm, five JavaScript files for a total of 234.3K and six &lt;span class="caps"&gt;CSS&lt;/span&gt; files for a total of 18K. We definitely need to work on that.&lt;/p&gt;


	&lt;p&gt;In order to compress JavaScript and &lt;span class="caps"&gt;CSS&lt;/span&gt; files in my applications, I use Scott Becker&amp;#8217;s &lt;a href="http://github.com/sbecker/asset_packager/tree/master"&gt;AssetPackager plugin&lt;/a&gt;. Go ahead and install it:&lt;/p&gt;


&lt;pre name="code"&gt;
  script/plugin install git://github.com/sbecker/asset_packager.git
&lt;/pre&gt;

	&lt;p&gt;The first step after installation is to create the configuration file for AssetPackager:&lt;/p&gt;


&lt;pre name="code"&gt;
  $ rake asset:packager:create_yml
&lt;/pre&gt;

	&lt;p&gt;You should see a message to reorder the files under &amp;#8216;base&amp;#8217;, so let&amp;#8217;s go ahead and do that. Open up the newly-created /config/asset_packages.yml file. You&amp;#8217;ll notice that there are two top-level entries &amp;#8211; one for &amp;#8216;javascripts&amp;#8217; and one for &amp;#8216;stylesheets&amp;#8217;. AssetPackager should have correctly generated the required files for the &amp;#8216;javascripts&amp;#8217; section, but we&amp;#8217;ll need to add the Blueprint files. Your completed asset_packages.yml file should look something like this (again, I added a base.css file):&lt;/p&gt;


&lt;pre class="yaml" name="code"&gt;
    --- 
    javascripts: 
    - base: 
      - prototype
      - effects
      - dragdrop
      - controls
      - application
    stylesheets: 
    - base:
      - blueprint/reset
      - blueprint/typography
      - blueprint/forms
      - blueprint/grid 
      - base
    - print:
      - blueprint/print
    - ie:
      - blueprint/ie
&lt;/pre&gt;

	&lt;p&gt;Now that the config file is set up, you can go ahead and generate the combined, minified JavaScript and &lt;span class="caps"&gt;CSS&lt;/span&gt; files:&lt;/p&gt;


&lt;pre name="code"&gt;
  rake asset:packager:build_all
&lt;/pre&gt;

	&lt;p&gt;This command will output a &amp;#8220;[name]_packaged&amp;#8221; file for each entry under both &amp;#8216;javascripts&amp;#8217; and &amp;#8216;stylesheets&amp;#8217;. Now we have to tell our application to use those compressed files. Go back to your posts.html.erb layout and change the head to look like this:&lt;/p&gt;


&lt;pre class="rhtml" name="code"&gt;
  &amp;lt;head&amp;gt;
    ...
    &amp;lt;%= stylesheet_link_merged :base, :media =&amp;gt; "screen, projection" %&amp;gt;
    &amp;lt;%= stylesheet_link_merged :print, :media =&amp;gt; "print" %&amp;gt;
    &amp;lt;!--[if lt IE 8]&amp;gt;
    &amp;lt;%= stylesheet_link_merged :ie, :media =&amp;gt; "screen, projection" %&amp;gt;
    &amp;lt;![endif]--&amp;gt;
    &amp;lt;%= javascript_include_merged :defaults %&amp;gt;
  &amp;lt;/head&amp;gt;
&lt;/pre&gt;

	&lt;p&gt;Okay, now it&amp;#8217;s time to see the fruits of our labors. Restart the application in the Passenger preference pane, and reload the post page in Firefox. Now let&amp;#8217;s run YSlow again. This time, you should see output like this:&lt;/p&gt;


&lt;div class="thumbnail"&gt;&lt;a href="http://skitch.com/dramsay/biw5w/posts-show"&gt;&lt;img src="http://img.skitch.com/20090626-n1uc7n7u51srj4m61rr48gbeen.preview.jpg" alt="Posts: show" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family: Lucida Grande, Trebuchet, sans-serif, Helvetica, Arial; font-size: 10px; color: #808080"&gt;Uploaded with &lt;a href="http://plasq.com/"&gt;plasq&lt;/a&gt;&amp;#8217;s &lt;a href="http://skitch.com"&gt;Skitch&lt;/a&gt;!&lt;/span&gt;&lt;/div&gt;

	&lt;p&gt;Alright! We&amp;#8217;ve improved our grade up to an overall B, with an A for &amp;#8220;Make fewer &lt;span class="caps"&gt;HTTP&lt;/span&gt; requests&amp;#8221;. Let&amp;#8217;s take a look at the &amp;#8216;Components&amp;#8217; tab.&lt;/p&gt;


&lt;div class="thumbnail"&gt;&lt;a href="http://skitch.com/dramsay/biw5d/posts-show"&gt;&lt;img src="http://img.skitch.com/20090626-bwa4a17p4mtsxkkc8t1i58us5d.preview.jpg" alt="Posts: show" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family: Lucida Grande, Trebuchet, sans-serif, Helvetica, Arial; font-size: 10px; color: #808080"&gt;Uploaded with &lt;a href="http://plasq.com/"&gt;plasq&lt;/a&gt;&amp;#8217;s &lt;a href="http://skitch.com"&gt;Skitch&lt;/a&gt;!&lt;/span&gt;&lt;/div&gt;

	&lt;p&gt;Thanks to AssetPackager, we&amp;#8217;re down to one JavaScript file for a total of 171.7K and two &lt;span class="caps"&gt;CSS&lt;/span&gt; files for a total of 12.6K. Now there&amp;#8217;s eight fewer components, and we&amp;#8217;re saving 68K of bandwidth on each request. Nice work!&lt;/p&gt;


	&lt;p&gt;The source code for this sample application can be found at: &lt;a href="http://github.com/dramsay/built_for_speed"&gt;github.com/dramsay/built_for_speed&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;Check back for more performance tips in the future.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/intridea/~4/3eClZCy_VVY" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.intridea.com/posts/using-the-assetpackager-plugin</feedburner:origLink></entry>
  <entry xml:base="http://www.intridea.com">
    <author>
      <name>Michael Bleigh</name>
    </author>
    <id>tag:www.intridea.com,2009-06-19:190</id>
    <published>2009-06-19T21:11:00-04:00</published>
    <updated>2009-06-19T21:11:00-04:00</updated>
    <category term="jquery" />
    <category term="quick tip" />
    <category term="array" />
    <category term="convenience" />
    <link href="http://feedproxy.google.com/~r/intridea/~3/m-KID82SXFI/quick-tip-railsy-array-checks-in-jquery" rel="alternate" type="text/html" />
    <title>Quick Tip: Railsy Array Checks in jQuery</title>
    <content type="html">&lt;p&gt;I love the &lt;code&gt;any?&lt;/code&gt; and &lt;code&gt;empty?&lt;/code&gt; convenience methods that Rails and Ruby provide, they make conditional statements much easier to read. I also really dislike the default method of checking this behavior in jQuery:&lt;/p&gt;


&lt;pre name='code' class='js'&gt;if ($('some.element').length &amp;gt; 0) {
  // ...do something
}&lt;/pre&gt;

	&lt;p&gt;Well, luckily jQuery is ridiculously easy to extend, so why not just mix that functionality in with a couple of quick shot plugin methods? Just add this javascript sometime after you include jQuery:&lt;/p&gt;


&lt;pre name='code' class='js'&gt;jQuery.fn.any = function() {
  return (this.length &amp;gt; 0);
}

jQuery.fn.none = function() {
  return (this.length == 0);
}&lt;/pre&gt;

	&lt;p&gt;That&amp;#8217;s all you have to do! Now we can make the same call as before, but it looks a little cleaner:&lt;/p&gt;


&lt;pre name='code' class='js'&gt;if ($('some.element').any()) {
  // do something more readably...
}&lt;/pre&gt;

	&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;UPDATE&lt;/span&gt;:&lt;/strong&gt; Apologies, I added in the &lt;code&gt;empty&lt;/code&gt; bit as a last-second update to the post and forgot to check and realize that &lt;code&gt;empty()&lt;/code&gt; is part of jQuery core. Updated the name to &lt;code&gt;none&lt;/code&gt; instead.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/intridea/~4/m-KID82SXFI" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.intridea.com/posts/quick-tip-railsy-array-checks-in-jquery</feedburner:origLink></entry>
  <entry xml:base="http://www.intridea.com">
    <author>
      <name>Adam Bair</name>
    </author>
    <id>tag:www.intridea.com,2009-06-12:189</id>
    <published>2009-06-12T13:01:00-04:00</published>
    <updated>2009-06-12T13:01:00-04:00</updated>
    <category term="unconference" />
    <category term="hack" />
    <category term="hacking" />
    <category term="hackon" />
    <category term="craftsman" />
    <link href="http://feedproxy.google.com/~r/intridea/~3/vZI5tBMAfeg/hackon" rel="alternate" type="text/html" />
    <title>Intridea's Hackon in Portland, Maine</title>
    <content type="html">&lt;p&gt;I’m pleased to announce &lt;a href="http://www.intridea.com/hackon"&gt;Intridea’s Hackon&lt;/a&gt;, a 3-day co-working and unconference event we’ve organized at the Portland Harbor Hotel in Portland, Maine June 18-20th.&lt;/p&gt;


	&lt;p&gt;Thursday and Friday (17/18th) will be for informal hacking, coworking, and discussion and as we attempt to backfill interesting talks for Saturday (20th).&lt;/p&gt;


	&lt;p&gt;The &lt;a href="http://www.intridea.com/hackon"&gt;Hackon&lt;/a&gt; is intended to bring local software craftsman together to work on projects, exchange ideas, hack on open source, or just get some work done. There will be wifi, projection, food, and valet parking at the hotel.&lt;/p&gt;


	&lt;p&gt;And because we love developers and the community so much, we are hosting this event for &lt;span class="caps"&gt;FREE&lt;/span&gt;! Yes. Free. If you want to attend we only ask that you &lt;span class="caps"&gt;RSVP&lt;/span&gt; ahead of time so we can ensure that enough food, space, and power available.&lt;/p&gt;


	&lt;p&gt;Thank you to &lt;a href="http://meruby.org"&gt;&lt;span class="caps"&gt;MERUG&lt;/span&gt;&lt;/a&gt;, &lt;a href="http://nhruby.org"&gt;&lt;span class="caps"&gt;NHRUG&lt;/span&gt;&lt;/a&gt;, and &lt;a href="http://www.progmatica.com"&gt;#Progmatica&lt;/a&gt; for their support and their assistance in spreading the word!&lt;/p&gt;


	&lt;p&gt;Please head over to &lt;a href="http://www.intridea.com/hackon"&gt;intridea.com/hackon&lt;/a&gt; for details, rsvp, and talk submission.&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://www.intridea.com/hackon"&gt;&lt;img src="http://img.skitch.com/20090612-fqcjw5uxj3n7tmqg9jr6q5e4e8.gif" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/intridea/~4/vZI5tBMAfeg" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.intridea.com/posts/hackon</feedburner:origLink></entry>
</feed>
