Archive for February, 2009

28
Feb

Flash Catalyst DesignLayer tag pitfall tip

I am using Flash Catalyst for few projects now and I have to say that Flash Catalyst rocks!

I am able to convert vector images right into Flex Gumbo and no need to chop designers images any more. Keep in mind that Flash Catalyst is still in Alpha version so I don’t have the luxury to use it on all projects since it requires Flash 10.

Flash Catalyst allows you to import your art work from Adobe Illustrator and the graphic get converted to FXG, however if you try to compile and run your project you sometimes get a blank screen.. don’t get alarmed..

Flash Catalyst bring back all your layers from Flash Illustrator CS4, however it creates a tag around your layer, which cause Flex to ignore the entire block of code. The solution is simple. Remove the tags and you are all set.

Here’s an example of tags generated for a layer imported from Illustrator:


<DesignLayer d:id="2" userLabel="Layer1">
    // FXG code
</DesignLayer>

This little tip can save you about 15-30 valuable development time.

25
Feb

ActionScript generic Music Player API with implementation example and ASDOC

I just completed creating a generic music player API and added it to eladlib. The music player handles common tasks such as:

1. Downloading music files and firing events when needed.
2. Keep track of the music progress as the track playing.
3. Provides access to ID3 information.
4. Methods that are often used in a music player such as: play, stop, pause.

You can see the class ASDOC under: com.elad.framework.musicplayer:
http://elromdesign.com/blog/Flex/API/asdoc/

Here’s an example of a class that implements the API. You can insert any URL in the input box and hit submit. To view the code, right click the application and select view source.

Music Player AS3 API


<FxApplication xmlns="http://ns.adobe.com/mxml/2009">

	<Script>
		<![CDATA[
			import com.elad.framework.musicplayer.events.Id3Event;
			import com.elad.framework.musicplayer.events.PlayerEvent;
			import com.elad.framework.musicplayer.Player;
			import mx.events.SliderEvent;
			import com.elad.framework.musicplayer.events.DownloadEvent;
			import com.elad.framework.musicplayer.events.PlayProgressEvent;

			private var player:Player = new Player();
			private var songUrl:String;

			private function playSong():void
			{
				player.addEventListener(PlayProgressEvent.PLAYER_PROGRESS, onPlayerProgress);
				player.addEventListener(DownloadEvent.DOWNLOAD_PROGRESS, onDownloadProgress);
				player.addEventListener(PlayerEvent.PLAYER_ERROR, onPlayerError);
				player.addEventListener(Id3Event.ID3, onTrackDataInformation);
				player.playTrack(songUrl);  // songLenght
			}

			private function onTrackDataInformation(event:Id3Event):void
			{
				songInfoText.text = event.id3.artist+" - "+event.id3.album;
			}

			private function onPlayerProgress(event:PlayProgressEvent):void
			{
				songSlider.value = event.playPosition;
				currentTimeText.text = Player.formatTimeInSecondsToString(event.playPosition);
				totalTimeText.text = Player.formatTimeInSecondsToString(event.total);
				songSlider.maximum = event.total;
			}

			private function onPlayerError(event:PlayerEvent):void
			{
				throw new Error(event.message);
			}

			protected function dragStartHandler(event:SliderEvent):void
			{
				player.removeEventListener(PlayProgressEvent.PLAYER_PROGRESS, onPlayerProgress);
			}

			private function onDownloadProgress(event:DownloadEvent):void
			{
				progressBar.setProgress(event.bytesLoaded, event.bytesTotal);
			}

			protected function dragDropHandler(event:SliderEvent):void
			{
				player.setTrackPosition(songSlider.value);
				player.addEventListener(PlayProgressEvent.PLAYER_PROGRESS, onPlayerProgress);
			}
		]]>
	</Script>

	<Text id="songInfoText" x="10" y="5" text="Artist - song name" />

	<HSlider id="songSlider" y="25" x="10" width="400" minimum="0" showTrackHighlight="true" liveDragging="true"
		thumbDrag="dragStartHandler(event)" thumbRelease="dragDropHandler(event)"/>
	<ProgressBar id="progressBar" y="45" x="15" width="390" height="1" minimum="0" maximum="100" labelWidth="0"
		direction="right" mode="manual"  />

	<Text y="45" x="420" text="Track Loader"/>

	<HBox y="30" x="420" horizontalGap="0">
		<Text id="currentTimeText" text="00:00"/>
		<Text text="/"/>
		<Text id="totalTimeText" text="00:00"/>
	</HBox>

	<HBox y="60" x="10" horizontalGap="12">
		<Button id="playButton" label="play" click="playSong();" enabled="false" />
		<Button label="pause" click="player.pauseTrack()" />
		<Button label="stop" click="songSlider.value=0; currentTimeText.text = '00:00'; player.stopTrack()" />
		<Button label="fastforward" click="player.fastforward();" />
		<Button label="rewind" click="player.rewind();" />
	</HBox>	

	<FormItem y="90">
		<FormItem label="Music Url:" />
		<HBox>
			<TextInput id="textInput" width="200" height="20" text="http://www.themagicofdc.com/multimedia/mp3/WonderfulWorld.mp3"/>
			<Button label="Submit" click="this.songUrl=textInput.text; playSong(); playButton.enabled=true" />
		</HBox>
	</FormItem>

I am seeing many people with id3 issues. I want to point out that there are issues with the ID3 event. It appears that the ID3 event sometimes get fire without information. I solved the issue by checking the sound API during download progress event.


sound.addEventListener(ProgressEvent.PROGRESS, downloadProgressHandler);

private function downloadProgressHandler(event:ProgressEvent):void
{
     if (this.sound.id3.album != null || this.sound.id3.artist != null || this.sound.id3.songName != null || this.sound.id3.genere != null)
     {
          // ID3 information is avaliable
      }
}

Another challange to point out. While loading a music track from the Web it takes the loader some time (depands on the size of the song and the speed of your internet) before it gets the total length of the track, so you can either use the playTrack method with only the URL:


player.playTrack(songUrl);

Or use the song URL and the lenght of the song, like the example below:


player.playTrack(songUrl, songLenght);

Which will allow you to have a better user experience.

21
Feb

mp3tunes-as3-api open source API to use MP3Tunes in Flex/AIR/AS3 projects

mp3tunes is a service to load your audio files and share them between different devices such as: desktop, mobile, game consoles and the Web. I just completed creating a foundation API for AS3.0 so you can start using the API in your Flex/AIR/AS3.0 projects.
You can see the project in google code: http://code.google.com/p/mp3tunes-as3-api/
The SWC and ASDOC can be downloaded from here: http://mp3tunes-as3-api.googlecode.com/files/Archive.zip
And here’s a simple implementation of the API in Flex 4 (Gumbo). The code login into the MP3tunes Music API, retrieve album result, artist data, track data and plays the first audio file in your account.


<FxApplication xmlns="http://ns.adobe.com/mxml/2009"
	creationComplete="creationCompleteHandler(event)">
	<Script>
		<![CDATA[
			import flash.events.Event;
			import flash.media.Sound;
			import flash.net.URLRequest;
			import com.elad.MP3tunes.vo.TrackItemVO;
			import com.elad.MP3tunes.vo.TrackListVO;
			import com.elad.MP3tunes.events.TrackDataEvent;
			import com.elad.MP3tunes.vo.AlbumListVO;
			import com.elad.MP3tunes.events.AlbumDataEvent;
			import com.elad.MP3tunes.vo.ArtistItemVO;
			import com.elad.MP3tunes.vo.ArtistListVO;
			import mx.controls.Alert;
			import com.elad.MP3tunes.events.ArtistsResultEvent;
			import com.elad.MP3tunes.events.MusicEvent;
			import mx.events.FlexEvent;
			import com.elad.MP3tunes.Music;
			private var music:Music;
			protected function creationCompleteHandler(event:FlexEvent):void
			{
				music = new Music("YOUR_DEVELOPER_KEY");
				music.addEventListener(MusicEvent.LOGIN_SUCCESSFULL, onLogin);
				music.addEventListener(MusicEvent.LOGIN_ERROR, function():void { Alert.show("Error login"); } );
				music.login("YOUR_USERNAME", "YOUR_PASSWORD");
			}
			private function onLogin(event:MusicEvent):void
			{
				music.removeEventListener(MusicEvent.LOGIN_SUCCESSFULL, onLogin);
				music.addEventListener(ArtistsResultEvent.ARTIST_RESULT_COMPLETED, onArtistsResult);
				music.addEventListener(ArtistsResultEvent.ARTIST_RESULT_ERROR, function():void { Alert.show("Error getting artist list"); });
				music.getMusicByArtists();
			}
			private function onArtistsResult(event:ArtistsResultEvent):void
			{
				music.removeEventListener(ArtistsResultEvent.ARTIST_RESULT_COMPLETED, onArtistsResult);
				var artistList:ArtistListVO = new ArtistListVO(event.artistList.list.source);
				var item:ArtistItemVO = artistList.getItem(0);
				music.addEventListener(AlbumDataEvent.ALBUM_DATA_COMPLETED, onAlbumDataComplete);
				music.addEventListener(AlbumDataEvent.ALBUM_DATA_ERROR, function():void { Alert.show("Error getting album list"); });
				music.getAlbumData(item.artistId);
			}
			private function onAlbumDataComplete(event:AlbumDataEvent):void
			{
				music.removeEventListener(AlbumDataEvent.ALBUM_DATA_COMPLETED, onAlbumDataComplete);
				music.removeEventListener(AlbumDataEvent.ALBUM_DATA_ERROR, onAlbumDataComplete);
				var albumList:AlbumListVO = new AlbumListVO(event.collection.list.source);
				var albumId:String = albumList.getItem(0).albumId;
				music.addEventListener(TrackDataEvent.TRACK_DATA_COMPLETED, onTrackDataComplete);
				music.addEventListener(TrackDataEvent.TRACK_DATA_ERROR, function():void { Alert.show("Error getting track data"); });
				music.getTrackData(albumId);
			}
			private function onTrackDataComplete(event:TrackDataEvent):void
			{
				music.removeEventListener(AlbumDataEvent.ALBUM_DATA_COMPLETED, onAlbumDataComplete);
				music.removeEventListener(TrackDataEvent.TRACK_DATA_ERROR, function():void { Alert.show("Error getting track data"); });
				var trackList:TrackListVO = new TrackListVO(event.collection.list.source);
				var trackItem:TrackItemVO = trackList.getItem(0);
				playSong(trackItem.downloadURL);
			}
			private function playSong(url:String):void
			{
				var sound:Sound = new Sound();
				var req:URLRequest = new URLRequest(url);
				sound.load(req);
				sound.play();
			}
		]]>
	<Script>
<FxApplication>
</p>
21
Feb

Ant task to generate SWC and ASDOC

Ant task to generate SWC and ASDOC for a library.

First create a property file to store location of your sdk and other information regarding your application: asdoc.properties - set properties file;


###################################################################
# Author: Elad Elrom - creates ASDOC and SWC
###################################################################
# Location of sdks directories
sdk.home 	 = /Users/user/Applications/Adobe\ Flex\ Builder\ 3\ Plug-in/sdks
# Location of sdk version
sdk.dir      = ${sdk.home}/3.2.0
# Location of asdoc.exe
asdoc.exe    = ${sdk.dir}/bin/asdoc
# ASDOC information
src.dir      = /Users/user/Documents/workspace/Library
doc.dir		 = /Users/user/Documents/workspace/Library
doc.src		 = ${doc.dir}/src/com/elad/API
output.dir   = ${doc.dir}/asdoc
# Libpath location to be included
libpath		 = ${doc.dir}/libs
# file name and folder
swc.dir		 = /Users/user/Documents/workspace/Library/swc
swcfilename	 = library.swc
FLEX_HOME	 = ${sdk.dir}
# ASDOC title for html pages
main.title   = ASDOC Title
window.title = ASDOC Title
</p>

Next, create the ant task to generate the asdoc and SWC file. Notice that I placed the flexTasks.jar in my local library, but feel free to point to it directly.


<project name="ASDoc build" default="main" >
	<!-- make sure that flexTasks.jar which is located in skd/ant/lib/flexTasks.jar otherwise you'll get an error message -->
	<taskdef resource="flexTasks.tasks" classpath="libs/flexTasks.jar" />
	<!-- defines all values for the ASDoc compiler -->
<property file="asdoc.properties" />
    <!-- main target: cleans and compiles ASDocs -->
    <target name="main" depends="clean-asdoc-directory, create-docs, clean-swc-directory, swc-generator" />
    <!-- deletes and recreates the asdoc directory -->
    <target name="clean-asdoc-directory" >
       <delete dir="${output.dir}" />
       <mkdir  dir="${output.dir}" />
    </target>
    <!-- deletes and recreates the swc directory -->
    <target name="clean-swc-directory" >
       <delete dir="${swc.dir}" />
       <mkdir  dir="${swc.dir}" />
    </target>
    <!-- runs the asdoc.exe compiler on the source -->
    <target name="create-docs" >
        <exec executable="${asdoc.exe}" failonerror="true" >
        	<arg line="-external-library-path='${libpath}/'" />
            <arg line="-doc-sources ${doc.src}" />
            <arg line="-output ${output.dir}" />
        </exec>
    	<echo>ASDOC created successfully</echo>
    </target>
	 <!-- generate the swc -->
	<target name="swc-generator" description="Compile the SWC file">
		<compc output="${swc.dir}/${swcfilename}">
			<include-libraries file="${libpath}/" />
			<!-- include our Class packages into the build (com folder) -->
			<include-sources dir="${doc.dir}/src/com" includes="*" />
		</compc>
		<echo>SWC created successfully</echo>
	</target>
</project>
</p>
18
Feb

Flash 10 on Mobile devices in early 2010

Adobe announced at the GSMA Mobile World Congress this month, that Flash Player 10, will be available on Smartphones running Windows Mobile, Google’s Android, Nokia S60 / Symbian, and Palm. These mobile devices with Flash Player 10 are expected to hit the market starting early 2010.

What about the iPhone?

In recent interview to Bloomberg Television, Adobe announced that onus is on them to create a well working version of Flash that runs on iPhone. Shantanu Narayan, CEO of Adobe, said:

“It’s a hard technical challenge, and that’s part of the reason Apple and Adobe are collaborating [...] The ball is in our court. The onus is on us to deliver.”

Adobe already has a version of Flash for the iPhone running on emulation software. So far Apple seems to be interested of people developing applications using their Objective C as well as promoting Sproutcore, which is a JavaScript framework that compete with Flash.

I believe that the challenge in bringing Flash 10 to mobile is taking in consideration mobile constrains such as limited resources, platform awareness and adaptation. Taking desktop application and deploying them on mobile with usage of 3D graphics, sound and video can drain the battery pretty quickly and show poor performance. Adobe will most likely to create a version of Flash 10 that has reduced functionality, however has some additional APIs to be able to tap into the touch screen as well as the GPS or other hardware devices.

17
Feb

Passing FlashVars using Flex template html

Adobe Livedoc (see here) indicates that you can pass flashvars in different ways through the URL or the flashvar object. I am using Flash Player 10 on Mozilla browser and it seems that the current player doesn’t work as explained.

It seems that there is only one way to pass the flash vars when using the template page that Flex builder 3.0 generates. You need to set it in the src under the javascript tag:


AC_FL_RunContent(
			"src", "${swf}?myName=Elad",
			"width", "${width}",
			"height", "${height}",
			"align", "middle",
			"id", "${application}",
			"quality", "high",
			"bgcolor", "${bgcolor}",
			"name", "${application}",
			"allowScriptAccess","sameDomain",
			"type", "application/x-shockwave-flash",
			"pluginspage", "http://www.adobe.com/go/getflashplayer"
	);

You can then easily read it in your Flex application:


var myName:String = mx.core.Application.application.parameters.myName;

I tested all the other options and nothing else seems to work. I also notices some other posts talking about the same issue, such as here:
http://flexblog.faratasystems.com/?m=200610

This issue may be related to the way the swf is deployed, in any case, I couldn’t get the examples from the livedoc to work. Remember to make the changes in the html-template folder so it will generate your template automatically every time you clean your project.

If anyone have more information, feel free to post it here.

16
Feb

Declaration tag in Flex Gumbo

Flex Gumbo have added a new tag called declaration. The new tag has to be used in cases where you want to reference a component that is not part of the mx.core or classes that are not display objects.

For instance, when creating Cairngorm projects you need to set references in the entry point to your controller, services and view such as the following code:


	<view:MainApp />
	<control:Controller />
	<business:Services />

However, in Flex Gumbo classes that are not display objects needs to be placed in a a declarations tag. Change your code easily by placing your classes to the declaration tag as follow;


	<view:MainApp />
	<Declarations>
		<control:Controller />
		<business:Services />
	</Declarations>

Otherwise you will get the following runtime error message.


TypeError: Error #1034: Type Coercion failed: cannot convert com.domain.project.control::Controller@21cf9d61 to flash.display.DisplayObject.
	at mx.components::Group/itemAdded()[E:\dev\gumbo_alpha\frameworks\projects\flex4\src\mx\components\Group.as:752]
	at mx.components::Group/initializeChildrenArray()[E:\dev\gumbo_alpha\frameworks\projects\flex4\src\mx\components\Group.as:251]
	at mx.components::Group/commitProperties()[E:\dev\gumbo_alpha\frameworks\projects\flex4\src\mx\components\Group.as:267]
	at mx.core::UIComponent/validateProperties()[E:\dev\gumbo_alpha\frameworks\projects\framework\src\mx\core\UIComponent.as:6130]
	at mx.managers::LayoutManager/validateProperties()[E:\dev\gumbo_alpha\frameworks\projects\framework\src\mx\managers\LayoutManager.as:539]
	at mx.managers::LayoutManager/doPhasedInstantiation()[E:\dev\gumbo_alpha\frameworks\projects\framework\src\mx\managers\LayoutManager.as:659]
	at Function/http://adobe.com/AS3/2006/builtin::apply()
	at mx.core::UIComponent/callLaterDispatcher2()[E:\dev\gumbo_alpha\frameworks\projects\framework\src\mx\core\UIComponent.as:8849]
	at mx.core::UIComponent/callLaterDispatcher()[E:\dev\gumbo_alpha\frameworks\projects\framework\src\mx\core\UIComponent.as:8789]

Notice that I haven’t placed my view in the declaration tag, since my view is a Canvas component, which extends Container. So what?

Component that doesn’t implements the mx.core namespace has to go into the declaration tag, including all the Fx components, however Canvas extends Container which is part of mx.core so no need to place it in the declaration tag.

By the way, you may have the same issue with PureMVC projects. The view reference in your entry point may need to be placed in the declaration tag, as explained above.

09
Feb

Using Pixel Bender to do heavy lifting calculations, makes Flash Player multi-thread.

In Flash 10 Adobe added a compiler to handle filters, which is possible through Pixel Bender kernels. Pixel Bender kernels is a program that calculate a single pixel at run time.

This is how it works. The Pixel Bender graph is an XML language for combining individual pixel-processing operations called kernels, which are in PBK file format.
We can create the PBK XML file using Pixel Bender toolkit. After our kernel is ready we can then export it as a byte-code called PBJ. PBJ can then be used in the Flash 10 player.
Flex Gumbo Bender shader is the Pixel Bender kernels, which uses a separate thread than Flash Player to calculate a single pixel.

You can use the following math functions for in pixel bender for calculations:

1. sin(x) - Trigonometric sine function.
2. cos(x) - Cosine function.
3. tan(x) – Tangent function.
4. asin(x) - Arcsine (inverse sine) function.
5. acos(x) - inverse cosine (arccosine) function.
6. atan(x) - Arctangent (inverse tangent) function.
7. atan(x, y) - Arctangent (inverse tangent) function.
8. exp(x) - exponential function.
9. log(x) – Logarithm function.
10. pow(x, y) - power of function.
11. reciprocal(x) - multiplicative inverse function.
12. sqrt(x) - square root function.

The challenge with Flash related to single thread processing always caused issues, and while the Flash Player is processing information we cannot run another thread to do other things. We often find the player get “stuck” when doing heavy lifting. Pixel Bender can help in certain cases. I managed to create an example and an API that uses Pixel Bender to calculate information, while a video is playing. In the example here you can run calculations while the video is playing and compare performance with Flash Player doing the same calculation.

First play the video and hit the Pixel Bender calculation and while the video is playing calculations are being made in the background. The results are astonishing, using Flash Player to calculate 5M sine took about 10 seconds (on iMac 2.8GHz and 4GB memory) and the video paused. Using Pixel Bender the video had a light glitch and we received the results back for the 5M calculation after about 10 secounds, without the user noticing.


Pixel Bender for calculation

Create the pbj file in Pixel Bender Toolkit:


<languageVersion : 1.0;>
kernel SinCalculator
<
    namespace : "pixelBender";
    vendor : "Elad Elrom";
    version : 1;
    description : "Sin Calculator";
>
{
    input image1 src;
    output pixel3 result;

    void evaluatePixel()
    {
    	pixel1 value = pixel1(sin(sample(src, outCoord())));
    	result = pixel3(value, 0.0, 0.0);
    }
}

The API handle calculating with Pixel bender by splitting the process into chucks of 5,000 per kernal, since Pixel Bender produce an error message on large calculations.


package com.elad.framework.pixelBender
{
	import com.elad.framework.pixelBender.events.PixelBenderCalcEvent;

	import flash.display.Shader;
	import flash.display.ShaderJob;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.utils.ByteArray;
	import flash.utils.Endian;

	[Event(name="completed", type="com.elad.pixelBender.events.PixelBenderCalcEvent")]

	/**
	 *  The PixelBenderCalculator class is the base class for math calculation with pixel bender
	 */
	public class PixelBenderCalculator extends EventDispatcher
	{
		public var kernalClass:Class;
		public var numberCollection:Array;

		private var shader:Shader;
		private var shaderJob:ShaderJob;
		private var input:ByteArray;
		private var output:ByteArray;
		private var retCollection:Array;
		private var requestsCounter:Number;
		private var numberOfRequest:Number;

		/**
		 * Number of calculations per kernal
		 */
		private const COLLECTION_SIZE:int = 5000;

		/**
		 * Default constructor for the pixel bender calculator
		 *
		 * @param numberCollection	collection contain numbers
		 * @param kernalClass	the kernal class of type pbj to be used to run the calculation
		 *
		 */
		public function PixelBenderCalculator(numberCollection:Array, kernalClass:Class)
		{
			reset();

			this.kernalClass = kernalClass;
			this.numberCollection = numberCollection;

			requestsCounter = numberCollection.length/COLLECTION_SIZE;
		}

		/**
		 * Method to start the calculation
		 *
		 */
		public function start():void
		{
		    output = new ByteArray();
		    output.endian = Endian.LITTLE_ENDIAN;

		    var start:int = numberOfRequest*COLLECTION_SIZE;
		    var end:int = ( (numberOfRequest+1)*COLLECTION_SIZE > numberCollection.length) ? numberCollection.length : ((numberOfRequest+1)*COLLECTION_SIZE);

		    input = convertArrayToByteArray(numberCollection, start, end);
		    createShaderJob();
		    numberOfRequest++;
		}

		/**
		 * Creates a shader class based on the kernal to pass the numbers and start the calculations.
		 *
		 * @see flash.display.ShaderJob
		 * @see flash.display.Shader
		 *
		 */
		private function createShaderJob():void
		{
			var width:int = input.length >> 2;
		    var height:int = 1;

		    shader = new Shader(new kernalClass());
		    shader.data.src.width = width;
		    shader.data.src.height = height;
		    shader.data.src.input = input;			    

		    shaderJob = new ShaderJob(shader, output, width, height);
		    shaderJob.addEventListener(Event.COMPLETE, shaderJobCompleteHandler);
		    shaderJob.start();
		}

		/**
		 * Static method to convert the array given into byte array.
		 *
		 * @param array
		 * @return
		 *
		 */
		private static function convertArrayToByteArray(array:Array, start:int, end:int):ByteArray
		{
			var retVal:ByteArray = new ByteArray();
		    var number:Number;

		    retVal.endian = Endian.LITTLE_ENDIAN;

		    for (var i:int=start; i<end; i++)
		    {
		    	number = Number(array[i]);
		    	retVal.writeFloat(number);
		    }

		    retVal.position = 0;
		    return retVal;
		}

		/**
		 * Convert the a <code>ByteArray</code> into an <code>Array</code>
		 *
		 * @param byteArray
		 * @return an array collection
		 *
		 */
		private function addByteArrayToCollection(byteArray:ByteArray):void
		{
		    var length:int = byteArray.length;
		    var number:Number;

		    for(var i:int=0; i<length; i+=4)
		    {
				number = byteArray.readFloat();
				if(i % 3 == 0)
				{
		    		retCollection.push(number);
		  		}
		    }
		}

		/**
		 * Handler for the shader once job is completed.
		 *
		 * @param event
		 *
		 */
		private function shaderJobCompleteHandler(event:Event):void
		{
		    output.position = 0;
			addByteArrayToCollection(output);

			input = null;
			output = null;

			if (requestsCounter>numberOfRequest)
			{
				start();
			}
			else
			{
				calculationCompleted();
			}

		}

		/**
		 * Method to dispatch an event once calculation is completed and reset this class.
		 *
		 */
		private function calculationCompleted():void
		{
			this.dispatchEvent( new PixelBenderCalcEvent(retCollection) );

			reset();
		}

		/**
		 * Method to clean up this class so we are not using un-needed memory.
		 *
		 */
		public function reset():void
		{
			retCollection = new Array();
			numberCollection = new Array();
			requestsCounter = 0;
			numberOfRequest = 0;
			numberCollection = null;
		}
	}
}

The implimentation is straight forward:


<FxApplication xmlns="http://ns.adobe.com/mxml/2009" xmlns:local="*" viewSourceURL="srcview/index.html">

	<!-- 

	////////////////////////////////////////////////////////////////////////////////
	//
	//  Elad Elrom (elad@elromdesign.com)
	//  Copyright 2009 Elorm LLC,
	//  All Rights Reserved.
	//
	//  NOTICE: Elad Elrom permits you to use, modify, and distribute this file
	//  in accordance with the terms of the license agreement accompanying it.
	//
	////////////////////////////////////////////////////////////////////////////////

 	@author  Elad Elrom

	-->

	<Script>
		<![CDATA[

			import com.elad.framework.pixelBender.PixelBenderCalculator;
			import com.elad.framework.pixelBender.events.PixelBenderCalcEvent;

			import mx.collections.ArrayCollection;
			import mx.collections.IList;
			import mx.events.FlexEvent;

			[Embed(source="SinCalculator.pbj", mimeType="application/octet-stream")]
			private var kernalClass:Class;
			private var pixelBenderCalc:PixelBenderCalculator;

			protected function startCalculatorPixelBender():void
			{
				// create a number collection
				var numberCollection:Array = new Array();

				for (var i:int=0; i<5000000; i++)
				{
					numberCollection.push( i );
				}

				// calculate
				pixelBenderCalc = new PixelBenderCalculator(numberCollection, kernalClass);
				pixelBenderCalc.addEventListener(PixelBenderCalcEvent.COMPLETED, onComplete );

				pixelBenderCalc.start();
			}

			private function startCalculatorFlashPlayer():void
			{
				// create a number collection
				var numberCollection:Array = new Array();

				for (var i:int=0; i<5000000; i++)
				{
					numberCollection.push( Math.sin(i) );
				}

				list.dataProvider = new ArrayCollection(numberCollection);
			}			

			private function onComplete(event:PixelBenderCalcEvent):void
			{
				list.dataProvider = new ArrayCollection(event.numberCollection);
				pixelBenderCalc.removeEventListener(PixelBenderCalcEvent.COMPLETED, onComplete);
			}

		]]>
	</Script>

	<List id="list" width="200" height="531.5"/>
	<Button label="Calculate with Pixel Bender" width="200" height="20" y="545" click="startCalculatorPixelBender()"/>
	<Button label="Calculate with Flash Player" width="200" height="20" y="574" click="startCalculatorFlashPlayer()"/>

	<VideoDisplay id="vid" width="355" height="290"
		source="http://thehq.tv/wp-content/uploads/flv/super-street-fighter-2-hd-round-1-trailer.flv"
		autoPlay="false" x="209" y="-1"/>
	<Button label="Play" click="vid.play();" x="213" y="303"/>

	<local:MemoryDashBoard  x="211" y="343"/>

</FxApplication>