<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>Dave Dash</title>
 <link href="http://davedash.com/tag/yahoo!/atom.xml" rel="self"/>
 <link href="http://davedash.com/tag/yahoo!"/>
 <updated>2012-01-17T21:54:19-08:00</updated>
 <id>http://davedash.com/</id>
 <author>
   <name>Dave Dash</name>
   <email>dd+atom1@davedash.com</email>
 </author>

 
 <entry>
   <title>On leaving Delicious</title>
   <link href="http://davedash.com/2009/05/21/on-leaving-delicious/"/>
   <updated>2009-05-21T00:00:00-07:00</updated>
   <id>http://davedash.com/2009/05/21/on-leaving-delicious</id>
   <content type="html">&lt;p&gt;In short I am quitting my awesome job at Yahoo! working on &lt;a href=&quot;http://delicious.com/&quot;&gt;Delicious&lt;/a&gt; and will be starting somewhere else next month.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://delicious.com/&quot;&gt;Delicious&lt;/a&gt; has been one of my favorite web &quot;properties&quot; for a number of years and has influenced my work long before I started here.  I've really respected my fellow engineers, managers and product team despite all the transitions we've had to bear.  I am really amazed by how much everyone in our current team has changed over the year and a half.&lt;/p&gt;

&lt;p&gt;Delicious has had it's ups and downs, both as a team, as part of Yahoo! and even for me personally.  Lucky for me, I stayed motivated the whole way through and I am glad to be leaving the party while its still fun.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Optimizing via YSlow</title>
   <link href="http://davedash.com/2009/03/22/optimizing-via-yslow/"/>
   <updated>2009-03-22T00:00:00-07:00</updated>
   <id>http://davedash.com/2009/03/22/optimizing-via-yslow</id>
   <content type="html">&lt;p&gt;I'm not a performance person per se.  I am a heuristics type of guy.  Meaning you tell me a bunch of things to look out for, I get an understanding for those things, and if I agree, I'll fix them.  I work off lists :)&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://developer.yahoo.com/yslow/&quot;&gt;YSlow&lt;/a&gt; is therefore a boon to me.  If you aren't familiar with it, it is a plugin for Firefox (with a dependency on Firebug) that will grade the performance of a given site based on a set of rules determined by &lt;a href=&quot;http://developer.yahoo.com/&quot;&gt;YDN&lt;/a&gt;.  This is my list, and YDN went into great detail to explain each of these items is important.&lt;/p&gt;

&lt;p&gt;The following is my journey through optimization.  I went from a D- to a C in a single day.  While that might not seem like much, I could have nabbed an A if I used a CDN, like &lt;a href=&quot;http://aws.amazon.com/cloudfront/&quot;&gt;CloudFront&lt;/a&gt;, or even a &lt;a href=&quot;http://spindrop.us/2009/03/08/appengine-is-not-a-free-cdn/&quot;&gt;fake CDN&lt;/a&gt; and dropped Google AdSense and Analytics.  Those tools are helpful for me, and worth keeping around, so I opted to take the grade penalty.&lt;/p&gt;

&lt;!--more--&gt;


&lt;h3&gt;Begin: D - 61&lt;/h3&gt;

&lt;p&gt;I began with a D.  It's actually not that bad.  In most dimensions I was getting an A.  Namely because I use a web framework (Django) that is optimized for being cached and served well.&lt;/p&gt;

&lt;h3&gt;YUI Combo-loading: Sneaking up to D - 62&lt;/h3&gt;

&lt;p&gt;My first goal was to reduce the HTTP requests.&lt;/p&gt;

&lt;p&gt;I use the &lt;a href=&quot;http://developer.yahoo.com/yui/&quot;&gt;YUI&lt;/a&gt; CSS and javascript framework as the foundation for my CSS and javascript.  One major benefit is that they offer to host this for you on a true &lt;acronym title=&quot;Content Delivery Network&quot;&gt;CDN&lt;/acronym&gt;.  The javascript framework is very thorough and can do quite a lot.  Because it's so robust, it is split into several files.  Originally I had been doing this:&lt;/p&gt;

&lt;div&gt;&lt;textarea name=&quot;code&quot; class=&quot;html&quot;&gt;

&lt;script type=&quot;text/javascript&quot; src=&quot;http://yui.yahooapis.com/2.6.0/build/yahoo-dom-event/yahoo-dom-event.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;http://yui.yahooapis.com/2.6.0/build/connection/connection-min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;http://yui.yahooapis.com/2.6.0/build/datasource/datasource-min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;http://yui.yahooapis.com/2.6.0/build/autocomplete/autocomplete-min.js&quot;&gt;&lt;/script&gt;

&lt;/textarea&gt;&lt;/div&gt;


&lt;p&gt;That was 4 separate calls from the web browser to this server.  While they are all fast requests, it'd be better to make a single request that catches all of this.&lt;/p&gt;

&lt;p&gt;Luckily, YUI has &quot;combo-handling&quot;.  I was able to turn those four requests into the following:&lt;/p&gt;

&lt;div&gt;&lt;textarea name=&quot;code&quot; class=&quot;html&quot;&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;http://yui.yahooapis.com/combo?2.7.0/build/yahoo-dom-event/yahoo-dom-event.js&amp;2.7.0/build/connection/connection-min.js&amp;2.7.0/build/datasource/datasource-min.js&amp;2.7.0/build/autocomplete/autocomplete-min.js&quot;&gt;&lt;/script&gt;
&lt;/textarea&gt;&lt;/div&gt;


&lt;p&gt;A very quick fix, that brought my overall grade up by a single point.&lt;/p&gt;

&lt;h3&gt;Concatenation and Minification: Instant C- - 72&lt;/h3&gt;

&lt;p&gt;I still had a large number of HTTP requests.  Luckily &lt;a href=&quot;http://developer.yahoo.com/yui/&quot;&gt;YUI&lt;/a&gt; has the &lt;a href=&quot;http://developer.yahoo.com/yui/compressor/&quot;&gt;YUI Compressor&lt;/a&gt;.  It compresses javascript and CSS and even gives you tips on writing better code (or more compressible code).&lt;/p&gt;

&lt;p&gt;This used to be scary and not something I'd want to deal with, but if I can run it from the commandline, then I can add it to &lt;a href=&quot;http://spindrop.us/2009/03/02/a-stitch-in-fabric-saves-time/&quot;&gt;my deployment script&lt;/a&gt;.  Now on each deployment my CSS and javascript are concatenated and compressed and uploaded to my server.  When my app is in production mode, it seeks out minified code, versus more verbose human-readable code.&lt;/p&gt;

&lt;p&gt;The javascript compression was great.  The output was at least compressed in half.  This skyrocketed the score to 72.  Less HTTP requests and Javascript minification were the individual rules in YSlow that were boosted.&lt;/p&gt;

&lt;h3&gt;Google: They want you to fail&lt;/h3&gt;

&lt;p&gt;This is of course tongue-in-cheek.  Google has some wonderful tools like AdSense and Analytics that do hinder the score and ever so slightly the speed of your site.&lt;/p&gt;

&lt;p&gt;As far as javascript is concerned, I am linking to:
* YUI
* My own JS
* Google Analytics
* Google Adsense&lt;/p&gt;

&lt;p&gt;Google Adsense is by far the worst offender.  You think you're calling just one solitary call to Google to fetch an ad, but it's actually 4 calls.  I'm sure this could be engineered better.  The good news is it's usually not too slow.&lt;/p&gt;

&lt;p&gt;There's an option to self-serve &lt;code&gt;ga.js&lt;/code&gt; the Analytics code.  While this might result in a higher score, there are a few issues.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The process is more error prone, there's a chance that the file you download from Google might get corrupted and your unit tests might miss it.&lt;/li&gt;
&lt;li&gt;You are serving from your own servers - which could either be expensive or slower.&lt;/li&gt;
&lt;li&gt;Many sites include a call for &lt;code&gt;ga.js&lt;/code&gt; and therefore there's a high likelihood that it's already browser-cached.&lt;/li&gt;
&lt;li&gt;The code could get out of date.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;For this reason, it's better to lose about 5 points for not serving it.  This score is large because it effects a lot of YSlow's rulesets.  If you'd still like to self-serve here's &lt;a href=&quot;http://www.askapache.com/javascript/google-analytics-speed-tips.html&quot;&gt;some discussion on that&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This will likely give you an &quot;F&quot; on the Expires Header ruleset as well.&lt;/p&gt;

&lt;h3&gt;Content Delivery Network (CDN)&lt;/h3&gt;

&lt;p&gt;A lot of people freak that CDN is on YSlow and feel like not all sites need/require a CDN.  They are right that the don't need a CDN, but in my opinion they don't necessarily need to get an &quot;A&quot; either.  All this is an approximation of doing the best you can do to make your frontend code as fast and efficient as possible.&lt;/p&gt;

&lt;p&gt;With that said, CDN's are becoming more and more in reach.  Amazon Cloud Files which &lt;a href=&quot;http://spindrop.us/2009/03/08/appengine-is-not-a-free-cdn/&quot;&gt;I mentioned&lt;/a&gt; is a pay as you go system, which is quite affordable (I estimated &amp;lt; $1/month for my needs).&lt;/p&gt;

&lt;p&gt;I configured YSlow to list some of the standard Google and Yahoo API hosts as CDNs.  This didn't affect my score, and I didn't want to integrate S3/Cloudfiles at this stage, so I took the &quot;F&quot;.&lt;/p&gt;

&lt;h3&gt;Gzip files (still at 72)&lt;/h3&gt;

&lt;p&gt;Adding Gzip to the Nginx configuration was easy, however my grade still stayed at 72, but it did up my score for that specific rule.  Gzip compression is supported in most modern browsers and is usually a config change away.&lt;/p&gt;

&lt;p&gt;Again, note that &lt;code&gt;ga.js&lt;/code&gt; is not served compressed.&lt;/p&gt;

&lt;h3&gt;Upgrading from &lt;code&gt;urchin.js&lt;/code&gt; (up to 73)&lt;/h3&gt;

&lt;p&gt;In the process of tweaking my Gzip configuration, I noticed that I was still using the legacy &lt;code&gt;urchin.js&lt;/code&gt; instead of the more modern &lt;code&gt;ga.js&lt;/code&gt;.  Simply changing this boosted me to 73.&lt;/p&gt;

&lt;h3&gt;Move Javascript to the bottom (still at 73)&lt;/h3&gt;

&lt;p&gt;Moving the javascript to the bottom is another trick.  This at least loads most of the HTML before the Javascript loads (and in many cases, waits).&lt;/p&gt;

&lt;p&gt;Some refactoring of Django templates makes this a breeze.&lt;/p&gt;

&lt;h3&gt;Conclusions&lt;/h3&gt;

&lt;p&gt;I was able to raise the score from a low D to a mid C, at some point I could make the score a high C, but it was inevitably not worth it.&lt;/p&gt;

&lt;p&gt;From my perspective, Google could do a few things to help webmasters who use their widgets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a decent expires header to &lt;code&gt;ga.js&lt;/code&gt; - this file is safe to cache for some degree of time.  Being at the latest and greatest &lt;code&gt;ga.js&lt;/code&gt; is nice, but not necessary.&lt;/li&gt;
&lt;li&gt;Serve files Gzipped&lt;/li&gt;
&lt;li&gt;Use a single host for serving public APIs.  Yahoo can improve on this as well.  They can potentially do combo-hosting a la Yahoo Developer Network&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Ultimately YSlow is a good guideline for speeding up your page render times.  It's not perfect, nor exact.  There's no realistic way to determine a users experience with page load times.  Slow network connectivity and bad browsers can make all your attempts in vain.  However, YSlow is an easy to follow set of heuristics which every site owner should attempt to implement as well as possible.&lt;/p&gt;

&lt;p&gt;YSlow's &lt;a href=&quot;http://www.slideshare.net/stoyan/yslow-20-presentation&quot;&gt;future incarnations&lt;/a&gt; will yield some more flexibility.  Even in its default state it should yield better scores for people who are doing the right thing.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>You can't go home again: A year in the Bay Area</title>
   <link href="http://davedash.com/2008/11/07/you-cant-go-home-again-a-year-in-the-bay-area/"/>
   <updated>2008-11-07T00:00:00-08:00</updated>
   <id>http://davedash.com/2008/11/07/you-cant-go-home-again-a-year-in-the-bay-area</id>
   <content type="html">&lt;p&gt;Yesterday as I left work it dawned on me that I had been in the San Francisco
Bay Area for a year.  It is one of the most drastic changes in my life since
going to college.&lt;/p&gt;

&lt;p&gt;I remember announcing to my family that Katie and I were moving to the Bay Area
as I had accepted a job at Yahoo! working on one of my favorite web sites,
&lt;a href=&quot;http://delicious.com/&quot;&gt;Delicious&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The decision to move, the actual move itself, the settling in period, exploring
the area, meeting friends new and old... it was all an adventure.  The question
everyone asks is how's california... it's awesome... even after a year.&lt;/p&gt;

&lt;!--more--&gt;


&lt;ul&gt;
&lt;li&gt;&lt;a class=&quot;right&quot; href=&quot;http://www.flickr.com/photos/44124375866@N01/62923133&quot;
title=&quot;View 'Back of our house' on Flickr.com&quot;&gt;&lt;img
src=&quot;http://farm1.static.flickr.com/33/62923133_f93daffaea_m.jpg&quot;
alt=&quot;Back of our house&quot; border=&quot;0&quot; width=&quot;180&quot; height=&quot;240&quot; /&gt;&lt;/a&gt;
We've successfully unanchored from our house and life in Minneapolis&lt;/li&gt;
&lt;li&gt;&lt;img class=&quot;left&quot;
src=&quot;http://farm3.static.flickr.com/2135/2051049464_e8d10fb317_m.jpg&quot; /&gt; Took the kitties on a plane ride and had them live in 4 different places in 3 days.&lt;/li&gt;
&lt;li&gt;Took up a position working on &lt;a href=&quot;http://delicious.com/&quot;&gt;Delicious&lt;/a&gt; and helped launch the new version of the site.&lt;/li&gt;
&lt;li&gt;Had our car shipped across country&lt;/li&gt;
&lt;li&gt;Had movers move all our stuff for us&lt;/li&gt;
&lt;li&gt;Moved on up to a more spacious living arrangement that has rent that costs more than our mortgage.&lt;/li&gt;
&lt;li&gt;We're a short distance  a Costco, Target, restaurants and the middle of a small town&lt;/li&gt;
&lt;li&gt;Reconnected with friends from High School, College, Minneapolis and met new friends...&lt;/li&gt;
&lt;li&gt;3 of our friends (2 are a couple) live a block away.&lt;/li&gt;
&lt;li&gt;We run into people we know&lt;/li&gt;
&lt;li&gt;We got sucked into Veronica Mars, Buffy and Angel&lt;/li&gt;
&lt;li&gt;Bike to work regularly... otherwise shuttle... rarely drive.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/dave_dash/status/764147810&quot;&gt;Learned python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;img class=&quot;left&quot; src=&quot;http://farm4.static.flickr.com/3012/2641297326_8a3a0c0e17_m.jpg&quot;/&gt; Saw some pretty trees at Sequoia National Park&lt;/li&gt;
&lt;li&gt;Went to Apple Hill&lt;/li&gt;
&lt;li&gt;&lt;img src=&quot;http://farm4.static.flickr.com/3183/2963859390_64e3c61be0_m.jpg&quot;
class=&quot;right&quot; /&gt; Saw Mos Def&lt;/li&gt;
&lt;li&gt;We can't go home again...&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;We've been to Minnesota three times, and each time it feels less and less like home.  The home I grew up in is alien, the house we own isn't our home.  Stores open, stores close.  Minneapolis has changed and we've changed.  It still holds a special place in our heart.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.youtube.com/watch?v=0TjPpCU05o4&quot;&gt;enjoy...&lt;/a&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;
&lt;img src=&quot;http://farm3.static.flickr.com/2397/2439642635_cedf059812.jpg&quot; /&gt;
&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Full Time Web Developers (willing to relocate to the Bay Area)</title>
   <link href="http://davedash.com/2008/01/22/full-time-web-developers-willing-to-relocate-to-the-bay-area/"/>
   <updated>2008-01-22T00:00:00-08:00</updated>
   <id>http://davedash.com/2008/01/22/full-time-web-developers-willing-to-relocate-to-the-bay-area</id>
   <content type="html">&lt;p&gt;[tags]jobs, yahoo, symfony[/tags]&lt;/p&gt;

&lt;p&gt;If anybody (preferably with symfony experience) would like to work with me full time, please send me an email or leave a comment here.&lt;/p&gt;

&lt;p&gt;I'm preferably looking for someone with symfony experience that's great with CSS and JS, especially with YUI.&lt;/p&gt;

&lt;p&gt;-d&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Textmate Snippets for YUI em calculations</title>
   <link href="http://davedash.com/2007/05/08/textmate-snippets-for-yui-em-calculations/"/>
   <updated>2007-05-08T00:00:00-07:00</updated>
   <id>http://davedash.com/2007/05/08/textmate-snippets-for-yui-em-calculations</id>
   <content type="html">&lt;p&gt;[tags]yui, yahoo, css, snippet, textmate, ems, px[/tags]&lt;/p&gt;

&lt;p&gt;If you use &lt;a href=&quot;http://developer.yahoo.com/yui/grids/&quot;&gt;YUI grid layouts&lt;/a&gt; you'll notice that &lt;code&gt;ems&lt;/code&gt; are the preferred units and for good reason.  But ems don't make sense to people like us who want to be super precise down to the pixel... pixels make sense.&lt;/p&gt;

&lt;p&gt;So type in a number select it and run this &lt;code&gt;ruby&lt;/code&gt; script as a TextMate command (that outputs as a snippet):&lt;/p&gt;

&lt;div&gt;&lt;textarea name=&quot;code&quot; class=&quot;ruby&quot; cols=&quot;100&quot; rows=&quot;15&quot;&gt;
#!/usr/bin/env ruby
#
# This script will do the necessary YUI calculations from px to ems
#
# The result is inserted as a snippet, so it's
# possible to tab through the place holders.

# validate input
input    = ENV['TM_SELECTED_TEXT'].to_i;
width    = input.to_f/13
ie_width = width * 0.9759

print &quot;${1:width}:&quot;+width.to_s+&quot;em;*$1:&quot;+ie_width.to_s+&quot;em;$0&quot;
&lt;/textarea&gt;&lt;/div&gt;


&lt;p&gt;You'll have the proper tab stops to change the newly calculated &lt;code&gt;ems&lt;/code&gt; from &lt;code&gt;width&lt;/code&gt; to &lt;code&gt;margin-left&lt;/code&gt; or &lt;code&gt;margin-right&lt;/code&gt; or whatever it is you desire.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>TextMate + YUI = YUI snippets!</title>
   <link href="http://davedash.com/2007/04/30/textmate-yui-yui-snippets/"/>
   <updated>2007-04-30T00:00:00-07:00</updated>
   <id>http://davedash.com/2007/04/30/textmate-yui-yui-snippets</id>
   <content type="html">&lt;p&gt;I do a lot of &lt;a href=&quot;http://developer.yahoo.com/yui/grids/&quot;&gt;YUI grid layouts&lt;/a&gt; and I love the nestable grids:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;yui-g$1&quot;&amp;gt; 
    &amp;lt;div class=&quot;yui-u first&quot;&amp;gt;
        $2
    &amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;yui-u&quot;&amp;gt;
        $3
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There's a tab stop after &lt;code&gt;yui-g&lt;/code&gt; in case you want to use one of the variants (&lt;code&gt;yui-gb&lt;/code&gt;, &lt;code&gt;yui-gc&lt;/code&gt;, etc).&lt;/p&gt;

&lt;p&gt;I'm working on a site that uses two equal width columns... a lot... so this comes in quite handy.  So long tables.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Going international... kinda</title>
   <link href="http://davedash.com/2006/07/06/going-international-kinda/"/>
   <updated>2006-07-06T00:00:00-07:00</updated>
   <id>http://davedash.com/2006/07/06/going-international-kinda</id>
   <content type="html">&lt;p&gt;Some of the first non-Minnesotan restaurants to show up were &lt;a href=&quot;http://reviewsby.us/restaurant/flying-dog&quot;&gt;Flying Dog&lt;/a&gt;, &lt;a href=&quot;http://reviewsby.us/restaurant/bangalore&quot;&gt;Bangalore&lt;/a&gt; and &lt;a href=&quot;http://reviewsby.us/restaurant/konstam&quot;&gt;Konstam&lt;/a&gt;... all of them outside the US.  Wasn't expecting that... but then again, I wasn't really surprised.&lt;/p&gt;

&lt;p&gt;I finally updated our location tables to account for different countries.  Currently it'll only plot what it can Geocode, and relies exclusively on Yahoo! for GeoCoding.&lt;/p&gt;

&lt;p&gt;I've only tested this with a Canadian restaurant.  Hopefully it'll work elsewhere soon.  If anybody plans on adding any non-US, non-Canadian restaurants, let me know if you can figure out how to GeoCode things properly.&lt;/p&gt;

&lt;p&gt;Also, I'm pleased as punch that the map on the homepage shows three states as having recent restaurants.  Rock on!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>More maps, better presentation and prices</title>
   <link href="http://davedash.com/2006/05/05/more_maps_better_presentation_and_prices/"/>
   <updated>2006-05-05T00:00:00-07:00</updated>
   <id>http://davedash.com/2006/05/05/more_maps_better_presentation_and_prices</id>
   <content type="html">&lt;p&gt;I added a lot more features to &lt;a href=&quot;http://reviewsby.us&quot;&gt;the reviewsby.us site&lt;/a&gt;.  One thing I was &lt;a href=&quot;http://reviewsby.us/feedback&quot;&gt;ask&lt;/a&gt;ed about was adding a price field.  I added that in, it could use some work, but it is a start.  I also cleaned up some of the location formatting (see &lt;a href=&quot;http://reviewsby.us/restaurant/tony-romas/location/mall-of-america&quot;&gt;Tony Roma's at the MOA&lt;/a&gt;) so the phone numbers are legible.&lt;/p&gt;

&lt;p&gt;The real exciting thing is maps.  Applying the same principles from the &lt;a href=&quot;http://spindrop.us/2006/04/26/easy_yahoo_maps_and_georss_with_symfony&quot;&gt;Yahoo! Map tutorial&lt;/a&gt;, I added maps to all the tag pages.  Want to know &lt;a href=&quot;http://reviewsby.us/tag/fried&quot;&gt;where to find fried food&lt;/a&gt;?  Just look at the map.  I'm taking a few shortcuts now.  For example most of our restaurants are located in Minneapolis, therefore the maps seem to center in on the Twin Cities area.  This of course may get messy over time when more restaurants get added outside the Minneapolis area.  By then, I'll have some personalization setup to narrow down on restaurants based on where the visitor is located.&lt;/p&gt;

&lt;p&gt;I wrote a few tutorials that we should see later this month based on what I did.  Fairly simple stuff, but still useful in my opinion.&lt;/p&gt;

&lt;p&gt;Enjoy the site, and &lt;a href=&quot;http://reviewsby.us/feedback&quot;&gt;let me know what you want to see&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Easy Yahoo! Maps and  GeoRSS with symfony</title>
   <link href="http://davedash.com/2006/04/26/easy_yahoo_maps_and_georss_with_symfony/"/>
   <updated>2006-04-26T00:00:00-07:00</updated>
   <id>http://davedash.com/2006/04/26/easy_yahoo_maps_and_georss_with_symfony</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://developer.yahoo.com/maps/georss/index.html&quot;&gt;GeoRSS&lt;/a&gt; is an extension of RSS that incorporates geographic data (i.e. latitude/longitude coordinates).  This is useful for plotting any data that might need to be placed on a map.&lt;/p&gt;

&lt;p&gt;While building out the &lt;a href=&quot;http://reviewsby.us/&quot;&gt;reviewsby.us&lt;/a&gt; map, I decided to use the &lt;a href=&quot;http://developer.yahoo.com/maps/index.html&quot;&gt;Yahoo! Maps API&lt;/a&gt; versus the &lt;a href=&quot;http://www.google.com/apis/maps/&quot;&gt;Google Maps API&lt;/a&gt; because I wanted to gain some familiarity with another API.&lt;/p&gt;

&lt;p&gt;It was worth trying &lt;a href=&quot;http://developer.yahoo.com/maps/index.html&quot;&gt;Yahoo!'s API&lt;/a&gt;.  First of all, &lt;a href=&quot;http://reviewsby.us/&quot;&gt;reviewsby.us&lt;/a&gt; has addresses for restaurants and Yahoo! provides a simple &lt;a href=&quot;http://developer.yahoo.com/maps/rest/V1/geocode.html&quot;&gt;Geocoding REST&lt;/a&gt; service.  This made it easy for me to convert street addresses to latitude and longitude pairs (even though this wasn't required as we'll soon see).&lt;sup id=&quot;fnr1&quot;&gt;&lt;a href=&quot;#fn1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;  The real selling point of &lt;a href=&quot;http://developer.yahoo.com/maps/index.html&quot;&gt;Yahoo!&lt;/a&gt; was the &lt;a href=&quot;http://developer.yahoo.com/maps/georss/index.html&quot;&gt;GeoRSS&lt;/a&gt; functionality.  I can extend an RSS feed (which &lt;a href=&quot;http://www.symfony-project.com/&quot;&gt;symfony&lt;/a&gt; generates quite easily) to add latitude or longitude points (or even the street address), direct my &lt;a href=&quot;http://developer.yahoo.com/maps/index.html&quot;&gt;Yahoo! map&lt;/a&gt; to the feed and voila, all the locations in that feed are now on the map, and when I click on them, the RSS item is displayed.  That cut down on a lot of development time.&lt;/p&gt;

&lt;!--break--&gt;


&lt;!--more--&gt;


&lt;h3&gt;&lt;a href=&quot;http://developer.yahoo.com/maps/georss/index.html&quot;&gt;Yahoo's GeoRSS&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;The GeoRSS format that Yahoo uses is fairly simple to grasp if you know what an RSS feed looks like.  Here's a typical RSS feed:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&amp;gt;
&amp;lt;rss version=&quot;2.0&quot;&amp;gt;
    &amp;lt;channel&amp;gt;
        &amp;lt;title&amp;gt;Latest restaurants&amp;lt;/title&amp;gt;
        &amp;lt;link&amp;gt;http://reviewsby.us/&amp;lt;/link&amp;gt;
        &amp;lt;description&amp;gt;A list of the latest restaurants posted to my reviewsby.us&amp;lt;/description&amp;gt;
        &amp;lt;language&amp;gt;en&amp;lt;/language&amp;gt;
        &amp;lt;item&amp;gt;
            &amp;lt;title&amp;gt;Bubba Gump Shrimp Co. Restaurant and Market&amp;lt;/title&amp;gt;
            &amp;lt;description&amp;gt;A *Forest Gump* themed restaurant.  Featuring a large selection of seafood items.&amp;lt;/description&amp;gt;
            &amp;lt;link&amp;gt;http://reviewsby.us/restaurant/bubba-gump-shrimp-co-restaurant-and-market&amp;lt;/link&amp;gt;
            &amp;lt;guid&amp;gt;25&amp;lt;/guid&amp;gt;
            &amp;lt;pubDate&amp;gt;Sun, 23 Apr 2006 08:04:00 -0700&amp;lt;/pubDate&amp;gt;
        &amp;lt;/item&amp;gt;
        &amp;lt;item&amp;gt;
            &amp;lt;title&amp;gt;Famous Dave's Barbeque&amp;lt;/title&amp;gt;
            &amp;lt;link&amp;gt;http://reviewsby.us/restaurant/famous-daves-barbeque&amp;lt;/link&amp;gt;
            &amp;lt;guid&amp;gt;24&amp;lt;/guid&amp;gt;
            &amp;lt;pubDate&amp;gt;Wed, 19 Apr 2006 19:58:08 -0700&amp;lt;/pubDate&amp;gt;
        &amp;lt;/item&amp;gt;
    &amp;lt;/channel&amp;gt;
&amp;lt;/rss&amp;gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;item /&amp;gt;&lt;/code&gt; in this example is a restaurant.  To turn this into a GeoRSS feed, we only need to change a few things:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&amp;gt;
&amp;lt;rss version=&quot;2.0&quot; xmlns:geo=&quot;http://www.w3.org/2003/01/geo/wgs84_pos#&quot;&amp;gt;
    &amp;lt;channel&amp;gt;
        &amp;lt;title&amp;gt;Latest restaurants' locations&amp;lt;/title&amp;gt;
        &amp;lt;link&amp;gt;http://reviewsby.us/&amp;lt;/link&amp;gt;
        &amp;lt;description&amp;gt;A geocoded list of the latest restaurants' locations posted to my reviewsby.us&amp;lt;/description&amp;gt;
        &amp;lt;language&amp;gt;en&amp;lt;/language&amp;gt;
        &amp;lt;item&amp;gt;
            &amp;lt;title&amp;gt;Bubba Gump Shrimp Co. Restaurant and Market (Mall of America (Bloomington, MN))&amp;lt;/title&amp;gt;
            &amp;lt;link&amp;gt;http://reviewsby.us/restaurant/bubba-gump-shrimp-co-restaurant-and-market/location/mall-of-america&amp;lt;/link&amp;gt;
            &amp;lt;guid&amp;gt;18&amp;lt;/guid&amp;gt;
            &amp;lt;pubDate&amp;gt;Sun, 23 Apr 2006 08:08:19 -0700&amp;lt;/pubDate&amp;gt;
            &amp;lt;geo:lat&amp;gt;44.85380173&amp;lt;/geo:lat&amp;gt;
            &amp;lt;geo:long&amp;gt;-93.24040222&amp;lt;/geo:long&amp;gt;
        &amp;lt;/item&amp;gt;
    &amp;lt;/channel&amp;gt;
&amp;lt;/rss&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We just added &lt;code&gt;xmlns:geo=&quot;http://www.w3.org/2003/01/geo/wgs84_pos#&quot;&lt;/code&gt; as an attribute to the &lt;code&gt;&amp;lt;rss/&amp;gt;&lt;/code&gt; tag and added &lt;code&gt;&amp;lt;geo:lat /&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;geo:long /&amp;gt;&lt;/code&gt; tags to any given item.  If you'd rather use address, city, state and zip fields instead of latitude and longitude coordinates, &lt;a href=&quot;http://developer.yahoo.com/maps/georss/index.html&quot;&gt;the Yahoo! Georss page&lt;/a&gt; will tell you how.&lt;/p&gt;

&lt;h3&gt;&lt;a href=&quot;http://www.symfony-project.com/&quot;&gt;symfony&lt;/a&gt; and Geodata&lt;/h3&gt;

&lt;p&gt;I knew full well that &lt;a href=&quot;http://developer.yahoo.com/maps/index.html&quot;&gt;Yahoo! Maps&lt;/a&gt; did not require me to have everything in latitude longitude coordinates, but I felt that from an efficiency standpoint, it made more sense for me to convert them once using a &lt;a href=&quot;http://developer.yahoo.com/maps/rest/V1/geocode.html&quot;&gt;geocoder&lt;/a&gt; and then Yahoo! wouldn't have to translate them later.  Also, I'm trying to think ahead when more than just Minneapolis restaurants become a part of the &lt;a href=&quot;http://reviewsby.us/&quot;&gt;reviewsby.us&lt;/a&gt; site, I now have an easy way of determining distance between a user's home and a given restaurant.  Also, if Yahoo! Maps doesn't work out, I can use these coordinates in other mapping systems.&lt;/p&gt;

&lt;h4&gt;Extending the model&lt;/h4&gt;

&lt;p&gt;Models in &lt;a href=&quot;http://www.symfony-project.com/&quot;&gt;symfony&lt;/a&gt; lend themselves to being easily extended.  So we can easily take a model for a location:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;table name=&quot;location&quot; phpName=&quot;Location&quot;&amp;gt;
    &amp;lt;column name=&quot;id&quot; type=&quot;integer&quot; primaryKey=&quot;true&quot; autoIncrement=&quot;true&quot;/&amp;gt;
    &amp;lt;column name=&quot;restaurant_id&quot; type=&quot;integer&quot; /&amp;gt;
    &amp;lt;foreign-key foreignTable=&quot;restaurant&quot;&amp;gt;
        &amp;lt;reference local=&quot;restaurant_id&quot; foreign=&quot;id&quot;/&amp;gt;
    &amp;lt;/foreign-key&amp;gt;
    &amp;lt;column name=&quot;stripped_title&quot; type=&quot;varchar&quot; size=&quot;255&quot; /&amp;gt;
    &amp;lt;column name=&quot;name&quot; type=&quot;varchar&quot; size=&quot;255&quot; /&amp;gt;
    &amp;lt;column name=&quot;address&quot; type=&quot;varchar&quot; size=&quot;255&quot; /&amp;gt;
    &amp;lt;column name=&quot;city&quot; type=&quot;varchar&quot; size=&quot;128&quot; /&amp;gt;
    &amp;lt;column name=&quot;state&quot; type=&quot;varchar&quot; size=&quot;16&quot; /&amp;gt;
    &amp;lt;column name=&quot;zip&quot; type=&quot;varchar&quot; size=&quot;9&quot; /&amp;gt;
    &amp;lt;column name=&quot;phone&quot; type=&quot;varchar&quot; size=&quot;16&quot; /&amp;gt;
    &amp;lt;column name=&quot;approved&quot; type=&quot;boolean&quot; /&amp;gt;
    &amp;lt;column name=&quot;updated_at&quot; type=&quot;TIMESTAMP&quot; /&amp;gt;
    &amp;lt;column name=&quot;created_at&quot; type=&quot;TIMESTAMP&quot; /&amp;gt;
&amp;lt;/table&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and simply add two columns inside the &lt;code&gt;&amp;lt;table/&amp;gt;&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;column name=&quot;latitude&quot; type=&quot;float&quot; size=&quot;10&quot; scale=&quot;8&quot;/&amp;gt;
&amp;lt;column name=&quot;longitude&quot; type=&quot;float&quot; size=&quot;10&quot; scale=&quot;8&quot;/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Easy!  However, we don't want to have to set the latitude and longitude by hand each time we update a &lt;code&gt;Location&lt;/code&gt;.  So first we write a function that takes an address and converts it to latitude/longitude.  I placed mine in a &lt;code&gt;myTools.class.php&lt;/code&gt; in my &lt;code&gt;lib&lt;/code&gt; folder:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class myTools
{
    public static function getLatLng($address, $city = null, $state = null, $zip = null)
    {
        $url = sfConfig::get('app_yahoo_geocode');
        $query['appid'] = sfConfig::get('app_yahoo_app_id');
        $query['street'] = $address;
        $query['city'] = $city;
        $query['state'] = $state;
        $query['zip'] = $zip;
        $query['output'] = 'php'; 
        $url .= '?' . http_build_query($query); 
        $response = @file_get_contents($url);
        if ($response) {
            $response = unserialize($response);
            return $response['ResultSet']['Result'];
        }
        return null;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Defined in my &lt;code&gt;app.yml&lt;/code&gt; is &lt;code&gt;app_yahoo_geocode&lt;/code&gt; and my &lt;code&gt;app_yahoo_app_id&lt;/code&gt;.  &lt;code&gt;myTools::getLatLng()&lt;/code&gt; queries the &lt;a href=&quot;http://developer.yahoo.com/maps/rest/V1/geocode.html&quot;&gt;Yahoo! REST&lt;/a&gt; service and returns the coordinates that Yahoo! delivers.  Note that the generated query string includes &lt;code&gt;output=php&lt;/code&gt;.  Yahoo! supports serializing output as PHP instead of XML.  This can save a bundle of time over decoding XML.&lt;/p&gt;

&lt;p&gt;So now let's look at our &lt;code&gt;Location.php&lt;/code&gt; and override its inherited save function:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public function save($con = null)
{
    // save latitude and longitude
    $locdata = myTools::getLatLng($this-&amp;gt;getAddress(), $this-&amp;gt;getCity(), $this-&amp;gt;getState(), $this-&amp;gt;getZip());
    if ($locdata) 
    {
        $this-&amp;gt;setLatitude($locdata['Latitude']);
        $this-&amp;gt;setLongitude($locdata['Longitude']);
    }
    parent::save($con);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you stop here, you'll at least now know how to add latitude and longitude coordinates to an object automagically.&lt;/p&gt;

&lt;h4&gt;Producing a GeoRSS feed&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;http://www.symfony-project.com/&quot;&gt;symfony&lt;/a&gt; very easily will allow you to &lt;a href=&quot;http://www.symfony-project.com/content/book/page/syndication.html&quot;&gt;generate an RSS feed&lt;/a&gt;.  How do we create a &lt;a href=&quot;http://developer.yahoo.com/maps/georss/index.html&quot;&gt;GeoRSS&lt;/a&gt; feed?  Just extend the &lt;code&gt;sfFeed&lt;/code&gt; class.  Rather than instantiating a feed like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$feed = sfFeed::newInstance('rss201rev2');
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We do this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$feed = sfFeed::newInstance('geoRSS');  
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And then create an &lt;a href=&quot;http://spindrop.us/files/symfony/sfGeoRssFeed.class.txt&quot;&gt;sfGeoRssFeed.class.php&lt;/a&gt; and we're done.  We've created a GeoRSS feed fairly easily.  Comb through &lt;a href=&quot;http://spindrop.us/files/symfony/sfGeoRssFeed.class.txt&quot;&gt;sfGeoRssFeed.class.php&lt;/a&gt; and compare it to the &lt;a href=&quot;http://www.symfony-project.com/trac/browser/trunk/lib/symfony/addon/sfFeed/sfRss201rev2Feed.class.php?rev=403&quot;&gt;sfRss201rev2Feed.class.php&lt;/a&gt;, you'll notice it's not that different and that it's fairly easy to extend the sfFeed plugin for &lt;a href=&quot;http://www.symfony-project.com/&quot;&gt;symfony&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Adding your feed to a Yahoo! Map.&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://developer.yahoo.com/maps/ajax/index.html#ex6&quot;&gt;Adding a GeoRSS feed to Yahoo! maps&lt;/a&gt; is simple.  Before I embedded the RSS feed into my Yahoo! Map I was prepared to write an algorithm to cluster only on the points in my RSS feed, lucky for me (and you), &lt;a href=&quot;http://developer.yahoo.com/maps/index.html&quot;&gt;Yahoo! Maps&lt;/a&gt; does this automatically.  One pitfall you might reach during development is that Yahoo! Maps must be able to reach your GeoRSS feed.  My development machine is my personal laptop, so this didn't work so well until I uploaded to a publically accessible staging server.  &lt;a href=&quot;http://reviewsby.us/&quot;&gt;The maps&lt;/a&gt; worked like a charm as you can see.&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://developer.yahoo.com/maps/index.html&quot;&gt;Yahoo! Maps&lt;/a&gt; are very powerful, and &lt;a href=&quot;http://www.symfony-project.com/&quot;&gt;symfony&lt;/a&gt; is up to the task.  I hope you found this tutorial useful.  If you have any trouble, let me know.  I hope your &lt;a href=&quot;http://reviewsby.us/&quot;&gt;next meal&lt;/a&gt; is a good one.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot;&gt;
    &lt;ol&gt;
        &lt;li id=&quot;fn1&quot;&gt;
            &lt;p&gt;
                Using Yahoo! Maps wasn't a requisite of using the Yahoo! Geocoder.  
                The datasets that were returned could have been used to populate a Google Map just as easily.
                &lt;a href=&quot;#fnr1&quot;  class=&quot;footnoteBackLink&quot;  title=&quot;Jump back to footnote 1 in the text.&quot;&gt;&amp;#8617;&lt;/a&gt;
            &lt;/p&gt;
        &lt;/li&gt;
    &lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 

</feed>

