Jul 15

attending
I am pretty thrill to announce that I will be speaking in Adobe Flash Platform Summit 2010 in the coming August at Bangalore, India! The topic I will be covering will be “Real Time Web in Flash Player 10.1″ . I hope to cover a range of items in the talk including RTMFP, as well as to cover some other useful techniques that using PubSubHubbub + Socket to deliver real time information to clients built on the Flash Platform. Looking at the things I ‘hope’ to cover, 45 minutes is definitely not enough, so I will be doing some filtering and make sure that I can stuff as much goodies into the talk as possible. Friends like Alvin Zhan and Peter Elst will be there as well, so it will be an exciting conference!

About Adobe Flash Platform Summit
Adobe DevSummit was launched in 2008 as the flagship Adobe Flash Platform conference in India. With the objective of spreading the goodness of Adobe Flash Platform to the community in India, showcasing innovations, and sharing the future directions for the platform, Adobe DevSummit has established itself as the numero uno conference for product users and enthusiasts alike. Now, in its third year, Adobe is reaching out to the sub-continent’s developers and designers with a much larger Adobe Flash Platform Summit (AFPS) brand that will feature a convergence of over 2000 designers and developers.

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!


Video title:

Description: