Flash, ECMAScript snippets and tips collection

The aim of this document is to gather informations, snippets, tips and links not provided by any official documentation, related to Flash Platform or others ECMAScript languages.

Fonts

Bitmap fonts

Flash renames bitmap fonts and adds the suffix: _{size}pt_st, where {size} is the bitamp size of the font.

Exemple:

Effects on no-embedded fonts (alpha, rotation, etc.)

In FlashPlayer 9, to apply alpha, use filters, cacheAsBitmap or blend mode "layer"

textField.filters = [new BlurFilter(0,0,0)];//use emtpy filter to cache text
//or
textField.blendMode = BlendMode.LAYER;
//and finaly
textField.alpha = 0.5;

For other effect (rotation, scale, etc.) draw TextField in a BitmapData

In FlashPlayer 10, no more problems with alpha, but remain for transfrom effects like rotation, scale, etc.

In FlashPlayer 10 flash.text.engine natively support it

Flash player

flash.external::ExternalInterface$/_callIn

Adoption / market penetration

6 to 9 month for all new version to reach ~90% of adoption

Flash right click (disable ContextMenu)

/**
 * 
 * Copyright 2007
 * 
 * Paulius Uza
 * http://www.uza.lt
 * http://www.uza.lt/blog/2007/08/solved-right-click-in-as3
 * 
 * Dan Florio
 * http://www.polygeek.com
 * 
 * Project website:
 * http://code.google.com/p/custom-context-menu/
 * 
 * --
 * RightClick for Flash Player. 
 * Version 0.6.2
 * 
 */

var RightClick = {
	/**
	 *  Constructor
	 */ 
	init: function () {
		this.FlashObjectID = "customRightClick";
		this.FlashContainerID = "flashcontent";
		this.Cache = this.FlashObjectID;
		if(window.addEventListener){
			 window.addEventListener("mousedown", this.onGeckoMouse(), true);
		} else {
			document.getElementById(this.FlashContainerID).onmouseup = function() { document.getElementById(RightClick.FlashContainerID).releaseCapture(); }
			document.oncontextmenu = function(){ if(window.event.srcElement.id == RightClick.FlashObjectID) { return false; } else { RightClick.Cache = "nan"; }}
			document.getElementById(this.FlashContainerID).onmousedown = RightClick.onIEMouse;
		}
	},
	/**
	 * GECKO / WEBKIT event overkill
	 * @param {Object} eventObject
	 */
	killEvents: function(eventObject) {
		if(eventObject) {
			if (eventObject.stopPropagation) eventObject.stopPropagation();
			if (eventObject.preventDefault) eventObject.preventDefault();
			if (eventObject.preventCapture) eventObject.preventCapture();
	   		if (eventObject.preventBubble) eventObject.preventBubble();
		}
	},
	/**
	 * GECKO / WEBKIT call right click
	 * @param {Object} ev
	 */
	onGeckoMouse: function(ev) {
	  	return function(ev) {
	    if (ev.button != 0) {
			RightClick.killEvents(ev);
			if(ev.target.id == RightClick.FlashObjectID && RightClick.Cache == RightClick.FlashObjectID) {
	    		RightClick.call();
			}
			RightClick.Cache = ev.target.id;
		}
	  }
	},
	/**
	 * IE call right click
	 * @param {Object} ev
	 */
	onIEMouse: function() {
	  	if (event.button > 1) {
			if(window.event.srcElement.id == RightClick.FlashObjectID && RightClick.Cache == RightClick.FlashObjectID) {
				RightClick.call(); 
			}
			document.getElementById(RightClick.FlashContainerID).setCapture();
			if(window.event.srcElement.id)
			RightClick.Cache = window.event.srcElement.id;
		}
	},
	/**
	 * Main call to Flash External Interface
	 */
	call: function() {
		document.getElementById(this.FlashObjectID).rightClick();
	}
}

ExternalInterface JavaScript evaluation

ExternalInterface evaluate given JavaScript string (anonymous functions): ExternalInterface.call("(function(param1, param2) {/* javascript code here */})", parameter1, parameter2);

Note: don’t use the dash character "-" or other special chars in the DOM id of your flash element. IE need id attribute for using ExtenralInterface, others need name attribute.

IE native JavaScript function for hanlding Flash & JS exchanges

function __flash__arrayToXML(obj)
{
	var s = "<array>";
	for (var i=0; i<obj.length; i++)
		s += "<property id=\"" + i + "\">" + __flash__toXML(obj[i]) + "</property>";
	return s+"</array>";
}

function __flash__argumentsToXML(obj, index)
{
	var s = "<arguments>";
	for (var i=index; i<obj.length; i++)
		s += __flash__toXML(obj[i]);
	return s+"</arguments>";
}

function __flash__objectToXML(obj)
{
	var s = "<object>";
	for (var prop in obj)
		s += "<property id=\"" + prop + "\">" + __flash__toXML(obj[prop]) + "</property>";
	return s+"</object>";
}

function __flash__escapeXML(s)
{
	return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
}

function __flash__toXML(value)
{
	var type = typeof(value);
	if (type == "string")
		return "<string>" + __flash__escapeXML(value) + "</string>";
	else if (type == "undefined")
		return "<undefined/>";
	else if (type == "number")
		return "<number>" + value + "</number>";
	else if (value == null)
		return "<null/>";
	else if (type == "boolean")
		return value ? "<true/>" : "<false/>";
	else if (value instanceof Date)
		return "<date>" + value.getTime() + "</date>";
	else if (value instanceof Array)
		return __flash__arrayToXML(value);
	else if (type == "object")
		return __flash__objectToXML(value);
	else
		return "<null/>"; //???
}

function __flash__addCallback(instance, name)
{
	instance[name] = function()
		{ 
			return eval(instance.CallFunction("<invoke name=\""+name+"\" returntype=\"javascript\">" + __flash__argumentsToXML(arguments,0) + "</invoke>"));
		}
}

function __flash__removeCallback(instance, name)
{
	instance[name] = null;
}

Extending Flash

Execute command line through JSFL

FLfile.runCommandLine("command line here");

Metadata

Add document metadata in Flash:

var frame = fl.getDocumentDOM().timelines[0].layers[0].frames[0];
var headerText = "[SWF(width=800, height=800, backgroundColor=0xffffff, frameRate=24)]\n"
	+ "stage.align = StageAlign.TOP_LEFT;\n"
	+ "stage.scaleMode = StageScaleMode.NO_SCALE;\n\n";
frame.actionScript = headerText + frame.actionScript;

[Transient] metadata

package foo
{
	[RemoteClass(alias="foo.Bar")]
	public class Bar
	{
		// public field
		public var prop1:String;

		// private field but keeped
		[Transient]
		private var prop2:Array;
	}
}

Applied in all places using AMF encoding (RemoteObject, NetConnection, byteArray.readObject();)

See flash.net.registerClassAlias()

Use AS3 metadata

-keep-as3-metadata+=Meta1,Meta2
package
{
	[Meta2(param1 = "param 1 value")]
	public class TestClass
	{
		[Meta1(param1 = "param 1 value", param2 = "param 2 value")]
		public var test1:String;
		
		
		[Meta2(paramA = "param 1 value", paramB = "param 2 value")]
		public function get test2():String
		{
			return null;
		}
		
		public function set test2(val:String):void
		{
		
		}
		
		[Meta1(param1 = "param 1 value")]
		public function someMethod():void
		{
		
		}
	}
}
var classMetadatas:XMLList = describeType(TestClass).factory.metadata;
var methodsMetadatas:XMLList = describeType(TestClass).factory.method.metadata;
var variablesMetadatas:XMLList = describeType(TestClass).factory.variable.metadata;
var accessorsMetadatas:XMLList = describeType(TestClass).factory.accessor.metadata;

Conditional compilation

-define=namespace::variable_name,value
CONDITIONAL_COMPILATION::value
{
	//Do something only when compilation condition is verified
}

if(some condition)
{
	//Do something
}
else
{
	CONDITIONAL_COMPILATION::value
    {
		//Something only when compilation condition is verified
	}
}
CONDITIONAL_COMPILATION::value = 'true'

Inline

package
{
	CONFIG::debugging
	public class MyClass
	{
		//some declarations
	}

	CONFIG::release
	public class MyClass
	{
		//some declarations
	}
}
CONFIG::debugging = 'true'
CONFIG::release = '!CONFIG::debugging'
private static const companyName:String = NAMES::Company;
NAMES::Company = '"Company name"'

Conditional compilation is string replacement

CONDITIONAL_COMPILATION::value = '1 > 2'
CONDITIONAL_COMPILATION::value1 = 'false'
CONDITIONAL_COMPILATION::value2 = 'CONDITIONAL_COMPILATION::value1 && false'

FLA format

Since CS5, FLA file format is an XML based format. May be compressed in a ZIP file.

XFL file format

ABC Format

SWF Format

<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.0 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Original Author <alessandro@sephiroth.it> |
// +----------------------------------------------------------------------+
//http://www.sephiroth.it/swfreader.php


/**
* required base PEAR package
*/
require_once "PEAR.php";
/**
* Required package File for I/O operations
*/
require_once "File.php";

/**
* error constant
*/
define('PEAR_SWF_ID_ERR', 1);

/**
* Base SWF class
*
* This class requires the File PEAR.
* Read the SWF header informations and return an
* associative array with the property of the SWF File, the result array
* will contain framerate, framecount, background color, compression, filetype
* version and movie size.
* <code>
* <?php
* require_once "File/File_SWF.php";
* $file = "any_file.swf";
*
* $swf = &new File_SWF($file);
* if($swf->isValid){
* $result = $swf->stat();
* print_r($result);
* }
* <?
* </code>
* @author Alessandro Crugnola <alessandro@sephiroth.it>
* @access public
* @version 0.2
* @package File_SWF
*/
class File_SWF
{
	/**
	* current unpacked binary string
	* @var mixed
	*/
	var $current = "";
	/**
	* internal pointer
	* @var integer
	*/
	var $position = 0;
	/**
	* use zlib compression
	* @var boolean
	*/
	var $compression = 0;
	/**
	* current position
	* @var integer
	*/
	var $point = 0;
	/**
	* is a valid swf
	* @var boolean
	* @access private
	*/
	var $isValid = 0;
	/**
	* stirng file name to parse
	* @var string
	*/
	var $file = "";
	/**
	* determine if file is protected
	* @var boolean
	*/
	var $protected = false;
	/**
	* password for protected files
	* @var mixed
	*/
	var $password;

	/**
	* Deconstructor
	* does anything right now
	* @access public
	*/
	function _File_SWF()
	{
	}

	/**
	* Costructor
	* creates a new SWF object
	* reads the given file and parse it
	* @param string $file file to parse
	* @access public
	*/
	function File_SWF($file="")
	{
		$this->compression = 0;
		$this->isValid = 0;
		$this->point = 0;
		$this->file = $file;
		$head = File::read($this->file, 3);
		if(PEAR::isError($head)){
			return $head;
		}
		File::rewind($this->file, "rb");
		if($head == "CWS"){
			$data = File::read($this->file, 8);
			$_data = gzuncompress(File::read($this->file, filesize($this->file)));
			$data = $data . $_data;
			$this->data = $data;
			$this->compression = 1;
			$this->isValid = 1;
		} else if ($head == "FWS"){
			$this->data = File::read($this->file, filesize($this->file));
			$this->isValid = 1;
		} else {
			/**
			* invalid SWF file, or invalid head tag found
			*/
			$this->isValid = 0;
		}
		File::close($this->file, "rb");
	}

	/**
	* Is a valid SWF file
	* @return boolean
	* @access public
	*/
	function is_valid()
	{
		return $this->isValid;
	}

	/**
	* Return if swf file is protected from import
	* @return boolean
	* @access public
	*/
	function getProtected()
	{
		if($this->getVersion() >= 8){
			$this->_seek(31);
		} else {
			$this->_seek(26);
		}
		$data = $this->_readTag();
		$tag	= $data[0];
		$this->protected = $tag == 24;
		return $this->protected;
	}

	/**
	* Define import protection for the SWF
	* @param boolean $protect define is file must be protected
	* @access public
	*/
	function setProtected($protect)
	{
		if($protect and !$this->protected){
			if($this->getVersion() >= 8){
				$pre = substr($this->data, 0, 31);
				$post = substr($this->data, 31);
			} else {
				$pre = substr($this->data, 0, 26);
				$post = substr($this->data, 26);
			}
			$middle = pack("v", 1536);
			$this->data = $pre . $middle . $post;
			$this->password = 0;
			$this->protected = true;
		} else if(!$protect and $this->protected){
			if($this->getVersion() >= 8){
				$pos = 31;
			} else {
				$pos = 26;
			}
			$this->_seek($pos);
			if($this->_readData()){
				$this->data = substr($this->data,0, $pos) . substr($this->data, $this->point - (is_string($this->password) == 1 ? 0 : 1));
			}
		}
	}

	/**
	* Return the current SWF frame rate
	* @return mixed interger frame rate in fps or Error if invalid file
	* @access public
	*/
	function getFrameRate()
	{
		if(!$this->is_valid()){
			return PEAR::raiseError("Invalid SWF head TAG found in " . $this->file, PEAR_SWF_ID_ERR);
		}
		if($this->getVersion() >= 8){
			$this->_seek(16);
		} else {
			$this->_seek(17);
		}
		$fps = unpack('vrate',$this->_read(2));
		return $fps['rate']/256;
	}

	/**
	* Set the new Frame Rate
	* @access public
	*/
	function setFrameRate($num)
	{
		if(!$this->is_valid()){
			return;
		}
		$num = intval($num);
		if($num > 0 and $num <= 120){
			$fps = pack('v', $num*256);
			if($this->getVersion() >= 8){
				$this->_seek(16);
				$this->data = substr($this->data, 0, 16) . $fps . substr($this->data, 18);
			} else {
				$this->_seek(17);
				$this->data = substr($this->data, 0, 17) . $fps . substr($this->data, 19);
			}
		}
	}

	/**
	* Return the current number of frames
	* @return mixed interger or error if invalid file format
	* @access public
	*/
	function getFrameCount()
	{
		if(!$this->is_valid()){
			return PEAR::raiseError("Invalid SWF head TAG found in " . $this->file, PEAR_SWF_ID_ERR);
		}
		if($this->getVersion() >= 8){
			$this->_seek(18);
		} else {
			$this->_seek(19);
		}
		return $this->_readshort();
	}

	/**
	* Return the current movie size in pixel
	* @return mixed array or error if invalid file format
	* @access public
	*/
	function getMovieSize()
	{
		if(!$this->is_valid()){
			return PEAR::raiseError("Invalid SWF head TAG found in " . $this->file, PEAR_SWF_ID_ERR);
		}
		$this->_seek(8);
		return $this->_readRect();
	}

	/**
	* Return the current file type (CWS, FWS)
	* @return mixed string or error if invalid file format
	* @access public
	*/
	function getFileType()
	{
		if(!$this->is_valid()){
			return PEAR::raiseError("Invalid SWF head TAG found in " . $this->file, PEAR_SWF_ID_ERR);
		}
		$this->_seek(0);
		return $this->_read(3);
	}

	/**
	* Return the current compression used
	* @return mixed interger or error if invalid file format
	* @access public
	*/
	function getCompression()
	{
		if(!$this->is_valid()){
			return PEAR::raiseError("Invalid SWF head TAG found in " . $this->file, PEAR_SWF_ID_ERR);
		}
		return $this->compression;
	}

	/**
	* Set the compression
	* @return string based on the compression used
	* @param integer $mode compression on/off
	* @access public
	*/
	function setCompression($mode = 0)
	{
		if(!$this->is_valid()){
			return;
		}
		$data = "";
		$real_size = pack("V", strlen($this->data));
		$this->data = substr($this->data, 0, 4) . $real_size . substr($this->data, 8, strlen($this->data));
		if($mode == 0){
			$this->compression = 0;
			$this->data = "FWS" . substr($this->data, 3);
			$_n1 = substr($this->data, 0, 8);
			$_n2 = substr($this->data, 8, strlen($this->data));
			$data = $_n1 . $_n2;
		} else if($mode == 1){
			$this->compression = 1;
			$this->data = "CWS" . substr($this->data, 3);
			$_n1 = substr($this->data, 0, 8);
			$_n2 = substr($this->data, 8, strlen($this->data));
			$_n3 = gzcompress($_n2);
			$data = $_n1 . $_n3;
		}
		return $data;
	}

	/**
	* Return the current version of player used
	* @return mixed interger or error if invalid file format
	* @access public
	*/
	function getVersion()
	{
		if(!$this->is_valid()){
			return PEAR::raiseError("Invalid SWF head TAG found in " . $this->file, PEAR_SWF_ID_ERR);
		}
		$this->_seek(3);
		return $this->_readbyte();
	}

	/**
	* Return the current SWF file size
	* @return mixed interger or error if invalid file format
	* @access public
	*/
	function filesize()
	{
		if(!$this->is_valid()){
			return PEAR::raiseError("Invalid SWF head TAG found in " . $this->file, PEAR_SWF_ID_ERR);
		}
		$this->_seek(4);
		$real_size = unpack("Vnum", $this->_read(4));
		if($this->getCompression()){
			$n = $this->data;
			$n = "CWS" . substr($n, 3, 8) . gzcompress(substr($n, 8, strlen($n)));
			$file_size = strlen($n) -3;
		} else {
			$file_size = strlen($this->data)-3;
		}
		return array($file_size, $real_size['num'], "compressed" => $file_size, "real" => $real_size['num']);
	}

	/**
	* Return the current background color
	* @return mixed array or error if invalid file format
	* @access public
	*/
	function getBackgroundColor()
	{
		if(!$this->is_valid()){
			return PEAR::raiseError("Invalid SWF head TAG found in " . $this->file, PEAR_SWF_ID_ERR);
		}
		if($this->getVersion() >= 8){
			$this->_seek(26);
		} else {
			$this->_seek(21);
		}
		return $this->_readData();
	}

	/**
	* Set the new background color
	* @param integer $r (0,255)
	* @param integer $g (0,255)
	* @param integer $b (0,255)
	* @access public
	*/
	function setBackgroundColor($r=0, $g=0, $b=0)
	{
		if(!$this->is_valid()){
			return;
		}
		$color	= pack("C", $r);
		$color .= pack("C", $g);
		$color .= pack("C", $b);

		if($this->getVersion() >= 8){
			$data = substr($this->data, 0, 28);
			$data .= $color;
			$this->data = $data . substr($this->data, 31, strlen($this->data));
		} else {
			$data = substr($this->data, 0, 23);
			$data .= $color;
			$this->data = $data . substr($this->data, 26, strlen($this->data));
		}
	}

	/**
	* Save current swf as a new file
	* @param string $filename filename
	* @param boolean $overwrite overwrite existing file
	* @return boolean true if saved succesfully
	* @access public
	*/
	function write($filename, $overwrite = 1)
	{
		if(!$this->is_valid()){
			return false;
		}
		if(is_writeable(dirname($filename))){
			if(is_file($filename)){
				if($overwrite == 0){
					return false;
				}
			}
			$newdata = $this->setCompression($this->getCompression());
			File::write ($filename, $newdata, $mode = "wb");
			File::close($filename, "wb");
			return true;
		} else {
			return false;
		}
	}

	/**
	* reads the SWF header
	* @return mixed associative array or error on fault
	* @access private
	*/
	function stat()
	{
		if(!$this->is_valid()){
			return PEAR::raiseError("Invalid SWF head TAG found in " . $this->file, PEAR_SWF_ID_ERR);
		}
		$filetype = $this->getFileType();
		$version = $this->getVersion();
		$filelength = $this->filesize();
		$rect = $this->getMovieSize();
		$framerate = $this->getFrameRate();
		$framecount = $this->getFrameCount();
		$background = $this->getBackgroundColor();
		$protection = $this->getProtected();
		return array(
			"zlib-compression" => $this->getCompression(),
			"fileType" => $filetype,
			"version" => $version,
			"fileSize" => $filelength,
			"frameRate" => $framerate,
			"frameCount" => $framecount,
			"movieSize" => $rect,
			"background" => $background,
			"protected" => $protection,
		);
	}

	/**
	* read tag type, tag length
	* @return array
	* @access private
	*/
	function _readTag()
	{
		$n = $this->_readshort();
		if($n == 0)
		{
			return false;
		}
		$tagn = $n>>6;
		$length = $n&0x3F;
		if($length == 0x3F)
		{
			$length = $this->_readlong();
		}
		return array($tagn,$length);
	}

	/**
	* read long
	* @access private
	*/
	function _readlong(){
		$ret = unpack("Nnum", $this->_read(4));
		return $ret['num'];
	}

	/**
	* read data of next tag
	* @return array
	* @access private
	*/
	function _readData()
	{
		$tag = $this->_readTag();
		$tagn = $tag[0];
		$length = $tag[1];
		if($tagn == 9)
		{
			$r = $this->_readbyte();
			$g = $this->_readbyte();
			$b = $this->_readbyte();
			$data = array($r,$g,$b, "hex" => sprintf("#%X%X%X", $r, $g, $b));
			return $data;
		} else if($tagn == 24)
		{
			if($this->_readbyte() == 0x00){
				$this->_readbyte();
				$this->password = $this->_readstring();
			} else {
				$this->password = 0;
			}
			return true;
		}
		return array();
	}

	/**
	* read a string
	* @return string
	* @access private
	*/
	function _readstring()
	{
		$s = "";
		while(true){
			$ch = $this->_read(1);
			if($this->point > strlen($this->data)){
				break;
			}
			if($ch == "\x00"){
				break;
			}
			$s .= $ch;
		}
		return $s;
	}


	/**
	* read internal data file
	* @param integer $n number of byte to read
	* @return array
	* @access private
	*/
	function _read($n)
	{
		$ret = substr($this->data, $this->point, $n);
		$this->point += $n;
		return $ret;
	}

	/**
	* move the internal pointer
	* @param integer $num
	* @access private
	*/
	function _seek($num){
		if($num < 0){
			$num = 0;
		} else if($num > strlen($this->data)){
			$num = strlen($this->data);
		}
		$this->point = $num;
	}

	/**
	* read short
	* @return string
	* @access private
	*/
	function _readshort(){
		$pack = unpack('vshort',$this->_read(2));
		return $pack['short'];
	}

	/**
	* read single byte
	* @return string
	* @access private
	*/
	function _readByte(){
		$ret = unpack("Cbyte",$this->_read(1));
		return $ret['byte'];
	}
	/**
	* read a rect type
	* @return rect
	* @access private
	*/
	function _readRect(){
		$this->_begin();
		$l = $this->_readbits(5);
		$xmin = $this->_readbits($l)/20;
		$xmax = $this->_readbits($l)/20;
		$ymin = $this->_readbits($l)/20;
		$ymax = $this->_readbits($l)/20;
		$rect = array(
			$xmax,
			$ymax,
			"width" => $xmax,
			"height" => $ymax
		);
		return $rect;
	}

	/**
	* read position internal to rect
	* @access private
	*/
	function _incpos(){
		$this->position += 1;
		if($this->position>8){
			$this->position = 1;
			$this->current = $this->_readbyte();
		}
	}
	/**
	* read bites
	* @param integer $nbits number of bits to read
	* @return string
	* @access private
	*/
	function _readbits($nbits){
		$n = 0;
		$r = 0;
		while($n < $nbits){
			$r = ($r<<1) + $this->_getbits($this->position);
			$this->_incpos();
			$n += 1;
		}
		return $r;
	}

	/**
	* getbits
	* @param integer $n
	* @return long
	* @access private
	*/
	function _getbits($n){
		return ($this->current>>(8-$n))&1;
	}

	/**
	* begin reading of rect object
	* @access private
	*/
	function _begin(){
		$this->current = $this->_readbyte();
		$this->position = 1;
	}
}
?>

Libraries

XML

Intercept E4X XML events

xml.setNotification(callback:Function);
function callback(currentTarget:Object, type:String, target:Object, value:Object, detail:Object):void;

Types:

attributeAdded
Occur when an attribute was added
attributeChanged
Occur when an attribute was changed
attributeRemoved
Occur when an attribute was removed
nodeAdded
Occur when a node was added
nodeChanged
Occur when a node was changed
nodeRemoved
Occur when a node was removed
nameSet
Occur when the node name changed
namespaceAdded
Occur when a namespace was added to the node
namespaceRemoved
Occur when a namespace was removed
namespaceSet
Occur when the node's namespace changed
textSet
Occur when a text node was added to the node

E4X

Exemple:

<node name="Mike" age="34"><address><![CDATA[Fake address]]></address></node>

Get in items all XML nodes node:

xml.node.(items.push(new User(@name, uint(@age))));

The same but with address:

xml.node.(
	items.push(item = new User(@name, uint(@age))),
	item.address = address[0].toString()
);

Get all nodes with age greater than 30:

xml.node.(int(@age)>30).(
	items.push(item = new User(@name, uint(@age))),
	item.address = address[0].toString()
);

The same but with only one cycle

xml.node.(
	// ?: condition
	int(@age)>30 ? (
		// if condition equals TRUE actions, separated by commas
		item = new User(@name, uint(@age)),
		items.push(item),
		item.address = address[0].toString()
	) : false // if condition equals FALSE actions
);

Application domain

Child SWF uses parent domain definitions. If defined there, otherwise its own.

var childDefinitions:LoaderContext = new LoaderContext();
childDefinitions.applicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain);

child SWF adds its unique definitions to parent SWF; both SWFs share the same domain child SWFs definitions do not overwrite parents

var addedDefinitions:LoaderContext = new LoaderContext();
addedDefinitions.applicationDomain = ApplicationDomain.currentDomain;

child SWF domain is completely separate and each SWF uses its own definitions

var separateDefinitions:LoaderContext = new LoaderContext();
separateDefinitions.applicationDomain = new ApplicationDomain();

set loader context in load()

myLoader.load(request, separateDefinitions);

Obfuscation

//http://www.morearty.com/blog/2009/04/01/aprilscript-actionscript-worst-practices/
package {
	import flash.display.*
	import flash.text.*

	public class AprilFools extends Sprite {
		エイプリルフール var Number = 4..toString()

		use namespace エイプリルフール

		function AprilFools()
		{
			get = set
			set = get

			with (createTextField())
			text = new Date(Number).toDateString()
		}

		function get get() { return Number + <><{Number}
			b={"/"+Number.split(/\//)[0]*502.25}/>..@b }
		function set get(set) { Number = set+'/'+set/4 }

		function get set() { return Number }
		function set set(get) { Number = get }

		// nothing fun here
		function createTextField():TextField
		{
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			var textField:TextField = new TextField();
			textField.width = 1000;
			addChild(textField);
			return textField;
		}
	}
}

namespace エイプリルフール

Increment / decrement

i = -~i;//equal to i++
i = ~-i;//i--

ASDocs

Bugs : Talk:ASDoc:Creating ASDoc Comments - Adobe Labs

Don't use <code></code> in your @see text description.

The comment: /** @see "oops can't document this." */ will also cause the same exception

A better Flash

Solvable, common sense

Introductions

Search engine visibility

Accessibility

Takes long to load

CPU hog

Can't bookmark pages / back history

Video and sound

Regular expressions

\f
matches form-feed.
\r
matches carriage return.
\n
matches linefeed.
\t
matches horizontal tab.
\v
matches vertical tab.
\0
matches NUL character.
[\b]
matches backspace.
\s
matches whitespace (short for [\f\n\r\t\v\u00A0\u2028\u2029]).
\S
matches anything but a whitespace (short for [^\f\n\r\t\v\u00A0\u2028\u2029]).
\w
matches any alphanumerical character (word characters) including underscore (short for [a-zA-Z0-9_]).
\W
matches any non-word characters (short for [^a-zA-Z0-9_]).
\d
matches any digit (short for [0-9]).
\D
matches any non-digit (short for [^0-9]).
\b
matches a word boundary (the position between a word and a space).
\B
matches a non-word boundary (short for [^\b]).
\cX
matches a control character. E.g: \cm matches control-M.
\xhh
matches the character with two characters of hexadecimal code hh.
\uhhhh
matches the Unicode character with four characters of hexadecimal code hhhh.

Display

Draw a DisplayObject into a BitmapData

var displayObject:DisplayObject;
var bounds:Rectangle = displayObject.getBounds(displayObject);
var bitmapData:BitmapData = new BitmapData(uint(bounds.width + 0.5), uint(bounds.height + 0.5), true, 0);
bitmapData.draw(displayObject, new Matrix(1, 0, 0, 1, -bounds.x, -bounds.y));

Pixelize a DisplayObject

Draw it into a BitmapData (see above) with scale

var displayObject:DisplayObject;
var scale:Number = 0.5;
var bounds:Rectangle = displayObject.getBounds(displayObject);
var bitmapData:BitmapData = new BitmapData(uint((bounds.width + 0.5) * scale), uint((bounds.height + 0.5) * scale), true, 0);
bitmapData.draw(displayObject, new Matrix(scale, 0, 0, scale, -bounds.x * scale, -bounds.y * scale));

Then, set bitmap width & height to original sizes (bounds.width & bounds.height)

Bezier curves

Formula

//http://www.paultondeur.com/2008/03/09/drawing-a-cubic-bezier-curve-using-actionscript-3/
var anchor1:Point;
var anchor2:Point;
var control1:Point;
var control2:Point;
var position:Number; // between 0 and 1
 
var posX : Number = Math.pow(position, 3) * (anchor2.x + 3 * (control1.x - control2.x) - anchor1.x)
	+ 3 * Math.pow(positie, 2) * (anchor1.x - 2 * control1.x + control2.x)
	+ 3 * position * (control1.x - anchor1.x) + anchor1.x;
 
var posY : Number = Math.pow(position, 3) * (anchor2.y + 3 * (control1.y - control2.y) - anchor1.y)
	+ 3 * Math.pow(position, 2) * (anchor1.y - 2 * control1.y + control2.y)
	+ 3 * position * (control1.y - anchor1.y) + anchor1.y;
# given points p0, p0Out, and p1In, and p1, and t varying from 0.0 to 1.0...
a0 = (1 - t) ** 3
a1 = 3 * (1 - t) ** 2 * t
a2 = 3 * (1 - t) * t ** 2
a3 = t ** 3

# calculate x and y
x = a0 * p0.x + a1 * p0.xOut + a2 * p1.xIn + a3 * p1.x
y = a0 * p0.y + a1 * p0.yOut + a2 * p1.yIn + a3 * p1.y
fov = 2.0 * Math.atan( (width - 1) / (2 * focalX) ); nearPlane = focalX / 32; farPlane = focalX * 32;

Affine transformation

NetStream BitmapData capture

video.attachNetStream(null);
var snapshot:BitmapData = new BitmapData(…);
snapshot.draw(video);
video.attachNetStream(stream);

Draw a donut

public static function drawDonut(g:Graphics, radius1:Number, radius2:Number, startAngle:Number, endAngle:Number, x:Number = 0, y:Number = 0) : void
{
	var segAngle:Number = Math.PI/4;
	var angle:Number = startAngle;
	var angleMid:Number, bx:Number, by:Number, cx:Number, cy:Number, i:Number;
	var arc:Number = endAngle - angle;

	if(arc == 0)
		return;

	while(arc < 0)
		arc += Math.PI * 2;
	
	var segs:Number = Math.ceil(arc / segAngle);
	var rest:Number = arc % segAngle;
	var theta:Number = segAngle / 2;
	var cosTheta:Number = Math.cos(theta);
	var ax1:Number = Math.cos(angle) * radius1;
	var ay1:Number = Math.sin(angle) * radius1;
	var ax2:Number = Math.cos(angle) * radius2;
	var ay2:Number = Math.sin(angle) * radius2;
	g.moveTo(ax1 + x, ay1 + y);
	g.lineTo(ax2 + x, ay2 + y);

	for(i = 0 ; i < segs - 1 ; i++)
	{
		angle += segAngle;
		angleMid = angle - theta;
		bx = x + Math.cos(angle) * radius2;
		by = y + Math.sin(angle) * radius2;
		cx = x + Math.cos(angleMid) * (radius2 / cosTheta);
		cy = y + Math.sin(angleMid) * (radius2 / cosTheta);
		g.curveTo(cx, cy, bx, by);
	}

	angle += rest;
	angleMid = angle - rest / 2;
	bx = x + Math.cos(angle) * radius2;
	by = y + Math.sin(angle) * radius2;
	cx = x + Math.cos(angleMid) * (radius2 / Math.cos(rest / 2));
	cy = y + Math.sin(angleMid) * (radius2 / Math.cos(rest / 2));
	g.curveTo(cx, cy, bx, by);

	ax1 = Math.cos(endAngle) * radius1;
	ay1 = Math.sin(endAngle) * radius1;
	g.lineTo(ax1 + x, ay1 + y);

	angle -= rest;
	bx = x + Math.cos(angle) * radius1;
	by = y + Math.sin(angle) * radius1;
	cx = x + Math.cos(angleMid) * (radius1 / Math.cos(rest / 2));
	cy = y + Math.sin(angleMid) * (radius1 / Math.cos(rest / 2));
	g.curveTo(cx, cy, bx, by);

	for(i = segs-2 ; i > -1 ; i--)
	{
		angle -= theta * 2;
		angleMid = angle + theta;
		bx = x + Math.cos(angle) * radius1;
		by = y + Math.sin(angle) * radius1;
		cx = x + Math.cos(angleMid) * (radius1 / cosTheta);
		cy = y + Math.sin(angleMid) * (radius1 / cosTheta);
		g.curveTo(cx, cy, bx, by);
	}
}

Enhance video

Details restoration

//http://sonnati.wordpress.com/2010/10/06/flash-h-264-h-264-squared-%E2%80%93-part-iii/
// "video" is your video object istance
var filter:ConvolutionFilter = new flash.filters.ConvolutionFilter();
filter.matrixX = 3;
filter.matrixY = 3;
filter.matrix = [-1, 0, -1, 0, 8, 0, -1, 0, -1];
filter.bias =  0;
filter.divisor = 4;
video.filters = [filter];

Film Grain restoration (noise)

// Init noise frames
var baseX:Number = 1.3;
var baseY:Number = 1.3;
var numOctaves:Number = 1;
var stitch:Boolean = true;
var fractalNoise:Boolean = true;
var channelOptions:Number = BitmapDataChannel.BLUE | BitmapDataChannel.RED | BitmapDataChannel.GREEN;
var grayScale:Boolean = false;
var offsets:Array = new Array(new Point(), new Point());
var bitmapArray:Array = new Array();
var frameNumber:Number = 12;

for (var i = 0; i < frameNumber; i++)
{
	var bmpData:BitmapData = new BitmapData(1280, 720);
	var bmp:Bitmap = new Bitmap(bmpData);
	bmp.alpha = 0.20;
	bmp.blendMode = "overlay";
	bmpData.perlinNoise(baseX, baseY, numOctaves, Math.random() * 65000, stitch, fractalNoise, channelOptions, grayScale, offsets);
	bmp.visible = false;
	bitmapArray.push(bmp);
}
// Noise video sequence
var altcnt:uint = 0;

addEventListener(Event.ENTER_FRAME, frameHandler);
function frameHandler(event:Event):void
{
	altcnt = altcnt >= frameNumber ? 0 : altcnt + 1;
	for(var i = 0; i < frameNumber; i++)
		bitmapArray[i].visible = false;
	bitmapArray[altcnt].visible = true;
	bitmapArray[altcnt].alpha = (0.14 + 0.06 * Math.random()) * 1.5;
}

Outlined Text

new GlowFilter(0x000000, 1.0, 2.0, 2.0, 10, 2)

3D

A* serach path algorythm (3d version)

3D Engine Java (render engine)

Depth of field

Network & File IO

Upload file with URLLoader

/**
* Original:
* http://www.jooce.com/blog/?p=143
* Uploads a file using a given URLLoader object.
* 
* @param loader The URLLoader object to use
* @param url The location of the script recieving the upload
* @param file The file to upload
* @param fileName The name of the file
* @param contentType The content-type of the file
*/

var loader:URLLoader = new URLLoader();
var file:ByteArray = new ByteArray();
file.writeUTFBytes("Fake file content text.");

var request:URLRequest = new URLRequest("my/path/upload.php");
var fileName:String = "myfile.txt";
var contentType:String = "text/plain";//"application/octet-stream"
	
var i:int;
var boundary:String = "--";
var postData:ByteArray = new ByteArray;
var bytes:String;

for(i = 0; i < 0x10; i++)
	boundary += String.fromCharCode(int(97 + Math.random() * 25));

loader.dataFormat = URLLoaderDataFormat.BINARY;

request.url = url;
request.contentType = "multipart/form-data; boundary=" + boundary;
request.method = URLRequestMethod.POST;

postData.endian = Endian.BIG_ENDIAN;

// -- + boundary
postData.writeShort(0x2d2d);
for (i = 0; i < boundary.length; i++)
	postData.writeByte(boundary.charCodeAt(i));

// line break
postData.writeShort(0x0d0a);

// content disposition
bytes = "Content-Disposition: form-data; name=\"Filename\"";
for (i = 0; i < bytes.length; i++)
	postData.writeByte(bytes.charCodeAt(i));

// 2 line breaks
postData.writeInt(0x0d0a0d0a);

// file name
postData.writeUTFBytes(fileName);

// line break
postData.writeShort(0x0d0a);

// -- + boundary
postData.writeShort(0x2d2d);
for (i = 0; i < boundary.length; i++)
	postData.writeByte(boundary.charCodeAt(i));

// line break
postData.writeShort(0x0d0a);

// content disposition
bytes = "Content-Disposition: form-data; name=\"Filedata\"; filename=\"";
for (i = 0; i < bytes.length; i++)
	postData.writeByte(bytes.charCodeAt(i));

// file name
postData.writeUTFBytes(fileName);

// missing "
postData.writeByte(0x22);

// line break
postData.writeShort(0x0d0a);

// content type
bytes = "Content-Type: " + contentType;
for (i = 0; i < bytes.length; i++)
	postData.writeByte(bytes.charCodeAt(i));

// 2 line breaks
postData.writeInt(0x0d0a0d0a);

// file data
postData.writeBytes(file, 0, file.length);

// line break
postData.writeShort(0x0d0a);

// -- + boundary
postData.writeShort(0x2d2d);
for (i = 0; i < boundary.length; i++)
	postData.writeByte(boundary.charCodeAt(i));

// line break 
postData.writeShort(0x0d0a);

// upload field
bytes = "Content-Disposition: form-data; name=\"Upload\"";
for (i = 0; i < bytes.length; i++)
	postData.writeByte(bytes.charCodeAt(i));

// 2 line breaks
postData.writeInt(0x0d0a0d0a);

// submit
bytes = "Submit Query";
for (i = 0; i < bytes.length; i++)
	postData.writeByte(bytes.charCodeAt(i));

// line break
postData.writeShort(0x0d0a);

// -- + boundary + --
postData.writeShort(0x2d2d);
for (i = 0; i < boundary.length; i++)
	postData.writeByte(boundary.charCodeAt(i));
postData.writeShort(0x2d2d);

request.data = postData;
request.requestHeaders.push(new URLRequestHeader("Cache-Control", "no-cache"));
loader.load(request);

Common errors

Return nodes are not same object

var dic:Dictionary = new Dictionary(false);
var data:XML = <data><node/></data>;
dic[data] = true;
var node:XML = data.node[0];

trace(dic[data])
//output: true

trace(dic[node.parent()])//must be true (see after)
//output: undefined

for(var key:* in dic)
	trace(key == node.parent(), key === node.parent())//output: true true

Floating point number errors

http://www.zeuslabs.us/2007/01/30/flash-floating-point-number-errors/
/**
* Corrects errors caused by floating point math.
*/
public function correctFloatingPointError(number:Number, precision:int = 5):Number
{
	//default returns (10000 * number) / 10000
	//should correct very small floating point errors
	var correction:Number = Math.pow(10, precision);
	return Math.round(correction * number) / correction;
}

/**
* Tests if two numbers are almost equal.
*/
public function fuzzyEquals(number1:Number, number2:Number, precision:int = 5):Boolean
{
	var difference:Number = number1 - number2;
	var range:Number = Math.pow(10, - precision);
	//default check:
	//0.00001  - 0.00001
	return difference < range && difference > - range;
}

addFrameScript()

movieClip.addFrameScript(frame:uint, frameScript:Function, ...args):void
//Add multiples frames scripts in same time
movieClip.addFrameScript(0, frame1Script, 3, frame3Script, 20, frame20Script);

//Remove frame script
movieClip.addFrameScript(0, null);

Code tips & tricks

Comment toggle

/*
[code]
//*/
//*
[code]
//*/

Only add / char to comment

//*
[code 1]
/*/
[code 2]
//*/
/*
[code 1]
/*/
[code 2]
//*/

Works also on related comment

Conditional switch statement

var value:int = 2;
switch(value){
    case < 1:
        trace("Value is less than 1");
        break;
    case 2:
        trace("Value definitely equals 2");
        break;
    case >= 3:
        trace("Value is greater than or equal to 3");
        break;
    case > 1 && < 3:
        trace("Value is greater than 3 and less than 5");
        break;
    case !== 5:
        trace("Value definitely doesn't equal 5");
        break;
}

Inching (Simple easing)

displayObject.x += (targetX - displayObject.x) * easingCoeff;
displayObject.y += (targetY - displayObject.y) * easingCoeff;

Elastic

vx += (targetX - displayObject.x) * elasticCoef;
vy += (targetY - displayObject.y) * elasticCoef;
displayObject.x += (vx *= frictionForce);
displayObject.y += (vy *= frictionForce);

Flexible Partial Shifts

var dx:Number = displayObject.x - fixedX;
var dy:Number = displayObject.y - fixedY;
var angle:Number = Math.atan2(dy, dx);
var targetX:Number = fixedX + Math.cos(angle) * springLength;
var targetY:Number = fixedX + Math.sin(angle) * springLength;

Waveform

displayObject.y = centerScale + Math.sin(angle) * range;
angle += speed;

Heartthrob

displayObject.scaleX = displayObject.scaleY = centerScale + Math.sin(angle) * range;
angle += speed;

Convert Array to Vector.<T>

var array:Array = ["a", "b", "c"];
var vector:Vector.<String> = Vector.<String>(array);

Multiplication (power of 2 only)

y = x << 1;//equals (~300% faster) to: y = x * 2;
y = x << 6;//y = x * 64

Division (power of 2 only)

y = x >> 1;//equals (~350% faster) to: y = x / 2;
y = x >> 6;//y = x / 64

Number to integer conversion

y = x >> 0;//equals to: y = int(x); or y = Math.floor(x);

Hexadecimal color extraction

var _24bitsColor:uint = 0xff00cc;

var r:uint = _24bitsColor >> 16;
var g:uint = _24bitsColor >> 8 & 0xff;
var b:uint = _24bitsColor & 0xff;

Or 32 bit color (argb)

var _32bitsColor:uint = 0xddff00cc;

var a:uint = _32bitsColor >> 24 & 0xff;
var r:uint = _32bitsColor >> 16 & 0xff;
var g:uint = _32bitsColor >> 8 & 0xff;
var b:uint = _32bitsColor & 0xff;

//Or alpha and 24 bits color:
var a:uint = _32bitsColor >> 24 & 0xff;
var _24bitsColor:uint = _32bitsColor & 0xffffff;

Combining hexadecimal color components

var r:uint = 0xff;
var g:uint = 0x00;
var b:uint = 0xcc;

var _24bitColor:uint = r << 16 | g << 8 | b;

Or 32 bit color (argb)

var a:uint = 0xdd;
var r:uint = 0xff;
var g:uint = 0x00;
var b:uint = 0xcc;

var _32bitColor:uint = a << 24 | r << 16 | g << 8 | b;

Swap integers without a temporary variable using XOR (integer only)

x ^= y;
y ^= x;
x ^= y;

/*
equals (~20% faster) to:
	var z:int = x;
	x = y;
	y = z;
*/

Sign flipping using NOT or XOR (power of 2 only)

x = ~x + 1;//or
x = (x ^ -1) + 1;//equals (~300% faster) to x = -x;

Modulo operation using AND (power of 2 only)

z = x & (y - 1);//equals to z = x % y;

Check if an integer is even/uneven using AND

(x % y) == 0;//equals (~600% faster) to: (x & (y - 1)) == 0

Absolute value (signed interger only)

y = x < 0 ? -x : x;//equals (~2500% faster) to: y = Math.abs(x); or
y = (x ^ (x >> 31)) - (x >> 31);//equals (~20% faster) to Math.abs()

Sign comparaison (signed integers only)

z = x ^ y > 0;//equals (~35% faster) to: z = x * y > 0;

Binary flags

//Set differents flags
var flags:uint = FLAG_1 | FLAG_2;
//Add one flag
flags |= FLAG_3;
//Remove flag
flags &= ~FLAG_4;
//Get flag
var flag:Boolean = (flags & FLAG_2) > 0;

Where flag are unsigned integer with value power of 2: (0, 0x0), (1, 0x1), (2, 0x2, 1 << 1), (4, 0x4, 1 << 2), …

Determining if an integer is a power of 2

y = !(x & (x - 1)) && x;

Where x is integer tested and y is "if is power of 2".

indexOf

var myWord:String = "mychar";
if(~myWord.indexOf("d"))
	trace("found")
else
	trace("not found")

Extract ammount of bits in unsigned integer

y = (x >>> offset) & (0xffffffff >>> 32 - numBits);//or
y = (x >>> offset) & (Math.pow(2, numBits) - 1);

Where x is an unsigned interger and numBits is value of bits need to extract.

Compare real types of objects

With (final contructor) != is keyword

public static function typeEquals(object:*, constructor:Class):Boolean
{
	return o == null ? false : Object(object).constructor == constructor;
}

Extends Array

And support Array's arguments

public class SubArray extends Array
{
	function SubArray():void
	{
		super.constructor.apply(this, arguments);
	}
}

Is SubClass extends SuperClass

SuperClass.prototype.isPrototypeOf(SubClass.prototype);

Flash on 3 frames (preloading)

  1. Loading
  2. Libraries (classes …)
  3. Main

Desactivate constructor super call

if (0)
	super();

Normalize number

Angle between 0° and 360°

angle = (angle % 360 + 360) % 360;

Angle between -180° and 180°

angle = (angle % 360 + 540) % 360 - 180;

Infinit index

var values:Array = ["a", "b", "c"];
var index:int = -5;
var length:uint = values.length;
var realIndex:uint = (index % length + length) % length;// = 0, 1 or 2
values[realIndex];//= "b"

Homothetical resize

Fit all

var ratioSource:Number = displayObject.width / displayObject.height;
var ratioTarget:Number = WIDTH_TARGET / HEIGHT_TARGET;
var newWidth:Number = Math.min(ratioSource, ratioTarget) * HEIGHT_TARGET;
var newHeight:Number = WIDTH_TARGET / Math.max(ratioSource, ratioTarget);
var scale:Number = Math.min(WIDTH_TARGET / displayObject.width, HEIGHT_TARGET / displayObject.height);

Fit height

var ratioSource:Number = displayObject.width / displayObject.height;
		var newWidth:Number = ratioSource * HEIGHT_TARGET;
		var newHeight:Number = HEIGHT_TARGET;

Fit all (with original max size)

var widthTarget:Number = Math.min(WIDTH_TARGET, displayObject.width);
var heightTarget:Number = Math.min(HEIGHT_TARGET, displayObject.height);
var ratioSource:Number = displayObject.width / displayObject.height;
var ratioTarget:Number = widthTarget / heightTarget;
var newWidth:Number = Math.min(ratioSource, ratioTarget) * heightTarget;
var newHeight:Number = widthTarget / Math.max(ratioSource, ratioTarget);

Crop to fit

var ratioSource:Number = displayObject.width / displayObject.height;
var ratioTarget:Number = WIDTH_TARGET / HEIGHT_TARGET;
var newWidth:Number = Math.max(ratioSource, ratioTarget) * HEIGHT_TARGET;
var newHeight:Number = WIDTH_TARGET / Math.min(ratioSource, ratioTarget);

Estimate sound duration while loading

var duration:Number = this.sound.length;
if (this.sound.bytesTotal != this.sound.bytesLoaded && duration > 0)
	duration = (this.sound.bytesTotal / (this.sound.bytesLoaded / duration));

Estimate time needed for start playing video.

Assuming continuous bitrate (average), tested regularly.

if (duration > 0)
{
	var bufferingDuration:Number = getTimer() - startTimer;
	var totalLoadTime:Number = bytesLoaded == 0 ? Number.POSITIVE_INFINITY : bytesTotal / bytesLoaded * bufferingDuration;
	var duration:Number = duration * 1000;//s -> ms
	trace("(" + bytesLoaded + "/" + bytesTotal + ")" + bufferingDuration + " : " + totalLoadTime.toFixed(2))
	if (totalLoadTime < duration || bufferingDuration + duration > totalLoadTime)
		//tracehere video can be play with 
}

Where startTimer is value of getTimer() defined at begin of video loading and duration is length of video.

Forcing Garbage collecting

try
{
	new LocalConnection().connect('foo');
	new LocalConnection().connect('foo');//The GC will perform a full mark/sweep on the second call.
} catch (error:*) {}

LocalConnection limits

LocalConnection.send() limited to 40960 bytes. For one ByteArray is limited to 40864 (+ AMF data for one ByteArray: 96 bytes ?)

Throw error

Error.throwError(RangeError, 1005 /*kArrayIndexNotIntegerError*/, -3);//throw Error #1005: Array index is not an integer (-3)
Error.throwError(type:Class, errorID:uint, …rest);

Package are namespace

namespace flash_events = "flash.events";
trace(flash_events::MouseEvent); //output: [class MouseEvent]

Loading events order

  1. Event.OPEN
  2. ProgressEvent.PROGRESS * n
  3. Event.INIT (if SWF, first frame loaded)
  4. ProgressEvent.PROGRESS * n
  5. HTTPStatusEvent.HTTP_STATUS
  6. Event.COMPLETE

AS Native & Product

https://www.macromedia.com/bin/flashdownload.cgi?product=fpupdatept&signed=true&A=t&SA=t&SV=t&EV=t&MP3=t&AE=t&VE=t&ACC=f&PR=t&SP=t&SB=f&DEB=t&V=WIN%209%2C0%2C115%2C0&M=Adobe%20Windows&R=1920x1200&DP=72&COL=color&AR=1.0&OS=Windows%20XP&L=fr&IME=f&PT=External&AVD=f&LFD=f&WD=f&TLS=t&what=descr…

Product("digitaleditions2x0")
//AS2
var p = new System.Product("notepad");
p.download();
trace(p.IsInstalled());
trace(p.Launch());
And you copy "notepad.exe" to
// ApplicationData\Macromedia\FlashPlayer\www.macromedia.com\bin\notepad\

//AS3
var p:ProductManager = new adobe.utils.ProductManager()
p.launch();
p.download();
p.installed;
p.installedVersion;
p.running;

//AS3 launch AIR app
myLauncher:ProductManager = new ProductManager("airappinstaller");
var myArguments:Array = ["-launch", appID, publisherID, theOtherAppArguments];
myLauncher.launch(myArguments.join(" "));

Access to all members (inc. private) of a specified object (debug player only)

import flash.sampler.getMemberNames;
...
var members:Object = getMemberNames(myObject);

for each (var name:QName in members)
	if (name.localName == "memberName")
		trace(myObject[name]);

Get class from Loaded SWF

loader.contentLoaderInfo.applicationDomain.getDefinition("FullQualifiedClassName") as Class

Date offset by month

//Before = After - 5.5 months
var monthRatio:Number = 5.5;
var today:Date = new Date();
//trace("today: " + today.toDateString())

var after:Date = new Date(today.fullYear, today.month, today.date);
trace("after: " + after.toDateString());

var before:Date = new Date(today.fullYear, (today.month - uint(monthRatio)), 32);
trace((32 - before.date) + " jours");
before = new Date(before.fullYear, (today.month - uint(monthRatio)), today.date - Math.round(monthRatio % 1 * (32 - before.date)))
trace("before (after - " + monthRatio + " months): " + before.toDateString())

Clone object

Not work on DisplayObjects

//http://niko.informatif.org/blog/2007_07_20_clone_an_object_in_as3
package nc.utils
{
	import flash.utils.ByteArray;
	import flash.net.registerClassAlias;
	import flash.utils.getQualifiedClassName;
	import flash.net.getClassByAlias;
	import flash.utils.describeType;
	import flash.utils.getDefinitionByName;

	public class ObjectUtils
	{
		/**
		*	Clone an Object
		*
		*	@param object The Object to clone (Object is not a part of the displayList
		*	and object don't need arguments in constructor)
		*
		*	@param type The Class of the Object to clone.
		*
		*	@return a clone of Object
		*/
		public static function clone(object:*):*
		{
			var alias:String = getQualifiedClassName(object).split('::').join('.');
			var type:Class = getDefinitionByName(alias) as Class;

			traverse(object);

			var r:ByteArray = new ByteArray();
			r.writeObject(object);
			r.position = 0;
			var clone:*;
			
			try
			{
				clone = r.readObject();
				return clone as type;
			}
			catch(error:TypeError)
			{ 
				//trace(error);
			}
			
			return null;
		}

		private static function traverse(object:*):void
		{
			var alias : String = getQualifiedClassName(object).split('::').join('.');
			var type : Class = getDefinitionByName(alias) as Class;
			try
			{
				getClassByAlias(alias);
			}
			catch(error:ReferenceError)
			{
				registerClassAlias(alias, type); 
			}

			var x:XML = describeType(object),
				childrens:XMLList = x.children(),
				l:int = childrens.length(),
				i:int = -1,
				xClass:XML;
			
			while (++i " + alias + " as " + type);
							registerClassAlias(alias, type);
						}
					}
				}
			}
		}
	}
}

Allow socket

<?xml version="1.0" encoding="UTF-8"?>
<cross-domain-policy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.adobe.com/xml/schemas/PolicyFileSocket.xsd">;
	<allow-access-from domain="*" to-ports="*" secure="false" />
	<site-control permitted-cross-domain-policies="master-only" />
</cross-domain-policy>

Deliver policy file with command line PHP

#!/usr/local/bin/php
<?php
/**
 * Flash Policy Service v0.9.c
 *
 * This script listens for <policy-file-request/> on port 843 and serves up
 * an xml crossdomain policy file. This sort of service is necessary if any
 * flash content is going to connect to sockets on the running host.
 *
 * I have made every effort to package everything you need into a single
 * file here, even though it could easily have been split into 3 or more
 * scripts.
 *
 * Requirements:
 *  - PHP 5 with sockets, pcntl, and posix extensions
 *  - Root access (to bind to a <1024 port)
 *
 * Use:
 *  Simply execute the script from the command line as root:
 *    # ./FlashPolicyService.php
 *  You can enable debug mode by invoking the script with '-d' as a parameter:
 *    # ./FlashPolicyService.php -d
 *  To stop the daemon, simply send it a SIGTERM and it should attempt to
 *  exit cleanly.
 *
 *  If you get 'bad interpreter' errors or the like, change the #! line to
 *  reflect the actual installed location of your php cli.
 *
 * Configuration:
 *  At present, there aren't very many config options. Simply edit the
 *  section immediately following this header. Options are commented.
 *
 * License:
 *  This code is made available under a Creative Commons Attribution 3.0
 *  License. Basically, you can use it however you like, but I would
 *  appreciate some credit when you do.
 *
 * Disclaimer:
 *  I make no guarantees that this code won't make your server explode in a
 *  shower of blue flames. However, I don't expect that it will. I am actually
 *  confident that this code will be helpful.
 *
 *  That said, this is still my beta release. If you find any bugs, please
 *  let me know so I can fix them.
 *
 * - Ammon Lauritzen [Apr 21, '08]
 *   http://ammonlauritzen.com/blog/2008/04/22/flash-policy-service-daemon/
 *
 * Changelog
 * 0.9.c
 *   - Fixed some typoes that were the result of how I combined everything
 *     into a single file. Thanks Alex!
 * 0.9.b
 *   - Original version to be posted at this url.
 * 0.9.a
 *   - Original proof of concept code posted online.
 */

/*** Config ***/

// where should we save the log output?
$log_filename = "/tmp/flash-policy.log";

// uncomment these lines to choose which user to run the daemon as
// default behavior is to look up and attempt to run as 'nobody'
# $daemon_uid = 99;
# $daemon_gid = 99;

// set this if you want to use an external file in stead of the default
$xml_filename = "";
$default_xml =
    '<'.'?xml version="1.0" encoding="UTF-8"?'.'>'.
    '<cross-domain-policy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.adobe.com/xml/schemas/PolicyFileSocket.xsd">'.
        '<allow-access-from domain="*" to-ports="*" secure="false" />'.
        '<site-control permitted-cross-domain-policies="all" />'.
    '</cross-domain-policy>';

/*** You shouldn't have to edit anything below here ***/

/////////////////////////////////////////////////////////////////////////////
class Logger {
    public function __construct($logfile) {
        $this->logfile = $logfile;
        $this->open_log();
    }// end: constructor

    public function __destruct() {
        @fflush($this->fh);
        @fclose($this->fh);
    }// end: destructor

    public function log($msg) {
        // deal with redundant log spam
        if($msg == $this->last_msg) {
            $this->last_msg_count++;
            return;
        } else if($this->last_msg_count) {
            $this->write("Last message repeated ".$this->last_msg_count." times.");
        }
        $this->lasg_msg = $msg;
        $this->last_msg_count = 0;

        // actually write the log message out
        $this->write($msg);
    }// end: log

    private function write($msg) {
        $msg = sprintf("[%s] %s\n",date("y-m-d H:i:s"),$msg);
        $succ = @fwrite($this->fh, $msg);
        if($succ === FALSE) {
            echo $msg;
        }
    }// end: write

    private function open_log() {
        if(!file_exists($this->logfile)) {
            touch($this->logfile);
            chmod($this->logfile, 0664);
        }
        $this->fh = @fopen($this->logfile, "a");
    }
}// end: logger class

/////////////////////////////////////////////////////////////////////////////
class Daemon {
    public function __construct() {
        error_reporting(0);
        set_time_limit(0);

        global $log_filename, $pid_filename;
        $this->logger = new Logger($log_filename);
        $this->pid_filename = $pid_filename;

        $this->log_tag = $this->daemon_tag = "launcher";
        $this->debug("constructed", $this->daemon_tag);
    }// end: constructor

    public function __destruct() {
        $this->debug("destructing", $this->daemon_tag);
    }// end: destructor

    protected function log($msg, $tag = false) {
        if($tag == false)
            $tag = $this->log_tag;
        $this->logger->log($tag.": ".$msg);
    }// end: log
    protected function debug($msg, $tag = false) {
        if(DEBUG)
            $this->log($msg, $tag);
    }// end: debug

    protected function main() {
        $this->log("override main() in daemon subclass", $this->daemon_tag);
        $this->stop();
    }// end: main

    public function start() {
        $this->log("starting daemon", $this->daemon_tag);
        if(!$this->_start()) {
            $this->log("unable to start daemon", $this->daemon_tag);
            return;
        }

        // report execution details
        $this->log("uid = ".posix_getuid().", gid = ".posix_getgid());
        $this->log("cwd = ".getcwd());

        // invoke main loop
        $this->running = true;
        while($this->running) {
            $this->main();
        }
    }// end: start
    private function _start() {
        if(!$this->_fork()) {
            return false;
        }// end: try to fork

        if(!posix_setsid()) {
            $this->log("unable to setsid()", $this->daemon_tag);
            return false;
        }// end: try to set sid
       
        if(!$this->_suid()) {
            return false;
        }// end: try to set uid
       
        // register signal handler
        declare(ticks = 1);
        pcntl_signal(SIGTERM, array(&$this, "on_sigterm"));
        // chdir somewhere moderately safe by default
        chdir('/tmp');
        return true;
    }// end: _start
    private function _fork() {
        $this->log("forking…", $this->daemon_tag);
        $pid = pcntl_fork();
        if($pid == -1) {
            // error
            $this->log("unable to fork", $this->daemon_tag);
            return false;
        } else if($pid) {
            // parent
            $this->debug("done with parent", $this->daemon_tag);
            exit(0);
        } else {
            // child
            $this->daemon_tag = "daemon";
            $this->child = true;
            $this->pid = posix_getpid();
            $this->debug("child pid = ".$this->pid);
            return true;
        }
    }// end: _fork
    private function _suid() {
        global $daemon_uid, $daemon_gid;
        if(!isset($daemon_uid) || !isset($daemon_gid)) {
            // we didn't get a uid/gid, try to make one up
            $this->debug("searching for info on 'nobody'", $this->daemon_tag);
            $res = posix_getpwnam("nobody");
            if($res !== FALSE) {
                $uid = $res['uid'];
                $gid = $res['gid'];
            } else {
                // the 'nobody' user doesn't exist on this system, refuse
                // to daemonize as root
                $this->log("unable to find info on 'nobody' user", $this->daemon_tag);
                return false;
            }
        } else {
            $this->debug("got uid/gid of $daemon_uid/$daemon_gid", $this->daemon_tag);
            $uid = $daemon_uid;
            $gid = $daemon_gid;
        }
        // actually try to switch now
        if(!posix_setgid($gid)) {
            $this->log("unable to set gid to ".$gid, $this->daemon_tag);
            return false;
        } else if(!posix_setuid($uid)) {
            $this->log("unable to set uid to ".$uid, $this->daemon_tag);
            return false;
        } else {
            return true;
        }
    }// end: _suid

    public function stop() {
        $this->log("stopping daemon", $this->daemon_tag);
        $this->running = false;
    }// end: stop

    protected function on_sigterm($sig) {
        if($sig == SIGTERM) {
            $this->log("got SIGTERM", $this->daemon_tag);
            $this->stop();
            exit(0);
        }
    }// end: on_sigterm
}// end: daemon class

/////////////////////////////////////////////////////////////////////////////
class FlashPolicyService extends Daemon {
    public function __construct() {
        parent::__construct();
        $this->log_tag = "fps";
        $this->debug("constructing");

        $this->connections = array();
        $this->request_str = "<policy-file-request/>";
        $this->port = 843;

        // get our xml
        global $xml_filename, $default_xml;
        if(strlen($xml_filename) == 0 || !file_exists($xml_filename)) {
            $this->log("unable to read xml from '$xml_filename', using default");
            $this->xml = $default_xml;
        } else {
            $this->log("reading policy xml from $xml_filename");
            $this->xml = file_get_contents($xml_filename);
        }
        $this->debug("policy xml: ".$this->xml);
        // make sure we're null terminated
        $this->xml = trim($this->xml)."\n\0";

        // and get going
        $this->init();
    }// end: constructor

    public function __destruct() {
        parent::__destruct();
        if($this->sock)
            @fclose($this->sock);
    }// end: destructor

    private function init() {
        $this->debug("init…");
        if($this->check_socket()) {
            parent::start();
        } else {
            $this->log("not starting daemon");
        }
    }// end: init

    protected function main() {
        if($this->sock) {
            while(true) {
                $this->accept_socket();
            }
        } else {
            $this->log("server socket is closed?!");
            parent::stop();
        }
        // paranoia to keep from absolutely hosing cpu if something goes wrong
        usleep(10000);    // 10ms
    }// end: main

    private function check_socket() {
        $this->sock = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        if(!$this->sock) {
            $this->log("unable to create socket");
        } else {
            $succ = @socket_bind($this->sock, "0.0.0.0", $this->port);
            if(!$succ) {
                $this->log("unable to bind to port ".$this->port);
            } else {
                $backlog = 100;
                $succ = @socket_listen($this->sock, $backlog);
                if(!$succ) {
                    $this->log("unable to listen with backlog of $backlog");
                } else {
                    // everything's good
                    return true;
                }
            }// end: able to bind
        }// end: able to create socket

        // if we got here, it's an error. abort.
        $errno = socket_last_error($this->sock);
        $errstr = socket_strerror($errno);
        $this->log("socket error: $errno: $errstr");
        return false;
    }// end: check_socket

    private function accept_socket() {
        $r_socks = array_merge(array($this->sock), $this->connections);
        $this->debug("selecting on ".count($r_socks)." sockets");
       
        // block until something interesting happens
        $select = @socket_select($r_socks, $w_socks = NULL, $e_socks = NULL, NULL);
        if(!$select)
            return;

        // did we get a new connection?
        if(in_array($this->sock, $r_socks)) {
            $conn = @socket_accept($this->sock);
            if($conn !== false)
                @socket_getpeername($conn, $addr);
            $this->log("connection accepted from $addr, $conn");
            $this->connections[] = $conn;
        }// end: got a new connection

        // check for policy requests
        foreach($r_socks as $conn) {
            // ignore the server socket
            if($conn == $this->sock)
                continue;

            // read from the client
            $data = @socket_read($conn, 1024);
            if($data === FALSE) {
                $this->log("got disconnect from $conn");
            }// end: client closed connection
            else {
                $this->debug("read '".trim($data)."' from $conn");
                if(strpos($data, $this->request_str) !== FALSE) {
                    $this->log("sending policy xml to $conn");
                    @socket_write($conn, $this->xml);
                } else {
                    $this->log("got invalid request from $conn");
                }
            }// end: got data from the client

            // and always disconnect after having read something, whether
            // it was a valid request or not - especially if it wasn't ;)
            @socket_close($conn);
            $key = array_search($conn, $this->connections);
            if($key !== FALSE)
                unset($this->connections[$key]);
        }// end: foreach socket
    }// end: accept_socket

}// end: flash policy service class

/////////////////////////////////////////////////////////////////////////////
/**
 * Actual execution code here. This checks if the php install has all of our
 * requisite extensions, makes sure we're launching as root, and checks if
 * debug mode was requested before actually starting the daemon.
 */

// make sure we have required extensions
$required_extensions = array("sockets", "posix", "pcntl");
$missing_extension = false;
foreach($required_extensions as $ext) {
    if(!extension_loaded($ext)) {
        echo "Missing required php extension '$ext'.n";
        $missing_extension = true;
    }
}
if($missing_extension) {
    exit(1);
}

// make sure we launch as root, otherwise we can't bind to 843
if(posix_getuid() != 0 || posix_getgid() != 0) {
    echo "Policy service must be started as root.n";
    exit(1);
}

// see if we're in debug mode
define("DEBUG", in_array('-d',$argv));

// start the daemon
$fps = new FlashPolicyService();
?>
#!/usr/bin/php -q
<?php

error_reporting(E_ALL);

set_time_limit(0);

ob_implicit_flush();

echo "Enter Server IP:\n";
$address = trim(fgets(STDIN));
//$address = '127.0.0.1';
echo "Enter Port:\n";
$port = trim(fgets(STDIN));
//$port = 9999;
echo "Attempting to connect to $address:$port\n";

//---- Function to Send out Messages to Everyone Connected ----------------------------------------

function send_Message($allclient, $buf) {
	global $client_list;
	foreach($allclient as $client) {
	if($client_list[$client]['state'] && $client_list[$client]['nick'] != ""){
		socket_write($client, trim($buf).chr(0));
	}
	}
}

function who($allclient, $socket) {
	global $client_list;
	$buf = "";
	$counter = 0;
	foreach($allclient as $client) {
	$buf.=$client_list[$client]['nick'].", ";
	$counter++;
	}
	socket_write($socket, "There are $counter people in this room: $buf".chr(0));
}

function send_Single($socket, $buf) {
	socket_write($socket, $buf.chr(0));
}

function shutDown($allclients, $master){
	global $abort;
	$abort = false;
	foreach($allclients as $client){
	echo "$client connection closed\n";
	socket_close($client);
	}
	echo "$master connection closed\n";
	socket_close($master);
	echo "Server shutdown complete\n";
}

//---- Start Socket creation for PHP 5 Socket Server -------------------------------------

if (($master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0) {
	echo "socket_create() failed, reason: " . socket_strerror($master) . "\n";
}else{
	echo "$master socket created\n";
}

socket_set_option($master, SOL_SOCKET,SO_REUSEADDR, 1);


if (($ret = socket_bind($master, $address, $port)) < 0) {
	echo "socket_bind() failed, reason: " . socket_strerror($ret) . "\n";
}else{
	echo "$ret socket bound to $address:$port\n";
}


if (($ret = socket_listen($master, 5)) < 0) {
	echo "socket_listen() failed, reason: " . socket_strerror($ret) . "\n";
}else{
	echo "$ret listening…\n";
}



$read_sockets = array($master);
$client_list = array($master);
$abort = true;
$policy_file =
	'<'.'?xml version="1.0" encoding="UTF-8"?'.'>'.
	'<cross-domain-policy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.adobe.com/xml/schemas/PolicyFileSocket.xsd">'.
		'<allow-access-from domain="*" to-ports="*" secure="false" />'.
		'<site-control permitted-cross-domain-policies="master-only" />'.
	'</cross-domain-policy>';

//---- Create Persistent Loop to continuously handle incoming socket messages ---------------------
while ($abort) {
	$changed_sockets = $read_sockets;

	$num_changed_sockets = socket_select($changed_sockets, $write = NULL, $except = NULL, NULL);

	foreach($changed_sockets as $socket) {

	if ($socket == $master) {

		if (($client = socket_accept($master)) < 0) {
		echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n";
		continue;
		} else {
	echo "[connection]:$client\n";
		array_push($read_sockets, $client);
	$client_list[$client]['state'] = false;
	$client_list[$client]['nick'] = "";
	send_Single($client, $policy_file);
	send_Single($client, "<b>Enter a nickname:<b>");
		}
	} else {

		$bytes = socket_recv($socket, $buffer, 2048, 0);

		if ($bytes == 0) {
	$nick = $client_list[$socket]['nick'];
		$iindex = array_search($socket, $client_list);
		unset($client_list[$iindex]);
		$index = array_search($socket, $read_sockets);
		unset($read_sockets[$index]);
		$allclients = $read_sockets;
		array_shift($allclients);
	if($client_list[$socket]['nick'] != "" && $client_list[$socket]['nick'] != "<policy-file-request/>"){
		echo "[connection-terminated]:$socket\n";
			send_Message($allclients, "$nick has left the room");
	}
		socket_close($socket);
		}else{
	if($bytes){
		if($client_list[$socket]['state'] === false){
		$tempBuf = trim($buffer);
		$testCase = false;
		foreach($read_sockets as $clients){
			if ($client_list[$clients]['nick'] == $tempBuf) {
			$testCase = true;
			send_Single($socket, "Sorry, \"$tempBuf\" is already in use!");
			send_Single($socket, "Please choose another nickname:");
			break;
			}
		}
		if(!$testCase){
			$client_list[$socket]['nick'] = $tempBuf;
			echo "$tempBuf assigned to $socket\n";
			send_Single($socket, "Hello $tempBuf!	Welcome to the game!");
				$allclients = $read_sockets;
				array_shift($allclients);
			who($allclients, $socket);
			if($client_list[$socket]['nick'] != "" && $tempBuf != "<policy-file-request/>"){
				send_Message($allclients, $client_list[$socket]['nick']." has entered the game.");
			}
			$client_list[$socket]['state'] = true;
		}
		}else{
			$allclients = $read_sockets;
			array_shift($allclients);
		if(trim($buffer) == "shut-down-server"){
			shutDown($allclients, $master);
		}else{
			if(trim($buffer) == "/who"){
			who($allclients, $socket);
			}else{
				send_Message($allclients, $client_list[$socket]['nick']." wrote: ".$buffer);
			}
		}
		}
	}
		}
	}
	}
}

?>
//http://www.functionblog.com/?p=67=1
<?php
// PHP SOCKET SERVER
error_reporting(E_ERROR);
// Configuration variables
$host = "127.0.0.1";
$port = 4041;
$max = 20;
$client = array();

// No timeouts, flush content immediatly
set_time_limit(0);
ob_implicit_flush();

// Server functions
function rLog($msg){
			$msg = "[".date('Y-m-d H:i:s')."] ".$msg;
			print($msg."\n");

}
// Create socket
$sock = socket_create(AF_INET,SOCK_STREAM,0) or die("[".date('Y-m-d H:i:s')."] Could not create socket\n");
// Bind to socket
socket_bind($sock,$host,$port) or die("[".date('Y-m-d H:i:s')."] Could not bind to socket\n");
// Start listening
socket_listen($sock) or die("[".date('Y-m-d H:i:s')."] Could not set up socket listener\n");

rLog("Server started at ".$host.":".$port);
// Server loop
while(true){
			socket_set_block($sock);
			// Setup clients listen socket for reading
			$read[0] = $sock;
			for($i = 0;$i<$max;$i++){
							if($client[$i]['sock'] != null)
										$read[$i+1] = $client[$i]['sock'];
			}
			// Set up a blocking call to socket_select()
			$ready = socket_select($read,$write = NULL, $except = NULL, $tv_sec = NULL);
			// If a new connection is being made add it to the clients array
			if(in_array($sock,$read)){
							for($i = 0;$i<$max;$i++){
										if($client[$i]['sock']==null){
													if(($client[$i]['sock'] = socket_accept($sock))<0){
																rLog("socket_accept() failed: ".socket_strerror($client[$i]['sock']));
													}else{
																rLog("Client #".$i." connected");
													}
													break;
										}elseif($i == $max - 1){
													rLog("Too many clients");
										}
							}
							if(--$ready <= 0)
							continue;
			}
			for($i=0;$i<$max;$i++){
							if(in_array($client[$i]['sock'],$read)){
										$input = socket_read($client[$i]['sock'],1024);
										if($input==null){
													unset($client[$i]);
										}
										$n = trim($input);
										$com = split(" ",$n);
										if($n=="EXIT"){
													if($client[$i]['sock']!=null){
																// Disconnect requested
																socket_close($client[$i]['sock']);
																unset($client[$i]['sock']);
																rLog("Disconnected(2) client #".$i);
																for($p=0;$p<count($client);$p++){
																				socket_write($client[$p]['sock'],"DISC ".$i.chr(0));
																}
																if($i == $adm){
																				$adm = -1;
																}
													}
										}elseif($n=="TERM"){
													// Server termination requested
													socket_close($sock);
													rLog("Terminated server (requested by client #".$i.")");
													exit();
										}elseif($input){
													// Strip whitespaces and write back to user
													// Respond to commands
													/*$output = ereg_replace("[ \t\n\r]","",$input).chr(0);
													socket_write($client[$i]['sock'],$output);*/
													if($n=="PING"){
																socket_write($client[$i]['sock'],"PONG".chr(0));
													}
													if($n=="<policy-file-request/>"){
																rLog("Client #".$i." requested a policy file…");
																$cdmp="<?xml version=\"1.0\" encoding=\"UTF-8\"?><cross-domain-policy xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"http://www.adobe.com/xml/schemas/PolicyFileSocket.xsd\"><allow-access-from domain=\"*\" to-ports=\"*\" secure=\"false\" /><site-control permitted-cross-domain-policies=\"master-only\" /></cross-domain-policy>";
																socket_write($client[$i]['sock'],$cdmp.chr(0));
																socket_close($client[$i]['sock']);
																unset($client[$i]);
																$cdmp="";
													}
										}
							}else{
										//if($client[$i]['sock']!=null){
													// Close the socket
													//socket_close($client[$i]['sock']);
													//unset($client[$i]);
													//rLog("Disconnected(1) client #".$i);
										//}
							}
			}
}
// Close the master sockets
socket_close($sock);
?>

Threading

Therading is impossible in Flash. But:

Implementation of pseudo threading:

//http://blogs.adobe.com/aharui/2008/01/threads_in_actionscript_3.html
package
{
	import flash.display.DisplayObjectContainer;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.utils.getTimer;
	import flash.display.Sprite;

	public class PseudoThread extends EventDispatcher
	{
		public function PseudoThread(parent:Sprite, threadFunction:Function, threadObject:Object):void
		{
			fn = threadFunction;
			obj = threadObject;

			// add high priority listener for ENTER_FRAME
			parent.stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler, false, 100);
			parent.stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
			parent.stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);

			thread = new Sprite();
			parent.addChild(thread);
			thread.addEventListener(Event.RENDER, renderHandler);
		}

		// number of milliseconds we think it takes to render the screen
		public var RENDER_DEDUCTION:int = 10;

		private var fn:Function;
		private var obj:Object;
		private var thread:Sprite;
		private var start:Number;
		private var due:Number;

		private var mouseEvent:Boolean;
		private var keyEvent:Boolean;

		private function enterFrameHandler(event:Event):void
		{
			start = getTimer();
			var fr:Number = Math.floor(1000 / thread.stage.frameRate);
			due = start + fr;

			thread.stage.invalidate();
			thread.graphics.clear();
			thread.graphics.moveTo(0, 0);
			thread.graphics.lineTo(0, 0); 
		}

		private function renderHandler(event:Event):void
		{
			if (mouseEvent || keyEvent)
			due -= RENDER_DEDUCTION;

			while (getTimer() < due)
			{
				if (!fn(obj))
				{
					if (!thread.parent)
					return;

					thread.stage.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
					thread.stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
					thread.stage.removeEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
					thread.parent.removeChild(thread);
					thread.removeEventListener(Event.RENDER, renderHandler);
					dispatchEvent(new Event("threadComplete"));
				}
			}

			mouseEvent = false;
			keyEvent = false;
		}

		private function mouseMoveHandler(event:Event):void
		{
			mouseEvent = true;
		}

		private function keyDownHandler(event:Event):void
		{
			keyEvent = true;
		}
	} 
}