<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' version='2.0'><channel><atom:id>tag:blogger.com,1999:blog-8858725797618026895</atom:id><lastBuildDate>Tue, 25 Mar 2008 23:33:37 +0000</lastBuildDate><title>Marc's Musings</title><description/><link>http://www.rogue-development.com/blog/</link><managingEditor>Marc</managingEditor><generator>Blogger</generator><openSearch:totalResults>145</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-5651056291035664543</guid><pubDate>Mon, 24 Mar 2008 11:00:00 +0000</pubDate><atom:updated>2008-03-24T04:16:08.445-07:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>flex</category><category domain='http://www.blogger.com/atom/ns#'>AIR</category><title>AIR / Browser API example</title><description>&lt;div&gt;AIR / Browser API example&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;The &lt;a id="bw8j" href="http://www.rogue-development.com/blog/2008/03/interacting-with-air-app-from-browser.html" title="other day"&gt;other day&lt;/a&gt; I blogged about a &lt;a id="g_0." href="http://rogue-development.com/uploads/AirSwfAPI.zip" title="wrapper class"&gt;wrapper class&lt;/a&gt; that I wrote to handle the AIR / Browser integration API.  Below is an example of another class that I wrote that uses that wrapper class.  It's capable of detecting two different AIR applications, installing them, and running them.  It relies on the wrapper class to do all the heavy lifting, but I thought this might be a good example to help people get started.&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;div id="znci" style="margin-top: 0px; margin-bottom: 0px"&gt;&lt;/div&gt;&lt;div id="znci" style="margin-top: 0px; margin-bottom: 0px"&gt;&lt;span class="Apple-style-span" style="color: rgb(153, 0, 204); font-family: Monaco;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div id="znci" style="margin-top: 0px; margin-bottom: 0px"&gt;&lt;span class="Apple-style-span"  style=" ;font-family:Monaco;"&gt;&lt;span style="color: rgb(153, 0, 204)"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;package&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt; com.agileagenda.web&lt;span class="Apple-style-span" style="font-family: Georgia; "&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div id="znci" style="margin-top: 0px; margin-bottom: 0px"&gt;&lt;span class="Apple-style-span"  style=" ;font-family:Monaco;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;span class="Apple-style-span" style="font-family: Georgia; "&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div id="znci" style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px; margin-top: 0px; margin-bottom: 0px"&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;import&lt;/span&gt; com.roguedevelopment.air.AIRBrowserRuntime;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;import&lt;/span&gt; com.roguedevelopment.air.AIRBrowserRuntimeEvent;&lt;/p&gt;&lt;p style=" min-height: 15px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;import&lt;/span&gt; flash.events.IOErrorEvent;&lt;/p&gt;&lt;p style=" min-height: 15px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(153, 0, 204)"&gt;class&lt;/span&gt; InstalledApplications&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;{&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0, 51, 255)"&gt;static&lt;/span&gt; &lt;span style="color: rgb(51, 153, 102)"&gt;function&lt;/span&gt; &lt;span style="color: rgb(0, 51, 255)"&gt;get&lt;/span&gt; instance() : InstalledApplications&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;{&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;if&lt;/span&gt;( _instance == &lt;span style="color: rgb(0, 51, 255)"&gt;null&lt;/span&gt; ) { _instance = &lt;span style="color: rgb(0, 51, 255)"&gt;new&lt;/span&gt; InstalledApplications(); }&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;return&lt;/span&gt; _instance;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;}&lt;/p&gt;&lt;p style=" min-height: 15px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;protected&lt;/span&gt; &lt;span style="color: rgb(0, 51, 255)"&gt;static&lt;/span&gt; &lt;span style="color: rgb(102, 153, 204)"&gt;var&lt;/span&gt; _instance:InstalledApplications = &lt;span style="color: rgb(0, 51, 255)"&gt;null&lt;/span&gt;;&lt;/p&gt;&lt;p style=" min-height: 15px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;protected&lt;/span&gt; &lt;span style="color: rgb(102, 153, 204)"&gt;var&lt;/span&gt; api:AIRBrowserRuntime;   &lt;/p&gt;&lt;p style=" color: rgb(153, 0, 0); margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;protected&lt;/span&gt; &lt;span style="color: rgb(0, 51, 255)"&gt;static&lt;/span&gt; &lt;span style="color: rgb(0, 51, 255)"&gt;const&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0)"&gt; PUBLISHER_ID:String = &lt;/span&gt;"F49A4D8DF78A1FEE7A3BE440DC11BAB18D922274.1"&lt;span style="color: rgb(0, 0, 0)"&gt;;&lt;/span&gt;&lt;/p&gt;&lt;p style=" color: rgb(153, 0, 0); margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;protected&lt;/span&gt; &lt;span style="color: rgb(0, 51, 255)"&gt;static&lt;/span&gt; &lt;span style="color: rgb(0, 51, 255)"&gt;const&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0)"&gt; TRACKER_ID:String =  &lt;/span&gt;"com.agileagenda.AgileTracker"&lt;span style="color: rgb(0, 0, 0)"&gt;;&lt;/span&gt;&lt;/p&gt;&lt;p style=" color: rgb(153, 0, 0); margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;protected&lt;/span&gt; &lt;span style="color: rgb(0, 51, 255)"&gt;static&lt;/span&gt; &lt;span style="color: rgb(0, 51, 255)"&gt;const&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0)"&gt; MAIN_APP_ID:String = &lt;/span&gt;"com.agileagenda.AgileAgenda"&lt;span style="color: rgb(0, 0, 0)"&gt;;&lt;/span&gt;&lt;/p&gt;&lt;p style=" min-height: 15px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=" color: rgb(153, 0, 0); margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;protected&lt;/span&gt; &lt;span style="color: rgb(0, 51, 255)"&gt;static&lt;/span&gt; &lt;span style="color: rgb(0, 51, 255)"&gt;const&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0)"&gt; AGILE_AGENDA_INSTALL:String =  &lt;/span&gt;"http://www.agileagenda.com/download/AgileAgenda.air"&lt;span style="color: rgb(0, 0, 0)"&gt;;&lt;/span&gt;&lt;/p&gt;&lt;p style=" color: rgb(153, 0, 0); margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;protected&lt;/span&gt; &lt;span style="color: rgb(0, 51, 255)"&gt;static&lt;/span&gt; &lt;span style="color: rgb(0, 51, 255)"&gt;const&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0)"&gt; AGILE_TRACKER_INSTALL:String = &lt;/span&gt;"http://www.agileagenda.com/download/AgileTracker.air"&lt;span style="color: rgb(0, 0, 0)"&gt;;&lt;/span&gt;&lt;/p&gt;&lt;p style=" min-height: 15px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;[&lt;span style="color: rgb(0, 51, 255)"&gt;Bindable&lt;/span&gt;] &lt;span style="color: rgb(0, 51, 255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(102, 153, 204)"&gt;var&lt;/span&gt; isReady:Boolean=&lt;span style="color: rgb(0, 51, 255)"&gt;false&lt;/span&gt;;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;[&lt;span style="color: rgb(0, 51, 255)"&gt;Bindable&lt;/span&gt;] &lt;span style="color: rgb(0, 51, 255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(102, 153, 204)"&gt;var&lt;/span&gt; hasAIR:Boolean;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;[&lt;span style="color: rgb(0, 51, 255)"&gt;Bindable&lt;/span&gt;] &lt;span style="color: rgb(0, 51, 255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(102, 153, 204)"&gt;var&lt;/span&gt; agileAgendaVersion:String = &lt;span style="color: rgb(153, 0, 0)"&gt;""&lt;/span&gt;;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;[&lt;span style="color: rgb(0, 51, 255)"&gt;Bindable&lt;/span&gt;] &lt;span style="color: rgb(0, 51, 255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(102, 153, 204)"&gt;var&lt;/span&gt; agileTrackerVersion:String = &lt;span style="color: rgb(153, 0, 0)"&gt;""&lt;/span&gt;;&lt;/p&gt;&lt;p style=" min-height: 15px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(51, 153, 102)"&gt;function&lt;/span&gt; InstalledApplications()&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;{&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;  api = &lt;span style="color: rgb(0, 51, 255)"&gt;new&lt;/span&gt; AIRBrowserRuntime();&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;  api.addEventListener(AIRBrowserRuntimeEvent.READY, onReady );&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;  api.addEventListener(IOErrorEvent.IO_ERROR, onAirFail );&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;  api.load();&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;}&lt;/p&gt;&lt;p style=" min-height: 15px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=" min-height: 15px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;protected&lt;/span&gt; &lt;span style="color: rgb(51, 153, 102)"&gt;function&lt;/span&gt; onAirFail(event:IOErrorEvent) : &lt;span style="color: rgb(0, 51, 255)"&gt;void&lt;/span&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;{&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(204, 102, 102)"&gt;  trace&lt;/span&gt;( event.text );&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;}&lt;/p&gt;&lt;p style=" min-height: 15px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;protected&lt;/span&gt; &lt;span style="color: rgb(51, 153, 102)"&gt;function&lt;/span&gt; onReady(event:AIRBrowserRuntimeEvent ) : &lt;span style="color: rgb(0, 51, 255)"&gt;void&lt;/span&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;{&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;  hasAIR = api.getStatus() == &lt;span style="color: rgb(153, 0, 0)"&gt;'installed'&lt;/span&gt;;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;  isReady = &lt;span style="color: rgb(0, 51, 255)"&gt;true&lt;/span&gt;;&lt;/p&gt;&lt;p style=" min-height: 15px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;  api.addEventListener(AIRBrowserRuntimeEvent.APP_VERSION_RESULT, onTrackerVersionResult );&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;  api.getApplicationVersion( TRACKER_ID, PUBLISHER_ID );&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;}&lt;/p&gt;&lt;p style=" min-height: 15px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;/p&gt;&lt;p style=" min-height: 15px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;protected&lt;/span&gt; &lt;span style="color: rgb(51, 153, 102)"&gt;function&lt;/span&gt; onTrackerVersionResult(event:AIRBrowserRuntimeEvent) : &lt;span style="color: rgb(0, 51, 255)"&gt;void&lt;/span&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;{&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(204, 102, 102)"&gt;  trace&lt;/span&gt;(&lt;span style="color: rgb(153, 0, 0)"&gt;"Tracker version installed: "&lt;/span&gt; + event.detectedVersion );&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;  agileTrackerVersion = event.detectedVersion&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;  api.removeEventListener(AIRBrowserRuntimeEvent.APP_VERSION_RESULT, onTrackerVersionResult );&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;  api.addEventListener(AIRBrowserRuntimeEvent.APP_VERSION_RESULT, onAppVersionResult );&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;  api.getApplicationVersion( MAIN_APP_ID, PUBLISHER_ID );&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;}&lt;/p&gt;&lt;p style=" min-height: 15px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;protected&lt;/span&gt; &lt;span style="color: rgb(51, 153, 102)"&gt;function&lt;/span&gt; onAppVersionResult(event:AIRBrowserRuntimeEvent ) : &lt;span style="color: rgb(0, 51, 255)"&gt;void&lt;/span&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;{&lt;/p&gt;&lt;p style=" color: rgb(153, 0, 0); margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(204, 102, 102)"&gt;  trace&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0)"&gt;(&lt;/span&gt;"Application version installed: "&lt;span style="color: rgb(0, 0, 0)"&gt; + event.detectedVersion );&lt;/span&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;  agileAgendaVersion  = event.detectedVersion&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;  api.removeEventListener(AIRBrowserRuntimeEvent.APP_VERSION_RESULT, onAppVersionResult );&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;}&lt;/p&gt;&lt;p style=" min-height: 15px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(51, 153, 102)"&gt;function&lt;/span&gt; launchAgileAgenda( args:Array ) : &lt;span style="color: rgb(0, 51, 255)"&gt;void&lt;/span&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;{&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;  api.launchApplication( MAIN_APP_ID, PUBLISHER_ID, args );&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;}&lt;/p&gt;&lt;p style=" min-height: 15px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(51, 153, 102)"&gt;function&lt;/span&gt; launchAgileTracker( args:Array ) : &lt;span style="color: rgb(0, 51, 255)"&gt;void&lt;/span&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;{&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;  api.launchApplication( TRACKER_ID, PUBLISHER_ID, args );&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;}&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt; &lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(51, 153, 102)"&gt;function&lt;/span&gt; installAgileAgenda(args:Array) : &lt;span style="color: rgb(0, 51, 255)"&gt;void&lt;/span&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;{&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;  api.installApplication(AGILE_AGENDA_INSTALL, &lt;span style="color: rgb(153, 0, 0)"&gt;"1.0"&lt;/span&gt;, args );&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;}&lt;/p&gt;&lt;p style=" min-height: 15px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span style="color: rgb(0, 51, 255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(51, 153, 102)"&gt;function&lt;/span&gt; installAgileTracker(args:Array) : &lt;span style="color: rgb(0, 51, 255)"&gt;void&lt;/span&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;{&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;  api.installApplication(AGILE_TRACKER_INSTALL, &lt;span style="color: rgb(153, 0, 0)"&gt;"1.0"&lt;/span&gt;, args );&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;}&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p style=" min-height: 15px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;}&lt;/p&gt;&lt;p style=" margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;}&lt;/p&gt;&lt;div&gt;&lt;span class="Apple-style-span"   style="font-family:Monaco;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:11px;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description><link>http://www.rogue-development.com/blog/2008/03/air-browser-api-example-other-day-i.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-4114516776249349273</guid><pubDate>Sun, 23 Mar 2008 15:25:00 +0000</pubDate><atom:updated>2008-03-23T06:48:23.690-07:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>flex</category><category domain='http://www.blogger.com/atom/ns#'>AIR</category><title>Interacting with an AIR app from a browser based app</title><description>&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Interacting with an AIR app from a browser based app&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;            We've all seen the AIR installation badges that let you install an AIR application from a website.  But the API exposed to do that lets you do more than just a simple badge.  I've been working on a web-based service for AgileAgenda.  One of the components of that is to manage the list of files you've saved to the service and be able to open those in the desktop AIR application.  So right from within the online Flex based app it sure would be nice to detect if the application is installed, give the user the option to install, and then launch it for them and automatically open the desired file.  Something like this...&lt;div&gt;&lt;div id="x6zu"&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="h9ls"&gt;&lt;a target="_blank" href="http://www.blogger.com/File?id=dfxczdkr_16gxh5mvcz"&gt;&lt;img src="http://docs.google.com/File?id=dfxczdkr_16gxh5mvcz" style="width: 640px; height: 373.145px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="h9ls"&gt;To implement that we need to:&lt;/div&gt;&lt;div id="h9ls"&gt;&lt;ol&gt;&lt;li&gt;Detect whether or not the application is installed.&lt;/li&gt;&lt;li&gt;Display the version number if it is.  (Disable the "Open schedule in..." button if it's not)&lt;/li&gt;&lt;li&gt;When clicking on the "Open" link, launch the application with a few parameters so it know what to open.&lt;/li&gt;&lt;li&gt;When clicking on the "Install" link, install the application and pass a few parameters so it know what to open when it launches directly after the install.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;Doing things like that falls outside of the normal AS3 web development API.  But Adobe provides a swf that you can load at runtime and them make calls to.  You can read all about that over here: &lt;a id="hjad" href="http://livedocs.adobe.com/air/1/devappshtml/help.html?content=distributing_apps_3.html" target="_blank" title="http://livedocs.adobe.com/air/1/devappshtml/help.html?content=distributing_apps_3.html"&gt;http://livedocs.adobe.com/air/1/devappshtml/help.html?content=distributing_apps_3.html.&lt;/a&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;But there's an annoying thing with that.  You need to load up that remote swf and then access it like a dynamic object.  No compiler-time type checking.  Not the standard event mechanism.  And no code-completion from within Flex Builder.&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;Luckily for you, I went through and made a wrapper class that you can download from here:&lt;/div&gt;&lt;div&gt;&lt;a id="imj5" href="http://rogue-development.com/uploads/AirSwfAPI.zip" title="http://rogue-development.com/uploads/AirSwfAPI.zip" target="_blank"&gt;http://rogue-development.com/uploads/AirSwfAPI.zip&lt;/a&gt; &lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;This will handle the loading of the remote swf, dispatching events when it loads (or fails to load) and then wraps the API for the entire process.  There's nothing revolutionary in there, it's mostly takendirectly from that livedocs page above.&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;So now that you have that handy-dandy wrapper class, lets look at how to actually get something done.  &lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;b&gt;Setting up your AIR application to work with your website (&lt;span class="Apple-style-span"  style="color:#990000;"&gt;Important&lt;/span&gt;)&lt;/b&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;First thing, go into your AIR application's -app.xml file and make sure allowBrowserInvocation is set to true.  By default it's set to false.  &lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#3f7f7f;"&gt;&lt;span style="color:#008080;"&gt;&amp;lt;&lt;/span&gt;allowBrowserInvocation&lt;span style="color:#008080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#000000;"&gt;true&lt;/span&gt;&lt;span style="color:#008080;"&gt;&amp;lt;/&lt;/span&gt;allowBrowserInvocation&lt;span style="color:#008080;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#3f7f7f;"&gt;&lt;span class="Apple-style-span"  style="color:#008080;"&gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;If you don't do this, you won't even be able to query version information on your application.  But, be careful.  By doing this you're letting any website launch your AIR application from a web page. You need to be careful in how much your app trusts command line arguments passed to it.  For instance, you should never pass a file to delete on the command line. &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;Now that you've set &lt;i&gt;allowBrowserInvocation&lt;/i&gt; to true, create a new .air file and post that to your website somewhere.&lt;/p&gt;&lt;p style="text-align: auto;margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align: auto;margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"  style="font-family:Verdana;"&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Using the wrapper class to interact with your application&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align: auto;margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align: auto;margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt;Either open an existing Flex or Actionscript project in FlexBuilder and put the source to the AIRBrowserRuntime.as somewhere that the compiler will find it.  Somewhere in your main application, create an AIRBrowserRuntime object, set some event listeners, and call the load() method to load the air.swf file from Adobe's servers.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align: auto;margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align: auto;margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt;var api:&lt;span class="Apple-style-span"   style=" ;font-family:Monaco;font-size:11px;"&gt;AIRBrowserRuntime;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align: auto;margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt; &lt;/p&gt;&lt;p style="text-align: auto;margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;...&lt;/p&gt;&lt;p style="text-align: auto;margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt; &lt;/p&gt;&lt;p style="text-align: auto;margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;/p&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;api = &lt;span style="color:#0033ff;"&gt;new&lt;/span&gt; AIRBrowserRuntime();&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;api.addEventListener(AIRBrowserRuntimeEvent.READY, onReady );&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-style-span"  style="color:#38761D;"&gt;&lt;i&gt;// Optional: api.addEventListener(IOErrorEvent.IO_ERROR, onAirFail );&lt;/i&gt;&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;api.load();&lt;/p&gt;&lt;/span&gt;&lt;p&gt; &lt;/p&gt;&lt;p style="text-align: auto;margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align: auto;margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align: auto;margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt;Once the READY event is dispatched, you can start calling methods to query application versions, install apps, or launch applications.  &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align: auto;margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align: auto;margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"  style="font-family:Verdana;"&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Checking if AIR is installed&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="text-align: auto;margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;To see if the AIR runtime is installed, call the &lt;i&gt;getStatus&lt;/i&gt;() method.  It will return one of three values.&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt;available - The AIR runtime can be installed on this computer but currently it is not installed&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt;unavailable - The AIR runtime cannot be installed on this computer.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt;installed - The AIR runtime is installed on this computer.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt;Example:&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt;switch(  api.getStatus()  )&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt;   case "available": trace("AIR is available, but not installed."); break;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt;   case "unavailable": trace("AIR is not available for this computer."); break;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt;   case "installed": trace("AIR is already installed on this computer."); break;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #3f5fbf"&gt; &lt;/p&gt;&lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:Verdana;"&gt;Checking the version of an installed application&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #3f5fbf"&gt; &lt;/p&gt;&lt;p&gt;The getApplicationVersion method will check to see if a given application is installed and give you the version if it is.  This method operates asynchronously so you have to create an event listener before you call it.  If you look at the method signature...&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #3f5fbf"&gt; &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span style="color:#0033ff;"&gt;public&lt;/span&gt; &lt;span style="color:#339966;"&gt;function&lt;/span&gt; getApplicationVersion(applicationID:String, publisherID:String) : &lt;span style="color:#0033ff;"&gt;void&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;  &lt;/p&gt; &lt;p style="text-align: auto;margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px"&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span class="Apple-style-span"   style="font-family:Verdana;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style="font-size:13px;"&gt;You'll see that it takes an applicationID and a publisherID.  The applicationID is just value of the &amp;lt;id&amp;gt; tag of your application descriptor (the -app.xml file).  It'll probably be something like this, but you need to make sure to make each application unique:&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span style="color:#008080;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#3f7f7f;"&gt;id&lt;/span&gt;&lt;span style="color:#008080;"&gt;&amp;gt;&lt;/span&gt;com.agileagenda.AgileTracker&lt;span style="color:#008080;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#3f7f7f;"&gt;id&lt;/span&gt;&lt;span style="color:#008080;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;The publisherID is a little trickier to find.  That doesn't get assigned until you actually sign your .AIR file with your code-signing key.  I know of 2 ways of finding it, but there's probably an easier way (please leave a comment if you know how).&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;&lt;span class="Apple-style-span"  style="color:#660000;"&gt;&lt;i&gt;Warning about Publisher ID:  If you change the key your sign your app with, the publisher ID will change.&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;&lt;b&gt;Option 1: Get it at runtime.&lt;/b&gt;&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;In your application's main MXML throw up an Alert message with the publisher ID.  Then build a .air, install the .air and run it.  Copy &amp;amp; Paste the result.  Example:&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#990000;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;mx:WindowedApplication&lt;/span&gt;&lt;span style="color:#000000;"&gt; xmlns:mx="&lt;/span&gt;http://www.adobe.com/2006/mxml&lt;span style="color:#000000;"&gt;" &lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;    creationComplete="init()" &lt;span class="Apple-style-span" style="color: rgb(0, 0, 255)"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-style-span"  style="color:#0000FF;"&gt; &lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #990000"&gt;&lt;/p&gt;&lt;span class="Apple-style-span"  style="color:#0000FF;"&gt;&lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#006633;"&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 255)"&gt;  &amp;lt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 51)"&gt;mx:Script&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Verdana;font-size:13px;"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Monaco;font-size:11px;"&gt;  &amp;lt;![CDATA[&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt; &lt;/p&gt;&lt;/span&gt;&lt;p&gt; &lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #990000"&gt;&lt;/p&gt;&lt;span class="Apple-style-span"  style="color:#0000FF;"&gt;&lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#0033ff;"&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 255)"&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 51, 255)"&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 255)"&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 51, 255)"&gt;    protected &lt;span style="color:#339966;"&gt;function&lt;/span&gt;&lt;span style="color:#000000;"&gt; init() : &lt;/span&gt;void &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Verdana;font-size:13px;"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Monaco;font-size:11px;"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Verdana;font-size:13px;"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Monaco;font-size:11px;"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Verdana;font-size:13px;"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Monaco;font-size:11px;"&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Verdana;font-size:13px;"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Monaco;font-size:11px;"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Verdana;font-size:13px;"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Monaco;font-size:11px;"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Verdana;font-size:13px;"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Monaco;font-size:11px;"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Verdana;font-size:13px;"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Monaco;font-size:11px;"&gt;      Alert.show( nativeApplication.publisherID);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Verdana;font-size:13px;"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Monaco;font-size:11px;"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Verdana;font-size:13px;"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Monaco;font-size:11px;"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Verdana;font-size:13px;"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Monaco;font-size:11px;"&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;/span&gt;&lt;p&gt; &lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #990000"&gt;&lt;/p&gt;&lt;span class="Apple-style-span"  style="color:#0000FF;"&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;  ]]&amp;gt;&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#006633;"&gt;&lt;span class="Apple-style-span"   style="color: rgb(0, 0, 255);  font-family:Verdana;font-size:13px;"&gt;&lt;span class="Apple-style-span"   style="color: rgb(0, 102, 51);  font-family:Monaco;font-size:11px;"&gt;  &amp;lt;/mx:Script&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #006633"&gt; &lt;/p&gt;&lt;/span&gt;&lt;p&gt; &lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #990000"&gt;&lt;/p&gt;&lt;span class="Apple-style-span"  style="color:#0000FF;"&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #0000ff"&gt;&amp;lt;/mx:WindowedApplication&amp;gt;&lt;/p&gt;&lt;/span&gt; &lt;p&gt; &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;Which results in something resembling:&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="znci"&gt;&lt;img src="http://docs.google.com/File?id=dfxczdkr_178g528pdz" style="width: 370px; height: 153px" /&gt;&lt;/div&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="znci"&gt;It's hard to see in that picture, but the publisher ID is: F49A4D8DF78A1FEE7A3BE440DC11BAB18D922274.1 as it wraps to two lines.&lt;/div&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="znci"&gt;&lt;b&gt;Option 2: Get it after install &lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="znci"&gt;This is probably a bit easier, but I'm not 100% sure where this directory goes on a windows box.&lt;/div&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="znci"&gt;On OSX (maybe on Windows, I'm not sure exactly where) the application storage directory that gets created for your application has the publisher ID appended to it.  So if you look in your user directory -&amp;gt; Library -&amp;gt; Preferences, you should see a directory that starts with your application ID and ends with your publisher ID.&lt;/div&gt;&lt;div id="znci"&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="aax4"&gt;&lt;img src="http://docs.google.com/File?id=dfxczdkr_18jfj8vg54" style="width: 737px; height: 126px" /&gt;&lt;/div&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="aax4"&gt;As you can see there, we get the same publisher ID value as Option #1.&lt;/div&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="aax4"&gt;&lt;b&gt;On to checking installed version&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="aax4"&gt;Now that you have your application ID and your publisher ID you can make a call from your web application to the API to request the installed version of your AIR application.  This operates asynchronously so you'll need an event listener for the result.&lt;/div&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="aax4"&gt;Example:&lt;/div&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="aax4"&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;api.addEventListener(AIRBrowserRuntimeEvent.APP_VERSION_RESULT, onTrackerVersionResult );&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;api.getApplicationVersion( &lt;span class="Apple-style-span" style="color: rgb(153, 0, 0)"&gt;"com.agileagenda.AgileTracker"&lt;/span&gt;, &lt;span class="Apple-style-span" style="color: rgb(153, 0, 0)"&gt;"F49A4D8DF78A1FEE7A3BE440DC11BAB18D922274.1"&lt;/span&gt; );&lt;/p&gt;&lt;/div&gt;&lt;div id="aax4"&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-style-span"  style="color:#0033FF;"&gt;...&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-style-span"  style="color:#0033FF;"&gt; &lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span style="color:#0033ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#339966;"&gt;function&lt;/span&gt; onTrackerVersionResult(event:AIRBrowserRuntimeEvent) : &lt;span style="color:#0033ff;"&gt;void&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;{&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;  &lt;span style="color:#cc6666;"&gt;trace&lt;/span&gt;(&lt;span style="color:#990000;"&gt;"Tracker version installed: "&lt;/span&gt; + event.detectedVersion );     &lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;}&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt; &lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;The event.detectedVersion that comes back will be the value in your application descriptor version tag.  Mine looks like this:&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt; &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#3f7f7f;"&gt;&lt;span style="color:#008080;"&gt;&amp;lt;&lt;/span&gt;version&lt;span style="color:#008080;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#000000;"&gt;v1&lt;/span&gt;&lt;span style="color:#008080;"&gt;&amp;lt;/&lt;/span&gt;version&lt;span style="color:#008080;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#3f7f7f;"&gt;&lt;span class="Apple-style-span"  style="color:#008080;"&gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;So the trace output looks like this:&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span class="Apple-style-span"  style="color:#073763;"&gt;Tracker version installed: v1&lt;/span&gt;&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Launching an installed AIR application&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="znci"&gt;Assuming you followed along in the previous section, you have an Application ID and a Publisher ID ready.  To launch an AIR app from a web app you just call&lt;/div&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="znci"&gt;&lt;b&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;api.launchApplication( &lt;span class="Apple-style-span" style="color: rgb(153, 0, 0)"&gt;"com.agileagenda.AgileTracker"&lt;/span&gt;, &lt;span class="Apple-style-span" style="color: rgb(153, 0, 0)"&gt;"F49A4D8DF78A1FEE7A3BE440DC11BAB18D922274.1"&lt;/span&gt; );&lt;/p&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="znci"&gt;launchApplication has a third, optional, parameter called arguments and is typed as an array.  Anything you pass into that will be passed along to the application in an INVOKE event.  This way you can pass information from the web application to the AIR application.  Example:&lt;/div&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="znci"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Monaco;font-size:11px;"&gt;api.launchApplication( &lt;span class="Apple-style-span" style="color: rgb(153, 0, 0)"&gt;"com.agileagenda.AgileTracker"&lt;/span&gt;, &lt;span class="Apple-style-span" style="color: rgb(153, 0, 0)"&gt;"F49A4D8DF78A1FEE7A3BE440DC11BAB18D922274.1", ["Argument1","Argument2" ]&lt;/span&gt; );&lt;/span&gt;&lt;/div&gt;&lt;div id="znci"&gt;Be careful, the arguments are &lt;b&gt;very restrictive&lt;/b&gt; in what characters can be passed.  Things like dashes, percent signs, underscores, all cause a runtime exception on the web application.  You're probably safest only using alphanumeric characters.  I haven't found a comprehensive list of what characters are or are not valid.  If someone has that, please leave a comment below.  This was done for security reasons.&lt;/div&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="znci"&gt;&lt;span class="Apple-style-span"  style="font-size:180%;"&gt;&lt;span class="Apple-style-span"  style="font-size:18px;"&gt;&lt;b&gt;Installing an AIR application&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="znci"&gt;To install an AIR application, all you need to do is call the &lt;span class="Apple-style-span"   style=" ;font-family:Monaco;font-size:11px;"&gt;&lt;i&gt;installApplication&lt;/i&gt; with the absolute URL to the .air file you want to install.  Example:&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="znci"&gt;&lt;span class="Apple-style-span"   style=" ;font-family:Monaco;font-size:11px;"&gt;api.installApplication("&lt;span class="Apple-style-span" style="color: rgb(153, 0, 0)"&gt;http://www.agileagenda.com/download/AgileTracker.air"&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;p&gt;This will take care of installing the AIR runtime, installing the application, and launching it for the first time.  installApplication has two more optional parameters.  The AIR runtime that the application requires, and arguments that can be passed to the application for it's first run.  Example:&lt;/p&gt;&lt;div id="znci"&gt; &lt;/div&gt;&lt;div id="znci"&gt;&lt;span class="Apple-style-span"&gt;api.installApplication("&lt;span class="Apple-style-span" style="color: rgb(153, 0, 0)"&gt;http://www.agileagenda.com/download/AgileTracker.air","1.0",["Arg1","Arg2"]&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div id="znci"&gt; &lt;/div&gt;&lt;div id="znci"&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;That's all there is to it.&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div id="znci"&gt;&lt;span class="Apple-style-span"  style="font-size:180%;"&gt;&lt;span class="Apple-style-span"  style="font-size:18px;"&gt;&lt;b&gt; &lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div id="znci"&gt;So that's it, pretty simple, huh?  You might also want to look into using a LocalConnection to do realtime communication between your web-app and your air-app once the air-app has been launched.  Recap of the links:&lt;/div&gt;&lt;div id="znci"&gt; &lt;/div&gt;&lt;div id="znci"&gt; &lt;/div&gt;&lt;div id="znci"&gt;Wrapper Class:&lt;/div&gt;&lt;div id="znci"&gt;&lt;a id="imj5" href="http://rogue-development.com/uploads/AirSwfAPI.zip" title="http://rogue-development.com/uploads/AirSwfAPI.zip" target="_blank"&gt;http://rogue-development.com/uploads/AirSwfAPI.zip&lt;/a&gt;&lt;/div&gt;&lt;div id="znci"&gt; &lt;/div&gt;&lt;div id="znci"&gt;Adobe's Documentation:&lt;/div&gt;&lt;div id="znci"&gt;&lt;a id="hjad" href="http://livedocs.adobe.com/air/1/devappshtml/help.html?content=distributing_apps_3.html" target="_blank" title="http://livedocs.adobe.com/air/1/devappshtml/help.html?content=distributing_apps_3.html"&gt;http://livedocs.adobe.com/air/1/devappshtml/help.html?content=distributing_apps_3.html&lt;/a&gt;&lt;/div&gt;&lt;div id="znci"&gt; &lt;/div&gt;&lt;div id="znci"&gt;My Blog (where any updates to the wrapper class will be posted)&lt;/div&gt;&lt;div id="znci"&gt;&lt;a id="tk_d" href="http://www.rogue-development.com/blog/" title="http://www.rogue-development.com/blog/"&gt;http://www.rogue-development.com/blog/&lt;/a&gt; &lt;/div&gt;&lt;div id="znci"&gt; &lt;/div&gt;&lt;div id="znci"&gt;The actual air.swf that does all the heavy lifting (This URL is wrong in some of the docs!)&lt;/div&gt;&lt;div id="znci"&gt;&lt;p&gt;http://airdownload.adobe.com/air/browserapi/air.swf&lt;/p&gt;&lt;/div&gt;&lt;div id="znci"&gt; &lt;/div&gt;&lt;div id="znci"&gt; &lt;/div&gt;&lt;div id="znci"&gt; &lt;/div&gt;&lt;div id="znci"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="znci"&gt; &lt;/div&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="znci"&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description><link>http://www.rogue-development.com/blog/2008/03/interacting-with-air-app-from-browser.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-4409398348761605357</guid><pubDate>Sun, 23 Mar 2008 01:50:00 +0000</pubDate><atom:updated>2008-03-22T19:09:59.899-07:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>flex</category><category domain='http://www.blogger.com/atom/ns#'>ObjectHandles</category><title>ObjectHandles Demo</title><description>Here's a short demo of some of the stuff that &lt;a href="http://www.rogue-development.com/objectHandles.html"&gt;ObjectHandles&lt;/a&gt; (my Flex library for moving &amp;amp; resizing stuff) can do with a very minimal amount of code.  &lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="350"&gt; &lt;param name="movie" value="http://www.youtube.com/v/1N9YppLtmIw"&gt;  &lt;embed src="http://www.youtube.com/v/1N9YppLtmIw" type="application/x-shockwave-flash" width="425" height="350"&gt;&lt;/embed&gt;  &lt;/object&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;The custom things I did:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Has a MOVING / RESIZING event handler to show a custom tooltip (hides the tooltip on MOVED / RESIZED)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Has custom resize handle images that look like grey horizontal bars&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Only allows vertical resizing (allowHResize = false).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;On a MOVED event, the objects have an animation that snaps them to a column.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;It's a little hard to see in that video, but the duration &amp;amp; start time in the tooltip update as you move or resize the boxes around.&lt;/div&gt;&lt;/div&gt;</description><link>http://www.rogue-development.com/blog/2008/03/objecthandles-demo.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-4432403924293833544</guid><pubDate>Sat, 22 Mar 2008 13:51:00 +0000</pubDate><atom:updated>2008-03-22T19:10:09.924-07:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>BFUG</category><title>Boston Flex Users Group</title><description>&lt;div&gt;I saw this posted today by &lt;a href="http://www.joeberkovitz.com/"&gt;Joe Berkovitz&lt;/a&gt; and it made my day.  There's a new Flex users' group starting up and the best part, it's in Newton which is a few short miles from where I work.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.bostonfug.org/"&gt;http://www.bostonfug.org/&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</description><link>http://www.rogue-development.com/blog/2008/03/boston-flex-users-group.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-7088551631819820600</guid><pubDate>Mon, 17 Mar 2008 17:00:00 +0000</pubDate><atom:updated>2008-03-18T05:31:37.931-07:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>rss</category><title>The power of RSS</title><description>A year ago I didn't read any RSS feed.  I browsed the internet like it was meant to be browsed, through websites!  I read 3, maybe 4, sites daily.  I occasionally viewed another dozen less frequently.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.rogue-development.com/blog/uploaded_images/webclips-790973.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://www.rogue-development.com/blog/uploaded_images/webclips-790968.PNG" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;A year ago I started to add sites to my "web clips" bar on the top of my GMail account.  They were all development related sites, mostly flash/flex.  Pretty soon I had a dozen or so and I found myself clicking that little "&gt;" button on the webclips bar over and over and over again to see more and more and more.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.rogue-development.com/blog/uploaded_images/reader-773774.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://www.rogue-development.com/blog/uploaded_images/reader-773766.PNG" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Six months ago I switched to &lt;a href="http://www.google.com/reader/view/"&gt;Google Reader&lt;/a&gt;.  I copied my list of RSS feeds from web-clips.  And I added a few more.  This was great, way easier reading them from the webclips interface.  I subscribed to my Bugzilla bug list at work, no more refreshing a page to get a list.  I unsubscribed from a few mailing lists I was a part of and picked up their feeds.&lt;br /&gt;&lt;br /&gt;I now had a single, central, place to go to look for news items about software development.&lt;br /&gt;&lt;br /&gt;A month or two after that I started adding feeds for other topics besides development.  Project management, web comics, even a blog from a guy making art out of &lt;a href="http://bentobjects.blogspot.com/2008/03/example-of-some-preliminary-doodles.html"&gt;bent objects&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It's around that time that the RSS reader became my first destination when browsing the web for any reason.  I wouldn't hit slashdot, or cnn, or whatever.  I'd hit my RSS feeds.  I'd be able to quickly browse over more content, in nice neat categories, than I ever could before.&lt;br /&gt;&lt;br /&gt;Now, I have two main jumping points for the web.  1) Google when I'm searching for a specific thing.  2) My RSS reader for everything else.&lt;br /&gt;&lt;br /&gt;So when I go to a website that I might want to remember in the future, I don't instinctively go for that add-bookmark button.  I look for the little "RSS" icon.&lt;br /&gt;&lt;br /&gt;I think more and more people are ending up like this.  I was certainly a late-comer to the world of RSS in the group of "geeks", but I wonder if we'll hit a point like the www hit when only geeks used a web browser, to everyone using a web browser.&lt;br /&gt;&lt;br /&gt;I ran a survey for AgileAgenda on what features people are interested in seeing in future versions.  Out of curiosity I put in "Subscribe to schedules through an RSS feed."   Amazingly, that was the only option with near 100% "yes" votes.  I didn't even know what that means.  I've talked to a few people and they all thought it was a great idea, but then I pressed on why.  Nobody seemed to quite know what type of data those feeds should have in them.  &lt;br /&gt;&lt;br /&gt;It feels like the time we hit a few years back when "everything" has to be on the web.  But now it's "everything" has to be in an RSS feed.  When deciding to put things in an RSS feed, I hope our web-lessons help and we can tell between what is an Amazon.com idea, or a Pets.com idea.&lt;br /&gt;&lt;br /&gt;&lt;div&gt;If you're writing Flex/Flash code to parse out RSS feeds, you should check out:&lt;/div&gt;&lt;div&gt;&lt;a href="http://code.google.com/p/as3syndicationlib/"&gt;http://code.google.com/p/as3syndicationlib/&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It handles the differences between the various RSS/Atom formats for you.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;p.s.    I've since come up with a plan for RSS based schedules, but don't want to spoil the surprise before it's ready.  It's going to rock.&lt;/span&gt;&lt;/div&gt;</description><link>http://www.rogue-development.com/blog/2008/03/power-of-rss.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-5224974063642855722</guid><pubDate>Mon, 17 Mar 2008 12:28:00 +0000</pubDate><atom:updated>2008-03-17T05:32:45.659-07:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>flex</category><title>Custom Cursors + Multiple Windows</title><description>Quick tip.  Don't use CursorManager.setCursor anymore.  It works fine for single-window flex apps, but breaks once you have an AIR app with multiple windows.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;UIComponent now has a cursorManager property that references the cursor manager for the current window.  If you use that it'll work all the time, not just in web Flex apps.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I understand why they left CursorManager in there for backwards compatibility, but it's a shame we can't mark it as @deprecated like in the Java world.&lt;/div&gt;</description><link>http://www.rogue-development.com/blog/2008/03/custom-cursors-multiple-windows.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-1873719132889250244</guid><pubDate>Sun, 16 Mar 2008 00:18:00 +0000</pubDate><atom:updated>2008-03-15T17:20:48.662-07:00</atom:updated><title>Flex-Spreadsheet update</title><description>Fixed a few bugs, and made a couple improvements on the Flex-Spreadsheet component today.  This fixes most of the flickering problems when using the scroll wheel.  It also addresses some placement issues with item editors when the user did "funky" things with changing focus.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;View the &lt;a href="http://www.rogue-development.com/spreadsheet/"&gt;project page&lt;/a&gt;, or download the latest version of &lt;a href="http://www.agileagenda.com/download/"&gt;AgileAgenda&lt;/a&gt; to see it in action.&lt;/div&gt;</description><link>http://www.rogue-development.com/blog/2008/03/flex-spreadsheet-update.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-7287519500908202630</guid><pubDate>Fri, 14 Mar 2008 23:20:00 +0000</pubDate><atom:updated>2008-03-14T16:26:21.403-07:00</atom:updated><title>Degrafa + ObjectHandles</title><description>&lt;div&gt;Here's a neat little experiment I did with combining &lt;a id="zs2q" href="http://www.degrafa.com/" title="Degrafa"&gt;Degrafa&lt;/a&gt;  and &lt;a id="r5dd" href="http://www.rogue-development.com/objectHandles.html" title="ObjectHandles"&gt;ObjectHandles&lt;/a&gt;.  (View-source is enabled for the example.)&lt;/div&gt;&lt;div&gt;&lt;a id="kh0z" href="http://rogue-development.com/objectHandles/degrafaExample/OH_Degrafa.html" title="http://rogue-development.com/objectHandles/degrafaExample/OH_Degrafa.html" style="color: rgb(85, 26, 139)"&gt;http://rogue-development.com/objectHandles/degrafaExample/OH_Degrafa.html&lt;/a&gt; &lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;div style="text-align: center; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="h0gp"&gt;&lt;img src="http://docs.google.com/File?id=dfxczdkr_12gtnhrbgq" style="width: 619px; height: 372px" /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;br /&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;It lets you move and resize shapes drawn with Degrafa by using the ObjectHandles stuff.  It was amazingly simple to make this work, essentially just something like:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&amp;lt;oh:ObjectHandle id="myHandle"&amp;gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'Courier New';"&gt;&lt;pre&gt;&lt;span class="MXMLComponent_Tag" style=""&gt;  &lt;/span&gt;&lt;span class="MXMLComponent_Tag" style="color: rgb(0, 0, 255)"&gt;&amp;lt;degrafa:Surface left="0" top="0"&amp;gt;&lt;/span&gt;                                  &lt;span class="MXMLComponent_Tag" style="color: rgb(0, 0, 255)"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="MXMLComponent_Tag" style="color: rgb(0, 0, 255)"&gt;  &amp;lt;degrafa:fills&amp;gt;&lt;/span&gt;             &lt;span class="MXMLComponent_Tag" style="color: rgb(0, 0, 255)"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="MXMLComponent_Tag" style="color: rgb(0, 0, 255)"&gt;    &amp;lt;degrafa:SolidFill &lt;/span&gt;&lt;span class="MXMLDefault_Text"&gt;id="&lt;/span&gt;&lt;span class="MXMLString" style="color: rgb(153, 0, 0)"&gt;aqua&lt;/span&gt;&lt;span class="MXMLDefault_Text"&gt;" colorKey="&lt;/span&gt;&lt;span class="MXMLString" style="color: rgb(153, 0, 0)"&gt;aqua&lt;/span&gt;&lt;span class="MXMLDefault_Text"&gt;"&lt;/span&gt;&lt;span class="MXMLComponent_Tag" style="color: rgb(0, 0, 255)"&gt;/&amp;gt;&lt;/span&gt;                     &lt;span class="MXMLComponent_Tag" style="color: rgb(0, 0, 255)"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="MXMLComponent_Tag" style="color: rgb(0, 0, 255)"&gt;  &amp;lt;/degrafa:fills&amp;gt;&lt;/span&gt;                  &lt;span class="MXMLComponent_Tag" style="color: rgb(0, 0, 255)"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="MXMLComponent_Tag" style="color: rgb(0, 0, 255)"&gt;  &amp;lt;degrafa:GeometryGroup&amp;gt;&lt;/span&gt;             &lt;span class="MXMLComponent_Tag" style="color: rgb(0, 0, 255)"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="MXMLComponent_Tag" style="color: rgb(0, 0, 255)"&gt;    &amp;lt;degrafa:Elipse width="{&lt;/span&gt;&lt;span class="MXMLComponent_Tag"&gt;myHandle.widt&lt;/span&gt;&lt;span class="MXMLComponent_Tag" style="color: rgb(0, 0, 255)"&gt;h}" height="{&lt;/span&gt;&lt;span class="MXMLComponent_Tag"&gt;myHandle.height&lt;/span&gt;&lt;span class="MXMLComponent_Tag" style="color: rgb(0, 0, 255)"&gt;}}" &lt;/span&gt;&lt;span class="MXMLDefault_Text"&gt;fill="&lt;/span&gt;&lt;span class="MXMLString" style="color: rgb(153, 0, 0)"&gt;{&lt;/span&gt;&lt;span class="ActionScriptDefault_Text"&gt;aqua&lt;/span&gt;&lt;span class="MXMLString" style="color: rgb(153, 0, 0)"&gt;}&lt;/span&gt;&lt;span class="MXMLDefault_Text"&gt;" radius="&lt;/span&gt;&lt;span class="MXMLString" style="color: rgb(153, 0, 0)"&gt;20&lt;/span&gt;&lt;span class="MXMLDefault_Text"&gt;"&lt;/span&gt;&lt;span class="MXMLComponent_Tag" style="color: rgb(0, 0, 255)"&gt;/&amp;gt;&lt;/span&gt;                    &lt;span class="MXMLComponent_Tag" style="color: rgb(0, 0, 255)"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="MXMLComponent_Tag" style="color: rgb(0, 0, 255)"&gt;  &amp;lt;/degrafa:GeometryGroup&amp;gt;&lt;/span&gt;              &lt;span class="MXMLComponent_Tag" style="color: rgb(0, 0, 255)"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="MXMLComponent_Tag" style="color: rgb(0, 0, 255)"&gt;&amp;lt;/degrafa:Surface&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;lt;/oh:ObjectHandle&amp;gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;I bet it'd be amazingly simple to make some sort of impressive drawing or charting application with this.&lt;/div&gt;</description><link>http://www.rogue-development.com/blog/2008/03/heres-neat-little-experiment-i-did-with.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-3179940226830174636</guid><pubDate>Fri, 14 Mar 2008 20:57:00 +0000</pubDate><atom:updated>2008-03-14T14:31:46.066-07:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Spreadsheet</category><title>Flex-Spreadsheet first release</title><description>&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="m.vo"&gt;&lt;a target="_blank" href="http://www.blogger.com/File?id=dfxczdkr_10gkpn8tdk"&gt;&lt;img src="http://docs.google.com/File?id=dfxczdkr_10gkpn8tdk" style="width: 640px; height: 124.675px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;                        The first public release of my Flex spreadsheet component is now available from &lt;a id="eaxa" href="http://code.google.com/p/flex-spreadsheet/downloads/list" title="Google Code"&gt;Google Code&lt;/a&gt;.  This component is very similar to the Flex datagrid with a few notable distinctions:  &lt;div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;It's designed for extensibility, not for speed or ease of use.&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Item Renderers or Item Editors can implement a custom interface to get more information and control over the spreadsheet they're in.&lt;/li&gt;&lt;ul&gt;&lt;li&gt;They get more data about the spreadsheet.&lt;/li&gt;&lt;li&gt;They can dispatch a variety of events to cause the spreadsheet to do things&lt;/li&gt;&lt;li&gt;Editors don't neccessarily need to be confined to the size of the&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;li&gt;It's designed primarily for data-input, not data-display&lt;/li&gt;&lt;ul&gt;&lt;li&gt;The spreadsheet can have a "placeholder" row.  &lt;/li&gt;&lt;ul&gt;&lt;li&gt;This row is created by the spreadsheet and is only inserted into the underlying data model when it's "valid".  &lt;/li&gt;&lt;li&gt;You can specify a class factory for creating these, and a custom validator class to determine when a row is or is not valid. &lt;/li&gt;&lt;li&gt;Visually, it's slightly greyed out.&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;li&gt;Keyboard navigation is sane&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Tabbing between cells&lt;/li&gt;&lt;li&gt;Using the arrows between cells.&lt;/li&gt;&lt;li&gt;Using the arrows within while editing a cell &lt;/li&gt;&lt;li&gt;Hitting enter submits an entire row.&lt;/li&gt;&lt;li&gt;Leaving a cell submits that cell&lt;/li&gt;&lt;li&gt;Build-in support for auto completion of cells with sane keyboard navigation of the auto-complete&lt;/li&gt;&lt;li&gt;Hitting escape cancels a cell-edit&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;div style="text-align: left; padding-top: 1em; padding-bottom: 1em; padding-right: 0px; padding-left: 0px" id="q2lk"&gt;&lt;a target="_blank" href="http://www.blogger.com/File?id=dfxczdkr_9cnj52ncr"&gt;&lt;img src="http://docs.google.com/File?id=dfxczdkr_9cnj52ncr" style="width: 640px; height: 130.246px" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;I originally wrote this for &lt;a id="qo4q" href="http://www.agileagenda.com/" title="AgileAgenda"&gt;AgileAgenda&lt;/a&gt;, recently we began using it for another project at my day-job.  Seeing how it was general enough for that, I thought it might be worth sharing for comments / suggestions / etc.&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;This component is not ready for general-use.  If you want to try it out expect:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;It's not well documented.&lt;/li&gt;&lt;li&gt;There are bugs&lt;/li&gt;&lt;li&gt;For large data sets (300+ rows) it's slow&lt;/li&gt;&lt;ul&gt;&lt;li&gt;I do have several specific plans for greatly improving this, but I like to optimize last.  You never know when feature changes can really affect performance.&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;The partitioning feature will be completely re-written, don't play with it yet.&lt;/li&gt;&lt;li&gt;You will have questions.  I don't have time to answer them right now.&lt;/li&gt;&lt;li&gt;Many of the features (like sorting) have only been implemented enough to support my current projects and are not general enough to support every need yet.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;So why am I posting this now?  I'm looking for feedback.  What works well, what doesn't.  What other things might you need to use it in your projects?&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;Getting started:&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;Grab the source and look at Main.mxml, it has a moderately commented example of using the component.  Also, Spreadsheet.as has a few comments in it that may be useful.&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;If you want to test out a sample, go here:&lt;/div&gt;&lt;div&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #3f5fbf"&gt;&lt;a id="pyvr" href="http://www.rogue-development.com/spreadsheet/" title="http://www.rogue-development.com/spreadsheet/"&gt;http://www.rogue-development.com/spreadsheet/&lt;/a&gt; &lt;/p&gt;&lt;/div&gt;&lt;div&gt;Eventually, more information about the project will be at that URL.&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;   &lt;/div&gt;</description><link>http://www.rogue-development.com/blog/2008/03/first-public-release-of-my-flex.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-2235701222100075896</guid><pubDate>Thu, 13 Mar 2008 12:29:00 +0000</pubDate><atom:updated>2008-03-13T05:32:03.154-07:00</atom:updated><title>Kasai</title><description>I've been looking for an open source user management system to build project upon.  Someone pointed out Kasai to me a while back and I took a quick look.  It' seemed to be about 1/2 of what I wanted.&lt;br /&gt;&lt;br /&gt;But I just took a more in-depth look at the docs and it might actually be much closer to what I was hoping to find.  It looks promising.  Hopefully I'll be able to give it a try sometime soon and see how far it gets me.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://kasai.manentiasoftware.com"&gt;http://kasai.manentiasoftware.com/&lt;/a&gt;</description><link>http://www.rogue-development.com/blog/2008/03/kasai.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-1111035523841491939</guid><pubDate>Sun, 09 Mar 2008 22:54:00 +0000</pubDate><atom:updated>2008-03-09T16:35:32.276-07:00</atom:updated><title>Timezone freakiness</title><description>&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;Just solved a mind-boggling problem I was having with some date manipulation.&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;The Date constructor returns a date with a different timezone depending on whether the date is today &amp;amp; before, or in the future.&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span style="color:#6699cc;"&gt;var&lt;/span&gt; today:Date = &lt;span style="color:#0033ff;"&gt;new&lt;/span&gt; Date();&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt; &lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span style="color:#6699cc;"&gt;var&lt;/span&gt; yesterday:Date = &lt;span style="color:#0033ff;"&gt;new&lt;/span&gt; Date( today.fullYear, today.month, today.date - 1 );&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span style="color:#6699cc;"&gt;var&lt;/span&gt; today2:Date =    &lt;span style="color:#0033ff;"&gt;new&lt;/span&gt; Date( today.fullYear, today.month, today.date     );&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span style="color:#6699cc;"&gt;var&lt;/span&gt; tomorrow:Date =  &lt;span style="color:#0033ff;"&gt;new&lt;/span&gt; Date( today.fullYear, today.month, today.date + 1 );&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span style="color:#cc6666;"&gt;trace&lt;/span&gt;( yesterday.timezoneOffset );&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span style="color:#cc6666;"&gt;trace&lt;/span&gt;( today2.timezoneOffset );&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span style="color:#cc6666;"&gt;trace&lt;/span&gt;( tomorrow.timezoneOffset );&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Monaco; "&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Monaco; "&gt;Traces output:&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Monaco; "&gt;300&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Monaco; "&gt;300&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Monaco; "&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(255, 0, 0);"&gt;240&lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Monaco; "&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Monaco; "&gt;What's worse if you then subtract a day from "tomorrow" it doesn't equal today.&lt;/p&gt;&lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Monaco; "&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font: normal normal normal 11px/normal Monaco; "&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;tomorrow.date--;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span style="color:#cc6666;"&gt;trace&lt;/span&gt;( tomorrow.time == today.time );&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span style="color: rgb(204, 102, 102); "&gt;trace&lt;/span&gt;( tomorrow == today );&lt;span class="Apple-tab-span" style="white-space: pre; "&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt;   &lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;Output: false / false&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;Guess why?&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;Today's daylight savings switchover day.  Arghhh.&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;I really wish Actionscript had a date-only type.&lt;/p&gt; &lt;p&gt;&lt;/p&gt;</description><link>http://www.rogue-development.com/blog/2008/03/date-constructor-bug.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-7872415802837318577</guid><pubDate>Sat, 08 Mar 2008 20:42:00 +0000</pubDate><atom:updated>2008-03-08T12:46:28.394-08:00</atom:updated><title>New pulse particle build posted</title><description>A new version of &lt;a href="http://rogue-development.com/pulseParticles.html"&gt;Pulse Particles&lt;/a&gt; has been released.&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This one has one new feature.  If you create a MovieClip for your particle, there's a new rule which will randomly pick a frame in that MovieClip to use.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;From the particle explorer, you just have to check off the box on the "intial" tab to get this functionality.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.rogue-development.com/blog/uploaded_images/SafariScreenSnapz015-737428.png" border="0" alt="" /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;This lets you create a single effect with multiple particles very easily.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;If you were using animated particles you could still do that by placing an animated movie clip on each frame of the main particle's movie clip.  Or don't check that box off and nothing changes.&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;</description><link>http://www.rogue-development.com/blog/2008/03/new-pulse-particle-build-posted.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-6245860175798334282</guid><pubDate>Thu, 06 Mar 2008 18:27:00 +0000</pubDate><atom:updated>2008-03-06T10:30:06.234-08:00</atom:updated><title>OSF Book on Amazon</title><description>I've been working with a few other (much more well known) authors on an open source flash book and it just hit Amazon for preorders.  Neat stuff!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.amazon.com/Essential-Guide-Source-Flash-Development/dp/1430209933/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1204814390&amp;amp;sr=8-1"&gt;http://www.amazon.com/Essential-Guide-Source-Flash-Development/dp/1430209933/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1204814390&amp;amp;sr=8-1&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Check it out :)  Too bad they spelled my name wrong.&lt;br /&gt;&lt;br /&gt;-Marc</description><link>http://www.rogue-development.com/blog/2008/03/osf-book-on-amazon.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-4899540688169416894</guid><pubDate>Wed, 05 Mar 2008 13:10:00 +0000</pubDate><atom:updated>2008-03-05T05:14:27.406-08:00</atom:updated><title>Any open source user management/subscription systems?</title><description>A &lt;a href="http://www.rogue-development.com/blog/2008/02/are-there-any-open-source-user.html"&gt;while back&lt;/a&gt; I probed around to see if there are any open source user management systems out there and didn't come up with any great leads.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Weird thing, at my day-job, yesterday, the general manager asked me the same question.  Clearly there is a need for something like this.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My original list of requirements went something like this:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 51); font-family: Verdana; font-size: 13px; line-height: 19px; "&gt;&lt;ul style="margin-top: 0px; margin-right: 0px; margin-bottom: 20px; margin-left: 30px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "&gt;&lt;li style="padding-left: 14px; margin-bottom: 3px; "&gt;Allowing users to sign up (email verification, catpcha support, configurable list of user details to require)&lt;/li&gt;&lt;li style="padding-left: 14px; margin-bottom: 3px; "&gt;Assign various access levels (or attributes?) to users.&lt;/li&gt;&lt;li style="padding-left: 14px; margin-bottom: 3px; "&gt;Allow users to log in / log out &lt;/li&gt;&lt;li style="padding-left: 14px; margin-bottom: 3px; "&gt;Detect multiple failed logins for a user or from a source host with configurable temporary lockouts&lt;/li&gt;&lt;li style="padding-left: 14px; margin-bottom: 3px; "&gt;Provide a simple API to use in applications that build upon it to get login status &amp;amp; access level (preferably language-agnostic)&lt;/li&gt;&lt;li style="padding-left: 14px; margin-bottom: 3px; "&gt;Mechanism for retrieval of forgotten passwords (email? security question(s)?, combination?)&lt;/li&gt;&lt;li style="padding-left: 14px; margin-bottom: 3px; "&gt;Provide a simple html based UI to handle all of these functions (including administrative functions like approving, disabling, changing access, etc.).&lt;/li&gt;&lt;li style="padding-left: 14px; margin-bottom: 3px; "&gt;Provide an XML-RPC based interface to perform all of the functions so it's easily customizable by application that build upon it.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;A new requirement that this request brought up was:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Support for paid subscriptions&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;So here's another blog post, and I'll go hit up the OSFlash mailing list to see if anything comes up.&lt;/div&gt;&lt;/span&gt;&lt;/div&gt;</description><link>http://www.rogue-development.com/blog/2008/03/any-open-source-user.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-6153926020006395917</guid><pubDate>Wed, 05 Mar 2008 12:44:00 +0000</pubDate><atom:updated>2008-03-05T04:45:38.163-08:00</atom:updated><title>PS</title><description>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.rogue-development.com/blog/uploaded_images/mars-712462.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.rogue-development.com/blog/uploaded_images/mars-712457.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;Ever see something that's just screaming to be run through photoshop?  I just couldn't help myself this morning.&lt;div&gt; &lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</description><link>http://www.rogue-development.com/blog/2008/03/ps.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-3422358377859663630</guid><pubDate>Sun, 02 Mar 2008 15:13:00 +0000</pubDate><atom:updated>2008-03-02T07:17:20.781-08:00</atom:updated><title>Detecting whether running in ADL vs. installed AIR</title><description>I noticed something while implementing the solution I &lt;a href="http://www.rogue-development.com/blog/2008/03/self-signed-vs-ca-signed-air-apps.html"&gt;talked about yesterday&lt;/a&gt; for dealing with self-signed vs. CA signed AIR apps.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The publisherId field is a blank string when running from within ADL.  It's an easy way to detect an installed AIR version vs. a version running within the debugger or just directly using ADL.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I haven't really needed it so I haven't searched the docs.  There might be an explicit way to detect that scenario in the AIR api (feel free to comment and point it out), but if not and you need it, there you go.&lt;/div&gt;</description><link>http://www.rogue-development.com/blog/2008/03/detecting-whether-running-in-adl-vs.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-6503840903596293155</guid><pubDate>Sat, 01 Mar 2008 17:06:00 +0000</pubDate><atom:updated>2008-03-01T09:24:31.224-08:00</atom:updated><title>Self signed vs. CA signed AIR apps</title><description>I got my official Thawte code-signing certificate this week.  It turns out you can't upgrade an application from a self-signed to a CA-signed version in AIR.  If you have the same problem you might be interested in the solution I'm going to use.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;First, here's my goals:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Migrate people to the new CA signed version&lt;/li&gt;&lt;li&gt;Don't force most people with the Self-Signed version to upgrade immediately&lt;/li&gt;&lt;li&gt;Keep both self and CA signed versions up to date (for a limited amount of time)&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'll be moving the website download to the signed version &lt;br /&gt;&lt;ul&gt;&lt;li&gt;New people will get the signed version.&lt;/li&gt;&lt;li&gt;Existing users who go to the website to upgrade will be told they can't install it.  Those people will have to manually uninstall their version, and install the new signed version.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I have an auto-upgrade option in the software.  Most people use this to upgrade.  Previous versions checked a file called appUpdate.xml to see if there was an available update.  I'll start publishing two versions of that file.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;appUpdate.xml - This will continue to point to the self-signed version&lt;br /&gt;&lt;/li&gt;&lt;li&gt;signedAppUpdate.xml - This will point to the new CA-signed version&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;In my application, I'll add code to determine which of those to choose.  Luckily, the nativeApplication.publisherID variable will be different depending on how the AIR app was signed.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#990000;"&gt;&lt;span style="color:#0033ff;"&gt;if&lt;/span&gt;&lt;span style="color:#000000;"&gt;( nativeApplication.publisherID == &lt;/span&gt;"MY_SIGNED_PUBLISHER_ID"&lt;span style="color:#000000;"&gt; )&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;{&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #009900"&gt;// This is our officially signed version&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#990000;"&gt;&lt;span style="color:#000000;"&gt;appUpdater.updateURL = &lt;/span&gt;"http://www.agileagenda.com/download/signedAppUpdate.xml"&lt;span style="color:#000000;"&gt;;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#990000;"&gt;&lt;span style="color:#000000;"&gt;}&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #0033ff"&gt;else&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;{&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #009900"&gt;// This is our self signed version&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#990000;"&gt;&lt;span style="color:#000000;"&gt;appUpdater.updateURL = &lt;/span&gt;"http://www.agileagenda.com/download/appUpdate.xml"&lt;span style="color:#000000;"&gt;;&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;}&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;And finally, I update my ANT build script so I generate two different .air files, and create both the appUpdate XML files.&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;I'll also put a nag into the self-signed version's upgrade window saying something like:&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;We've recently started cryptographically signing our applications for your safety.  Unfortunately, you can't upgrade from a non-signed version to a signed version.  For your security we suggest that you uninstall this unsigned software and then download and install from our website.  You may continue using unsigned versions if you prefer.&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;And then someday I'll completely disable the auto-update of the self-signed version when enough people have migrated over.&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;</description><link>http://www.rogue-development.com/blog/2008/03/self-signed-vs-ca-signed-air-apps.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-1543782291603593996</guid><pubDate>Thu, 28 Feb 2008 16:47:00 +0000</pubDate><atom:updated>2008-02-28T09:29:26.674-08:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>Actionscript</category><title>ArrayCollection weirdness</title><description>I ran into a head-scratcher today...&lt;br /&gt;&lt;br /&gt;How can this code:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;var index:Number = rows.getItemIndex(partition.placeholderRow );&lt;br /&gt;trace( index + " " + (rows.getItemAt(0) === partition.placeholderRow ) );&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;give this output?&lt;br /&gt;&lt;br /&gt;-1 true&lt;br /&gt;&lt;br /&gt;rows is an ArrayCollection with one element.  partition.placeholderRow exists and is a valid object.  I haven't mucked around with rows.source at all.&lt;br /&gt;&lt;br /&gt;Answer follows in comment (so you don't peek ahead and cheat!)</description><link>http://www.rogue-development.com/blog/2008/02/arraycollection-weirdness.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-2814109829784362336</guid><pubDate>Wed, 27 Feb 2008 02:21:00 +0000</pubDate><atom:updated>2008-02-26T18:33:24.172-08:00</atom:updated><title>Been a crazy couple AIR days</title><description>&lt;div&gt;I knew about the AIR release for a few weeks now, but never hadn't had the chance to update AgileAgenda for the new runtime by the release yesterday morning.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Boy am I sorry I didn't.  I went to work yesterday and my mailbox was clogged with comments about &lt;a href="http://www.agileagenda.com/"&gt;AgileAgenda&lt;/a&gt; and notifications from Google Checkout about purchases.  WAY more than any other day.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When I got home I saw that AgileAgenda was featured on the &lt;a href="http://www.adobe.com/cfusion/exchange/index.cfm?event=productHome&amp;amp;exc=24&amp;amp;loc=en_us"&gt;AIR marketplace&lt;/a&gt; again, and I chalked it up to that.  So I scrambled to get a new release out as quick as possible.  Without it being updated for the 1.0 release, I have to imagine a lot of people who tried ended up failing to install.  I really wish I had stayed up on Sunday to get that release done, I bet a lot more people would have gotten a look at the app.  Oh well, live and learn.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So then today I noticed that AgileAgenda wasn't featured in the marketplace anymore, but the traffic hadn't died down.  I was perplexed.  All the referrers in the logs were from the marketplace, but AgileAgenda wasn't even on the first page anymore so it didn't make sense to me.  Then I got a helpful email from a helpful Adobe employee.  It seems AgileAgenda is featured right smack in the middle of the thank you page whenever someone downloads AIR!  And of course that leads to the &lt;a href="http://www.adobe.com/cfusion/exchange/index.cfm?event=extensionDetail&amp;amp;loc=en_us&amp;amp;extid=1289518"&gt;marketplace link&lt;/a&gt;, which in turn leads to the &lt;a href="http://www.agileagenda.com/download/"&gt;download&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.agileagenda.com/blog/uploaded_images/SafariScreenSnapz008-754645.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.agileagenda.com/blog/uploaded_images/SafariScreenSnapz008-754638.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;How cool is that!?!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So anyways, I'm really motivated to work on the project again.  I've been spending a lot of time on the AgileTracker (Previously called the Dev Client) which gives each resource working on the project a time tracking / task list / time sheet interface that can subscribe to AgileAgenda schedules.&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.rogue-development.com/blog/uploaded_images/SafariScreenSnapz009-783489.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.rogue-development.com/blog/uploaded_images/SafariScreenSnapz009-783487.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's been fun working on that since I've been using the &lt;a href="http://spicefactory.org/parsley/"&gt;Pa&lt;/a&gt;&lt;a href="http://spicefactory.org/parsley/"&gt;rsley framework&lt;/a&gt; which gives a nice IoC container and an MVC architecture to boot.  I like learning new things.   I'll be publishing some work I've done with that related to loading and management of assets through the IoC container that might be useful to a lot of people.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But everyone should definitely check out Parsley.  The author, Jens Halm, has been very helpful on the forums over there.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</description><link>http://www.rogue-development.com/blog/2008/02/been-crazy-couple-air-days.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-5386377312061596993</guid><pubDate>Tue, 26 Feb 2008 12:35:00 +0000</pubDate><atom:updated>2008-02-28T05:49:32.460-08:00</atom:updated><title>#ifdef</title><description>&lt;span style="font-style: italic;"&gt;EDIT: Ignore this, they got it.  See the comments.  Learn something new every day I guess.  Don't I feel like a fool now :)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I have a new #1 feature request for Actionscript.  (Actually, I guess it's a request for the compiler toolset)&lt;br /&gt;&lt;br /&gt;Please add in #ifdef support, even if just for a predefined set of conditions.&lt;br /&gt;&lt;br /&gt;#ifdef AIR&lt;br /&gt;#ifdef NOT_AIR&lt;br /&gt;&lt;br /&gt;Trying to dual-purpose code for web and AIR applications would be so much simpler with these constructs.&lt;br /&gt;&lt;br /&gt;Last night I was adding a popup menu item to an app.&lt;br /&gt;&lt;br /&gt;var menu:NativeMenu = new NativeMenu();&lt;br /&gt;&lt;br /&gt;The app that I had worked so hard to completely abstract the AIR vs. the universal support was just AIRified.  I ended up spending 20 minutes refactoring the code, but it would have been sooo nice to just #ifdef that out.</description><link>http://www.rogue-development.com/blog/2008/02/ifdef.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-8523133885926819905</guid><pubDate>Thu, 14 Feb 2008 01:21:00 +0000</pubDate><atom:updated>2008-02-13T18:11:24.506-08:00</atom:updated><title>Pulse Particles + BitmapData</title><description>&lt;div&gt;Did a little work with getting the &lt;a href="http://www.rogue-development.com/pulseParticles.html"&gt;Pulse Particle system&lt;/a&gt; working with a BitmapData object.  Now you can do fun things like get particle trails, apply blur filters, etc.  Below are two examples of using that.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://rogue-development.com/experiments/BitmapExample.swf"&gt;&lt;br /&gt;&lt;/a&gt;&lt;/div&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.rogue-development.com/blog/uploaded_images/SafariScreenSnapz004-748746.png" border="0" alt="" /&gt;&lt;br /&gt;&lt;div&gt;This &lt;a href="http://rogue-development.com/experiments/BitmapExample.swf"&gt;first example&lt;/a&gt; shows a very simple particle system with some particle trails.  We're also using a new rule called the "ColorTransformRule" which causes a color transformation to happen over time.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="actionscript"&gt;&lt;br /&gt;package&lt;br /&gt;{&lt;br /&gt;import com.roguedevelopment.pulse.PulseEngine;&lt;br /&gt;import com.roguedevelopment.pulse.emitter.BitmapEmitter;&lt;br /&gt;import com.roguedevelopment.pulse.simple.SimpleParticles;&lt;br /&gt;&lt;br /&gt;import flash.display.Bitmap;&lt;br /&gt;import flash.display.BitmapData;&lt;br /&gt;import flash.display.Sprite;&lt;br /&gt;import flash.display.StageScaleMode;&lt;br /&gt;&lt;br /&gt;[SWF(backgroundColor="#000000", frameRate="30", width="500", height="350")]&lt;br /&gt;public class BitmapExample extends Sprite&lt;br /&gt;{&lt;br /&gt; [Embed(source="example_assets/spark.png")]&lt;br /&gt; protected var spark:Class; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt; public function BitmapExample()&lt;br /&gt; {&lt;br /&gt;  stage.scaleMode = StageScaleMode.NO_SCALE;&lt;br /&gt;  super();  &lt;br /&gt;  PulseEngine.instance.root = this;  &lt;br /&gt;  var bmd:BitmapData = new BitmapData( 500, 350, false, 0 );&lt;br /&gt;  var bm:Bitmap = new Bitmap(bmd);&lt;br /&gt;  addChild(bm);  &lt;br /&gt;  var emitter:BitmapEmitter = new BitmapEmitter(20, bmd );&lt;br /&gt;  SimpleParticles.configureEmitterByObject(emitter, {bound:[0,0,500,350],colorTransform:[300,3000,0,0,0,200,200,0], pps:23,x:250, y:40, width:1, height:1,image:spark, movement:true, minSpeed:80, maxSpeed:100, minAngle:0, maxAngle:360, minScale:0.4, maxScale:0.75, gravity:6, fade:2350, lifespan:2340} );     &lt;br /&gt; } &lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt; &lt;/div&gt;&lt;div style="text-align: center;"&gt; &lt;/div&gt;&lt;div style="text-align: center;"&gt; &lt;/div&gt;&lt;div style="text-align: center;"&gt; &lt;/div&gt;&lt;div style="text-align: center;"&gt; &lt;/div&gt;&lt;div style="text-align: center;"&gt; &lt;/div&gt;&lt;a href="http://rogue-development.com/experiments/StarPower.swf"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.rogue-development.com/blog/uploaded_images/SafariScreenSnapz003-741992.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://rogue-development.com/experiments/StarPower.swf"&gt;The second example &lt;/a&gt;takes the StarPower example from before and adds the same sort of effect.&lt;div&gt;&lt;br /&gt;&lt;div&gt;Source code follows...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="actionscript"&gt;&lt;br /&gt;/*&lt;br /&gt;This examples creates three particle emitters.&lt;br /&gt;&lt;br /&gt;Each of those emitters is on a container sprite which is not in the display list.&lt;br /&gt;&lt;br /&gt;We have an ENTER_FRAME event handler which copies the image from those containers to a BitmapData object which is displayed on screen.  Every&lt;br /&gt;frame we also apply a color transformation to cause previous draws to fade out.  This leaves a pleasing trail.&lt;br /&gt;&lt;br /&gt;Finally, we use Tweener to rotate, scale, and position the containers randomly giving some fairly interesting visual behavior.&lt;br /&gt;*/&lt;br /&gt;package&lt;br /&gt;{&lt;br /&gt;import caurina.transitions.Tweener;&lt;br /&gt;&lt;br /&gt;import com.roguedevelopment.pulse.emitter.GenericEmitter;&lt;br /&gt;import com.roguedevelopment.pulse.simple.SimpleParticles;&lt;br /&gt;&lt;br /&gt;import flash.display.Bitmap;&lt;br /&gt;import flash.display.BitmapData;&lt;br /&gt;import flash.display.Sprite;&lt;br /&gt;import flash.events.Event;&lt;br /&gt;import flash.events.TimerEvent;&lt;br /&gt;import flash.filters.BitmapFilter;&lt;br /&gt;import flash.filters.ColorMatrixFilter;&lt;br /&gt;import flash.geom.Matrix;&lt;br /&gt;import flash.geom.Point;&lt;br /&gt;import flash.geom.Rectangle;&lt;br /&gt;import flash.utils.Timer;&lt;br /&gt;&lt;br /&gt;[SWF(backgroundColor="#000000", frameRate="30", width="500", height="350")]&lt;br /&gt;public class StarPower extends Sprite&lt;br /&gt;{&lt;br /&gt;protected var containers:Array = [];&lt;br /&gt;protected var timer:Timer;&lt;br /&gt;protected var ease:int = 0;&lt;br /&gt;&lt;br /&gt;[Embed(source="example_assets/star.png")]&lt;br /&gt;protected var star:Class;&lt;br /&gt;[Embed(source="example_assets/spark.png")]&lt;br /&gt;protected var spark:Class;&lt;br /&gt;[Embed(source="example_assets/snowflake.png")]&lt;br /&gt;protected var snow:Class;&lt;br /&gt;&lt;br /&gt;protected var bmd:BitmapData;&lt;br /&gt;protected var bm:Bitmap;&lt;br /&gt;protected var fullRect:Rectangle = new Rectangle(0,0,500,350);&lt;br /&gt;protected var origin:Point = new Point(0,0);&lt;br /&gt;&lt;br /&gt;protected var filterz:Array = [   //new BlurFilter( 1, 1, 1 ) ,&lt;br /&gt;        new ColorMatrixFilter( [ 1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0.85,0 ] ) ];&lt;br /&gt;    &lt;br /&gt;&lt;br /&gt;public function StarPower()&lt;br /&gt;{&lt;br /&gt;super();&lt;br /&gt;&lt;br /&gt;addEmitter(star,10);&lt;br /&gt;addEmitter(snow,5);&lt;br /&gt;addEmitter(spark,15);&lt;br /&gt;&lt;br /&gt;bmd = new BitmapData(500,350,false,0x000000);&lt;br /&gt;bm = new Bitmap( bmd );&lt;br /&gt;addChild(bm);&lt;br /&gt;&lt;br /&gt;stage.scaleMode = "noScale";&lt;br /&gt;onTimer(null);&lt;br /&gt;timer = new Timer(5000);&lt;br /&gt;timer.addEventListener(TimerEvent.TIMER, onTimer );&lt;br /&gt;timer.start();&lt;br /&gt;addEventListener(Event.ENTER_FRAME, onEnterFrame );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;protected function onEnterFrame(event:Event) : void&lt;br /&gt;{&lt;br /&gt;// First, apply any filters we set up, in this example it's just the one color transform&lt;br /&gt;for each (var filter:BitmapFilter in filterz )&lt;br /&gt;{&lt;br /&gt;bmd.applyFilter( bmd, fullRect, origin, filter );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Then, for each of our particle containers, copy that to the bitmap with the appropriate transformations.&lt;br /&gt;for each ( var container:Sprite in containers )&lt;br /&gt;{&lt;br /&gt;var m:Matrix = new Matrix();// container.x, container.y);&lt;br /&gt;m.rotate( container.rotation * Math.PI / 180);&lt;br /&gt;m.translate( container.x, container.y );&lt;br /&gt;m.scale( container.scaleX, container.scaleY );&lt;br /&gt;bmd.draw(container,m);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* This creates a simple emitter that was configured using the particle explorer.&lt;br /&gt;**/&lt;br /&gt;protected function addEmitter( image:Class, pps:Number ) : void&lt;br /&gt;{&lt;br /&gt;var container:Sprite = new Sprite();    &lt;br /&gt;var emitter:GenericEmitter = SimpleParticles.createEmitter({pps:pps,x:100, image:image, y:100, width:1, height:1,size:15, color:2588900, movement:true, minSpeed:63.3, maxSpeed:353.6, minAngle:0, maxAngle:360, minScale:0.2, maxScale:1, lifespan:3140} ) as GenericEmitter;&lt;br /&gt;emitter.root = container;&lt;br /&gt;emitter.start();&lt;br /&gt;containers.push(container);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Every 5 seconds we cause the containers to go through a new random tweening&lt;br /&gt;protected function onTimer(e:Event) : void&lt;br /&gt;{&lt;br /&gt;for each( var container:Sprite in containers )&lt;br /&gt;{&lt;br /&gt;animateContainer( container );&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected function animateContainer(container:Sprite) : void&lt;br /&gt;{&lt;br /&gt;var eases:Array = ["easeinoutsine","easeoutcirc","easeoutback","easeoutbounce","easeoutelastic"];&lt;br /&gt;var scale:Number = Math.random()  + 0.05;&lt;br /&gt;ease++; ease %= 5;&lt;br /&gt;Tweener.addTween( container, { y:Math.random() * 350, x:Math.random()*500, scaleX:scale,  scaleY:scale, time:5, transition:eases[ease] });&lt;br /&gt;Tweener.addTween(container, {rotation: Math.random() * 360, time:5, transition:eases[ease] }) ;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description><link>http://www.rogue-development.com/blog/2008/02/pulse-particles-bitmapdata.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-1486720607333204798</guid><pubDate>Mon, 11 Feb 2008 12:25:00 +0000</pubDate><atom:updated>2008-02-11T04:30:23.825-08:00</atom:updated><title>Pulse Particles - StopMovementRule</title><description>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.rogue-development.com/blog/uploaded_images/SafariScreenSnapz001-701723.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.rogue-development.com/blog/uploaded_images/SafariScreenSnapz001-701718.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;A new version of Pulse particles is out with a new rule "StopMovementRule".  This rule lets you set an area on screen.  When a particle enters that area, it will stop moving.  This is useful to have particles fall onto something and come to rest.&lt;div&gt;&lt;br /&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;a href="http://www.rogue-development.com/pulseParticles.html"&gt;Project Page&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;The particle explorer and Flash .mxp packages have also been updated.&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;/div&gt;</description><link>http://www.rogue-development.com/blog/2008/02/pulse-particles-stopmovementrule.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-3964072933997058821</guid><pubDate>Sun, 10 Feb 2008 15:43:00 +0000</pubDate><atom:updated>2008-02-11T04:12:31.177-08:00</atom:updated><title>AIR Install Badge + Google Analytics</title><description>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.rogue-development.com/blog/uploaded_images/AnalyticsExample-700256.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.rogue-development.com/blog/uploaded_images/AnalyticsExample-700235.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt; &lt;/div&gt;I use Google Analytics to track web usage.  It's a great tool and since I mainly use AdWords for advertising, it really fills my needs.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A big part of Analytics is "goal" tracking.  You set up a goal page, and Analytics will tell you all kinds of information about the users who hit that goal.  In the past I set up my general "Download" page as a goal.  But visiting the download page, and actually downloading the application are two very different things.  It would be a lot more valuable to track who actually downloads vs. who went to the download page.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My &lt;a href="http://www.agileagenda.com/"&gt;main product&lt;/a&gt; is an AIR application.  It uses an AIR badge installer to let people install the application.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;By modifying the install-badge code slightly, and adding a javascript function we can detect when someone clicks the install badge.  Furthermore, we can even track if they had to install the application + the AIR runtime, or just the application.  Here's how...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;First, open up the badge.fla file that comes with the AIR SDK in Flash.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Next, open up the AIRBadge.as source file.  Find the "onButtonClicked" event handler and add in some ExternalInterface calls to report back to the webpage on what's clicked.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="actionscript"&gt;&lt;br /&gt;private function onButtonClicked(e:Event):void {&lt;br /&gt;try {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;switch (_air.getStatus()) {&lt;br /&gt;case "installed" :&lt;br /&gt; root.statusMessage.htmlText =&lt;br /&gt;     "&amp;lt;p align='center'&amp;gt;&amp;lt;font color='#" +&lt;br /&gt;     _messageColor +&lt;br /&gt;      "'&amp;gt;Downloading... Click the 'Open' button when prompted.&amp;lt;/font&amp;gt;&amp;lt;/p&amp;gt;";&lt;br /&gt; _air.installApplication( _appURL, _airVersion );&lt;br /&gt;&lt;br /&gt; try&lt;br /&gt; {  &lt;br /&gt;  ExternalInterface.call("badgeClicked","INSTALL_APP");&lt;br /&gt; }&lt;br /&gt; catch( e:Error ) {} // eat any errors to not interfere with the installation&lt;br /&gt;&lt;br /&gt; break;&lt;br /&gt;case "available" :&lt;br /&gt; try&lt;br /&gt; {&lt;br /&gt;  ExternalInterface.call("badgeClicked","INSTALL_AIR_APP");&lt;br /&gt; }&lt;br /&gt; catch( e:Error ) {} // eat any errors to not interfere with the installation&lt;br /&gt;&lt;br /&gt; root.statusMessage.htmlText = "&amp;lt;p align='center'&amp;gt;&amp;lt;font color='#" +&lt;br /&gt;             _messageColor +&lt;br /&gt;            "'&amp;gt;Downloading... Click the 'Open' button when prompted.&amp;lt;/font&amp;gt;&amp;lt;/p&amp;gt;";&lt;br /&gt; _air.installApplication( _appURL, _airVersion );&lt;br /&gt; break;&lt;br /&gt;case "unavailable" :&lt;br /&gt; try&lt;br /&gt; {&lt;br /&gt;  ExternalInterface.call("badgeClicked","INSTALL_FAIL");&lt;br /&gt; }&lt;br /&gt; catch( e:Error ) {} // eat any errors to not interfere with the installation&lt;br /&gt;&lt;br /&gt; // do nothing&lt;br /&gt; break;&lt;br /&gt;}&lt;br /&gt;} catch (e:Error) {&lt;br /&gt;root.statusMessage.text = e.message;&lt;br /&gt;}&lt;br /&gt;/* clearInterval( _global.installIntId ); */&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Notice that I also modified the message displayed to the user.   I always thought the message displayed was a bit confusing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As you can see, we're calling a badgeClicked function with three different parameters depending on the status of the currently installed AIR runtime.  Now... over to the HTML for the download page we need to define that function.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre name="code" class="actionscript"&gt;&lt;br /&gt;function badgeClicked( clickType )&lt;br /&gt;{&lt;br /&gt;urchinTracker("/download/badge/" + clickType );&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;Assuming you already have the analytics code set up on the page, that's it!  &lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;Now, when a user uses the download badge to install, you'll see an entry like one of these:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;/download/badge/INSTALL_AIR_APP&lt;/div&gt;&lt;div&gt;/download/badge/INSTALL_APP&lt;br /&gt;&lt;/div&gt;&lt;div&gt;/download/badge/INSTALL_FAIL&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;in your google analytics, and you can track that like any "real" page view.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;If you have multiple AIR badges throughout your site, you can modify your badgeClicked method to differentiate them.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;A few things to make this work:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Make sure your allowscriptaccess is set to "always" in your flash embed code.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Make sure your regular analytics code runs before the user can click on the badge (just setting it up like normal will do)&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;You can see a full HTML example by viewing the source of &lt;a href="http://www.agileagenda.com/download/"&gt;this page&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;I've &lt;a href="http://www.rogue-development.com/downloads/Badge_plus_google_analytics.zip"&gt;zipped up&lt;/a&gt; my modified badge.fla and badge.swf if you want to download and use it just like my example without changes.&lt;/div&gt;</description><link>http://www.rogue-development.com/blog/2008/02/air-badge-google-analytics.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-3905496733178808640</guid><pubDate>Fri, 08 Feb 2008 13:49:00 +0000</pubDate><atom:updated>2008-02-08T06:51:06.641-08:00</atom:updated><title>Are there any open source user management systems?</title><description>Blogs, CMS, bulletin boards, chat systems, social networks, most RIA's... they all have something in common.  Users.  Users need to sign up and log in.  Why is it that each system, even open source systems, end up implementing their own user management system?  I bet there's several million login form implementations out there by now, that's stupid.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Are there any open source stand alone user-management systems out there?  Something that does the basics and lets you build upon it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've seen plenty of user management systems integrated into other products, but they all seem tightly integrated into a much larger product.  I'd rather not start with a huge codebase (of potential security problems) and whittle it down.  I'd much prefer to have a simple, small system that handles things like:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Allowing users to sign up (email verification, catpcha support, configurable list of user details to require)&lt;/li&gt;&lt;li&gt;Assign various access levels (or attributes?) to users.&lt;/li&gt;&lt;li&gt;Allow users to log in / log out &lt;/li&gt;&lt;li&gt;Detect multiple failed logins for a user or from a source host with configurable temporary lockouts&lt;/li&gt;&lt;li&gt;Provide a simple API to use in applications that build upon it to get login status &amp;amp; access level (preferably language-agnostic)&lt;/li&gt;&lt;li&gt;Mechanism for retrieval of forgotten passwords (email? security question(s)?, combination?)&lt;/li&gt;&lt;li&gt;Provide a simple html based UI to handle all of these functions (including administrative functions like approving, disabling, changing access, etc.).&lt;/li&gt;&lt;li&gt;Provide an XML-RPC based interface to perform all of the functions so it's easily customizable by application that build upon it.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Bonus points for &lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;A Java or PHP solution since that's what I'm generally working in :)&lt;/li&gt;&lt;li&gt;Time based subscriptions&lt;/li&gt;&lt;li&gt;Configurable database back end (MySql minimum)&lt;/li&gt;&lt;li&gt;Session inactivity timeouts&lt;/li&gt;&lt;li&gt;AS3 library&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;I've done a little searching, but haven't found a simple solution.  (Plenty of complex single-sign on solutions!)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;</description><link>http://www.rogue-development.com/blog/2008/02/are-there-any-open-source-user.html</link><author>Marc</author></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-8858725797618026895.post-7129078025837133790</guid><pubDate>Thu, 07 Feb 2008 15:50:00 +0000</pubDate><atom:updated>2008-02-07T07:52:31.779-08:00</atom:updated><title>Agile Agenda update</title><description>Been a while since I wrote about &lt;a href="http://www.agileagenda.com/"&gt;AgileAgenda&lt;/a&gt;, so here's an update on some of the recent happenings.  If you haven't heard of it before, AgileAgenda is an AIR application for project scheduling that I've been working on in my spare time for a few months now.&lt;br /&gt;&lt;br /&gt;It's been a big couple weeks of development for me. I've fixed a bunch of bugs and improved a few of the outstanding usability problems. I got Basecamp integration working to a point where I'm ready to release after a bit more testing.&lt;div&gt;&lt;br /&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;But the big news is the Dev Client has been completely revamped.  I've also renaming it the "Agile Tracker" since not only "Developers" might be using it, but anyone who wishes to track their time on AgileAgenda tasks. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;Using the AgileTracker you'll be able to subscribe to multiple schedules published to the AgileAgenda.com website. Once you're subscribed, you'll be able to track your time across projects or tasks, view how much time on the project you've spent, and view an overall timesheet for time spent week to week.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;Here's a couple screenshots for you to wet your appetite with.&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.agileagenda.com/blog/uploaded_images/PreviewScreenSnapz002-704453.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://www.agileagenda.com/blog/uploaded_images/PreviewScreenSnapz002-704448.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.agileagenda.com/blog/uploaded_images/adlScreenSnapz009-782538.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://www.agileagenda.com/blog/uploaded_images/adlScreenSnapz009-782531.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There's also been some work to help future proof the file format so new versions of the software will still be able to read schedules made with older versions of the software.&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As we near a real release more and more attention is being focused on only releasing quality, well tested, builds. The changes mentioned above mean we have a huge chunk of code to test in the application, in the agile tracker, and in the server code. We're shooting for a new beta build in about two weeks depending on how our internal testing goes.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</description><link>http://www.rogue-development.com/blog/2008/02/agile-agenda-update.html</link><author>Marc</author></item></channel></rss>