<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" 
      xmlns:thr="http://purl.org/syndication/thread/1.0">
  <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html" />
  <link rel="self" type="application/atom+xml" href="http://www.insideria.com/atom.xml" />
  <id>tag:www.insideria.com,2009://34/tag:www.insideria.com,2009://34.34951-</id>
  <updated>2009-11-20T15:04:27Z</updated>
  <title>Comments for Developing Mashup Air Apps: Consuming Flickr Web Services (http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html)</title>
  <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.21-en</generator>
  <entry>
    <id>tag:www.insideria.com,2009://34.34951</id>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blogs.oreilly.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=34/entry_id=34951" title="Developing Mashup Air Apps: Consuming Flickr Web Services" />
    <published>2009-03-10T13:48:31Z</published>
    <updated>2009-03-10T13:48:31Z</updated>
    <title>Developing Mashup Air Apps: Consuming Flickr Web Services</title>
    <summary>Excerpted from Chapter 18 of the Adobe AIR 1.5 Cookbook. Mashup applications are based on the possibility of consuming remote data sources, and to create one, you need a good understanding of the APIs available. AIR offers even greater possibilities for creating mashup applications and widgets. With AIR, you can go beyond all the sandbox security of the browser and add advanced features to the application to interact with the file system or local storage with SQLite. This chapter demonstrates how to integrate the Flickr, Yahoo Maps, and Twitter web services to create desktop mashup applications with AIR.</summary>
    <author>
      <name>Marco Casario</name>
      
    </author>
    
    <category term="Features" />
    
    <content type="html" xml:lang="en" xml:base="http://www.insideria.com/">
      <![CDATA[<p><em>This is excerpted from Chapter 18 of the <a href="http://oreilly.com/catalog/9780596522506/" target="_blank">Adobe AIR 1.5 Cookbook</a> by <a href="http://www.oreillynet.com/pub/au/3416">David Tucker</a>, <a href="http://www.oreillynet.com/pub/au/3417">Marco Casario</a>, <a href="http://www.oreillynet.com/pub/au/3427">Koen De Weggheleire</a>, and <a href="http://www.oreillynet.com/pub/au/3426">Rich Tretola</a>. The book includes hands-on recipes to help you solve a variety of tasks and scenarios often encountered when using Adobe AIR to build Rich Internet Applications for the desktop.</em></p>

<div class="ap_r_front" style="width:180px;"><a href="http://oreilly.com/catalog/9780596522506/?CMP=ILC-dm_nav_related-books" target="_blank"><img border="0" src="http://www.oreilly.com/catalog/covers/9780596522506_cat.gif" width="180" height="233" /></a>
<div class="apcaption">Get the <a href="http://oreilly.com/catalog/9780596522506/?CMP=ILC-dm_nav_related-books" target="_blank">Adobe AIR 1.5 Cookbook</a> or download the <a href="http://cachefly.oreilly.com/digitalmedia/9780596522506/9780596522506_bonus_ch18.pdf" target="_blank">PDF</a> of this entire chapter.</div></div>

<h3>Introduction</h3>
<p>The term <span class="emphasis"><em>mashup</em></span> has been used in the music industry for quite some time to define the result of producing a new sound by mixing two or more existing pieces together, so it&#8217;s easy to guess that in the world of web applications the term means the ability of an application to combine data from more than one source.</p>

<p>Web application mashups were born at the same time as the new approach of <span class="keep-together">Web 2.0</span>, which, among its many objectives, was aimed at reusing different data sources to create hybrid applications. So, mashups owe their success to the growth of user-<span class="keep-together">generated</span> content on the Web. For example, with the increase of blogs on the Internet, bloggers wanted to offer services and multimedia elements in addition to classical web content, which is how services such as YouTube, Flickr, and Google Maps started to be integrated in millions of posts, adding value to the simple text. But all this wouldn&#8217;t have been possible if it hadn&#8217;t been for the increase of web services and XML data sources that could be used and invoked by the applications. Another great catalyst of mashup applications was the success of Ajax and technologies such as Flex, Ruby on Rails, and now Adobe AIR.</p><p>Useful mashup applications are born on the Web every day. Here are a few examples that you can try straightaway to get a better idea of what it means to combine different data sources in one application:</p>

<div class="variablelist"><dl><dt><span class="term"><strong><a href="http://www.kayak.com">Kayak</a></strong></span></dt>
<dd><p>A mashup that consumes Expedia, Traveloprice, and other travel web services to help you choose your flight or hotel at your convenience. In the trip ideas section (<a href="http://www.kayak.com/h/buzz" target="_top">http://www.kayak.com/h/buzz</a>), it uses Google Maps.</p></dd>
<dt><span class="term"><strong><a href="http://www.flashearth.com" target="_top">Flash Earth</a></strong></span></dt><dd><p>A zoomable mashup of satellite applications created with Flash. It consumes web services from many sources: NASA, Google Maps, Virtual Earth, Yahoo Maps, and OpenLayers&#8212;to name just a few.</p></dd>
<dt><span class="term"><strong><a href="http://www.netvibes.com" target="_top">Netvibes</a></strong></span></dt><dd><p>Netvibes is a personalized start page similar to Pageflakes, My Yahoo, iGoogle, and Microsoft Live. It is written in Ajax and organized into tabs, with each tab <span class="keep-together">containing</span> user-defined modules. It integrates and consumes an RSS/Atom feed reader, local weather forecasts, a calendar supporting iCal, bookmarks, notes, to-do lists, and multiple searches. It also has support for POP3, IMAP4 email, and the webmail providers Gmail, Yahoo Mail, Hotmail, and AOL Mail. In addition, it supports Box.net web storage, del.icio.us, Meebo, Flickr photos, podcasts (via a built-in audio player), and more.</p><div class="note" style="border: 1px solid #CCCCCC; background-color: #efefef; padding: 5px;"><p>Note: You can find a more complete and updated list of available   mashups at <a href="http://www.programmableweb.com/mashups" target="_top">http://www.programmableweb.com/mashups</a>.</p></div></dd></dl></div><p>Mashup applications are based on the possibility of consuming remote data sources, and to create one, you need a good understanding of the APIs available. (You can find an updated list of APIs at <a href="http://www.programmableweb.com/apis/directory" target="_top">http://www.programmableweb.com/apis/directory</a>.) AIR offers even greater possibilities for creating mashup applications and widgets. With AIR, you can go beyond all the sandbox security of the browser and add advanced features to the application to interact with the file system or local storage with SQLite. This chapter demonstrates how to <span class="emphasis"><em>integrate</em></span> the Flickr, Yahoo Maps, and Twitter web services to create desktop mashup applications with AIR.</p>

<div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="consuming_flickr_web_services"></a>Consuming Flickr Web Services</h2></div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id428022"></a>Problem</h3></div></div></div>

<p>You want to consume Flickr (<a href="http://www.flickr.com" target="_top">http://www.flickr.com</a>) web services.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id428032"></a>Solution</h3></div></div></div>

<div class="ap_r_front">
<a href="http://www.insideria.com/2009/03/10/flickrlogo.jpg" class="highslide" onclick="return hs.expand(this)"><img src="http://www.insideria.com/2009/03/10/flickrlogo.jpg" alt="Developing Mashup Air Apps: Consuming Flickr Web Services" title="Click to enlarge" width="148"/></a>
</div>

<p>Useful to amateur and professional photographers alike, Flickr is a portal that provides photographic material. You can use it as a simple private archive of password-protected photographs or as an online portfolio that can be freely accessed by potential clients or whoever else is interested. Flickr&#8217;s services, however, have limits. For example, because Flickr is a web application, it requires you use a web browser to access the service.</p><p>You can avoid this limitation with AIR.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id428058"></a>Discussion</h3></div></div></div><p>AIR applications allow you to access many functions that can&#8217;t normally be accessed by traditional web developers, such as reading and writing files on the user&#8217;s computer and creating multiwindow applications. By joining the simplicity of Flickr&#8217;s services with the power and flexibility of the AIR software development kit (SDK), you can create very interesting mashup applications. The only limits to the integrations are your imagination and needs.</p><p>To access Flickr services, you first must register and request a free application key (<a href="http://www.flickr.com/services/api/keys/apply/" target="_top">http://www.flickr.com/services/api/keys/apply/</a>). The key consists of two codes: an access key and a shared secret key; the combined use of the two keys allows you to access all the services provided by the portal. To get the application key, you&#8217;ll be asked to fill out a simple online form (<a href="#flickr_wizard_to_obtain_your_free" title="Figure 18.1. Flickr wizard to obtain your free application key">Figure 18.1, &#8220;Flickr wizard to obtain your free application key&#8221;</a>), specifying the type of application you are creating, the technologies involved, and whether the final product will be commercial.</p><div class="figure"><a name="flickr_wizard_to_obtain_your_free"></a>
<div class="ap_c"><a href="http://insideria.com/riaimages/aacb_1801.png" class="highslide" onclick="return hs.expand(this)"><img src="http://insideria.com/riaimages/aacb_1801.png" alt="Figure 2" title="Click to enlarge" width="400"/></a><div class="apcaption">Figure 18.1. Flickr wizard to obtain your free application key</div></div>

</div><br class="figure-break"><p>Once you obtain the application key to use the service, you can begin using Flickr. The documentation (<a href="ch18.html#flickr_api_online_documentation" title="Figure 18.2. Flickr API online documentation">Figure 18.2, &#8220;Flickr API online documentation&#8221;</a>), which is very easy to understand, is available online at <a href="http://www.flickr.com/services/api" target="_top">http://www.flickr.com/services/api</a>.</p>

<div class="figure"><a name="flickr_api_online_documentation"></a><a name="I_mediaobject18_d1e23153"></a>

<div class="ap_c"><a href="http://insideria.com/riaimages/aacb_1802.png" class="highslide" onclick="return hs.expand(this)"><img src="http://insideria.com/riaimages/aacb_1802.png" alt="Figure 1" title="Click to enlarge" width="400"/></a><div class="apcaption">Figure 18.2. Flickr API online documentation</div></div>

</div><br class="figure-break"><p>The online documentation lists which functions are available to developers and how to use them. You will also find a list of the libraries to access existing Flickr services for the main web and desktop programming languages, such as PHP, .NET, Java, Delphi, Perl, and obviously ActionScript. The libraries that have been created to access the Flickr web service enable you to interact with the functions of the portal without having to worry about communication details between the web services and your development environment.</p><p>The recommended library on the Flickr portal, and the one used in this example, is as3flickrlib, developed by Mike Chambers and available as a Google Code project (<a href="http://code.google.com/p/as3flickrlib/downloads/list" target="_top">http://code.google.com/p/as3flickrlib/downloads/list</a>). In addition, as3flickrlib requires the as3corelib library in order to manage HTTP queries to the web services and to parse the returned XML data. You can download as3corelib from <a href="http://code.google.com/p/as3corelib/downloads/list" target="_top">http://code.google.com/p/as3corelib/downloads/list</a>.</p><div class="note" style="border: 1px solid #CCCCCC; background-color: #efefef; padding: 5px;"><p>Note: If the libraries don&#8217;t offer the specific functions that your   application needs, you can either create a new library to communicate   with Flickr services or extend one of the existing libraries.</p></div><p>The downloads are compressed archives that contain ActionScript 3 sources, documents in HTML format regarding the available functions, and compressed libraries in SWC format (<a href="ch18.html#actionscript_3_required_libraries" title="Figure 18.3. ActionScript 3 required libraries">Figure 18.3, &#8220;ActionScript 3 required libraries&#8221;</a>). For AIR applications, you need the two libraries&#8217; SWC files. They should automatically decompress to the lib folder in your project folder, which contains the AIR application project.</p><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="actionscript_solidus_flash_cs4"></a>ActionScript/Flash CS4</h4></div></div></div><p>Once you obtain the necessary data from Flickr to consume its web services, you can begin creating the ActionScript class to control the mashup of the remote data.</p><p>From ASDoc in as3flickrlib (<a href="http://as3flickrlib.googlecode.com/svn/trunk/docs/index.html" target="_top">http://as3flickrlib.googlecode.com/svn/trunk/docs/index.html</a>), take a look at the classes you&#8217;ll be working with:</p><div class="itemizedlist"><ul type="disc"><li><p><code>FlickrService</code>: Abstracts the Flickr API found at <a href="http://www.flickr.com/services/api" target="_top">http://www.flickr.com/services/api</a></p></li><li><p><code>FlickrError</code>: Common errors that can happen during a call to a Flickr method</p></li><li><p><code>FlickrResultEvent</code>: Event class that contains information about events broadcast in response to data events from the Flickr API</p></li><li><p><code>PagedPhotoList</code>: A <code>ValueObject</code> for the Flickr API</p></li><li><p><code>Photo</code>: A <code>ValueObject</code> for the Flickr API</p></li><li><p><code>PhotoSize</code>: A <code>ValueObject</code> for the Flickr API</p></li><li><p><code>User</code>: A <code>ValueObject</code> for the Flickr API</p></li></ul></div><div class="figure-float"><div class="figure"><a name="actionscript_3_required_libraries"></a>

<a name="I_mediaobject18_d1e23234"></a><div class="ap_c"><a href="http://insideria.com/riaimages/aacb_1803.png" class="highslide" onclick="return hs.expand(this)"><img src="http://insideria.com/riaimages/aacb_1803.png" alt="Figure 3" title="Click to enlarge" width="400"/></a><div class="apcaption">Figure 18.3. ActionScript 3 required libraries</div></div>

</div><br class="figure-break"></div><p>Here is the complete code of the <code>FlickrWS.as</code>
 class to launch a search and display the response data using Flickr APIs:</p><a name="I_programlisting18_d1e23244"></a>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>package com.oreilly.aircookbook.bonus
{
     <span class="category1">import</span> com.adobe.webapis.flickr.FlickrService;
     <span class="category1">import</span> com.adobe.webapis.flickr.PagedPhotoList;
     <span class="category1">import</span> com.adobe.webapis.flickr.Photo;
     <span class="category1">import</span> com.adobe.webapis.flickr.PhotoSize;
     <span class="category1">import</span> com.adobe.webapis.flickr.User;
     <span class="category1">import</span> com.adobe.webapis.flickr.events.FlickrResultEvent;
 
     <span class="category1">import</span> flash.display.Bitmap;
     <span class="category1">import</span> flash.display.Loader;
     <span class="category1">import</span> flash.events.Event;
     <span class="category1">import</span> flash.events.IOErrorEvent;
     <span class="category1">import</span> flash.net.URLRequest;
     <span class="category1">import</span> flash.system.Security;
 
     <span class="category1">import</span> mx.collections.ArrayCollection;
 
     [Bindable]
     <span class="category1">public</span> <span class="category1">class</span> FlickrWS
     {
          <span class="category1">private</span> const CROSSDOMAIN_ADDRESS:<span class="category2">String</span> = "<span class="quote">http://api.flickr.com/crossdomain.xml</span>";
          <span class="category1">private</span> const SECRET_KEY:<span class="category2">String</span> = "<span class="quote">YOURSECRETKEY</span>";
          <span class="category1">private</span> const SHARED_SHARED_KEY:<span class="category2">String</span> = "<span class="quote">YOURSHAREDKEY</span>";
  
          <span class="category1">private</span> const THUMBHEIGHT:<span class="category2">Number</span> = 175;
          <span class="category1">private</span> const THUMBWIDTH:<span class="category2">Number</span> = 155;
  
          <span class="category1">public</span> <span class="category1">var</span> fs:FlickrService;
  
          <span class="category1">private</span> <span class="category1">var</span> imgList:PagedPhotoList;
  
          <span class="category1">private</span> <span class="category1">var</span> userVO:User;
  
          <span class="category1">private</span> <span class="category1">var</span> activePhotoVO:Photo;
  
          <span class="category1">private</span> <span class="category1">var</span> _currImage:<span class="category2">Number</span> = 0;
  
          <span class="category1">public</span> <span class="category1">function</span> <span class="category2">get</span> currImage():<span class="category2">Number</span>
          {
               <span class="category1">return</span> _currImage;
           }
  
          <span class="category1">public</span> <span class="category1">function</span> <span class="category1">set</span> currImage(_currImage:<span class="category2">Number</span>):<span class="category1">void</span>
          {
               <span class="category1">this</span>._currImage = _currImage;
           }
  
          <span class="category1">public</span> <span class="category1">function</span> <span class="category2">get</span> thumbsDP():ArrayCollection
          {
               <span class="category1">return</span> _thumbsDP;
           }
  
          <span class="category1">public</span> <span class="category1">function</span> FlickrWS()
          {
               Security.loadPolicyFile( CROSSDOMAIN_ ADDRESS );
               fs = <span class="category1">new</span> FlickrService(SHARED_KEY);
               fs.secret = SECRET_KEY;
   
               fs.addEventListener( FlickrResultEvent.PHOTOS_GET_SIZES, onPhotoSize );
               fs.addEventListener( FlickrResultEvent.PEOPLE_GET_INFO, onUserInfo );
               fs.addEventListener( FlickrResultEvent.PHOTOS_SEARCH , onPhotoList );
   
           }
  
          <span class="category1">private</span> <span class="category1">function</span> onPhotoList( evt:FlickrResultEvent ):<span class="category1">void</span>
          {
   
               imgList = evt.<span class="category2">data</span>.photos as PagedPhotoList;
   
               <span class="category1">if</span> (imgList &amp;amp;&amp;amp; imgList.total &gt; 0)
               {
                    loadNextImage();
    
                } <span class="category1">else</span>
               {
                    <span class="category2">trace</span>("<span class="quote">No results</span>");
                }
           }
  
          <span class="category1">private</span> <span class="category1">function</span> onUserInfo( evt:FlickrResultEvent ):<span class="category1">void</span>
          {
               userVO = evt.<span class="category2">data</span>.user as User;
   
               checkReadyStatus();
           }
  
          <span class="category1">private</span> <span class="category1">function</span> onPhotoSize( evt:FlickrResultEvent ):<span class="category1">void</span>
          {
               <span class="category1">if</span> ( evt.success )
               {
                    <span class="category1">var</span> availableSizeList:<span class="category2">Array</span> = evt.<span class="category2">data</span>.photoSizes;
    
                    <span class="category1">var</span> availableSize:PhotoSize;
    
                <span class="category1">for</span>(<span class="category1">var</span> i:<span class="category1">int</span> = 0; i &lt; availableSizeList.<span class="category2">length</span>; i++)
                {
                     availableSize = availableSizeList[i];
     
                 <span class="category1">if</span> ( availableSize.<span class="category2">width</span> &gt; THUMBWIDTH || 
                      availableSize.<span class="category2">height</span> &gt; THUMBHEIGHT )
                 {
                      <span class="category1">break</span>;
                  }
             }
    
            <span class="category1">if</span>( availableSize.source != <span class="category1">null</span> || availableSize.source != "<span class="quote"></span>" )
            {
     
             <span class="category1">if</span>( imgLoader != <span class="category1">null</span> )
             {
                  imgLoader.contentLoaderInfo.removeEventListener( Event.COMPLETE, onImageReady );
                  imgLoader.contentLoaderInfo.removeEventListener( IOErrorEvent.IO_ERROR, 
                                                                   onImageError );
              }
     
             imgLoader = <span class="category1">new</span> Loader();
     
             imgLoader.contentLoaderInfo.addEventListener( Event.COMPLETE, onImageReady );
             imgLoader.contentLoaderInfo.addEventListener( IOErrorEvent.IO_ERROR, onImageError );
     
             imgLoader.<span class="category2">load</span>( <span class="category1">new</span> URLRequest( availableSize.source ) );
     
             } <span class="category1">else</span>
            {
                 loadNextImage();
             }
    
            } <span class="category1">else</span>
           {
                loadNextImage();
            }
           }
  
  
          <span class="category1">private</span> <span class="category1">function</span> checkReadyStatus():<span class="category1">void</span>
          {
               <span class="category1">if</span> ( isImgReady )
               {
                    <span class="category1">var</span> photoDataRow:<span class="category2">Object</span> = <span class="category1">new</span> <span class="category2">Object</span>();
    
                    photoDataRow[ '<span class="quote">label</span>' ] = imageTitle + "<span class="quote"> [</span>" + imageAuthor + "<span class="quote">]</span>";
    
                    photoDataRow[ '<span class="quote">source</span>' ] = thumbnailImage;
    
                    photoDataRow[ '<span class="quote">scaleContent</span>' ] = <span class="category1">true</span>;
    
                    photoDataRow[ '<span class="quote">photoVO</span>' ] = activePhotoVO;
    
                    _thumbsDP.<span class="category2">addItem</span>( photoDataRow );
    
                    loadNextImage();
    
                } <span class="category1">else</span>
               {
                    isImgReady = <span class="category1">true</span>;
                }
           }
  
  
          <span class="category1">public</span> <span class="category1">function</span> loadNextImage():<span class="category1">void</span>
          {
               <span class="category1">if</span> (currImage &gt;= imgList.photos.<span class="category2">length</span>)
               {
                    <span class="category1">return</span>;
                }
   
                   activePhotoVO = imgList.photos[ currImage ];
   
                   isImgReady = <span class="category1">false</span>;
   
               <span class="category1">if</span>( activePhotoVO != <span class="category1">null</span> )
               {
    
                <span class="category1">if</span>( activePhotoVO.id != <span class="category1">null</span> )
                {
     
                 fs.photos.getSizes( activePhotoVO.id );
     
                 <span class="category1">if</span>( activePhotoVO.ownerId != <span class="category1">null</span> )
                 {
      
                      fs.people.getInfo( activePhotoVO.ownerId );
      
                  }<span class="category1">else</span>
                 {
      
                      isImgReady = <span class="category1">true</span>;
                  }
                 } <span class="category1">else</span>
                {
                     currImage++;
     
                     loadNextImage();
     
                     <span class="category1">return</span>;
                 }
                } <span class="category1">else</span>
               {
    
                }
   
                   currImage++;
               }
  
  
          <span class="category1">private</span> <span class="category1">function</span> onImageReady( evt:Event ):<span class="category1">void</span>
          {
               <span class="category1">try</span>
               {
                    <span class="category1">var</span> imageAlias:Bitmap = Bitmap( imgLoader.content );
    
                    checkReadyStatus();
    
                } <span class="category1">catch</span> (e:<span class="category2">Error</span>)
               {
                 <span class="category2">trace</span>("<span class="quote">Returned image was not a proper bitmap: </span>" + imgLoader.loaderInfo.<span class="category2">url</span>);
    
    
                loadNextImage();
            }
           }
  
  
          <span class="category1">private</span> <span class="category1">function</span> onImageError( evt:IOErrorEvent ):<span class="category1">void</span>
          {
               <span class="category2">trace</span>( "<span class="quote">Error loading image: </span>" + imgLoader.loaderInfo.<span class="category2">url</span> );
   
               loadNextImage();
           }
  
  
  
          <span class="category1">public</span> <span class="category1">function</span> <span class="category2">get</span> thumbnailImage():Bitmap
          {
            <span class="category1">return</span> imgLoader.content as Bitmap;
           }
  
  
          <span class="category1">public</span> <span class="category1">function</span> <span class="category2">get</span> imageTitle():<span class="category2">String</span>
          {
            <span class="category1">return</span> activePhotoVO.title;
           }
  
  
          <span class="category1">public</span> <span class="category1">function</span> <span class="category2">get</span> imageAuthor():<span class="category2">String</span>
          {
            <span class="category1">return</span> userVO.fullname;
           }
          }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The ActionScript <span class="category1">class</span> uses the Flickr library <span class="category1">and</span> imports all the classes it needs <span class="category1">with</span> a series of imports that point to the &lt;code&gt;com.adobe.webapis.flickr&lt;/code&gt; package. It defines <span class="category1">private</span> constants that contain your API keys <span class="category1">and</span> the URL of the cross-<span class="category2">domain</span> file:&lt;/p&gt;&lt;a <span class="category2">name</span>="<span class="quote">I_programlisting18_d1e23251</span>"&gt;&lt;/a&gt;

&lt;div <span class="category1">class</span>="<span class="quote">acode</span>" style="<span class="quote">overflow: auto; padding: 10px;</span>" &gt;&lt;div style="<span class="quote">overflow-x: visible;</span>"&gt;
&lt;mt:CodeBeautify <span class="category2">language</span>="<span class="quote">actionscript</span>"&gt;<span class="category1">private</span> const CROSSDOMAIN_ADDRESS:<span class="category2">String</span> = "<span class="quote">http://api.flickr.com/crossdomain.xml</span>";
<span class="category1">private</span> const SECRET_KEY:<span class="category2">String</span> = "<span class="quote">YOURSECRETKEY</span>";
<span class="category1">private</span> const SHARED_KEY:<span class="category2">String</span> = "<span class="quote">YOURSHAREDKEY</span>";&lt;/pre&gt;&lt;p&gt;The <span class="category1">class</span> <span class="category2">constructor</span> creates event listeners to control the response <span class="category2">data</span> of a search, which includes the information returned <span class="category1">on</span> the images <span class="category1">and</span> the users:&lt;/p&gt;&lt;a <span class="category2">name</span>="<span class="quote">I_programlisting18_d1e23255</span>"&gt;&lt;/a&gt;&lt;pre&gt;fs.addEventListener( FlickrResultEvent.PHOTOS_GET_SIZES, onPhotoSize );
fs.addEventListener( FlickrResultEvent.PEOPLE_GET_INFO, onUserInfo );
fs.addEventListener( FlickrResultEvent.PHOTOS_SEARCH , onPhotoList );&lt;/pre&gt;&lt;p&gt;The <span class="category2">data</span> provider is populated <span class="category1">in</span> the &lt;code&gt;onPhotoSize&lt;/code&gt; event listener, which is triggered by the &lt;code&gt;Result&lt;/code&gt; event of the Flickr <span class="category2">call</span>, <span class="category1">and</span> then the <span class="category2">data</span> provider is passed into the &lt;code&gt;tileList&lt;/code&gt; control to display the images:&lt;/p&gt;&lt;a <span class="category2">name</span>="<span class="quote">I_programlisting18_d1e23269</span>"&gt;&lt;/a&gt;&lt;pre&gt;<span class="category1">var</span> photoDataRow:<span class="category2">Object</span> = <span class="category1">new</span> <span class="category2">Object</span>();

photoDataRow[ '<span class="quote">label</span>' ] = imageTitle + "<span class="quote"> [</span>" + imageAuthor + "<span class="quote">]</span>";

photoDataRow[ '<span class="quote">source</span>' ] = thumbnailImage;

photoDataRow[ '<span class="quote">scaleContent</span>' ] = <span class="category1">true</span>;

photoDataRow[ '<span class="quote">photoVO</span>' ] = activePhotoVO;

_thumbsDP.<span class="category2">addItem</span>( photoDataRow );


loadNextImage();</pre>
</code>

</div></div>

<p>A <code>photoDataRow</code> object is created, holding the returned image and metaproperties such as <code>label</code>, <code>scaleContent</code>, and <code>photoVO</code>. This is added to the <code>_thumbsDP ArrayCollection</code> using the <code>addItem</code> method.</p><p>Then the <code>loadNextImage</code> method is called, which repeats the actions for each element in the response data.</p>

<p>The ActionScript class can now easily be implemented in an AIR application. The following is the MXML code that uses the class you just created:</p><a name="I_programlisting18_d1e23299"></a>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>&lt;?xml <span class="category2">version</span>="<span class="quote">1.0</span>" encoding="<span class="quote">utf-8</span>"?&gt;

&lt;mx:WindowedApplication xmlns:mx="<span class="quote">http://www.adobe.com/2006/mxml</span>"
 <span class="category2">initialize</span>="<span class="quote">init()</span>"
 showFlexChrome="<span class="quote">false</span>"
 showStatusBar="<span class="quote">false</span>"&gt;

&lt;mx:DefaultTileListEffect id="<span class="quote">TLEffect</span>"
fadeOutDuration="<span class="quote">350</span>"
fadeInDuration="<span class="quote">350</span>"
moveDuration="<span class="quote">1000</span>" /&gt;
&lt;mx:Script&gt;
&lt;![CDATA[

    <span class="category1">import</span> mx.controls.Alert;
    <span class="category1">import</span> flash.events.MouseEvent;
    <span class="category1">import</span> com.oreilly.aircookbook.bonus.FlickrWS;

    [Bindable]
    <span class="category1">private</span> <span class="category1">var</span> fsClass:FlickrWS;

    <span class="category1">private</span> <span class="category1">function</span> <span class="category2">init</span>():<span class="category1">void</span>
    {
         fsClass = <span class="category1">new</span> FlickrWS();
         searchBtn.addEventListener( MouseEvent.CLICK, startNewSearch );
     }

    <span class="category1">private</span> <span class="category1">function</span> startNewSearch( evt:MouseEvent ):<span class="category1">void</span>
    {
 
         <span class="category1">if</span>( searchTxt.<span class="category2">text</span> == "<span class="quote"></span>" )
         {
              <span class="category1">return</span>;
          }
 
         fsClass.thumbsDP.<span class="category2">removeAll</span>();
 
         fsClass.currImage = 0;
 
         <span class="category1">var</span> tagSearch:<span class="category2">String</span>;
         <span class="category1">var</span> generalSearch:<span class="category2">String</span>;
 
         <span class="category1">if</span>( searchCbx.selectedLabel == "<span class="quote">tag</span>" )
         {
              tagSearch = searchTxt.<span class="category2">text</span>;
              generalSearch = "<span class="quote"></span>";
  
          }<span class="category1">else</span> {
  
              tagSearch = "<span class="quote"></span>";
              generalSearch = searchTxt.<span class="category2">text</span>;
          }
 
         fsClass.fs.photos.search("<span class="quote"></span>", tagSearch, "<span class="quote">any</span>", generalSearch, <span class="category1">null</span>, <span class="category1">null</span>, <span class="category1">null</span>, <span class="category1">null</span>, 
                                  &amp;#8722;1, "<span class="quote"></span>", 20, 1, "<span class="quote">interestingness-desc</span>");
 
     }
]]&gt;
&lt;/mx:Script&gt;


&lt;mx:TextInput id="<span class="quote">searchTxt</span>" /&gt;

&lt;mx:<span class="category2">Button</span> <span class="category1">label</span>="<span class="quote">Search</span>" id="<span class="quote">searchBtn</span>" /&gt;

&lt;mx:TileList id="<span class="quote">photoTL</span>" dataProvider="<span class="quote">{fsClass.thumbsDP}</span>"
 columnCount="<span class="quote">4</span>" rowCount="<span class="quote">3</span>" rowHeight="<span class="quote">155</span>" columnWidth="<span class="quote">175</span>"
 itemRenderer="<span class="quote">com.oreilly.aircookbook.bonus.FlickrThumbnail</span>"
 itemsChangeEffect ="<span class="quote">{TLEffect}</span>"
 dragEnabled="<span class="quote">true</span>"
 dropEnabled="<span class="quote">true</span>"
 dragMoveEnabled="<span class="quote">true</span>"  /&gt;

&lt;mx:ComboBox id="<span class="quote">searchCbx</span>"&gt;
&lt;mx:dataProvider&gt;
&lt;mx:<span class="category2">Object</span> <span class="category1">label</span>="<span class="quote">Tag Search</span>" <span class="category2">data</span>="<span class="quote">tag</span>" /&gt;
&lt;mx:<span class="category2">Object</span> <span class="category1">label</span>="<span class="quote">Text Search</span>" <span class="category2">data</span>="<span class="quote">text</span>" /&gt;
&lt;/mx:dataProvider&gt;

&lt;/mx:ComboBox&gt;
&lt;/mx:WindowedApplication&gt;</pre>
</code>

</div></div>

<p>The application has a <code>ComboBox</code> control to
        allow the user to launch the search by using the text or a tag (inserted by the user) as a parameter in a <code>TextInput</code> control. The search on the Flickr web services actually occurs when the <code>startNewSearch</code> method is invoked, triggered by the <code>click</code> event of the <code>Button</code> control. The <code>search</code>
 method of the Flickr SWC library is invoked, and the parameters it needs to obtain the images from the Flickr web service are sent to it:</p><a name="I_programlisting18_d1e23322"></a>
 
<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>fsClass.fs.photos.search("<span class="quote"></span>", tagSearch, "<span class="quote">any</span>", generalSearch, <span class="category1">null</span>, <span class="category1">null</span>, <span class="category1">null</span>, <span class="category1">null</span>, 
&amp;#8722;1, "<span class="quote"></span>", 20, 1, "<span class="quote">interestingness-desc</span>");</pre>
</code>

</div></div>

<p>The request data is controlled by the <code>onPhotoList</code> method of the ActionScript class, which populated the <code>thumbsDP</code> data provider typed as <code>ArrayCollection</code>. This value is passed onto the <code>TileList</code> control, creating a data binding:</p><a name="I_programlisting18_d1e23338"></a>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>&lt;mx:TileList id="<span class="quote">photoTL</span>" dataProvider="<span class="quote">{fsClass.thumbsDP}</span>"
 columnCount="<span class="quote">4</span>" rowCount="<span class="quote">3</span>" rowHeight="<span class="quote">155</span>" columnWidth="<span class="quote">175</span>"
 itemRenderer="<span class="quote">com.oreilly.aircookbook.bonus.FlickrThumbnail</span>"
 itemsChangeEffect ="<span class="quote">{TLEffect}</span>"
 dragEnabled="<span class="quote">true</span>"
 dropEnabled="<span class="quote">true</span>"
 dragMoveEnabled="<span class="quote">true</span>"  /&gt;</pre>
</code>

</div></div>
 
<p>This control uses an item renderer to display the image and text as an element of the list. The renderer is passed to it with the <code>itemRenderer</code> property, where an external component, called <code>FlickrThumbnail</code>, is specified in <code>com.oreilly.aircookbook.bonus</code>.</p><p>The <code>TileList</code> control also makes it possible to drag and drop items in it by applying the specified effect to the movements at the beginning of the MXML application:</p><a name="I_programlisting18_d1e23357"></a>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>&lt;mx:DefaultTileListEffect id="<span class="quote">TLEffect</span>"
fadeOutDuration="<span class="quote">350</span>"
fadeInDuration="<span class="quote">350</span>"
moveDuration="<span class="quote">1000</span>" /&gt;</pre>
</code>

</div></div>

<p>This is the code of the <code>FlickrThumbnail.mxml</code> component, which exploits the data property that is propagated by the <code>TileList</code> in the item renderer and contains the data provider and all its properties:</p><a name="I_programlisting18_d1e23367"></a>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>&lt;?xml <span class="category2">version</span>="<span class="quote">1.0</span>" encoding="<span class="quote">utf-8</span>"?&gt;
&lt;mx:VBox xmlns:mx="<span class="quote">http://www.adobe.com/2006/mxml</span>"
    horizontalAlign="<span class="quote">center</span>"
    verticalGap="<span class="quote">0</span>"
    borderStyle="<span class="quote">none</span>" <span class="category2">backgroundColor</span>="<span class="quote">white</span>" &gt;

    &lt;mx:Image id="<span class="quote">image</span>" <span class="category2">width</span>="<span class="quote">60</span>" <span class="category2">height</span>="<span class="quote">60</span>" source="<span class="quote">{data.source}</span>"/&gt;
    &lt;mx:Label <span class="category2">text</span>="<span class="quote">{data.label}</span>" <span class="category2">width</span>="<span class="quote">120</span>" <span class="category2">textAlign</span>="<span class="quote">center</span>"/&gt;

&lt;/mx:VBox&gt;</pre>
</code>

</div></div>

<p>This simple mashup implements and consumes only one method from the Flickr APIs. You could improve it by adding remote features and by exploiting AIR SDKs to allow users to save images locally or create a local database with SQLite to store their favorite images.</p></div>

<div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="html_solidus_javascript"></a>HTML/JavaScript</h4></div></div></div>
<div class="ap_r_front" style="width:180px;"><a href="http://oreilly.com/catalog/9780596522506/?CMP=ILC-dm_nav_related-books" target="_blank"><img border="0" src="http://www.oreilly.com/catalog/covers/9780596522506_cat.gif" width="180" height="233" /></a>
<div class="apcaption">Get the <a href="http://oreilly.com/catalog/9780596522506/?CMP=ILC-dm_nav_related-books" target="_blank">Adobe AIR 1.5 Cookbook</a> or download the <a href="http://cachefly.oreilly.com/digitalmedia/9780596522506/9780596522506_bonus_ch18.pdf" target="_blank">PDF</a> of this entire chapter.</div></div>

<p>You can also consume Flickr services by using HTML and JavaScript. Before you begin, it&#8217;s worth consulting the API explorer tool (<a href="http://www.flickr.com/services/api/explore" target="_top">http://www.flickr.com/services/api/explore</a>), with which you can query any method of Flickr&#8217;s APIs, send parameters to it, and display the response. The syntax is <code>http://www.flickr.com/services/api/explore/?method=METHODNAME</code>. For example, the following URL invokes the <code>search</code> method of the APIs, and, in the page that opens, you can send the parameters by filling in the text inputs:</p><table class="simplelist" border="0" summary="Simple list"><tr><td><strong class="userinput"><code>http://www.flickr.com/services/api/explore/?method=flickr.photos.search</code></strong></td></tr></table>

<p>What the API explorer actually does is build the web page to pass the parameters of the method using the reflection approach and build the REST URL of that method.</p>

<p>Once you get familiar with Flickr&#8217;s APIs, you can start interacting with them. By using a Flickr <span class="emphasis"><em>badge</em></span>, for example, you can create a web page showing your photos by importing the badge from <a href="http://www.flickr.com/badge_new.gne" target="_top">http://www.flickr.com/badge_new.gne</a>. Then again, you can create your own Flickr badge to insert in your AIR application with a few lines of JavaScript code.</p>

<p>Flickr generates feeds in different formats and for different types of content, so your application can consume these feed links in various languages. You can, for example, consume the feeds to obtain recent public photos that have been uploaded on Flickr from <a href="http://api.flickr.com/services/feeds/photos_public.gne" target="_top">http://api.flickr.com/services/feeds/photos_public.gne</a>
 or your own public photos from <a href="http://api.flickr.com/services/feeds/photos_public.gne?id=USER-NSID" target="_top">http://api.flickr.com/services/feeds/photos_public.gne?id=USER-NSID</a>.</p>
 
 <p>Now all you have to do is choose the format to consume: RSS, ATOM, PHP, JSON, CSV, YAML, or SQL. The example uses the JavaScript Object Notation (JSON).</p>
 
 <div class="note" style="border: 1px solid #CCCCCC; background-color: #efefef; padding: 5px; margin-bottom: 15px;"><p>Note: According to Wikipedia, JSON is a lightweight computer data interchange format. It is a text-based, human-readable format to represent simple data structures and associative arrays (called <span class="emphasis"><em>objects</em></span>). The JSON format is often used for transmitting structured data over a network connection in a process called <span class="emphasis"><em>serialization</em></span>. Its main application is in Ajax web application programming, where it serves as an alternative to the XML format. Although JSON was based on a subset of JavaScript and is commonly used with that language, it is considered to be a language-<span class="keep-together">independent</span> data format. Code for parsing and generating JSON data is readily available for a large variety of programming languages. You can find a comprehensive listing of existing JSON bindings, organized by language, at <a href="http://www.json.org" target="_top">http://www.json.org</a>.</p></div>
 
<p>When you launch the URL <a href="http://api.flickr.com/services/feeds/photos_public.gne?id=44124469126@N01&amp;format=json" target="_top">http://api.flickr.com/services/feeds/photos_public.gne?id=44124469126@N01&amp;format=json</a> from your browser, the following JavaScript code is generated:</p><a name="I_programlisting18_d1e23424"></a>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>jsonFlickrFeed({
           "<span class="quote">title</span>": "<span class="quote">Uploads from Marco Casario</span>",
           "<span class="quote">link</span>": "<span class="quote">http://www.flickr.com/photos/44124469126@N01/</span>",
           "<span class="quote">description</span>": "<span class="quote"></span>",
           "<span class="quote">modified</span>": "<span class="quote">2008-07-27T21:10:55Z</span>",
           "<span class="quote">generator</span>": "<span class="quote">http://www.flickr.com/</span>",
           "<span class="quote">items</span>": [
        {
                 "<span class="quote">title</span>": "<span class="quote">STA72737</span>",
                 "<span class="quote">link</span>": "<span class="quote">http://www.flickr.com/photos/44124469126@N01/2708076572/</span>",
                 "<span class="quote">media</span>": {"<span class="quote">m</span>":"<span class="quote">http://farm4.static.flickr.com/3115/2708076572_505dc798eb_m.jpg</span>"},
                 "<span class="quote">date_taken</span>": "<span class="quote">2008-07-27T23:10:55-08:00</span>",
                 "<span class="quote">description</span>": "<span class="quote">&amp;amp;lt;p&amp;amp;gt;&amp;amp;lt;a 
  href=&amp;amp;quot;http://www.flickr.com/people/44124469126@N01/&amp;amp;quot;&amp;amp;gt;Marco 
  Casario&amp;amp;lt;/a&amp;amp;gt; posted a photo:&amp;amp;lt;/p&amp;amp;gt; &amp;amp;lt;p&amp;amp;gt;&amp;amp;lt;a 
  href=&amp;amp;quot;http://www.flickr.com/photos/44124469126@N01/2708076572/&amp;amp;quot; 
  title=&amp;amp;quot;STA72737&amp;amp;quot;&amp;amp;gt;&amp;amp;lt;img 
  src=&amp;amp;quot;http://farm4.static.flickr.com/3115/2708076572_505dc798eb_m.jpg&amp;amp;quot; 
  width=&amp;amp;quot;240&amp;amp;quot; height=&amp;amp;quot;180&amp;amp;quot; alt=&amp;amp;quot;STA72737&amp;amp;quot; /&amp;amp;gt;&amp;amp;lt;/a&amp;amp;gt;&amp;amp;lt;/p&amp;amp;gt; </span>",
                 "<span class="quote">published</span>": "<span class="quote">2008-07-27T21:10:55Z</span>",
                 "<span class="quote">author</span>": "<span class="quote">nobody@flickr.com (Marco Casario)</span>",
                 "<span class="quote">author_id</span>": "<span class="quote">44124469126@N01</span>",
                 "<span class="quote">tags</span>": "<span class="quote">seychelles</span>"
         },
        {
                 "<span class="quote">title</span>": "<span class="quote">STA72447</span>",
                 "<span class="quote">link</span>": "<span class="quote">http://www.flickr.com/photos/44124469126@N01/2708076122/</span>",
                 "<span class="quote">media</span>": {"<span class="quote">m</span>":"<span class="quote">http://farm4.static.flickr.com/3118/2708076122_e04bf714d7_m.jpg</span>"},
                 "<span class="quote">date_taken</span>": "<span class="quote">2008-07-27T23:10:46-08:00</span>",
                 "<span class="quote">description</span>": "<span class="quote">&amp;amp;lt;p&amp;amp;gt;&amp;amp;lt;a 
  href=&amp;amp;quot;http://www.flickr.com/people/44124469126@N01/&amp;amp;quot;&amp;amp;gt;Marco 
  Casario&amp;amp;lt;/a&amp;amp;gt; posted a photo:&amp;amp;lt;/p&amp;amp;gt; &amp;amp;lt;p&amp;amp;gt;&amp;amp;lt;a 
  href=&amp;amp;quot;http://www.flickr.com/photos/44124469126@N01/2708076122/&amp;amp;quot; 
  title=&amp;amp;quot;STA72447&amp;amp;quot;&amp;amp;gt;&amp;amp;lt;img 
  src=&amp;amp;quot;http://farm4.static.flickr.com/3118/2708076122_e04bf714d7_m.jpg&amp;amp;quot; 
  width=&amp;amp;quot;240&amp;amp;quot; height=&amp;amp;quot;180&amp;amp;quot; alt=&amp;amp;quot;STA72447&amp;amp;quot; /&amp;amp;gt;&amp;amp;lt;/a&amp;amp;gt;&amp;amp;lt;/p&amp;amp;gt; </span>",
                 "<span class="quote">published</span>": "<span class="quote">2008-07-27T21:10:46Z</span>",
                 "<span class="quote">author</span>": "<span class="quote">nobody@flickr.com (Marco Casario)</span>",
                 "<span class="quote">author_id</span>": "<span class="quote">44124469126@N01</span>",
                 "<span class="quote">tags</span>": "<span class="quote">seychelles</span>"
         },
 ....
}
]
})</pre>
</code>

</div></div>

<p>You can use this feed to dynamically create an HTML page by using JavaScript only. The following is the JavaScript code, saved to a file called <code class="filename">FlickrBadge.js</code>, that creates the elements in an HTML page and displays the photos of a Flickr user:</p><a name="I_programlisting18_d1e23432"></a>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre><span class="category1">function</span> jsonFlickrFeed(feed)
{
 
   <span class="category1">var</span> flickrRegExp = /(http:\/\/farm4.<span class="category1">static</span>.flickr.com\/\d+\/\d+_[0-9a-z]+)_m\.jpg/;
   <span class="category1">var</span> htmlContent = "<span class="quote"></span>";
   <span class="category1">var</span> items = feed['<span class="quote">items</span>'];
 
   htmlContent += '<span class="quote">&lt;div id="flickr_badge_uber_wrapper"&gt;</span>';
   htmlContent += '<span class="quote">&lt;p class="title"&gt;&lt;nobr&gt;Go to&lt;/nobr&gt;&lt;a href="</span>' + feed['<span class="quote">link</span>'] + '<span class="quote">"&gt;</span>' + 
                  feed['<span class="quote">title</span>'] + '<span class="quote">&lt;/a&gt;&lt;/p&gt;</span>';
 
   htmlContent += '<span class="quote">&lt;ul id="flickr_badge_source"&gt;</span>';
 
 
   <span class="category1">for</span> (<span class="category1">var</span> i = 0; i &lt; items.<span class="category2">length</span>; i++)
   {
      <span class="category1">var</span> <span class="category2">data</span> = flickrRegExp.exec(items[i]['<span class="quote">description</span>']);
  
      <span class="category1">if</span> (<span class="category2">data</span> != <span class="category1">null</span>)
      {
         <span class="category1">var</span> image = <span class="category2">data</span>[1] + '<span class="quote">_s.jpg</span>';
   
         htmlContent += '<span class="quote">&lt;li class="flickr_badge_image"&gt;&lt;a href="</span>' + items[i]['<span class="quote">link</span>'] + '<span class="quote">" 
                        id="flickr_www"&gt;&lt;img src="</span>'
             + image + '<span class="quote">" /&gt;&lt;/a&gt;&lt;/li&gt;</span>';
       }
    }
   htmlContent += '<span class="quote">&lt;/ul&gt;&lt;p id="flickr_badge_source_txt"&gt;&lt;nobr&gt;Go to&lt;/nobr&gt; &lt;a href="</span>' + 
                  feed['<span class="quote">link</span>'] + '<span class="quote">"&gt;</span>' + feed['<span class="quote">title</span>'] + '<span class="quote">&lt;/a&gt;&lt;/p&gt;</span>'
 
   htmlContent += '<span class="quote">&lt;/div&gt;</span>';
 
   document.writeln(htmlContent);
}</pre>
</code>

</div></div>

<p>This script dynamically generates an HTML <code>&lt;ul&gt;</code> list of elements that repeats a <code>for</code> loop as many times as the number of items that are returned from the feed.</p><p>Most of the work is carried out by the regular expression, which returns the string that matches the URL of the Flickr image:</p><a name="I_programlisting18_d1e23444"></a>

<pre>var flickrRegExp = /(http:\/\/farm4.static.flickr.com\/\d+\/\d+_[0-9a-z]+)_m\.jpg/;</pre>

<p>The URL address <a href="http://farm4.static.flickr.com" target="_top">http://farm4.static.flickr.com</a> may change for your photos. Pay attention to the URL used by Flickr to store your public photos in the <code>media</code> property of the JSON feed:</p><a name="I_programlisting18_d1e23453"></a><pre>"media": {"m":"http://farm4.static.flickr.com/3115/2708076572_505dc798eb_m.jpg"},</pre><p>The response data of the method <code>flickrRegExp.exec(items[i]['description'])</code> actually creates the image list.</p><p>Now you can create the web page that calls the JSON feed and this simple JavaScript library:</p><a name="I_programlisting18_d1e23462"></a>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>&lt;!DOCTYPE <span class="category2">html</span> PUBLIC "<span class="quote">-//W3C//DTD XHTML 1.0 Transitional//EN</span>" 
"<span class="quote">http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd</span>"&gt;

&lt;<span class="category2">html</span> xmlns="<span class="quote">http://www.w3.org/1999/xhtml</span>"&gt;
&lt;head&gt;
&lt;meta http-equiv="<span class="quote">Content-Type</span>" content="<span class="quote">text/html; charset=utf-8</span>" /&gt;

&lt;link rel="<span class="quote">stylesheet</span>" <span class="category2">type</span>="<span class="quote">text/css</span>" href="<span class="quote">css/main.css</span>"/&gt;

&lt;script <span class="category2">type</span>="<span class="quote">text/javascript</span>" src="<span class="quote">FlickrBadge.js</span>"&gt;&lt;/script&gt;

&lt;script
src='<span class="quote">http://api.flickr.com/services/feeds/photos_public.gne?id=44124469126@N01&amp;amp;format=json</span>'
<span class="category2">type</span>='<span class="quote">text/javascript</span>'&gt;&lt;/script&gt;

&lt;title&gt;Flickr Badge&lt;/title&gt;
&lt;/head&gt;

&lt;body&gt;
&lt;/body&gt;
&lt;/<span class="category2">html</span>&gt;</pre>
</code>

</div></div>

<p>This HTML page doesn&#8217;t specify any content in its body. All the work is carried out by the JavaScript contained in the <code class="filename">FlickrBadge.js</code> file. The <code class="filename">main.css</code> file applies a style formation to the page with the following CSS syntax:</p><a name="I_programlisting18_d1e23472"></a>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>body {padding:0; <span class="category2">font</span>: 12px Arial, Helvetica, Sans serif; <span class="category2">color</span>:#666666;}

.flickr_badge_image {<span class="category2">text</span>-<span class="category2">align</span>:center !important;display: inline;<span class="category2">list</span>-style-<span class="category2">type</span>: none;}

.flickr_badge_image img {<span class="category2">border</span>: 1px solid black !important;}

#flickr_badge_uber_wrapper {<span class="category2">width</span>:120px;}
#flickr_www {display:block; <span class="category2">text</span>-<span class="category2">align</span>:center; padding:0 10px 0 10px !important; 
 <span class="category2">font</span>: 11px Arial, Helvetica, Sans serif !important; <span class="category2">color</span>:#3993ff !important;}

#flickr_badge_uber_wrapper a:hover,
#flickr_badge_uber_wrapper a:link,
#flickr_badge_uber_wrapper a:active,
#flickr_badge_uber_wrapper a:visited {<span class="category2">text</span>-decoration:none !important; <span class="category2">background</span>:inherit 
 !important;<span class="category2">color</span>:#3993ff;}
#flickr_badge_wrapper {<span class="category2">background</span>-<span class="category2">color</span>:#ffffff;<span class="category2">border</span>: solid 1px #000000}

#flickr_badge_source {padding:0 !important; <span class="category2">font</span>: 11px Arial, Helvetica, Sans serif 
 !important; <span class="category2">color</span>:#666666 !important;<span class="category2">width</span>: 190px; margin: 0; padding: 0;}</pre>
</code>

</div></div></div></div></div>

<div style="width:520px; overflow: auto; padding: 10px 15px; border-top: 1px solid #ccc; border-bottom: 1px solid #ccc; margin-bottom: 15px;"><a href="http://oreilly.com/catalog/9780596522506/?CMP=ILC-dm_nav_related-books" target="_blank"><img border="0" style="float: right;" src="http://www.oreilly.com/catalog/covers/9780596522506_thumb.gif" /></a>
<p><strong>Go to the <a href="http://oreilly.com/catalog/9780596522506/?CMP=ILC-dm_nav_related-books" target="_blank">catalog page</a> for the Adobe AIR 1.5 Cookbook. Download the <a href="http://cachefly.oreilly.com/digitalmedia/9780596522506/9780596522506_bonus_ch18.pdf" target="_blank">PDF</a> of this entire chapter. <a href="http://oreilly.com/catalog/9780596522506/toc.html" target="_blank">View</a> the book's table of contents.</strong></p><!--p><strong>Skip to another section of the Adobe AIR 1.5 Cookbook, Chapter 18:</strong><br /><a href="http://insideria.com/2009/01/ch-18-yahoo-maps-web-services.html">Consuming Yahoo Maps Web Services</a> | <a href="http://insideria.com/2009/01/ch-18-consuming-twitter-apis.html">Consuming Twitter APIs</a></p--></div>

<p><a href="http://www.insideria.com/david-tucker/">Read more from 
David Tucker</a>.
<span class="stay-connected" style="padding: 0px; float: none;">
<a href="http://www.insideria.com/david-tucker/atom.xml" onmouseover="showIconLabel(this);" onmouseout="hideIconLabel();">
<img src="http://www.insideria.com/riaimages/rss_icon.png" alt="David Tucker's Atom feed" title=""/></a></span></p>

<p><a href="http://www.insideria.com/rich-tretola/">Read more from 
Rich Tretola</a>.
<span class="stay-connected" style="padding: 0px; float: none;">
<a href="http://www.insideria.com/rich-tretola/atom.xml" onmouseover="showIconLabel(this);" onmouseout="hideIconLabel();">
<img src="http://www.insideria.com/riaimages/rss_icon.png" alt="Rich Tretola's Atom feed" title=""/></a> 
<a href="http://twitter.com/richtretola" onmouseover="showIconLabel(this);"  onmouseout="hideIconLabel();">
<img src="http://www.insideria.com/riaimages/icon_twitter.gif" alt="richtretola on Twitter" title=""/></a>					
</span></p>
 
]]>
      
    </content>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.34951-comment:2054999</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.34951" type="text/html" href="http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html#comment-2054999" />
    <title>Comment from Web application development on 2009-03-12</title>
    <author>
        <name>Web application development</name>
        <uri>http://www.sblsoftware.com/web-development.aspx</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://www.sblsoftware.com/web-development.aspx">
        <![CDATA[<p>Quite informative .  Thanks for sharing.</p>

<p>Regards,<br />
Software<br />
<a href="http://www.sblsoftware.com/embedded-prog.aspx">http://www.sblsoftware.com/embedded-prog.aspx</a></p>]]>
    </content>
    <published>2009-03-12T07:09:09Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.34951-comment:2055940</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.34951" type="text/html" href="http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html#comment-2055940" />
    <title>Comment from ilja.panin on 2009-03-25</title>
    <author>
        <name>ilja.panin</name>
        <uri>http://the33cows.com</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://the33cows.com">
        <![CDATA[<p>Great book.<br />
Cool information about flickr.</p>

<p>Usefull information I will use it in my new project!</p>]]>
    </content>
    <published>2009-03-25T16:56:24Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.34951-comment:2068097</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.34951" type="text/html" href="http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html#comment-2068097" />
    <title>Comment from Roulette playing strategy on 2009-07-11</title>
    <author>
        <name>Roulette playing strategy</name>
        <uri>http://www.playing-roulette.net</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://www.playing-roulette.net">
        <![CDATA[<p>The application has a Combo Box control to allow the user to launch the search by using the text or a tag (inserted by the user) as a parameter in a Text Input control. The search on the Flick web services actually occurs when the star tNew Search method is invoked, triggered by the click event of the Button control his simple smashup implements and consumes only one method from the Flickr APIs. You could improve it by adding remote features and by exploiting AIR SDKs to allow users to save images locally or create a local database with Sq Lite to store their favorite images.</p>]]>
    </content>
    <published>2009-07-11T10:15:53Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.34951-comment:2068098</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.34951" type="text/html" href="http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html#comment-2068098" />
    <title>Comment from  roulette downloads on 2009-07-11</title>
    <author>
        <name> roulette downloads</name>
        <uri>http://www.roulette-download.com</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://www.roulette-download.com">
        <![CDATA[<p>l. The search on the Flick web services actually occurs when the star tNew Search method is invoked, triggered by the click event of the Button control his simple smashup implements and consumes only one method from the Flickr APIs. You could improve it by adding remote features and by exploiting AIR SDKs to allow users to save images locally or create a local database with Sq Lite to store their favorite images...<br />
<a href="http://www.roulette-download.com">http://www.roulette-download.com</a></p>]]>
    </content>
    <published>2009-07-11T10:20:16Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.34951-comment:2094217</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.34951" type="text/html" href="http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html#comment-2094217" />
    <title>Comment from Cosmetic dentists Palm beach on 2009-09-12</title>
    <author>
        <name>Cosmetic dentists Palm beach</name>
        <uri>http://www.lernerlemongello.com/</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://www.lernerlemongello.com/">
        <![CDATA[<p>I am also using Flickr on my blogs. The Flickr API exposes identifiers for users, photos, photosets and other uniquely identifiable objects. These IDs should always be treated as opaque strings, rather than integers of any specific type. The format of the IDs can change over time, so relying on the current format may cause you problems in the future.</p>]]>
    </content>
    <published>2009-09-12T07:25:23Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.34951-comment:2104216</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.34951" type="text/html" href="http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html#comment-2104216" />
    <title>Comment from fit flops on 2009-09-18</title>
    <author>
        <name>fit flops</name>
        <uri>http://www.lookatmycrazyshoes.com</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://www.lookatmycrazyshoes.com">
        <![CDATA[<p>It is quite informative article. Adding data by two different sources are easy now with massup. Thanks for sharing it here.</p>]]>
    </content>
    <published>2009-09-18T16:05:46Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.34951-comment:2148620</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.34951" type="text/html" href="http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html#comment-2148620" />
    <title>Comment from Trish on 2009-10-20</title>
    <author>
        <name>Trish</name>
        <uri></uri>
    </author>
    <content type="html" xml:lang="en" xml:base="">
        <![CDATA[<p>The search on the Flick web services actually occurs when the star tNew Search method is invoked.<a href="http://www.pureresearchpapers.com/">Custom Research Paper</a><br />
</p>]]>
    </content>
    <published>2009-10-21T04:41:59Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.34951-comment:2154221</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.34951" type="text/html" href="http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html#comment-2154221" />
    <title>Comment from Geschenkideen on 2009-10-24</title>
    <author>
        <name>Geschenkideen</name>
        <uri>http://www.kultprodukte.de</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://www.kultprodukte.de">
        <![CDATA[<p>Well..according to Wikipedia, JSON is a lightweight computer data interchange format. It is a text-based, human-readable format to represent simple data structures and associative arrays (called objects). The JSON format is often used for transmitting structured data over a network connection in a process called serialization. Its main application is in Ajax web application programming, where it serves as an alternative to the XML format.<br />
Thanks<br />
</p>]]>
    </content>
    <published>2009-10-24T17:20:27Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.34951-comment:2156448</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.34951" type="text/html" href="http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html#comment-2156448" />
    <title>Comment from sem on 2009-10-26</title>
    <author>
        <name>sem</name>
        <uri>http://blog.csdn.net/hi3wsem</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://blog.csdn.net/hi3wsem">
        <![CDATA[<p>that's for sharing<br />
all the best~</p>]]>
    </content>
    <published>2009-10-26T07:40:58Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.34951-comment:2171657</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.34951" type="text/html" href="http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2009/03/ch-18-consuming-flickr-web-services.html#comment-2171657" />
    <title>Comment from Bob de Haan on 2009-11-04</title>
    <author>
        <name>Bob de Haan</name>
        <uri>http://www.leningwiki.nl</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://www.leningwiki.nl">
        <![CDATA[<p>I've been working on an flickr extension for MediaWiki on <a href="http://www.leningwiki.nl">LeningWiki</a>. Currently I have a problem figuring out to what extent copyright free images can be imported from the Flickr Api. Is this automatically done by the Flickr API, or should I use a restriction for that? For a Community integration this option is vital (you can't keep control on all image licenses if Flickr is integrated.)</p>

<p>Plz. contact me by email if you an answer for my problem</p>]]>
    </content>
    <published>2009-11-04T14:29:52Z</published>
  </entry>

</feed
