In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Libspark Threading example, english - including ThreadStepProcessor

This is a basic example of how to work with the

LIBSPARK THREAD LIBRARY

In this example first a twitter api call is done and
all the avatar images of this call are beeing arranged.

Then the user will be asked to click at the stage as
an example for event handling and timeout processing.

Finally a custom process will be triggered that does
some heavy math calculation which should take
considerable amount of time on all common computers.

The loading of the images is parallel, all errors
that can occur while loading will be displayed
as small text field.

have fun! The library is cool shit!

Ps.: This is utilizing the ThreadStepProcessor extension
for the Thread library.
/**
 * Copyright leichtgewicht ( http://wonderfl.net/user/leichtgewicht )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/lepP
 */

/*
  This is a basic example of how to work with the
  
  LIBSPARK THREAD LIBRARY
    
  In this example first a twitter api call is done and
  all the avatar images of this call are beeing arranged.
  
  Then the user will be asked to click at the stage as
  an example for event handling and timeout processing.
  
  Finally a custom process will be triggered that does
  some heavy math calculation which should take
  considerable amount of time on all common computers.
  
  The loading of the images is parallel, all errors
  that can occur while loading will be displayed
  as small text field.

  have fun! The library is cool shit!
  
  Ps.: This is utilizing the ThreadStepProcessor extension
       for the Thread library.
  
  */
package {
	
	import org.libspark.thread.*;
	import flash.display.*;
	
	public class ThreadLibraryExample extends Sprite {
		
		public function ThreadLibraryExample(){
			
			// Tell the Thread framework to use a EnterFrame
			// implementation of Executor for Pseudothreads
			Thread.initialize( new EnterFrameThreadExecutor() );
			
			// Create a startup thread and start it
			// -> I pass in this thread of 
			var setup: SetupThread = new SetupThread( this );
			setup.start();
		}
	}
}

import flash.utils.getQualifiedClassName;
import org.libspark.thread.Thread;
import org.libspark.thread.step.StepThread;
import org.libspark.thread.threads.display.LoaderThread;
import org.libspark.thread.threads.net.URLLoaderThread;
import org.libspark.thread.utils.Progress;
import org.libspark.thread.utils.IProgress;
import org.libspark.thread.utils.events.ProgressEvent;
import org.libspark.thread.utils.ParallelExecutor;
import org.libspark.thread.utils.IProgressNotifier;

import flash.net.navigateToURL;
import flash.display.*;
import flash.errors.IOError;
import flash.events.Event;
import flash.net.URLRequest;
import flash.text.*;
import flash.system.Security;

// The Setup Thread has to extend Thread in order to do Thread
// That is a bit annoying tbh.
import flash.events.MouseEvent;
class SetupThread extends Thread {
	
	private var _container: DisplayObjectContainer;
	private var _configLoader: URLLoaderThread;
	private var _allImagesLoader: ParallelExecutor;
	private var _messageDisplay: MessageDisplay;
	private var _pseudoThread: PseudoThread;

	public function SetupThread( container: DisplayObjectContainer ) {
		_container = container;
	}
	
	// Overriding the "run" template method of the Thread class
	// Other events like "start" will be triggered properly
	// around that 
	override protected function run(): void {
		
		
		// Create a URLLoaderThread for the twitterfeed that offers the images
		_configLoader = new URLLoaderThread( new URLRequest("http://search.twitter.com/search.atom?q=thread") );
		
		// Configloader is started!
		_configLoader.start();
		
		// Let _configLoader block the current thread
		// _configLoader is now a subthread
		_configLoader.join();
		
		// register error handlers, for both errors that occur
		error( IOError, handleError );
		error( SecurityError, handleError );
				
		// After the configuration is loaded, load the images that are specified in it
		next( loadImagesOfTwitterFeed );
	}
	
	// If a error occurs, show a error message!
	private function handleError( error: Error, thread: Thread ): void {
		
		message( error.message, true );
		
		// Interrupt eventually started subthreads and stop loading following
		interrupt();
	}
	
	private function loadImagesOfTwitterFeed(): void {
		// If a error occured, now the thread would be interrupted!
		if( !isInterrupted ) {
			
			var xml: XML = new XML( _configLoader.loader.data );
			var images: XMLList = xml..(xml.namespace())::link.(@type == "image/png" || @type == "image/jpeg" || @type == "image/jpg" || @type == "image/gif" );
			
			// Create a new ParallelExecutor that loads the images
			// beside each other
			_allImagesLoader = new ParallelExecutor();
			
			// Add all images of the xml as LoaderThread to the loader
			for each( var image: XML in images ) {
				_allImagesLoader.addThread( new LoaderThread( new URLRequest(image.@href) ) );
			}
			
			// Start the loading of all images
			_allImagesLoader.start();
			
			// Set this again as subthread in order to wait for the images
			// to be loaded
			_allImagesLoader.join();

			// The error handlers from before got removed
			// To listen again to the events added once more
			error( IOError, handleError );
			error( SecurityError, handleError );
			
			// Next call would be to add the images to the stage
			next( addImages );
			
		}
	}
	
	private function addImages(): void {
		// Could have been interrupted in last step!
		if( !isInterrupted ) {
			
			// Just for demo reasons: Draw all images
			var stageWidth: int = _container.stage.stageWidth;
			var maxHeight: int = 0;
			var x: int = 0;
			var y: int = 0;
			
			for( var i: int = 0; i< _allImagesLoader.numThreads; ++i ) {
				
				// Pulling the data from LoaderThread
				var content: DisplayObject = LoaderThread(_allImagesLoader.getThreadAt(i)).loader;
				
				if( x + content.width > stageWidth ) {
					x = 0;
					y += maxHeight;
				}
				content.x = x;
				content.y = y;
				if( content.height > maxHeight ) {
					maxHeight = content.height;
				}
				x += content.width;
				_container.addChild( content );
			}
			
			// Example for event handling
			// Message is displayed
			message( "click me in the next 5 seconds" );
			
			// And once a event occurs -> The next process is triggered
			event( _container.stage, MouseEvent.MOUSE_DOWN, startPseudoThread );
			
			// Unless you clicked in 5 seconds ( 5000 ms )
			wait( 5000 );
			
			// Tell the Thread system that it should show a message
			// once the timeout for wait has been exceeded
			timeout( showClickFailed );
		}
	}
	
	private function showClickFailed(): void {	
		// Wait triggered this timeout!
		message( "You were too slow!", true );
	}	
	
	private function startPseudoThread( event: Event = null ): void {
		message( "Starting pseudo thread" );
		
		// Initializing a pseudo thread as before
		_pseudoThread = new PseudoThread();
		
		// and starting it
		_pseudoThread.start();
		
		// waiting for it...
		_pseudoThread.join();
		
		// ... and displaying the progress
		_pseudoThread.progress.addEventListener( ProgressEvent.UPDATE, showPercentage );
		
		error( Error, handleError );
		next( finish );
	}
	
	private function showPercentage( event: ProgressEvent ): void {
		// Percentage is stored in Progress class from 0 to 1
		message( int( _pseudoThread.progress.percent * 100) + "%" );
	}
	
	private function finish(): void {
		// Wippa - the pseudo thread finished its calcuation
		message( "pseudo thread finished" );
	}
	
	override protected function finalize(): void {
		// Removing the references, for more controlled
		// garbage cleaning after everything is done 
		_container = null;
		_configLoader = null;
		_allImagesLoader = null;
		_messageDisplay = null;
	}	
	
	internal function message( message: String, error: Boolean = false ): void {
		if( _messageDisplay ) {
			_container.removeChild( _messageDisplay );
			_messageDisplay = null;
		}
		if( message ) {
			_container.addChild( _messageDisplay = new MessageDisplay( message, error ) );
		}
	}
}

// Pseudo thread that counts up to the MAX constant (nothing spectacular)
class PseudoThread extends StepThread implements IProgressNotifier {
	
	// amount to count up to
	private static const MAX: int = 50000000;
	
	private var _progress: Progress = new Progress();
	private var _i: int;
	
	override protected function init(): void {
		// initial state definition
		_progress.start( MAX );
		_i = 0;
	}
	
	override protected function process(): Boolean {
		++_i;
		// return true if its completly executed
		return _i >= MAX;
	}
	
	override protected function updateState(): void {
		// fill the current state into progress bar
		_progress.progress( _i );
	}
	
	// Implementation of IProgressNotifier method
	// for the progress bar.
	public function get progress(): IProgress {
		return _progress;
	}
}

// Just a display to show a occured error
class MessageDisplay extends Sprite {

	private var _text: TextField;

	public function MessageDisplay( message: String, error: Boolean ) {
		addChild( _text = new TextField() );
		_text.defaultTextFormat = new TextFormat( "Verdana", 10, 0xFFFFFF );
		_text.autoSize = TextFieldAutoSize.LEFT;
		_text.text = message;
			with( graphics ) {
			beginFill( error ? 0xAC0000 : 0x00AC00 );
			drawRoundRect( 0, 0, _text.textWidth+10, _text.textHeight+10, 5 );
			endFill();
		}
		addEventListener( Event.ADDED_TO_STAGE, render );
	}
	
	private function render( event: Event ): void {
		x = stage.stageWidth/2 - width/2;
		y = stage.stageHeight/2 - height/2;
	}	
}