Jul 24


Last year when I was in Seoul in got the chance to chat with Jason Calacanis, whom I told him about The Actionscript Conference. When I told him that it is still small, he told me “give it a few years”. His words bring me far and I am determined to turn TAC into one of the biggest Flash and Flex conference in South East Asia.

This year, TAC will be held on the 14th and 15th September, in the 550 seater of NTUC auditorium at One Marina Boulevard. For many attendees, it simply means crossing the road of Shenton way from their office to the venue. 2 Full days means we are invite more speakers, more topics and give you the updates and knowledge of Flex, Flash and Flash Player, and AIR that you are craving for.

I am proud to announced that ticketing is now opened. So register now!

Nov 21

 

It has been a great week at MAX ‘08, providing great experience for me and looking at all the new technology Adobe has to offer. Love the Keynote, Sneak Peaks, Great People and the excellent MAX Party!

Developer Point of View
Particularly interesting to me, in order of interest is Alchemy - C and C++ codes for Flash, Cocomo, ability to have P2P video in Flash, Flex 4 Gumbo and Server Side Actionscript, and Flash Catalyst (formly Thermo)

With Alchemy, it simply means the ceiling is now higher for us the developers. Anything is now possible now on the client side and developers will have to at least have an overview of how it works in order to be able to utilize the wide array of libraries existed nowadays and incorporate them in their client. Website owners should seriously look into this piece of technology to see how they can use Alchemy to create new experiences for their users. Using Alchemy, you can achieve things that are never possible in Flash (like the Quake demo in MAX ) and thus it also give rise to new business opportunities. I will be spending the next few weeks to dive deep into Alchemy and will post up some experiments I have here.

Cocomo is SaaS from a Social Networking point of view. Tied closely to Acrobat.com, it allows developers to tap into existing components in Acrobat.com, like video chat capability and real time file sharing, and use them in their own application. It is definitely a welcoming for us developers as it gives us another option to create RIA without installing our own infrastructure. 

Flex 4 , as most people might already know, will have better skinning workflow, better performance, separation between component business logic and UI elements, support of shapes and graphics in MXML (like degrafa). It also introduce a own new set of components extended from the FxComponent (like UIComponent in Flex 3), 2 way binding, and the feature that makes everyone claps - a “layer” property in the component that defines the depth rather than the childIndex! All these in a new MXML 2009 namespace ;)

And of course, Flash Catalyst (Fc), formerly Thermo, is also heavily showcased during the event. Fc allow designers to create their graphics in Photoshop or Illustrator, export them in a format FXG, and continue to work in Fc, and effectively saving the files as MXML into a Flex project! While I personally do not think Fc take off quickly as a tool of dictating the entire site UI (remember the Dreamweaver symdrome? ), but I do believe it will become real popular for developers in terms of component skinning. As Ryan Stewart demoed in MAX, with just a few click, it will skin a component like scrollbar automatically, which is a huge step from Flex 3. 

Community Manager Point of View

MAX provides a lot of opportunities for User group managers (UGM) to network with other User group managers and Adobe’s community managers . This time, Adobe launches Adobe Group, which FUG is part of it!. Flex Camp is also now officially Flash Camp. It is very encouraging that Adobe is pushing for the community than ever before, providing us the UGM with valuable resources and directly support. 

I also meet up with the UGM from Hong Kong, Taiwan and Seoul. Try to spot us in the photo below.

It is great when we start to see people from SEA and who knows, we might start seeing some asia speakers for MAX in the future!

Overall
Its been a great 3 days at MAX and an even better week in San Francisco. Now there is lots of new technologies to play, with the bar rise much higher than before! Work hard developers!

Lastly, not related to MAX, but hey I am on Seesmix!!!

 

Nov 06

The Problem
For many developers, this can be a no-brainer problem to start with. Most (if not all ) mashups uses videos from YouTube. There are tons of resources online that teach us how to “scrap” the FLV of youtube videos so we can play it in our own applications.

Going a few months back, YouTube had already released the chromeless player , a plain player without controls for playing youtube videos. However, there is no immediately “need” for developers to change their player to suit the chromeless player. Afterall, “if it ain’t broken, don’t fix it”. Last week however, YouYube removed some parameters in their APIs calls, effectively making some “scrapping” process not working. There are still some workarounds to get the FLV of their videos, but even if developers can “hack” to make it work, it is still against YouTube TOS. For many developers, the most straight forward solution is, well, use the chromeless player.

Chromeless Player is made in AS2 but I code in AS3
Now that the solution is pointing to Chromless Player, with the coherent and straightforward YouTube documentations, developers can easily fit the Chromeless Player into their application. For AS2 developers, it is a task of merely loading the SWF and passing commands to it. For AS3 developers, the problem arise as AS3 swfs cannot communicate with AS2 swfs directly. Thus, AS3 developers can load the Chromeless Player, but they cannot effectively communicate with it to get the play time, stop the video, pause the video etc.

AS2 Wrapper , LocalConnection to AS3
After searching around on google, many are facing this problem and the solution points down to using localconnection. Matthew Encinas posted this solution here, which works great. It involves creating an AS2 wrapper, which connects to a localconnection instance. The AS3 wrapper then load the AS2 wrapper, which in turns loads the Chromeless Player. To make things easier to understand, I have created a diagram below:

Codes from Matthew Encinas: http://groups.google.com/group/youtube-api-gdata/browse_thread/thread/3c98068961296b38/07ecb5ee1168cefb?lnk=gst&q=as3#07ecb5ee1168cefb

Help! LocalConnection naming problem!
The problem with this approach is that you are using a fixed localconnection name for your swf. If your player is a video player, which can have multiple instances at the same time, you will receive an error that the localconnection is already in used. To solve this problem, append something like ?key= when loading the AS2 Wrapper, and using that to name your localconnection name

Sample Classes
Modifying Matthew’s code, with the localconnection fix gives us the following 2 piece of codes:

AS2 Codes (the youtubewrapper.swf)

System.security.allowDomain('www.youtube.com');
System.security.allowDomain('gdata.youtube.com');
System.security.allowInsecureDomain('gdata.youtube.com');
System.security.allowInsecureDomain('www.youtube.com');
var loadInterval:Number;
var ytplayer:MovieClip = this.createEmptyMovieClip("ytplayer",
this.getNextHighestDepth());
 var key   = _root.key;
 
var swf:String = "http://www.youtube.com/apiplayer";
//This created a connection for AS3 to talk to it
var _as3_to_as2:LocalConnection = new LocalConnection();
_as3_to_as2.connect("AS3_to_AS2_" + key);
//This is to connect to a connection started by the AS3 file
var _as2_to_as3:LocalConnection = new LocalConnection();
ytPlayerLoaderListener = {};
ytPlayerLoaderListener.onLoadInit = function() {
    loadInterval = setInterval(checkPlayerLoaded, 250);
} 
 
function checkPlayerLoaded():Void {
    if (ytplayer.isPlayerLoaded()) {
                //Let the AS3 file know that the player is loaded
                // the function onSwfLoadComplete exists within the AS3 file
                _as2_to_as3.send("AS2_to_AS3_" + key, "onSwfLoadComplete");
                clearInterval(loadInterval); // IMPORTANT - kill the interval
                ytplayer.addEventListener("onStateChange", onPlayerStateChange);
                ytplayer.addEventListener("onError", onPlayerError); 
 
        }
} 
 
function onPlayerStateChange(newState:Number) {
	 // Possible values are unstarted (-1), ended (0), playing (1), paused (2), buffering (3), video cued (5)
 
	  _as2_to_as3.send("AS2_to_AS3_" + key, "onPlayerStateChange", newState); 
 
	 switch(newState)
	 {
			case -1:
		 	case "unstarted":
			break;
			case 0:
 
			case "ended":
			clearInterval(playInt)
			break;
 
			case 1:
			case "playing":
		playInt = setInterval(onPlay, 1000)
 
			break;
			case 2:
			case "paused":
			break
			case 3:
			case "buffering":
			 clearInterval(playInt)
			break
			case 5:
			case "video cued":
			break;
	 }
 
} 
 
function sendCurrentTime():Void
{
	var current = ytplayer.getCurrentTime()
 
	var duration = ytplayer.getDuration() 
 
_as2_to_as3.send("AS2_to_AS3_" + key, "onDuration", current, duration); 
 
}
function onPlay()
{
 
	sendCurrentTime();
}
function onPlayerError(errorCode:Number) {
    //do something on player error
} 
 
var ytPlayerLoader:MovieClipLoader = new MovieClipLoader();
ytPlayerLoader.addListener(ytPlayerLoaderListener);
ytPlayerLoader.loadClip(swf, ytplayer);
//////// CREATE EVENT HANDLERS
// These functions can be called from within the AS3 file
// This is the window where AS3 will access the API
// You can add any of the Javascript Api here
_as3_to_as2.pauseVideo = function(){
    ytplayer.pauseVideo();
}; 
 
_as3_to_as2.playVideo = function(){
    ytplayer.playVideo();
}; 
 
_as3_to_as2.stopVideo = function(){
    ytplayer.stopVideo();
}; 
 
_as3_to_as2.loadVideoById = function(id){
        ytplayer.loadVideoById(id, 0);
}; 
 
//setSize(width:Number, height:Number):Void
_as3_to_as2.setSize  = function(swidth:Number, sheight:Number):Void
{
	ytplayer.setSize(swidth, sheight)
}
 
_as3_to_as2.cueVideoById = function(video_id:String, second:Number):Void
{
	ytplayer.cueVideoById(video_id,  second)
}
 
function doDispatchEvent ()
{
 
}

AS3 Codes

package com.mypackage.view
{ 
 
import flash.display.Loader;
        import flash.events.Event;
        import flash.events.StatusEvent;
        import flash.net.LocalConnection;
        import flash.net.URLRequest;
        import flash.system.Security;
 
import mx.core.Application;
        import mx.core.UIComponent;
        import mx.events.FlexEvent;
        [Event(name="init", type="flash.events.Event")]
        public class YouTube extends  UIComponent
        {
                private var _loader:Loader;
                private var _as3_to_as2:LocalConnection;
                private var _as2_to_as3:LocalConnection;
                public function YouTube(){
 
Application.application.addEventListener(FlexEvent.APPLICATION_COMPLETE, init)
                }
 
public function init(e:FlexEvent){
                        Security.allowDomain('www.youtube.com');
                        Security.allowDomain('gdata.youtube.com');
                        Security.allowInsecureDomain('gdata.youtube.com');
                        Security.allowInsecureDomain('www.youtube.com');
                        _as3_to_as2 = new LocalConnection();
                        _as3_to_as2.addEventListener(StatusEvent.STATUS,
onLocalConnectionStatusChange);
                        _as2_to_as3 = new LocalConnection();
                        _as2_to_as3.addEventListener(StatusEvent.STATUS,
onLocalConnectionStatusChange);
                        _as2_to_as3.client = this;
                        //This enables the local connection to
//use functions of this class
 
_as2_to_as3.connect("AS2_to_AS3_" + key);
                        _loader = new Loader();
                        _loader.contentLoaderInfo.addEventListener(Event.INIT, onWrapperInit)
                        _loader.load(new URLRequest("youtubewrapper.swf?key=" + key));
                }
               private var key :String = generateKey()
                private function onWrapperInit(e:Event):void
                {
 
}
                private function generateKey():String
                {
                	return this.generationCharCode()
                }
 
protected function generationCharCode():String
 		{
 			var code:String = ""
 			while(code.length < 10)
 			{
 				var cc :uint = Math.floor(Math.random() * 1000 ) % 123
 				if(cc < 48 || (cc >= 58 && cc <= 64) ||  (cc >= 91 && cc <= 96))
 				{
 
continue;
 				}
 
code += String.fromCharCode(cc)
 			}
 			return code;
 
}
                public function stopVideo():void {
                	this.current = this.total = 0;
 
_as3_to_as2.send("AS3_to_AS2_" + key, "stopVideo");
                }
                public function playVideo():void {
                        _as3_to_as2.send("AS3_to_AS2_" + key, "playVideo");
                }
                public function pauseVideo():void {
                        _as3_to_as2.send("AS3_to_AS2_" + key, "pauseVideo");
                }
                public function loadVideoById(id:String):void {
                        _as3_to_as2.send("AS3_to_AS2_" + key, "loadVideoById", id);
                }
 
public function setSize(width:Number, height:Number):void
                {
                	_as3_to_as2.send("AS3_to_AS2_" + key, "setSize", width, height);
                }
                public function cueVideoById(video_id:String, seconds:Number):void
                {
                	_as3_to_as2.send("AS3_to_AS2_" + key, "cueVideoById", video_id, seconds)
 
}
 
public function onPlayerStateChange(stateName):void
                {
 
}
                public function onDuration(current, total):void
                {
 
this.current = current
                	this.total = total;
                }
 
[Bindable]    public var current:Number;
 
[Bindable]   public var total:Number;
 
public function onSwfLoadComplete():void {
                        addChild(_loader);
                        dispatchEvent(new Event(Event.INIT));
                }
 
private function onLocalConnectionStatusChange(e:StatusEvent):void{
                        // error was thrown without this handler
                }
        }
}

Happy YouTubing!

Nov 06

I am so thrill when I see this video! Lee Brimelow blow us away with this video he made himself with a Canon HV20, Premiere CS4 and of course his wonderful editing skills.

Get the Flash Player to see this player.

Thank you Lee ! You rock! This video make my day!

Oct 08

When building Web based Flex applications, one of the common pitfalls is that the API you consume does not provide you with a crossdomain policy file and as a result, your Flex application cannot call directly to the application due to the Security Sandbox. (AIR applications does not have this Security issue)

One of the solution to this problem is using a proxy on your server, proxying the call to the API via your server. What the server does is to simply create a GET / POST request to the original endpoint and proxy back to the flex application all the results.

However, this solution will pose a problem in terms of scaling as all the request, originally meant to only goes to third-party API website, now actually goes through your server.

Enter JSONP

The preceding solution is one of the most common approach I used to use in most of my previous Mashup. However, after research AJAX, GWT and having a chat with my colleague from Seesmic, Matthew Eernisse, who is a Javascript and Ruby guru, I realize the power of JSONP and the simplicity of it working together with Flex to create mashup.

JSONP basically means JSON with Padding. From Wikipedia, it is defined as “JSONP or “JSON with padding” is a JSON extension wherein the name of a callback function is specified as an input argument of the call itself.

In the nutshell, it means you will have something like this:

<script src="http://books.google.com/books?jscmd=viewapi&bibkeys=ISBN9780596529857&callback=onresults">

with a function “onresults”

Together with Flex, you will have to use document.createElement(”script”) and then setAttribute to set the src. When the results are returned from the third-party endpoint, the specified function will be invoked. You can then parse the data, and simply put the data back to Flex.

JSONP, JQuery and External Interface

One of the usage of JSONP in a recent Flex application I have done is the TAC Preorder Form. The Preorder Form is a books ordering form for our sponsor Oreilly for The Actionscript Conference. Oreilly has provided us with a list of books’ ISBN number. Hoping that the users can actually browse the books cover and content first, I decide to pull in date from Google Books API, which provide information of the books’ thumbnail, as well as a preview page where the users can browse the books first few chapters first

The issue with the API is that there is no crossdomain policy file. Thus, the only way to call it is either using a server-side proxy or JSONP. I decide to go with JSONP for simplicity purpose, as well as to take load off the server.

Using JQuery, JSONP is extremely simple. The following codes shows an example of calling Google Books API.

$.getJSON("http://books.google.com/books?jscmd=viewapi&amp;bibkeys=ISBN"+isbn+"&amp;callback=?", function(data){
 
var bookInfo = data["ISBN" + isbn];
 
bookInfo.isbn = isbn;
 
//bookapp is a SWF with External Interface "getBookCallback" function
document.getElementById('bookapp').getBookCallback(bookInfo);
 
});

Essentially with JQuery, we can easily do away with the hassle of manually creating the javascript tag . We also need not to add codes to manually removing it upon completion. The build in “getJSON” method does it all. Upon completing the request, the callback function will be called, and we will pass the json object right back to Actionscript. Code as follows:

//constructor
public function PreorderClass()
{
 
super();
//initialize Cairngorm model
model = AppModelLocator.getInstance();
 
//create a getBookCallback function for Javascript to call this SWF
ExternalInterface.addCallback("getBookCallback", getBookCallback);
 
}
 
private function getBookCallback(e:*):void
{
 
/*
The Javascript object automatically becomes Actionscript Object with the following properties
bib_key
embeddable
info_url
preview
preview_url
thumbnail_url
isbn
*/
 
//using Cairngoem model and a custom vo "BookVO"
var book:BookVO = model.getBook(e.isbn);
book.thumbnail_url = e.thumbnail_url;
book.preview_url = e.preview_url;
 
}

Summary
Matthew pointed out to me a few shortcoming of JSONP. Firstly, there is no error handling. If the API endpoint is un-responsive, then you will not get any errors. The callback function will simply not be called at all. Thus, it is essential for developers to implement timeouts for their calls.

Secondly, if you are not using JQuery, the developer has to ensure that any codes that add a new javascript tag for JSONP, has to remove the javascript tag after the call has been completed.

In short, if you are creating a Web base Flex, JSONP provides you with a quick and easy way to call endpoint without crossdomain policy files, removing the hassle of setting up a server solution to proxy the request. Using JQuery, empower you to create JSONP calls within a few lines and then using External Interface to get the results back to the main Flex application.

Happy Mashing!

Aug 31

Introduction
For many Flex/Flash developers developing Facebook applications, development maybe daunting at first without a very detailed documentations, sample codes and blogs posting around to help. Most of time, many cannot grasp the general architecture of creating a Facebook application. While I am no expert in Facebook application development, I have picked up some useful tips and tricks along the way and I hope to share it around. Do take note the date of this posting. Facebook platform changes from time to time so 6 months down the road, this post might be obsolete.

Note that when I speak about Facebook development, it means having your Flash/Flex content inside Facebook profile and its canvas page. I do not mean connecting to Facebook using Actionscript. If you are looking to communicate with Facebook using Actionscript, please refer to this AS3 Facebook Library:
http://code.google.com/p/facebook-actionscript-api/

The Basic
Before you get started, I will suggest reading this blog posting by padraenl, titled 10 Things That Would Have Been Nice to Know When Starting My Facebook Application. Facebook Platform native documentation is good for referencing, but there isn’t instructions to teach new developers the “standard way” of approaching problems. This blog post answers to many common questions a developer will have.

How it works:
To understand how Facebook Applications work is very simple. Facebook does not provide you with any hosting service. You host your own application on your own server, and tell Facebook where to retrieve it. You churn out your own HTML / FBML / Javascript codes and Facebook parse it on its server, as simple as that. Essentially, you can develop in any language you like, as long as your codes render out the proper HTML / FBML / Javascript.

Things to note is that some of the examples you found on Facebook currently might be obsolete as Facebook now has a New Profile Design. To understand the new profile, you can read it's documentation, or just scroll down to check the few screen shots I placed below:

New Profile

Instead of a one page profile now, there is now “Wall”, “Boxes”, and Application Tab. Therefore, you will need to plan at least 3 screens for your application.

Main Profile - Wall:


This is mostly visited page from the user’s friends. You have the real estate of a small column on the left hand side of the page. If you are using a Flash movie, it will only play after the user has clicked on a preview image due to Facebook restriction. This part is cached by Facebook and will refresh by using setFBML or the more scalable method fb:ref tag and fbml_refreshRefUrl method. I strongly recommend fbml_refreshRelUrl method. You can learn more about fb:ref here and view the code example here: http://wiki.developers.facebook.com/index.php/FBML_Dynamic_Setup.

Boxes

Boxes is the part where your application will be. Note that your application can EITHER be inside WALL or BOXES tab, and this is controlled by the user. (See the next Screenshot, where under the Video application, the user can choose to “Move to Wall Tab” or “Remove Box”). Also note that you can choose the left column (wide) or the right column (narrow) under your application settings.

Under Boxes tab, your Flash file will NOT show until the user clicks on a preview image.

All the Boxes content are cached and is refreshed by setFMBL or the more scalable method fb:ref tag and fbml_refreshRefUrl method.


Application Tab

This is the best privilege your application can have. A user loves your application so much that he/ she adds it to an application tab. In this case, your application has all the real estate of the entire page, and you can have a very customized UI / information like the below screenshot (Animoto application)

Note that this page is NOT cached by Facebook. So any content is taken directly from a URL you specified in the application settings. For example, you can set Facebook to take from http://expertria.com/myapp/profiletab.php. Facebook will load the page and display any HTML it loads from your server inside the Application Tab.

This also means you need to prepare your server for the load as this is no longer cached by Facebook. Also, if your server is slow is responding, Facebook will consider it as a timeout.

The Main Application.

This is the main application, outside the profile page. This is the part where user who have granted the application permission will see. Typically, it is under a url like http://apps.facebook.com/yourappname/yourapppageurl.

For example, if you set the base url of your application as http://expertria.com/myapp/. A page on Facebook “http://apps.facebook.com/appname/viewallmyfriends.php will be retreivng information from http://expertria.com/myapp/viewallmyfriends.php

You can have as many pages in your application as you want, as well as useful features like URL-rewriting for neater URL address, etc. Facebook does not care as long as they get a http 200 response for the page it request and the response contain valid HTML / FMBL, and that the response is not empty.


PHP development

You can develop Facebook application in any language on your server, but PHP has more code samples and examples around. I will chose PHP as the development language just for the reason of support. Note that as of the writing of this article, if you download the PHP library from Facebook developers site, you will get the old library (which does not has the full feature set for the New Profile Design).

To get the latest one, please download from their SVN:
http://svn.facebook.com/svnroot/platform/clients/php/branches/redesign-changes/

Where to keep my data
As mentioned, Facebook does not care what you do on your server, as long as your server response with valid HTML / FBML. Therefore, you can have data persistence in your own mySQL, or any database you want.

However, I will recommend using Facebook Datastore for a few reason. Firstly, you will not need to maintain another database. Secondly, you can do FQL to achieve something like  “Get those users who had installed this application,w ho are also the current user’s friends, who also are tagged in my application” , in a very direct  manner. Thirdly, there is a test console to help you test your FQL (Facebook Query Language).

Essentially, Facebook Datastore consist of Objects (like Tables) and Associations (like Foreign Key). I strongly suggestion anyone who is new to Facebook Datastore to check out this blog here [
Introduction to the Facebook Data Store API ->http://www.dereksantos.ca/?p=23]. It has far better explanation than Facebook documentation, and anyone with RDBMS knowledge will strike a chore instantly by reading the article.

Using FMBL and Javascripts
Learn FBML and Facebook's Javascript FBJS before building your application! While many HTML tags are supported in Facebook, you cannot use an Object tag to render your swf directly in Facebook. You will need to use <fb:swf> tag. Using FBML will also gives you a consistent look to your application, so that it will looks like Facebook native application. For example, there is no need to build a custom tab as there is fb:tab. There is also no need to create a blue button that imitate facebook buttons as you can always use Facebook’s css class=”inputbutton” to change the style of your button to match Facebook’s.

As for Javascript , there are also restriction to Javascript. For example, there is no innerHTML to get the content of your HTML. Thus, you will need to learn how FBJS works on Facebook. You will also need FBJS to communicate between your SWF and the main Facebook page.

Flash FBML
Refer to this page to see how to embed Flash in Facebook page. The documentation is complete
http://wiki.developers.facebook.com/index.php/Fb:swf

Essential you need to use Fb:swf to render your swf file.

Flash - JS Bridge
The <fb:fbjs-bridge/>  is essential for your SWF to communicate with the Javascript on your HTML page. It works like External Inteface basically. How it works is that it creates another SWF on Facebook page and your SWF communicates to it via LocalConnection. The bridge will then use External Interface to communicate to the Facebook page on your behalf.

Refer to this documenation for code samples: http://wiki.developers.facebook.com/index.php/Fb:fbjs_bridge

Also, check out this library to call / receive functions in AS3

Creating Flash in Javascript
There are two ways to create a SWF dynamically using Javascript. One way is to use a fb:js-string, which is a pre-setted FBML, initially invisible, and then use document.getElementById(’name of div to insert’).setInnerFBML(myjstringname) to show it on the page.

An fb:js-string example:
<fb:js-string var=”myjsstringname”>
<fb:fbjs-bridge/>
<fb:swf swfbgcolor=”333333″ imgstyle=”border-width:3px; border-color:white;” swfsrc=”http://expertria.com/swf/fb.swf”   width=”300″ height=”280″   />
</fb:js-string>
Another way is to use document.createElement(”fb:swf”), which will dynamically create a new SWF object. You can then set its swfsrc , width and height using the below code:

var swf = document.createElement(’fb:swf’);
swf.setId(’my_swf_id’);
swf.setWidth(’100′);
swf.setHeight(’100′);
swf.setSWFSrc(’FULL_URL_TO_MY_SWF’);
document.getElementById(’swfContainer’).appendChild(swf);

Summary
I hope the above article helps developers with Flex/Flash background in having a better understanding on Facebook Application. Feel free to drop any tips you have under the comments. There are a few things like Mock AJAX and AJAX javascript which I did not cover, but the above should be sufficient to get someone started.

Keep coding!


Video title:

Description: