#include "../assets/scripts/entities/camera.as"
#include "../assets/scripts/entities/dummy.as"
#include "../assets/scripts/entities/directional_light.as"
#include "../assets/scripts/entities/light.as"
#include "../assets/scripts/entities/player.as"
#include "../assets/scripts/entities/plane.as"

void main() {
    camera c(glm::vec3(-10, 4, 0), glm::quat(glm::radians(-15), glm::vec3(1, 0, 0)));
    c.activate();
    plane pl(glm::vec3(0, 1, 0), glm::quat(glm::radians(0), glm::vec3(1, 0, 0)), glm::vec3(1));
    dummy d(glm::vec3(4, 4, 0), glm::quat(glm::radians(45), glm::vec3(0, 1, 0)), glm::vec3(1.f), "meshes/dummy.msh");
    light l(glm::vec3(-4.f, 4.f, 2.f), glm::vec3(1), 20);
    light l2(glm::vec3(10.f, 2.f, -2.f), glm::vec3(0.f, 0.3f, 1.0f), 20);
    player p(glm::vec3(-3.f, 2.f, -14.f), glm::quat(glm::radians(90), glm::vec3(0, 1, 0)), glm::vec3(1), "meshes/human.msh", "anims/human.skl");
    p.impl().get_state_component().change_state("run");
    directional_light dl(glm::vec3(1, 0.3, 1), glm::vec3(1), 1, true);
    c.follow(p.id());
    c.impl().get_camera_follow_component().initial_position(glm::vec3(0,0,0));
    //d.impl().get_physics_component().apply_central_impulse(glm::vec3(5, 5, 0));
}

#include "../assets/scripts/entities/camera.as"
#include "../assets/scripts/entities/dummy.as"
#include "../assets/scripts/entities/directional_light.as"
#include "../assets/scripts/entities/light.as"
#include "../assets/scripts/entities/player.as"
#include "../assets/scripts/entities/plane.as"

void main() {
    camera c(glm::vec3(-10, 4, 0), glm::quat(glm::radians(-15), glm::vec3(1, 0, 0)));
    c.activate();
    plane pl(glm::vec3(0, 1, 0), glm::quat(glm::radians(0), glm::vec3(1, 0, 0)), glm::vec3(1));
    dummy d(glm::vec3(4, 4, 0), glm::quat(glm::radians(45), glm::vec3(0, 1, 0)), glm::vec3(1.f), "meshes/dummy.msh");
    light l(glm::vec3(-4.f, 4.f, 2.f), glm::vec3(1), 20);
    light l2(glm::vec3(10.f, 2.f, -2.f), glm::vec3(0.f, 0.3f, 1.0f), 20);
    player p(glm::vec3(-3.f, 2.f, -14.f), glm::quat(glm::radians(90), glm::vec3(0, 1, 0)), glm::vec3(1), "meshes/human.msh", "anims/human.skl");
    player_id = p.id();
    directional_light dl(glm::vec3(1, 0.3, 1), glm::vec3(1), 1, true);
    c.follow(p.id());
    c.impl().get_camera_follow_component().initial_position(glm::vec3(0,0,0));
    //d.impl().get_physics_component().apply_central_impulse(glm::vec3(5, 5, 0));
}

set player id in test.as

set player id in test.as


////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package org.apache.flex.html.beads.layouts
{
	import org.apache.flex.core.IBead;
    import org.apache.flex.core.IBeadView;
	import org.apache.flex.core.IStrand;
	import org.apache.flex.events.Event;
	import org.apache.flex.events.IEventDispatcher;

	/**
	 *  The LayoutChangeNotifier notifies layouts when a property
     *  it is watching changes.
	 *
	 *  @langversion 3.0
	 *  @playerversion Flash 10.2
	 *  @playerversion AIR 2.6
	 *  @productversion FlexJS 0.0
	 */
	public class LayoutChangeNotifier implements IBead
	{
		/**
		 *  constructor.
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 10.2
		 *  @playerversion AIR 2.6
		 *  @productversion FlexJS 0.0
		 */
		public function LayoutChangeNotifier()
		{
		}

		private var _strand:IStrand;

		/**
		 *  @copy org.apache.flex.core.IBead#strand
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 10.2
		 *  @playerversion AIR 2.6
		 *  @productversion FlexJS 0.0
		 */
		public function set strand(value:IStrand):void
		{
			_strand = value;
		}

        private var _value:* = undefined;

		/**
		 *  The number of tiles to fit horizontally into the layout.
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 10.2
		 *  @playerversion AIR 2.6
		 *  @productversion FlexJS 0.0
		 */
		public function set watchedProperty(value:Object):void
		{
			if (_value !== value)
            {
                _value = value;
                IBeadView(_strand).host.dispatchEvent(new Event("layoutNeeded"));
            }
		}

	}
}

////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package org.apache.flex.html.beads.layouts
{
	import org.apache.flex.core.IBead;
    import org.apache.flex.core.IBeadView;
	import org.apache.flex.core.IStrand;
	import org.apache.flex.events.Event;
	import org.apache.flex.events.IEventDispatcher;

	/**
	 *  The LayoutChangeNotifier notifies layouts when a property
     *  it is watching changes.
	 *
	 *  @langversion 3.0
	 *  @playerversion Flash 10.2
	 *  @playerversion AIR 2.6
	 *  @productversion FlexJS 0.0
	 */
	public class LayoutChangeNotifier implements IBead
	{
		/**
		 *  constructor.
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 10.2
		 *  @playerversion AIR 2.6
		 *  @productversion FlexJS 0.0
		 */
		public function LayoutChangeNotifier()
		{
		}

		private var _strand:IStrand;

		/**
		 *  @copy org.apache.flex.core.IBead#strand
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 10.2
		 *  @playerversion AIR 2.6
		 *  @productversion FlexJS 0.0
		 */
		public function set strand(value:IStrand):void
		{
			_strand = value;
		}

        private var _value:* = undefined;

		/**
		 *  The number of tiles to fit horizontally into the layout.
		 *
		 *  @langversion 3.0
		 *  @playerversion Flash 10.2
		 *  @playerversion AIR 2.6
		 *  @productversion FlexJS 0.0
		 */
		public function set watchedProperty(value:Object):void
		{
			if (_value !== value)
            {
                _value = value;
                if (_strand is IBeadView)
                    IBeadView(_strand).host.dispatchEvent(new Event("layoutNeeded"));
                else
                    IEventDispatcher(_strand).dispatchEvent(new Event("layoutNeeded"));
            }
		}

	}
}

handle being a bead on a component as well as a view


////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

package spark.skins.mobile.supportClasses
{
import flash.display.DisplayObject;
import flash.display.GradientType;
import flash.display.Graphics;
import flash.geom.Matrix;

import mx.core.DPIClassification;
import mx.core.mx_internal;
import mx.utils.ColorUtil;

import spark.skins.mobile.ActionBarSkin;
import spark.skins.mobile.ButtonSkin;

use namespace mx_internal;

/**
 *  Base skin class for ActionBar buttons in mobile applications. To support
 *  overlay modes in ViewNavigator, this base skin is transparent in all states
 *  except for the down state.
 *
 *  @see spark.components.ActionBar
 *  @see spark.components.supportClasses.ViewNavigatorBase#overlayControls
 *
 *  @langversion 3.0
 *  @playerversion Flash 10
 *  @playerversion AIR 2.5
 *  @productversion Flex 4.5
 */
public class ActionBarButtonSkinBase extends ButtonSkin
{
    //--------------------------------------------------------------------------
    //
    //  Class constants
    //
    //--------------------------------------------------------------------------

    private static var matrix:Matrix = new Matrix();

    //--------------------------------------------------------------------------
    //
    //  Constructor
    //
    //--------------------------------------------------------------------------
    /**
     *  Constructor.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10
     *  @playerversion AIR 2.5
     *  @productversion Flex 4.5
     *
     */
    public function ActionBarButtonSkinBase()
    {
        super();

        switch (applicationDPI)
        {
			case DPIClassification.DPI_640:
			{
				// Note provisional may need changes
				layoutBorderSize = 2;
				layoutPaddingTop = 24;
				layoutPaddingBottom = 20;
				layoutPaddingLeft = 40;
				layoutPaddingRight = 40;
				measuredDefaultWidth = 2012;
				measuredDefaultHeight = 172;
				break;
			}
			case DPIClassification.DPI_480:
			{
				// Note provisional may need changes
				layoutBorderSize = 1;
				layoutPaddingTop = 18;
				layoutPaddingBottom = 16;
				layoutPaddingLeft = 32;
				layoutPaddingRight = 32;
				measuredDefaultWidth = 162;
				measuredDefaultHeight = 130;
				break;
			}
            case DPIClassification.DPI_320:
            {
                layoutBorderSize = 1;
                layoutPaddingTop = 12;
                layoutPaddingBottom = 10;
                layoutPaddingLeft = 20;
                layoutPaddingRight = 20;
                measuredDefaultWidth = 106;
                measuredDefaultHeight = 86;
                break;
            }
            case DPIClassification.DPI_240:
            {
                layoutBorderSize = 1;
                layoutPaddingTop = 9;
                layoutPaddingBottom = 8;
                layoutPaddingLeft = 16;
                layoutPaddingRight = 16;
                measuredDefaultWidth = 81;
                measuredDefaultHeight = 65;
                break;
            }
			case DPIClassification.DPI_120:
			{
				// Note provisional may need changes
				layoutBorderSize = 1;
				layoutPaddingTop = 4;
				layoutPaddingBottom = 4;
				layoutPaddingLeft = 8;
				layoutPaddingRight = 8;
				measuredDefaultWidth = 40;
				measuredDefaultHeight = 33;
				break;
			}
            default:
            {
                // default DPI_160
                layoutBorderSize = 1;
                layoutPaddingTop = 6;
                layoutPaddingBottom = 5;
                layoutPaddingLeft = 10;
                layoutPaddingRight = 10;
                measuredDefaultWidth = 53;
                measuredDefaultHeight = 43;

                break;
            }
        }
    }

    /**
     * @private
     * Disabled state for ActionBar buttons only applies to label and icon
     */
    override protected function commitDisabled():void
    {
        var alphaValue:Number = (hostComponent.enabled) ? 1 : 0.5

        labelDisplay.alpha = alphaValue;
        labelDisplayShadow.alpha = alphaValue;

        var icon:DisplayObject = getIconDisplay();

        if (icon != null)
            icon.alpha = alphaValue;
    }

    //--------------------------------------------------------------------------
    //
    //  Overridden methods
    //
    //--------------------------------------------------------------------------

    /**
     * @private
     */
    override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void
    {
        // omit super.drawBackground() to drawRect instead
        // only draw chromeColor in down state (transparent hit zone otherwise)
        var isDown:Boolean = (currentState == "down");
        var chromeColor:uint = isDown ? getStyle(fillColorStyleName) : 0;
        var chromeAlpha:Number = isDown ? 1 : 0;

        graphics.beginFill(chromeColor, chromeAlpha);
        graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
        graphics.endFill();
    }
}
}

////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

package spark.skins.mobile.supportClasses
{
import flash.display.DisplayObject;
import flash.display.GradientType;
import flash.display.Graphics;
import flash.geom.Matrix;

import mx.core.DPIClassification;
import mx.core.mx_internal;
import mx.utils.ColorUtil;

import spark.skins.mobile.ActionBarSkin;
import spark.skins.mobile.ButtonSkin;

use namespace mx_internal;

/**
 *  Base skin class for ActionBar buttons in mobile applications. To support
 *  overlay modes in ViewNavigator, this base skin is transparent in all states
 *  except for the down state.
 *
 *  @see spark.components.ActionBar
 *  @see spark.components.supportClasses.ViewNavigatorBase#overlayControls
 *
 *  @langversion 3.0
 *  @playerversion Flash 10
 *  @playerversion AIR 2.5
 *  @productversion Flex 4.5
 */
public class ActionBarButtonSkinBase extends ButtonSkin
{
    //--------------------------------------------------------------------------
    //
    //  Class constants
    //
    //--------------------------------------------------------------------------

    private static var matrix:Matrix = new Matrix();

    //--------------------------------------------------------------------------
    //
    //  Constructor
    //
    //--------------------------------------------------------------------------
    /**
     *  Constructor.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10
     *  @playerversion AIR 2.5
     *  @productversion Flex 4.5
     *
     */
    public function ActionBarButtonSkinBase()
    {
        super();

        switch (applicationDPI)
        {
			case DPIClassification.DPI_640:
			{
				// Note provisional may need changes
				layoutBorderSize = 2;
				layoutPaddingTop = 24;
				layoutPaddingBottom = 20;
				layoutPaddingLeft = 40;
				layoutPaddingRight = 40;
				measuredDefaultWidth = 212;
				measuredDefaultHeight = 172;
				break;
			}
			case DPIClassification.DPI_480:
			{
				// Note provisional may need changes
				layoutBorderSize = 1;
				layoutPaddingTop = 18;
				layoutPaddingBottom = 16;
				layoutPaddingLeft = 32;
				layoutPaddingRight = 32;
				measuredDefaultWidth = 162;
				measuredDefaultHeight = 130;
				break;
			}
            case DPIClassification.DPI_320:
            {
                layoutBorderSize = 1;
                layoutPaddingTop = 12;
                layoutPaddingBottom = 10;
                layoutPaddingLeft = 20;
                layoutPaddingRight = 20;
                measuredDefaultWidth = 106;
                measuredDefaultHeight = 86;
                break;
            }
            case DPIClassification.DPI_240:
            {
                layoutBorderSize = 1;
                layoutPaddingTop = 9;
                layoutPaddingBottom = 8;
                layoutPaddingLeft = 16;
                layoutPaddingRight = 16;
                measuredDefaultWidth = 81;
                measuredDefaultHeight = 65;
                break;
            }
			case DPIClassification.DPI_120:
			{
				// Note provisional may need changes
				layoutBorderSize = 1;
				layoutPaddingTop = 4;
				layoutPaddingBottom = 4;
				layoutPaddingLeft = 8;
				layoutPaddingRight = 8;
				measuredDefaultWidth = 40;
				measuredDefaultHeight = 33;
				break;
			}
            default:
            {
                // default DPI_160
                layoutBorderSize = 1;
                layoutPaddingTop = 6;
                layoutPaddingBottom = 5;
                layoutPaddingLeft = 10;
                layoutPaddingRight = 10;
                measuredDefaultWidth = 53;
                measuredDefaultHeight = 43;

                break;
            }
        }
    }

    /**
     * @private
     * Disabled state for ActionBar buttons only applies to label and icon
     */
    override protected function commitDisabled():void
    {
        var alphaValue:Number = (hostComponent.enabled) ? 1 : 0.5

        labelDisplay.alpha = alphaValue;
        labelDisplayShadow.alpha = alphaValue;

        var icon:DisplayObject = getIconDisplay();

        if (icon != null)
            icon.alpha = alphaValue;
    }

    //--------------------------------------------------------------------------
    //
    //  Overridden methods
    //
    //--------------------------------------------------------------------------

    /**
     * @private
     */
    override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void
    {
        // omit super.drawBackground() to drawRect instead
        // only draw chromeColor in down state (transparent hit zone otherwise)
        var isDown:Boolean = (currentState == "down");
        var chromeColor:uint = isDown ? getStyle(fillColorStyleName) : 0;
        var chromeAlpha:Number = isDown ? 1 : 0;

        graphics.beginFill(chromeColor, chromeAlpha);
        graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
        graphics.endFill();
    }
}
}

Fix for https://issues.apache.org/jira/browse/FLEX-34189


import asunit.flash.utils.Timer;
import asunit.errors.ClassNameUndefinedError;
import asunit.util.ArrayUtil;
import asunit.framework.AsyncOperation;
import asunit.framework.TestResult;

import asunit.framework.TestListener;
import asunit.framework.Test;
import asunit.framework.Assert;
import asunit.flash.errors.IllegalOperationError;
import asunit.flash.events.Event;

import asunit.errors.AssertionFailedError;
import asunit.util.ArrayIterator;
import asunit.util.Iterator;

/**
 * A test case defines the fixture to run multiple tests. To define a test case

 * 1) implement a subclass of TestCase

 * 2) define instance variables that store the state of the fixture

 * 3) initialize the fixture state by overriding setUp

 * 4) clean-up after a test by overriding tearDown.

 * Each test runs in its own fixture so there
 * can be no side effects among test runs.
 * Here is an example:
 *

 * public class MathTest extends TestCase {
 *     protected double fValue1;
 *     protected double fValue2;
 *
 *    protected void setUp() {
 *         fValue1= 2.0;
 *         fValue2= 3.0;
 *     }
 * }
 *

 *
 * For each test implement a method which interacts
 * with the fixture. Verify the expected results with assertions specified
 * by calling assertTrue with a boolean.
 *

 *    public void testAdd() {
 *        double result= fValue1 + fValue2;
 *        assertTrue(result == 5.0);
 *    }
 *

 * Once the methods are defined you can run them. The framework supports
 * both a static type safe and more dynamic way to run a test.
 * In the static way you override the runTest method and define the method to
 * be invoked. A convenient way to do so is with an anonymous inner class.
 *

 * TestCase test= new MathTest("add") {
 *        public void runTest() {
 *            testAdd();
 *        }
 * };
 * test.run();
 *

 * The dynamic way uses reflection to implement runTest. It dynamically finds
 * and invokes a method.
 * In this case the name of the test case has to correspond to the test method
 * to be run.
 *

 * TestCase= new MathTest("testAdd");
 * test.run();
 *

 * The tests to be run can be collected into a TestSuite. JUnit provides
 * different test runners which can run a test suite and collect the results.
 * A test runner either expects a static method suite as the entry
 * point to get a test to run or it will extract the suite automatically.
 *

 * public static Test suite() {
 *      suite.addTest(new MathTest("testAdd"));
 *      suite.addTest(new MathTest("testDivideByZero"));
 *      return suite;
 *  }
 *

 * @see TestResult
 * @see TestSuite
 */
class asunit.framework.TestCase extends Assert implements Test {
	private static var PRE_SET_UP:Number		= 0;
	private static var SET_UP:Number 			= 1;
	private static var RUN_METHOD:Number 		= 2;
	private static var TEAR_DOWN:Number			= 3;
	private static var DEFAULT_TIMEOUT:Number 	= 1000;
	private var className:String;
	private var fName:String;
	private var result : TestListener;
	private var testMethods:Array;
	private var isComplete:Boolean;
	private var context : MovieClip;
	private var asyncQueue:Array;
	private var currentMethod:String;
	private var runSingle:Boolean;
	private var methodIterator:Iterator;
	private var layoutManager:Object;
	private var currentState:Number;

	private static var lastDepth:Number = 10;

	/**
	 * Constructs a test case with the given name.
	 */
	public function TestCase(testMethod:String) {
		if(testMethod==undefined) testMethod=null;
		if(testMethod != null) {
			testMethods = testMethod.split(", ").join(",").split(",");
			if(testMethods.length == 1) {
				runSingle = true;
			}
		} else {
			setTestMethods(this);
		}
		setName(this.className);
		// I don't think this is necessary for as2
//		resolveLayoutManager();
		asyncQueue = [];
	}

/*	private function resolveLayoutManager():Void {
		// Avoid creating import dependencies on flex framework
		// If you have the framework.swc in your classpath,
		// the layout manager will be found, if not, a mcok
		// will be used.
		try {
			var manager:Class = getDefinitionByName("mx.managers.LayoutManager") as Class;
			layoutManager = manager["getInstance"]();
			if(!layoutManager.hasOwnProperty("resetAll")) {
				throw new Error("TestCase :: mx.managers.LayoutManager missing resetAll method");
			}
		}
		catch(e:Error) {
			layoutManager = new Object();
			layoutManager.resetAll = function():Void {
			};
		}
	}
*/
	/**
	 * Sets the name of a TestCase
	 * @param name The name to set
	 */
	public function setName(name:String):Void {
		if(name==undefined || name==null){
			throw new ClassNameUndefinedError("You must assign a ClassName for your TestCase subclass.")
		}
		fName = name;
	}

	private function setTestMethods(obj:Object):Void {
		testMethods = [];
		_global.ASSetPropFlags(obj.__proto__, null, 6, true);
		for(var prop:String in obj) {
				// look for functions starting with "test"
			if((prop.indexOf("test")==0)  && (obj[prop] instanceof Function)){
				testMethods.push(prop);
			}
		}
		_global.ASSetPropFlags(this.__proto__, null, 1, true);
		testMethods.reverse();
	}

	public function getTestMethods():Array {
		return testMethods;
	}

	/**
	 * Counts the number of test cases executed by run(TestResult result).
	 */
	public function countTestCases():Number {
		return testMethods.length;
	}

	/**
	 * Creates a default TestResult object
	 *
	 * @see TestResult
	 */
	private function createResult():TestResult {
	    return new TestResult();
	}

	/**
	 * A convenience method to run this test, collecting the results with
	 * either the TestResult provided or a default, new TestResult object.
	 * Expects either:
	 * run():Void // will return the newly created TestResult
	 * run(result:TestResult):TestResult // will use the TestResult
	 * that was passed in.
	 *
	 * @see TestResult
	 */
	public function run():Void {
		getResult().run(this);
	}

	public function setResult(result:TestListener):Void {
		this.result = result;
	}

	public function getResult():TestListener {
		return (result == null) ? createResult() : result;
	}

	/**
	 * Runs the bare test sequence.
	 * @exception Error if any exception is thrown
	 *  throws Error
	 */
	public function runBare():Void {
		if(isComplete) {
			return;
		}
		var name:String;
		var itr:Iterator = getMethodIterator();
		if(itr.hasNext()) {
			name = String(itr.next());
			currentState = PRE_SET_UP;
			runMethod(name);
		}
		else {
			cleanUp();
			getResult().endTest(this);
			isComplete = true;
			dispatchEvent(new Event(Event.COMPLETE));
		}
	}

	private function getMethodIterator():Iterator {
		if(methodIterator == null) {
			methodIterator = new ArrayIterator(testMethods);
		}
		return methodIterator;
	}

	// Override this method in Asynchronous test cases
	// or any other time you want to perform additional
	// member cleanup after all test methods have run
	private function cleanUp():Void {
	}

	private function runMethod(methodName:String):Void {
		try {
			if(currentState == PRE_SET_UP) {
				currentState = SET_UP;
				getResult().startTestMethod(this, methodName);
				setUp(); // setUp may be async and change the state of methodIsAsynchronous
			}
			currentMethod = methodName;
			if(!waitForAsync()) {
				currentState = RUN_METHOD;
				this[methodName]();
			}
		}
		catch(assertionFailedError:AssertionFailedError) {
			getResult().addFailure(this, assertionFailedError);
		}
		catch(unknownError:Error) {
			getResult().addError(this, unknownError);
		}
		finally {
			if(!waitForAsync()) {
				runTearDown();
			}
		}
	}

	/**
	 * Sets up the fixture, for example, instantiate a mock object.
	 * This method is called before each test is executed.
	 * throws Exception on error
	 */
	private function setUp():Void {
	}
	/**
	 * Tears down the fixture, for example, delete mock object.
	 * This method is called after a test is executed.
	 *  throws Exception on error
	 */
	private function tearDown():Void {
	}
	/**
	 * Returns a string representation of the test case
	 */
	public function toString():String {
		if(getCurrentMethod()) {
			return getName() + "." + getCurrentMethod() + "()";
		}
		else {
			return getName();
		}
	}
	/**
	 * Gets the name of a TestCase
	 * @return returns a String
	 */
	public function getName():String {
		return fName;
	}

	public function getCurrentMethod():String {
		return currentMethod;
	}

	public function getIsComplete():Boolean {
		return isComplete;
	}

	public function setContext(context:MovieClip):Void {
		this.context = context;
	}

	public function getContext():MovieClip {
		return context;
	}

	private function addAsync(handler:Function, duration:Number):Function {
		if(handler == undefined) {
			handler = function():Void{};
		}
		if(duration == undefined) {
			duration = DEFAULT_TIMEOUT;
		}
		var async:AsyncOperation = new AsyncOperation(this, handler, duration);
		asyncQueue.push(async);
		return async.getCallback();
	}

	public function asyncOperationTimeout(async:AsyncOperation, duration:Number):Void{
		getResult().addError(this, new IllegalOperationError("TestCase.timeout (" + duration + "ms) exceeded on an asynchronous operation."));
		asyncOperationComplete(async);
	}

	public function asyncOperationComplete(async:AsyncOperation):Void{
		// remove operation from queue
		var i:Number = ArrayUtil.indexOf(asyncQueue, async);
		asyncQueue.splice(i,1);
		// if we still need to wait, return
		if(waitForAsync()) return;
		if(currentState == SET_UP) {
			runMethod(currentMethod);
		}
		else if(currentState == RUN_METHOD) {
			runTearDown();
		}
	}

	private function waitForAsync():Boolean{
		return asyncQueue.length > 0;
	}

	private function runTearDown():Void {
		currentState = TEAR_DOWN;
		if(isComplete) {
			return;
		}
		if(!runSingle) {
			getResult().endTestMethod(this, currentMethod);
			tearDown();
		}
		Timer.setTimeout(this, runBare, 5);
	}

	/**
	 * begin asunit25 specific methods
	 */

	private function createEmptyMovieClip(name:String, depth:Number):MovieClip {
		if(depth==undefined || depth===null) depth = getNextHighestDepth();
		return getContext().createEmptyMovieClip(name, depth);
	}

	private function createTextField(name:String, depth:Number, x:Number, y:Number, width:Number, height:Number):TextField {
	    getContext().createTextField(name, depth, x, y, width, height);
	    return TextField(getContext()[name]);
	}

	private function getNextHighestDepth():Number {
		return getContext().getNextHighestDepth();
	}

	/*
	 * This helper method will support the following method signatures:
	 *
	 * attachMovie(linkageId:String):MovieClip;
	 * attachMovie(linkageId:String, initObject:Object):MovieClip;
	 * attachMovie(linkageId:String, name:String, depth:Number):MovieClip;
	 * attachMovie(linkageId:String, name:String, depth:Number, initObject:Object):MovieClip;
	 *
	 * @return
	 * 	MovieClip
	 */
 	private function attachMovie():MovieClip {
 		var linkageId:String = arguments[0];
 		var name:String;
 		var depth:Number;
 		var initObj:Object = new Object();

		switch(arguments.length) {
			case 1 :
			case 2 :
				name = getValidName(getContext(), name);
				depth = getValidDepth(getContext());
 				initObj = arguments[1];
 				break;
 			case 3 :
 			case 4 :
 				name = arguments[1];
 				depth = arguments[2];
 				initObj = arguments[3];
 				break;
		}
		return getContext().attachMovie(linkageId, name, depth, initObj);
 	}

	public function getUpperEmptyDepth(parent:MovieClip, depth:Number):Number {
		if(depth == undefined || !isValidDepth(parent, depth)) {
			var high:Number = (depth == undefined) ? 1 : depth;
			for(var i:String in parent) {
				if(parent[i] instanceof MovieClip && parent[i].getDepth() != undefined) {
					high = Math.max(parent[i].getDepth()+1, high);
				}
			}
			return high;
		}
		return depth;
	}

	private function getValidName(parent:MovieClip, nm:Object):String {
		var incr:Number = 1;

		var name:String = (nm == undefined || nm instanceof Object) ? "item" : nm.toString();
		var ref:MovieClip = parent[name];

		var name2:String = name;
		while(ref != undefined && incr < 100) {
			name2 = name + "-" + (incr++);
			ref = parent[name2];
		}
		return name2;
	}

	private function isValidDepth(parent:MovieClip, depth:Number):Boolean {
		var item:MovieClip = getItemByDepth(parent, depth);
		return (item == null) ? true : false;
	}

	private function getItemByDepth(parent:MovieClip, depth:Number):MovieClip {
		for(var i:String in parent) {
			if(parent[i].getDepth() == depth) {
				return parent[i];
			}
		}
		return null;
	}

	/**
	 * Returns the next available depth for attaching a MovieClip.
	 *
	 * @return
	 *         Number of next available depth.
	 */
	public static function nextDepth():Number {
		return lastDepth++;
	}

	private function getValidDepth(mc:MovieClip):Number {
		var mcDepth:Number;
		var dp:Number = nextDepth();
		for(var i:String in mc) {
			mcDepth = mc[i].getDepth();
			if(mc[i] instanceof MovieClip && mcDepth < 10000) {
				dp = Math.max(mcDepth, dp);
			}
		}
		return ++dp;
	}

}

import asunit.flash.utils.Timer;
import asunit.errors.ClassNameUndefinedError;
import asunit.util.ArrayUtil;
import asunit.framework.AsyncOperation;
import asunit.framework.TestResult;

import asunit.framework.TestListener;
import asunit.framework.Test;
import asunit.framework.Assert;
import asunit.flash.errors.IllegalOperationError;
import asunit.flash.events.Event;

import asunit.errors.AssertionFailedError;
import asunit.util.ArrayIterator;
import asunit.util.Iterator;

/**
 * A test case defines the fixture to run multiple tests. To define a test case

 * 1) implement a subclass of TestCase

 * 2) define instance variables that store the state of the fixture

 * 3) initialize the fixture state by overriding setUp

 * 4) clean-up after a test by overriding tearDown.

 * Each test runs in its own fixture so there
 * can be no side effects among test runs.
 * Here is an example:
 *

 * public class MathTest extends TestCase {
 *     protected double fValue1;
 *     protected double fValue2;
 *
 *    protected void setUp() {
 *         fValue1= 2.0;
 *         fValue2= 3.0;
 *     }
 * }
 *

 *
 * For each test implement a method which interacts
 * with the fixture. Verify the expected results with assertions specified
 * by calling assertTrue with a boolean.
 *

 *    public void testAdd() {
 *        double result= fValue1 + fValue2;
 *        assertTrue(result == 5.0);
 *    }
 *

 * Once the methods are defined you can run them. The framework supports
 * both a static type safe and more dynamic way to run a test.
 * In the static way you override the runTest method and define the method to
 * be invoked. A convenient way to do so is with an anonymous inner class.
 *

 * TestCase test= new MathTest("add") {
 *        public void runTest() {
 *            testAdd();
 *        }
 * };
 * test.run();
 *

 * The dynamic way uses reflection to implement runTest. It dynamically finds
 * and invokes a method.
 * In this case the name of the test case has to correspond to the test method
 * to be run.
 *

 * TestCase= new MathTest("testAdd");
 * test.run();
 *

 * The tests to be run can be collected into a TestSuite. JUnit provides
 * different test runners which can run a test suite and collect the results.
 * A test runner either expects a static method suite as the entry
 * point to get a test to run or it will extract the suite automatically.
 *

 * public static Test suite() {
 *      suite.addTest(new MathTest("testAdd"));
 *      suite.addTest(new MathTest("testDivideByZero"));
 *      return suite;
 *  }
 *

 * @see TestResult
 * @see TestSuite
 */
class asunit.framework.TestCase extends Assert implements Test {
	private static var PRE_SET_UP:Number		= 0;
	private static var SET_UP:Number 			= 1;
	private static var RUN_METHOD:Number 		= 2;
	private static var TEAR_DOWN:Number			= 3;
	private static var DEFAULT_TIMEOUT:Number 	= 1000;
	private var className:String;
	private var fName:String;
	private var result : TestListener;
	private var testMethods:Array;
	private var isComplete:Boolean;
	private var context : MovieClip;
	private var asyncQueue:Array;
	private var currentMethod:String;
	private var runSingle:Boolean;
	private var methodIterator:Iterator;
	private var layoutManager:Object;
	private var currentState:Number;

	private static var lastDepth:Number = 10;

	/**
	 * Constructs a test case with the given name.
	 */
	public function TestCase(testMethod:String) {
		if(testMethod==undefined) testMethod=null;
		if(testMethod != null) {
			testMethods = testMethod.split(", ").join(",").split(",");
			if(testMethods.length == 1) {
				runSingle = true;
			}
		} else {
			setTestMethods(this);
		}
		try {
		    setName(this.className);
                }
	        catch(e:ClassNameUndefinedError) {
	            trace(">> WARNING: Concrete TestCase classes must have a 'className' parameter with the fully qualified class name in order for AsUnit to provide useful failures.");
                }

//		resolveLayoutManager();
		asyncQueue = [];
	}

/*	private function resolveLayoutManager():Void {
		// Avoid creating import dependencies on flex framework
		// If you have the framework.swc in your classpath,
		// the layout manager will be found, if not, a mcok
		// will be used.
		try {
			var manager:Class = getDefinitionByName("mx.managers.LayoutManager") as Class;
			layoutManager = manager["getInstance"]();
			if(!layoutManager.hasOwnProperty("resetAll")) {
				throw new Error("TestCase :: mx.managers.LayoutManager missing resetAll method");
			}
		}
		catch(e:Error) {
			layoutManager = new Object();
			layoutManager.resetAll = function():Void {
			};
		}
	}
*/
	/**
	 * Sets the name of a TestCase
	 * @param name The name to set
	 */
	public function setName(name:String):Void {
		if(name==undefined || name==null){
			throw new ClassNameUndefinedError("You must assign a ClassName for your TestCase subclass.")
		}
		fName = name;
	}

	private function setTestMethods(obj:Object):Void {
		testMethods = [];
		_global.ASSetPropFlags(obj.__proto__, null, 6, true);
		for(var prop:String in obj) {
				// look for functions starting with "test"
			if((prop.indexOf("test")==0)  && (obj[prop] instanceof Function)){
				testMethods.push(prop);
			}
		}
		_global.ASSetPropFlags(this.__proto__, null, 1, true);
		testMethods.reverse();
	}

	public function getTestMethods():Array {
		return testMethods;
	}

	/**
	 * Counts the number of test cases executed by run(TestResult result).
	 */
	public function countTestCases():Number {
		return testMethods.length;
	}

	/**
	 * Creates a default TestResult object
	 *
	 * @see TestResult
	 */
	private function createResult():TestResult {
	    return new TestResult();
	}

	/**
	 * A convenience method to run this test, collecting the results with
	 * either the TestResult provided or a default, new TestResult object.
	 * Expects either:
	 * run():Void // will return the newly created TestResult
	 * run(result:TestResult):TestResult // will use the TestResult
	 * that was passed in.
	 *
	 * @see TestResult
	 */
	public function run():Void {
		getResult().run(this);
	}

	public function setResult(result:TestListener):Void {
		this.result = result;
	}

	public function getResult():TestListener {
		return (result == null) ? createResult() : result;
	}

	/**
	 * Runs the bare test sequence.
	 * @exception Error if any exception is thrown
	 *  throws Error
	 */
	public function runBare():Void {
		if(isComplete) {
			return;
		}
		var name:String;
		var itr:Iterator = getMethodIterator();
		if(itr.hasNext()) {
			name = String(itr.next());
			currentState = PRE_SET_UP;
			runMethod(name);
		}
		else {
			cleanUp();
			getResult().endTest(this);
			isComplete = true;
			dispatchEvent(new Event(Event.COMPLETE));
		}
	}

	private function getMethodIterator():Iterator {
		if(methodIterator == null) {
			methodIterator = new ArrayIterator(testMethods);
		}
		return methodIterator;
	}

	// Override this method in Asynchronous test cases
	// or any other time you want to perform additional
	// member cleanup after all test methods have run
	private function cleanUp():Void {
	}

	private function runMethod(methodName:String):Void {
		try {
			if(currentState == PRE_SET_UP) {
				currentState = SET_UP;
				getResult().startTestMethod(this, methodName);
				setUp(); // setUp may be async and change the state of methodIsAsynchronous
			}
			currentMethod = methodName;
			if(!waitForAsync()) {
				currentState = RUN_METHOD;
				this[methodName]();
			}
		}
		catch(assertionFailedError:AssertionFailedError) {
			getResult().addFailure(this, assertionFailedError);
		}
		catch(unknownError:Error) {
			getResult().addError(this, unknownError);
		}
		finally {
			if(!waitForAsync()) {
				runTearDown();
			}
		}
	}

	/**
	 * Sets up the fixture, for example, instantiate a mock object.
	 * This method is called before each test is executed.
	 * throws Exception on error
	 */
	private function setUp():Void {
	}
	/**
	 * Tears down the fixture, for example, delete mock object.
	 * This method is called after a test is executed.
	 *  throws Exception on error
	 */
	private function tearDown():Void {
	}
	/**
	 * Returns a string representation of the test case
	 */
	public function toString():String {
		if(getCurrentMethod()) {
			return getName() + "." + getCurrentMethod() + "()";
		}
		else {
			return getName();
		}
	}
	/**
	 * Gets the name of a TestCase
	 * @return returns a String
	 */
	public function getName():String {
		return fName;
	}

	public function getCurrentMethod():String {
		return currentMethod;
	}

	public function getIsComplete():Boolean {
		return isComplete;
	}

	public function setContext(context:MovieClip):Void {
		this.context = context;
	}

	public function getContext():MovieClip {
		return context;
	}

	private function addAsync(handler:Function, duration:Number):Function {
		if(handler == undefined) {
			handler = function():Void{};
		}
		if(duration == undefined) {
			duration = DEFAULT_TIMEOUT;
		}
		var async:AsyncOperation = new AsyncOperation(this, handler, duration);
		asyncQueue.push(async);
		return async.getCallback();
	}

	public function asyncOperationTimeout(async:AsyncOperation, duration:Number):Void{
		getResult().addError(this, new IllegalOperationError("TestCase.timeout (" + duration + "ms) exceeded on an asynchronous operation."));
		asyncOperationComplete(async);
	}

	public function asyncOperationComplete(async:AsyncOperation):Void{
		// remove operation from queue
		var i:Number = ArrayUtil.indexOf(asyncQueue, async);
		asyncQueue.splice(i,1);
		// if we still need to wait, return
		if(waitForAsync()) return;
		if(currentState == SET_UP) {
			runMethod(currentMethod);
		}
		else if(currentState == RUN_METHOD) {
			runTearDown();
		}
	}

	private function waitForAsync():Boolean{
		return asyncQueue.length > 0;
	}

	private function runTearDown():Void {
		currentState = TEAR_DOWN;
		if(isComplete) {
			return;
		}
		if(!runSingle) {
			getResult().endTestMethod(this, currentMethod);
			tearDown();
		}
		Timer.setTimeout(this, runBare, 5);
	}

	/**
	 * begin asunit25 specific methods
	 */

	private function createEmptyMovieClip(name:String, depth:Number):MovieClip {
		if(depth==undefined || depth===null) depth = getNextHighestDepth();
		return getContext().createEmptyMovieClip(name, depth);
	}

	private function createTextField(name:String, depth:Number, x:Number, y:Number, width:Number, height:Number):TextField {
	    getContext().createTextField(name, depth, x, y, width, height);
	    return TextField(getContext()[name]);
	}

	private function getNextHighestDepth():Number {
		return getContext().getNextHighestDepth();
	}

	/*
	 * This helper method will support the following method signatures:
	 *
	 * attachMovie(linkageId:String):MovieClip;
	 * attachMovie(linkageId:String, initObject:Object):MovieClip;
	 * attachMovie(linkageId:String, name:String, depth:Number):MovieClip;
	 * attachMovie(linkageId:String, name:String, depth:Number, initObject:Object):MovieClip;
	 *
	 * @return
	 * 	MovieClip
	 */
 	private function attachMovie():MovieClip {
 		var linkageId:String = arguments[0];
 		var name:String;
 		var depth:Number;
 		var initObj:Object = new Object();

		switch(arguments.length) {
			case 1 :
			case 2 :
				name = getValidName(getContext(), name);
				depth = getValidDepth(getContext());
 				initObj = arguments[1];
 				break;
 			case 3 :
 			case 4 :
 				name = arguments[1];
 				depth = arguments[2];
 				initObj = arguments[3];
 				break;
		}
		return getContext().attachMovie(linkageId, name, depth, initObj);
 	}

	public function getUpperEmptyDepth(parent:MovieClip, depth:Number):Number {
		if(depth == undefined || !isValidDepth(parent, depth)) {
			var high:Number = (depth == undefined) ? 1 : depth;
			for(var i:String in parent) {
				if(parent[i] instanceof MovieClip && parent[i].getDepth() != undefined) {
					high = Math.max(parent[i].getDepth()+1, high);
				}
			}
			return high;
		}
		return depth;
	}

	private function getValidName(parent:MovieClip, nm:Object):String {
		var incr:Number = 1;

		var name:String = (nm == undefined || nm instanceof Object) ? "item" : nm.toString();
		var ref:MovieClip = parent[name];

		var name2:String = name;
		while(ref != undefined && incr < 100) {
			name2 = name + "-" + (incr++);
			ref = parent[name2];
		}
		return name2;
	}

	private function isValidDepth(parent:MovieClip, depth:Number):Boolean {
		var item:MovieClip = getItemByDepth(parent, depth);
		return (item == null) ? true : false;
	}

	private function getItemByDepth(parent:MovieClip, depth:Number):MovieClip {
		for(var i:String in parent) {
			if(parent[i].getDepth() == depth) {
				return parent[i];
			}
		}
		return null;
	}

	/**
	 * Returns the next available depth for attaching a MovieClip.
	 *
	 * @return
	 *         Number of next available depth.
	 */
	public static function nextDepth():Number {
		return lastDepth++;
	}

	private function getValidDepth(mc:MovieClip):Number {
		var mcDepth:Number;
		var dp:Number = nextDepth();
		for(var i:String in mc) {
			mcDepth = mc[i].getDepth();
			if(mc[i] instanceof MovieClip && mcDepth < 10000) {
				dp = Math.max(mcDepth, dp);
			}
		}
		return ++dp;
	}

}

Change failure to add 'className' to a test case from a sielent error to a traced warning


package com.threerings.util {

import flash.net.URLRequest;
//import flash.net.navigateToURL; // function import

public class NetUtil
{
    /**
     * Convenience method to load a web page in the browser window without
     * having to worry about SecurityErrors in various conditions.
     */
    public static function navigateToURL (
            url :String, preferSameWindowOrTab :Boolean = true) :void
    {
        var ureq :URLRequest = new URLRequest(url);
        if (preferSameWindowOrTab) {
            try {
                flash.net.navigateToURL(ureq, "_self");
                return;
            } catch (err :SecurityError) {
                // ignore; fall back to using a blank window, below...
            }
        }

        // open in a blank window
        try {
            flash.net.navigateToURL(ureq);
        } catch (err :SecurityError) {
            Log.getLog(NetUtil).warning(
                "Unable to navigate to URL [e=" + err + "].");
        }
    }

}
}

package com.threerings.util {

import flash.net.URLRequest;
//import flash.net.navigateToURL; // function import

public class NetUtil
{
    /**
     * Convenience method to load a web page in the browser window without
     * having to worry about SecurityErrors in various conditions.
     *
     * @return true if the url was unable to be loaded.
     */
    public static function navigateToURL (
            url :String, preferSameWindowOrTab :Boolean = true) :Boolean
    {
        var ureq :URLRequest = new URLRequest(url);
        if (preferSameWindowOrTab) {
            try {
                flash.net.navigateToURL(ureq, "_self");
                return true;
            } catch (err :SecurityError) {
                // ignore; fall back to using a blank window, below...
            }
        }

        // open in a blank window
        try {
            flash.net.navigateToURL(ureq);
            return true;
        } catch (err :SecurityError) {
            Log.getLog(NetUtil).warning(
                "Unable to navigate to URL [e=" + err + "].");
        }

        return false; // failure!
    }
}
}

Return true if we succeeded.

Return true if we succeeded.

git-svn-id: a1a4b28b82a3276cc491891159dd9963a0a72fae@4462 542714f4-19e9-0310-aa3c-eee0fc999fb1


/**
 * Copyright (c) 2009 Digital Primates IT Consulting Group
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * @author     Jeff Tapper
 * @version
 **/

package org.flexunit.listeners
{
	import flash.events.DataEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.TimerEvent;
	import flash.net.XMLSocket;
	import flash.utils.Timer;

	import org.flexunit.listeners.closer.ApplicationCloser;
	import org.flexunit.listeners.closer.StandAloneFlashPlayerCloser;
	import org.flexunit.reporting.FailureFormatter;
	import org.flexunit.runner.Descriptor;
	import org.flexunit.runner.IDescription;
	import org.flexunit.runner.Result;
	import org.flexunit.runner.notification.Failure;
	import org.flexunit.runner.notification.IAsyncStartupRunListener;
	import org.flexunit.runner.notification.ITemporalRunListener;
	import org.flexunit.runner.notification.async.AsyncListenerWatcher;

	public class CIListener extends EventDispatcher implements IAsyncStartupRunListener, ITemporalRunListener
	{
		protected static const DEFAULT_PORT : uint = 1024;
		protected static const DEFAULT_SERVER : String = "127.0.0.1";
		private static const SUCCESS:String = "success";
		private static const ERROR:String = "error";
		private static const FAILURE:String = "failure";
		private static const IGNORE:String = "ignore";

		private var successes:Array = new Array();
		private var ignores:Array = new Array();

		private var _ready:Boolean = false;

		private static const END_OF_TEST_ACK : String ="<endOfTestRunAck/>";
		private static const END_OF_TEST_RUN : String = "<endOfTestRun/>";
		private static const START_OF_TEST_RUN_ACK : String = "<startOfTestRunAck/>";

		private var socket:XMLSocket;

		[Inspectable]
		public var port : uint;

		[Inspectable]
		public var server : String; //this is local host. same machine

		public var closer : ApplicationCloser;

		private var lastFailedTest:IDescription;
		private var timeOut:Timer;
		private var lastTestTime:Number;

		public function CIListener(port : uint = DEFAULT_PORT, server : String = DEFAULT_SERVER)
		{
			this.port = port;
			this.server = server;
			this.closer = new StandAloneFlashPlayerCloser(); //default application closer

			socket = new XMLSocket ();
			socket.addEventListener( DataEvent.DATA, dataHandler );
			socket.addEventListener( Event.CONNECT, handleConnect );
			socket.addEventListener( IOErrorEvent.IO_ERROR, errorHandler);
			socket.addEventListener( SecurityErrorEvent.SECURITY_ERROR,errorHandler);
			socket.addEventListener( Event.CLOSE,errorHandler);

			timeOut = new Timer( 2000, 1 );
			timeOut.addEventListener(TimerEvent.TIMER_COMPLETE, declareBroken, false, 0, true );
			timeOut.start();

			try
			{
				socket.connect( server, port );
				timeOut.stop();
			} catch (e:Error) {
				//This needs to be more than a trace
				trace (e.message);
			}
		}

		private function declareBroken( event:TimerEvent ):void {
			errorHandler( new Event( "broken") );
		}

		[Bindable(event="listenerReady")]
		public function get ready():Boolean
		{
			return _ready;
		}

		private function setStatusReady():void {
			_ready = true;
			dispatchEvent( new Event( AsyncListenerWatcher.LISTENER_READY ) );
		}

		private function getTestCount( description:IDescription ):int
		{
			return description.testCount;
		}

		private function testTimeString( time:Number ):String {
			var timeShifted:Number = time * 1000;
			var timeFloor:Number = Math.floor( timeShifted );
			var timeStr:String = String( ( timeFloor/1000 ) );
			return timeStr;
		}

		public function testTimed( description:IDescription, runTime:Number ):void {
			lastTestTime = runTime;
			//trace( description.displayName + " took " + runTime + " ms " );
		}

		public function testRunStarted( description:IDescription ):void
		{
			//Since description tells us nothing about failure, error, and skip counts, this is
		   //computed by the Ant task as the process executes and no work is needed to signify
		   //the start of a test run.
		}

		public function testRunFinished( result:Result ):void
		{
			sendResults(END_OF_TEST_RUN);
		}

		public function testStarted( description:IDescription ):void
		{
			// called before each test
		}

		public function testFinished( description:IDescription ):void
		{
			// called after each test
			if(!lastFailedTest || description.displayName != lastFailedTest.displayName){
				var desc:Descriptor = getDescriptorFromDescription(description);
				sendResults("<testcase classname='"+desc.suite+"' name='"+desc.method+"' time='" + testTimeString( lastTestTime ) +"' status='"+SUCCESS+"'/>");
			}
		}

		public function testAssumptionFailure( failure:Failure ):void
		{
			// called on assumptionFail
		}

		public function testIgnored( description:IDescription ):void
		{
			// called on ignored test if we want to send ignore to ant.
			var descriptor:Descriptor = getDescriptorFromDescription(description);

			var xml:String =
				"<testcase classname='"+descriptor.suite+"' name='"+descriptor.method+"' time='" + testTimeString( lastTestTime ) + "' status='"+IGNORE+"'>"
				+ "<skipped />"
				+ "</testcase>";

			sendResults( xml );
		}

		public function testFailure( failure:Failure ):void
		{
			// called on a test failure
			lastFailedTest = failure.description;
			var descriptor:Descriptor =
				getDescriptorFromDescription(failure.description);
			var type : String = failure.description.displayName
			var message : String = failure.message;
			var stackTrace : String = failure.stackTrace;
			var methodName : String = descriptor.method;

			if ( stackTrace != null ) stackTrace = stackTrace.toString();

			stackTrace = FailureFormatter.xmlEscapeMessage( stackTrace );
			message = FailureFormatter.xmlEscapeMessage( message );

			var xml : String = null;

			if(FailureFormatter.isError(failure.exception))
			{
				xml =
					"<testcase classname='"+descriptor.suite+"' name='"+descriptor.method+"' time='" + testTimeString( lastTestTime ) +"' status='"+ERROR+"'>"
					+ "<error message='" + message + "' type='"+ type +"' >"
					+ "<![CDATA[" + stackTrace + "]]>"
					+ "</error>"
					+ "</testcase>";
			}
			else
			{
				xml =
					"<testcase classname='"+descriptor.suite+"' name='"+descriptor.method+"' time='" + testTimeString( lastTestTime ) +"' status='"+FAILURE+"'>"
					+ "<failure message='" + message + "' type='"+ type +"' >"
					+ "<![CDATA[" + stackTrace + "]]>"
					+ "</failure>"
					+ "</testcase>";
			}

			sendResults(xml);
		}

		/*
		* Internal methods
		*/
		private function getDescriptorFromDescription( description:IDescription ):Descriptor
		{
			// reads relavent data from descriptor
			/**
			 * JAdkins - 7/27/07 - FXU-53 - Listener was returning a null value for the test class
			 * causing no data to be returned.  If length of array is greater than 1, then class is
			 * not in the default package.  If array length is 1, then test class is default package
			 * and formats accordingly.
			 **/
			var descriptor:Descriptor = new Descriptor();
			var descriptionArray:Array = description.displayName.split("::");
			var classMethod:String;
			if ( descriptionArray.length > 1 )
			{
				descriptor.path = descriptionArray[0];
				classMethod =  descriptionArray[1];
			}
			else
			{
				classMethod =  descriptionArray[0];
			}
			var classMethodArray:Array = classMethod.split(".");
			descriptor.suite = ( descriptor.path == "" ) ?  classMethodArray[0] :
				descriptor.path + "::" + classMethodArray[0];
			descriptor.method = classMethodArray[1];
			return descriptor;
		}

		protected function sendResults(msg:String):void
		{
			if(socket.connected)
			{
				socket.send( msg );
			}

			trace(msg);
		}

		private function handleConnect(event:Event):void
		{
			//This is a good start, but we are no longer considering this a valid
			//time to begin sending results
			//We are going to wait until we get some data first
			//_ready = true;
			//dispatchEvent( new Event( AsyncListenerWatcher.LISTENER_READY ) );
		}

		private function errorHandler(event:Event):void
		{
			if ( !ready ) {
				//If we are not yet ready and received this, just inform the core so it can move on
				dispatchEvent( new Event( AsyncListenerWatcher.LISTENER_FAILED ) );
			} else {
				//If on the other hand we were ready once, then the core is counting on us... so, if something goes
				//wrong now, we are likely hung up. For now we are simply going to bail out of this process
				exit();
			}
		}

		private function dataHandler( event : DataEvent ) : void
		{
			var data : String = event.data;

			// If we received an acknowledgement on startup, the java server is read and we can start sending.
			if ( data == START_OF_TEST_RUN_ACK ) {
				setStatusReady();
			} else if ( data == END_OF_TEST_ACK ) {
				// If we received an acknowledgement finish-up.
				// Close the socket.
				socket.close();
				exit();
			}
		}

		/**
		 * Exit the test runner by calling the ApplicationCloser.
		 */
		protected function exit() : void
		{
			this.closer.close();
		}
	}
}

/**
 * Copyright (c) 2009 Digital Primates IT Consulting Group
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * @author     Jeff Tapper
 * @version
 **/

package org.flexunit.listeners
{
	import flash.events.DataEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.TimerEvent;
	import flash.net.XMLSocket;
	import flash.utils.Timer;

	import org.flexunit.listeners.closer.ApplicationCloser;
	import org.flexunit.listeners.closer.StandAloneFlashPlayerCloser;
	import org.flexunit.reporting.FailureFormatter;
	import org.flexunit.runner.Descriptor;
	import org.flexunit.runner.IDescription;
	import org.flexunit.runner.Result;
	import org.flexunit.runner.notification.Failure;
	import org.flexunit.runner.notification.IAsyncStartupRunListener;
	import org.flexunit.runner.notification.ITemporalRunListener;
	import org.flexunit.runner.notification.async.AsyncListenerWatcher;

	public class CIListener extends EventDispatcher implements IAsyncStartupRunListener, ITemporalRunListener
	{
		protected static const DEFAULT_PORT : uint = 1024;
		protected static const DEFAULT_SERVER : String = "127.0.0.1";
		private static const SUCCESS:String = "success";
		private static const ERROR:String = "error";
		private static const FAILURE:String = "failure";
		private static const IGNORE:String = "ignore";

		private var successes:Array = new Array();
		private var ignores:Array = new Array();

		private var _ready:Boolean = false;

		private static const END_OF_TEST_ACK : String ="<endOfTestRunAck/>";
		private static const END_OF_TEST_RUN : String = "<endOfTestRun/>";
		private static const START_OF_TEST_RUN_ACK : String = "<startOfTestRunAck/>";

		private var socket:XMLSocket;

		[Inspectable]
		public var port : uint;

		[Inspectable]
		public var server : String; //this is local host. same machine

		public var closer : ApplicationCloser;

		private var lastFailedTest:IDescription;
		private var timeOut:Timer;
		private var lastTestTime:Number;

		public function CIListener(port : uint = DEFAULT_PORT, server : String = DEFAULT_SERVER)
		{
			this.port = port;
			this.server = server;
			this.closer = new StandAloneFlashPlayerCloser(); //default application closer

			socket = new XMLSocket ();
			socket.addEventListener( DataEvent.DATA, dataHandler );
			socket.addEventListener( Event.CONNECT, handleConnect );
			socket.addEventListener( IOErrorEvent.IO_ERROR, errorHandler);
			socket.addEventListener( SecurityErrorEvent.SECURITY_ERROR,errorHandler);
			socket.addEventListener( Event.CLOSE,errorHandler);

			timeOut = new Timer( 2000, 1 );
			timeOut.addEventListener(TimerEvent.TIMER_COMPLETE, declareBroken, false, 0, true );
			timeOut.start();

			try
			{
				socket.connect( server, port );
				timeOut.stop();
			} catch (e:Error) {
				//This needs to be more than a trace
				trace (e.message);
			}
		}

		private function declareBroken( event:TimerEvent ):void {
			errorHandler( new Event( "broken") );
		}

		[Bindable(event="listenerReady")]
		public function get ready():Boolean
		{
			return _ready;
		}

		private function setStatusReady():void {
			_ready = true;
			dispatchEvent( new Event( AsyncListenerWatcher.LISTENER_READY ) );
		}

		private function getTestCount( description:IDescription ):int
		{
			return description.testCount;
		}

		private function testTimeString( time:Number ):String {
			var timeShifted:Number = time * 1000;
			var timeFloor:Number = Math.floor( timeShifted );
			var timeStr:String = String( ( timeFloor/1000 ) );
			return timeStr;
		}

		public function testTimed( description:IDescription, runTime:Number ):void {
			lastTestTime = runTime;
			//trace( description.displayName + " took " + runTime + " ms " );
		}

		public function testRunStarted( description:IDescription ):void
		{
			//Since description tells us nothing about failure, error, and skip counts, this is
		   //computed by the Ant task as the process executes and no work is needed to signify
		   //the start of a test run.
		}

		public function testRunFinished( result:Result ):void
		{
			sendResults(END_OF_TEST_RUN);
		}

		public function testStarted( description:IDescription ):void
		{
			// called before each test
		}

		public function testFinished( description:IDescription ):void
		{
			// called after each test
			if(!lastFailedTest || description.displayName != lastFailedTest.displayName){
				var desc:Descriptor = getDescriptorFromDescription(description);
				sendResults("<testcase classname=\""+desc.suite+"\" name=\""+desc.method+"\" time=\"" + testTimeString( lastTestTime ) +"\" status=\""+SUCCESS+"\" />");
			}
		}

		public function testAssumptionFailure( failure:Failure ):void
		{
			// called on assumptionFail
		}

		public function testIgnored( description:IDescription ):void
		{
			// called on ignored test if we want to send ignore to ant.
			var descriptor:Descriptor = getDescriptorFromDescription(description);

			var xml:String =
				"<testcase classname=\""+descriptor.suite+"\" name=\""+descriptor.method+"\" time=\"" + testTimeString( lastTestTime ) + "\" status=\""+IGNORE+"\">"
				+ "<skipped />"
				+ "</testcase>";

			sendResults( xml );
		}

		public function testFailure( failure:Failure ):void
		{
			// called on a test failure
			lastFailedTest = failure.description;
			var descriptor:Descriptor =
				getDescriptorFromDescription(failure.description);
			var type : String = failure.description.displayName
			var message : String = failure.message;
			var stackTrace : String = failure.stackTrace;
			var methodName : String = descriptor.method;

			if ( stackTrace != null ) stackTrace = stackTrace.toString();

			stackTrace = FailureFormatter.xmlEscapeMessage( stackTrace );
			message = FailureFormatter.xmlEscapeMessage( message );

			var xml : String = null;

			if(FailureFormatter.isError(failure.exception))
			{
				xml =
					"<testcase classname=\""+descriptor.suite+"\" name=\""+descriptor.method+"\" time=\"" + testTimeString( lastTestTime ) +"\" status=\""+ERROR+"\">"
					+ "<error message=\"" + message + "\" type=\""+ type +"\">"
					+ "<![CDATA[" + stackTrace + "]]>"
					+ "</error>"
					+ "</testcase>";
			}
			else
			{
				xml =
					"<testcase classname=\""+descriptor.suite+"\" name=\""+descriptor.method+"\" time=\"" + testTimeString( lastTestTime ) +"\" status=\""+FAILURE+"\">"
					+ "<failure message=\"" + message + "\" type=\""+ type +"\" >"
					+ "<![CDATA[" + stackTrace + "]]>"
					+ "</failure>"
					+ "</testcase>";
			}

			sendResults(xml);
		}

		/*
		* Internal methods
		*/
		private function getDescriptorFromDescription( description:IDescription ):Descriptor
		{
			// reads relavent data from descriptor
			/**
			 * JAdkins - 7/27/07 - FXU-53 - Listener was returning a null value for the test class
			 * causing no data to be returned.  If length of array is greater than 1, then class is
			 * not in the default package.  If array length is 1, then test class is default package
			 * and formats accordingly.
			 **/
			var descriptor:Descriptor = new Descriptor();
			var descriptionArray:Array = description.displayName.split("::");
			var classMethod:String;
			if ( descriptionArray.length > 1 )
			{
				descriptor.path = descriptionArray[0];
				classMethod =  descriptionArray[1];
			}
			else
			{
				classMethod =  descriptionArray[0];
			}
			var classMethodArray:Array = classMethod.split(".");
			descriptor.suite = ( descriptor.path == "" ) ?  classMethodArray[0] :
				descriptor.path + "::" + classMethodArray[0];
			descriptor.method = classMethodArray[1];
			return descriptor;
		}

		protected function sendResults(msg:String):void
		{
			if(socket.connected)
			{
				socket.send( msg );
			}

			trace(msg);
		}

		private function handleConnect(event:Event):void
		{
			//This is a good start, but we are no longer considering this a valid
			//time to begin sending results
			//We are going to wait until we get some data first
			//_ready = true;
			//dispatchEvent( new Event( AsyncListenerWatcher.LISTENER_READY ) );
		}

		private function errorHandler(event:Event):void
		{
			if ( !ready ) {
				//If we are not yet ready and received this, just inform the core so it can move on
				dispatchEvent( new Event( AsyncListenerWatcher.LISTENER_FAILED ) );
			} else {
				//If on the other hand we were ready once, then the core is counting on us... so, if something goes
				//wrong now, we are likely hung up. For now we are simply going to bail out of this process
				exit();
			}
		}

		private function dataHandler( event : DataEvent ) : void
		{
			var data : String = event.data;

			// If we received an acknowledgement on startup, the java server is read and we can start sending.
			if ( data == START_OF_TEST_RUN_ACK ) {
				setStatusReady();
			} else if ( data == END_OF_TEST_ACK ) {
				// If we received an acknowledgement finish-up.
				// Close the socket.
				socket.close();
				exit();
			}
		}

		/**
		 * Exit the test runner by calling the ApplicationCloser.
		 */
		protected function exit() : void
		{
			this.closer.close();
		}
	}
}

Fix to CIListener to use double quotes and correct spacing for result XML. Re-fixed from the pull from mlabriola.


/*
 * Copyright 2014 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package flash.events {
[native(cls='EventDispatcherClass')]
public class EventDispatcher implements IEventDispatcher {
  public function EventDispatcher(target:IEventDispatcher = null) {
    ctor(target);
  }
  public function toString():String {
    return '[object EventDispatcher]';
  }
  public native function addEventListener(type:String, listener:Function,
                                          useCapture:Boolean = false, priority:int = 0,
                                          useWeakReference:Boolean = false):void;
  public native function removeEventListener(type:String, listener:Function,
                                             useCapture:Boolean = false):void;
  public native function hasEventListener(type:String):Boolean;
  public native function willTrigger(type:String):Boolean;
  public function dispatchEvent(event:Event):Boolean {
    return dispatchEventFunction(event.target ? event.clone() : event);
  }
  private native function ctor(target: IEventDispatcher): void;
  private native function dispatchEventFunction(event: Event): Boolean;
}
}

/*
 * Copyright 2014 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package flash.events {
[native(cls='EventDispatcherClass')]
public class EventDispatcher implements IEventDispatcher {
  public function EventDispatcher(target:IEventDispatcher = null) {
    ctor(target);
  }
  public function toString():String {
    return Object.prototype.toString.call(this);
  }
  public native function addEventListener(type:String, listener:Function,
                                          useCapture:Boolean = false, priority:int = 0,
                                          useWeakReference:Boolean = false):void;
  public native function removeEventListener(type:String, listener:Function,
                                             useCapture:Boolean = false):void;
  public native function hasEventListener(type:String):Boolean;
  public native function willTrigger(type:String):Boolean;
  public function dispatchEvent(event:Event):Boolean {
    return dispatchEventFunction(event.target ? event.clone() : event);
  }
  private native function ctor(target: IEventDispatcher): void;
  private native function dispatchEventFunction(event: Event): Boolean;
}
}

Fix EventDispatcher#toString

Fix EventDispatcher#toString


package com.axis.rtspclient {
  import com.axis.ErrorManager;

  import flash.utils.ByteArray;

  public class BitArray extends ByteArray {
    private var src:ByteArray;
    private var byte:uint;
    private var bitpos:uint;

    public function BitArray(src:ByteArray) {
      this.src    = src;
      this.bitpos = 0;
      this.byte   = 0; /* This should really be undefined, uint wont allow it though */
    }

    public function readBits(length:uint):uint {
      if (32 < length || 0 === length) {
       /* To big for an uint */
       ErrorManager.dispatchError(819, null, true);
      }

      var result:uint = 0;
      for (var i:uint = 1; i <= length; ++i) {
        if (0 === bitpos) {
          /* Previous byte all read out. Get a new one. */
          byte = src.readUnsignedByte();
        }

        /* Shift result one left to make room for another bit,
           then add the next bit on the stream. */
        result = (result << 1) | ((byte >> (8 - (++bitpos))) & 0x01);
        bitpos %= 8;
      }

      return result;
    }

    public function readUnsignedExpGolomb():uint {
      var bitsToRead:uint = 0;
      while (readBits(1) !== 1) bitsToRead++;

      if (bitsToRead == 0) return 0; /* Easy peasy, just a single 1. This is 0 in exp golomb */
      if (bitsToRead >= 31) ErrorManager.dispatchError(820, null, true);

      var n:uint = readBits(bitsToRead); /* Read all bits part of this number */
      n |= (0x1 << (bitsToRead)); /* Move in the 1 read by while-statement above */

      return n - 1; /* Because result in exp golomb is one larger */
    }

    public function readSignedExpGolomb():uint {
        var r:uint = this.readUnsignedExpGolomb();
        if (r & 0x01) {
            r = (r+1) >> 1;
        } else {
            r = -(r >> 1);
        }
        return r;
    }
  }
}

package com.axis.rtspclient {
  import com.axis.ErrorManager;

  import flash.utils.ByteArray;

  public class BitArray extends ByteArray {
    private var src:ByteArray;
    private var byte:uint;
    private var bitpos:uint;

    public function BitArray(src:ByteArray) {
      this.src = clone(src);
      this.bitpos = 0;
      this.byte   = 0; /* This should really be undefined, uint wont allow it though */
    }

    public function readBits(length:uint):uint {
      if (32 < length || 0 === length) {
       /* To big for an uint */
       ErrorManager.dispatchError(819, null, true);
      }

      var result:uint = 0;
      for (var i:uint = 1; i <= length; ++i) {
        if (0 === bitpos) {
          /* Previous byte all read out. Get a new one. */
          byte = src.readUnsignedByte();
        }

        /* Shift result one left to make room for another bit,
           then add the next bit on the stream. */
        result = (result << 1) | ((byte >> (8 - (++bitpos))) & 0x01);
        bitpos %= 8;
      }

      return result;
    }

    public function readUnsignedExpGolomb():uint {
      var bitsToRead:uint = 0;
      while (readBits(1) !== 1) bitsToRead++;

      if (bitsToRead == 0) return 0; /* Easy peasy, just a single 1. This is 0 in exp golomb */
      if (bitsToRead >= 31) ErrorManager.dispatchError(820, null, true);

      var n:uint = readBits(bitsToRead); /* Read all bits part of this number */
      n |= (0x1 << (bitsToRead)); /* Move in the 1 read by while-statement above */

      return n - 1; /* Because result in exp golomb is one larger */
    }

    public function readSignedExpGolomb():uint {
        var r:uint = this.readUnsignedExpGolomb();
        if (r & 0x01) {
            r = (r+1) >> 1;
        } else {
            r = -(r >> 1);
        }
        return r;
    }

    public function clone(source:ByteArray):* {
        var temp:ByteArray = new ByteArray();
        temp.writeObject(source);
        temp.position = 0;
        return(temp.readObject());
    }
  }
}

Clone ByteArray in BitArray class to avoid side effects


package
{
	import com.adobe.images.PNGEncoder;
	import com.bit101.components.ScrollPane;

	import flash.desktop.NativeApplication;
	import flash.display.BitmapData;
	import flash.display.Loader;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.InvokeEvent;
	import flash.events.TimerEvent;
	import flash.filesystem.File;
	import flash.filesystem.FileStream;
	import flash.geom.Rectangle;
	import flash.geom.Matrix;
	import flash.net.URLRequest;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.utils.ByteArray;
	import flash.utils.Timer;

	public class swf2png extends Sprite
	{
		public var outputWidth:int;
		public var outputHeight:int;
		public var loadedSwf:MovieClip;
		public var loader:Loader;
		private var counter:int = 0;
		private var timer:Timer;
		private var totalFrames:int;
		private var inputFileName:String;
		private var inputFilePath:String;
		private var prefix:String;
		private var separator:String = "_";
		private var outfield:TextField;
		private var outputDirPath:String;
		private var offsetMatrix:Matrix;
		private var bBox:Rectangle;
		private var scaleFactor:Number;
		private var pane:ScrollPane;

		public function swf2png() {
			NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE, onInvoke);
			stage.align = 'TL';
			stage.scaleMode = 'noScale';
			outfield = new TextField();
			outfield.autoSize = TextFieldAutoSize.LEFT;
			pane = new ScrollPane(stage);

			pane.width = stage.stageWidth;
			pane.height = stage.stageHeight;
			pane.addChild(outfield);
			pane.update();

			stage.addEventListener(Event.RESIZE, onResize, false, 0, true);

		}

		//Loads in file
		private function loadSwf():void {

			loader = new Loader();
			log("Loading " + inputFilePath);
			loader.load(new URLRequest("file://" + inputFilePath));
			loader.contentLoaderInfo.addEventListener(Event.INIT, startLoop);

		}

		//Event handler called when the swf is loaded. Sets it up and starts the export loop
		private function startLoop(ev:Event):void {
			try {
				loadedSwf = MovieClip(ev.target.content);
			}
			catch(err:Error) {
				//AVM1 Movie not supported
				exit(5);
				return;
			}
			outputWidth = Math.ceil(ev.target.width);
			outputHeight = Math.ceil(ev.target.height);
			log("Loaded!");
			totalFrames = loadedSwf.totalFrames;
			log("Frame count: " + totalFrames);

			calculateBBox();

			stopClip(loadedSwf);
			goToFrame(loadedSwf, 0);
			timer = new Timer(1);

			timer.addEventListener(TimerEvent.TIMER, step);
			timer.start();

		}

		private function padNumber(input:int, target:int):String {
			var out:String = input.toString();
			var targetCount:int = target.toString().length;
			while(out.length < targetCount) {
				out = '0' + out;
			}
			return out;
		}

		private function calculateBBox():void {
			stopClip(loadedSwf);
			goToFrame(loadedSwf, 0);

			var boundsArray:Object = {
				"x" : new Array(),
				"y" : new Array(),
				"w" : new Array(),
				"h" : new Array()
			}
			var r:Rectangle;
			for(var currentFrame:int = 0; currentFrame < totalFrames; currentFrame++) {
				goToFrame(loadedSwf, currentFrame);
				r = loader.content.getRect(stage);
				boundsArray.x.push(r.x);
				boundsArray.y.push(r.y);
				boundsArray.w.push(r.width);
				boundsArray.h.push(r.height);
			}

			boundsArray.x.sort(Array.NUMERIC);
			boundsArray.y.sort(Array.NUMERIC);
			boundsArray.w.sort(Array.NUMERIC | Array.DESCENDING);
			boundsArray.h.sort(Array.NUMERIC | Array.DESCENDING);

			bBox = new Rectangle(
				Math.floor(boundsArray.x[0]),
				Math.floor(boundsArray.y[0]),
				Math.ceil(boundsArray.w[0]),
				Math.ceil(boundsArray.h[0])
			);

			log("Bounding box: " + bBox)

			outputWidth = bBox.width * scaleFactor;
			outputHeight = bBox.height * scaleFactor;
			offsetMatrix = new Matrix();
			offsetMatrix.translate(bBox.x * -1, bBox.y * -1);
			offsetMatrix.scale(scaleFactor, scaleFactor);

			return;
		}

		//Called for every frame
		private function step(ev:TimerEvent):void {
			counter++;
			if(counter <= totalFrames) {
				goToFrame(loadedSwf, counter);
				saveFrame();
			}
			else {
				timer.stop();
				log("Done!");
				exit(0);
				return;
			}
		}

		//Saves the current frame of the loader object to a png
		private function saveFrame():void {
			var bitmapData:BitmapData = new BitmapData(outputWidth, outputHeight, true, 0x0);
			bitmapData.draw(loader.content, offsetMatrix);
			var bytearr:ByteArray = PNGEncoder.encode(bitmapData);
			var increment:String = '';
			if(totalFrames > 1) {
				increment = separator + padNumber(counter, totalFrames);
			}
			var outfileName:String = outputDirPath + File.separator + prefix + increment + ".png"
			var file:File = new File(outfileName);

			log("Writing: " + outfileName);
			var stream:FileStream = new FileStream();
			stream.open(file, "write");
			stream.writeBytes(bytearr);
			stream.close();
		}

		//Stops the movie clip and all its subclips.
		private function stopClip(inMc:MovieClip):void {
			var l:int = inMc.numChildren;
			for (var i:int = 0; i < l; i++)
			{
				var mc:MovieClip = inMc.getChildAt(i) as MovieClip;
				if(mc) {
					mc.stop();
					if(mc.numChildren > 0) {
						stopClip(mc);
					}
				}
			}
			inMc.stop();
		}

		//Traverses the movie clip and sets the current frame for all subclips too, looping them where needed.
		private function goToFrame(inMc:MovieClip, frameNo:int):void {
			var l:int = inMc.numChildren;
			for (var i:int = 0; i < l; i++)
			{
				var mc:MovieClip = inMc.getChildAt(i) as MovieClip;
				if(mc) {
					mc.gotoAndStop(frameNo % inMc.totalFrames);
					if(mc.numChildren > 0) {
						goToFrame(mc, frameNo);
					}
				}
			}
			inMc.gotoAndStop(frameNo % inMc.totalFrames);
		}

		//Finds and checks for existance of input file
		private function getInputFile(ev:InvokeEvent):String {
			if(ev.arguments && ev.arguments.length) {
				inputFileName = ev.arguments[0];
				var matchNameRegExStr:String = '([^\\' + File.separator + ']+)$';
				var matchNameRegEx:RegExp = new RegExp(matchNameRegExStr);
				var matches:Array = inputFileName.match(matchNameRegEx);
				if(!matches) {
					// File inputFileName not valid
					exit(2);
					return "";
				}
				prefix = matches[1].split('.')[0];
				log("Prefix: " + prefix);
				var f:File = new File(ev.currentDirectory.nativePath);
				f = f.resolvePath(inputFileName);
				if(!f.exists) {
					log("Input file not found!");
					//Input file not found
					exit(3);
					return "";
				}
				return f.nativePath;
			}
			else {
				//App opened without input data
				exit(1);
				return "";
			}
		}

		//Finds and checks for existance of output directory
		private function getOutputDir(ev:InvokeEvent):String {
			var d:File;
			if(ev.arguments.length > 1) {
				outputDirPath = ev.arguments[1];
				d = new File(ev.currentDirectory.nativePath);
				d = d.resolvePath(outputDirPath);
				if(!d.isDirectory) {
					//outdir not a directory
					exit(4);
					return "";
				}
				return d.nativePath;
			}
			else if(inputFilePath) {
				d = new File(inputFilePath);
				if(!d.isDirectory) {
					d = d.resolvePath('..');
				}
				return d.nativePath;
			}
			else {
				if(ev.currentDirectory.nativePath === '/') {
					return File.desktopDirectory.nativePath;
				}
				else {
					return ev.currentDirectory.nativePath;
				}
			}
			return "";
		}
		private function getScaleFactor(ev:InvokeEvent):Number {
			if(ev.arguments.length > 2) {
				log("scale factor set to " + parseFloat(ev.arguments[2]));
				return parseFloat(ev.arguments[2]);
			}
			return 1;
		}

		private function log(message:String="", add_new_line:Boolean=true):void {
			outfield.appendText((add_new_line ? "\n" : "") + message);
			pane.update();
		}

		//Invoke handler called when started
		private function onInvoke(ev:InvokeEvent):void {

			inputFilePath = getInputFile(ev);
			outputDirPath = getOutputDir(ev);
			scaleFactor = getScaleFactor(ev);

			log("Input file: " + inputFilePath);
			log("Output directory: " + outputDirPath);
			loadSwf();
		}

		private function onResize(ev:Event):void {
			pane.width = stage.stageWidth;
			pane.height = stage.stageHeight;
			pane.update();
		}

		private function exit(code:int=0):void {
			log("Exit: " + code);
			NativeApplication.nativeApplication.exit(code);
		}
	}
}

package
{
	import com.adobe.images.PNGEncoder;
	import com.bit101.components.ScrollPane;

	import flash.desktop.NativeApplication;
	import flash.display.BitmapData;
	import flash.display.Loader;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.InvokeEvent;
	import flash.events.TimerEvent;
	import flash.filesystem.File;
	import flash.filesystem.FileStream;
	import flash.geom.Rectangle;
	import flash.geom.Matrix;
	import flash.net.URLRequest;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.utils.ByteArray;
	import flash.utils.Timer;

	public class swf2png extends Sprite
	{
		public var outputWidth:int;
		public var outputHeight:int;
		public var loadedSwf:MovieClip;
		public var loader:Loader;
		private var counter:int = 0;
		private var timer:Timer;
		private var totalFrames:int;
		private var inputFileName:String;
		private var inputFilePath:String;
		private var prefix:String;
		private var separator:String = "_";
		private var outfield:TextField;
		private var outputDirPath:String;
		private var offsetMatrix:Matrix = new Matrix();
		private var bBox:Rectangle;
		private var scaleFactor:Number;
		private var pane:ScrollPane;

		public function swf2png() {
			NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE, onInvoke);

			stage.align = 'TL';
			stage.scaleMode = 'noScale';
			stage.frameRate = 12;
			outfield = new TextField();
			outfield.autoSize = TextFieldAutoSize.LEFT;
			pane = new ScrollPane(stage);

			pane.width = stage.stageWidth;
			pane.height = stage.stageHeight;
			pane.addChild(outfield);
			pane.update();

			stage.addEventListener(Event.RESIZE, onResize, false, 0, true);

		}

		//Loads in file
		private function loadSwf():void {

			loader = new Loader();
			log("Loading " + inputFilePath);
			loader.load(new URLRequest("file://" + inputFilePath));
			loader.contentLoaderInfo.addEventListener(Event.INIT, startLoop);

		}

		//Event handler called when the swf is loaded. Sets it up and starts the export loop
		private function startLoop(ev:Event):void {
			try {
				loadedSwf = MovieClip(ev.target.content);
			}
			catch(err:Error) {
				//AVM1 Movie not supported
				exit(5);
				return;
			}
			outputWidth = Math.ceil(ev.target.width);
			outputHeight = Math.ceil(ev.target.height);
			log("Loaded!");
			totalFrames = loadedSwf.totalFrames;
			log("Frame count: " + totalFrames);

			stopClip(loadedSwf);
			goToFrame(loadedSwf, 0);
			timer = new Timer(1);

			timer.addEventListener(TimerEvent.TIMER, step);
			timer.start();

		}

		private function padNumber(input:int, target:int):String {
			var out:String = input.toString();
			var targetCount:int = target.toString().length;
			while(out.length < targetCount) {
				out = '0' + out;
			}
			return out;
		}

		//Called for every frame
		private function step(ev:TimerEvent):void {
			counter++;
			if(counter <= totalFrames) {
				goToFrame(loadedSwf, counter);
				saveFrame();
			}
			else {
				timer.stop();
				log("Done!");
				exit(0);
				return;
			}
		}

		//Saves the current frame of the loader object to a png
		private function saveFrame():void {
			var bitmapData:BitmapData = new BitmapData(outputWidth, outputHeight, true, 0x0);
			offsetMatrix.scale(scaleFactor, scaleFactor);
			bitmapData.draw(loader.content, offsetMatrix);
			var bytearr:ByteArray = PNGEncoder.encode(bitmapData);
			var increment:String = '';
			if(totalFrames > 1) {
				increment = separator + padNumber(counter, totalFrames);
			}
			var outfileName:String = outputDirPath + File.separator + prefix + increment + ".png"
			var file:File = new File(outfileName);

			log("Writing: " + outfileName);
			var stream:FileStream = new FileStream();
			stream.open(file, "write");
			stream.writeBytes(bytearr);
			stream.close();
		}

		//Stops the movie clip and all its subclips.
		private function stopClip(inMc:MovieClip):void {
			var l:int = inMc.numChildren;
			for (var i:int = 0; i < l; i++)
			{
				var mc:MovieClip = inMc.getChildAt(i) as MovieClip;
				if(mc) {
					mc.stop();
					if(mc.numChildren > 0) {
						stopClip(mc);
					}
				}
			}
			inMc.stop();
		}

		//Traverses the movie clip and sets the current frame for all subclips too, looping them where needed.
		private function goToFrame(inMc:MovieClip, frameNo:int):void {
			var l:int = inMc.numChildren;
			for (var i:int = 0; i < l; i++)
			{
				var mc:MovieClip = inMc.getChildAt(i) as MovieClip;
				if(mc) {
					mc.gotoAndStop(frameNo % inMc.totalFrames);
					if(mc.numChildren > 0) {
						goToFrame(mc, frameNo);
					}
				}
			}
			inMc.gotoAndStop(frameNo % inMc.totalFrames);
		}

		//Finds and checks for existance of input file
		private function getInputFile(ev:InvokeEvent):String {
			if(ev.arguments && ev.arguments.length) {
				inputFileName = ev.arguments[0];
				var matchNameRegExStr:String = '([^\\' + File.separator + ']+)$';
				var matchNameRegEx:RegExp = new RegExp(matchNameRegExStr);
				var matches:Array = inputFileName.match(matchNameRegEx);
				if(!matches) {
					// File inputFileName not valid
					exit(2);
					return "";
				}
				prefix = matches[1].split('.')[0];
				log("Prefix: " + prefix);
				var f:File = new File(ev.currentDirectory.nativePath);
				f = f.resolvePath(inputFileName);
				if(!f.exists) {
					log("Input file not found!");
					//Input file not found
					exit(3);
					return "";
				}
				return f.nativePath;
			}
			else {
				//App opened without input data
				exit(1);
				return "";
			}
		}

		//Finds and checks for existance of output directory
		private function getOutputDir(ev:InvokeEvent):String {
			var d:File;
			if(ev.arguments.length > 1) {
				outputDirPath = ev.arguments[1];
				d = new File(ev.currentDirectory.nativePath);
				d = d.resolvePath(outputDirPath);
				if(!d.isDirectory) {
					//outdir not a directory
					exit(4);
					return "";
				}
				return d.nativePath;
			}
			else if(inputFilePath) {
				d = new File(inputFilePath);
				if(!d.isDirectory) {
					d = d.resolvePath('..');
				}
				return d.nativePath;
			}
			else {
				if(ev.currentDirectory.nativePath === '/') {
					return File.desktopDirectory.nativePath;
				}
				else {
					return ev.currentDirectory.nativePath;
				}
			}
			return "";
		}
		private function getScaleFactor(ev:InvokeEvent):Number {
			if(ev.arguments.length > 2) {
				log("scale factor set to " + parseFloat(ev.arguments[2]));
				return parseFloat(ev.arguments[2]);
			}
			outputWidth *= scaleFactor;
			outputHeight *= scaleFactor;
			return 1;
		}

		private function log(message:String="", add_new_line:Boolean=true):void {
			outfield.appendText((add_new_line ? "\n" : "") + message);
			pane.update();
		}

		//Invoke handler called when started
		private function onInvoke(ev:InvokeEvent):void {

			inputFilePath = getInputFile(ev);
			outputDirPath = getOutputDir(ev);
			scaleFactor = getScaleFactor(ev);

			log("Input file: " + inputFilePath);
			log("Output directory: " + outputDirPath);
			loadSwf();
		}

		private function onResize(ev:Event):void {
			pane.width = stage.stageWidth;
			pane.height = stage.stageHeight;
			pane.update();
		}

		private function exit(code:int=0):void {
			log("Exit: " + code);
			NativeApplication.nativeApplication.exit(code);
		}
	}
}

Remove support for bounding box detection.


package org.pyamf.examples.guestbook
{
	/**
	 * Copyright (c) 2007-2009 The PyAMF Project.
	 * See LICENSE.txt for details.
	*/

	import flash.events.NetStatusEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.NetConnection;
	import flash.net.Responder;

	import mx.collections.ArrayCollection;
	import mx.core.Application;
	import mx.events.FlexEvent;

	import org.pyamf.examples.guestbook.components.SubmitBox;
	import org.pyamf.examples.guestbook.events.SubmitEvent;
	import org.pyamf.examples.guestbook.vo.Message;

	/**
	 * Simple guestbook using PyAMF, Twisted and Flash.
	 *
	 * @since 0.3.0
	 */
	public class GuestbookExample extends Application
	{
		private var _gateway		: NetConnection;

		[Bindable]
		public var messages			: ArrayCollection;

		[Bindable]
		public var totalMessages	: String = "Loading...";

		[Bindable]
		public var loading			: Boolean = true;

		public var submit			: SubmitBox;

		public function GuestbookExample()
		{
			super();

			addEventListener( FlexEvent.APPLICATION_COMPLETE, onInitApp );
		}

		private function onInitApp( event:FlexEvent ): void
		{
			// setup connection
            _gateway = new NetConnection();
			_gateway.addEventListener( NetStatusEvent.NET_STATUS, 			onStatus );
			_gateway.addEventListener( SecurityErrorEvent.SECURITY_ERROR, 	onError );

            // Connect to gateway
            _gateway.connect( "http://localhost:8080/gateway" );

            // Set responder property to the object and methods that will receive the
            // result or fault condition that the service returns.
            var responder:Responder = new Responder( onLoadResult, onFault );

            // Call remote service to fetch data
            _gateway.call( "guestbook.getMessages", responder);
		}

		public function addMessage( event:SubmitEvent ): void
		{
			var message:Message = event.message;
			loading = true;

            // set responder property to the object and methods that will receive the
            // result or fault condition that the service returns.
            var responder:Responder = new Responder( onSaveResult, onFault );

            // call remote service to save guestbook message.
            _gateway.call( "guestbook.addMessage", responder, new ObjectProxy(event.message) );

            // wait for result.
            totalMessages = "Saving message...";
		}

		private function onLoadResult( result:* ): void
        {
        	loading = false;

        	// update list
           	messages = result;
           	totalMessages = "Loaded " + messages.length + " message(s).";
        }

        private function onSaveResult( result:* ): void
        {
            var message:Message = result;

            loading = false;

            // add message to list
            messages.addItemAt( message, 0 );
            totalMessages = "Loaded " + messages.length + " message(s).";
        }

        private function onStatus( event:NetStatusEvent ): void
		{
                        submit.status = event.info.description + "!";
		}

		private function onError( event:* ): void
		{
              		submit.status = event.error + "!";

		}

        private function onFault( error:* ): void
        {
            // notify the user of the problem
            //trace("Remoting error:");
            for ( var d:String in error ) {
               //trace("   " + d + ": " + error[d]);
            }

            totalMessages = "Loaded " + messages.length + " message(s).";

            if ( error.fault.description != null ) {
            	submit.status = error.fault.description + "!";
            } else {
            	submit.status = error + "!";
            }
        }

	}
}

package org.pyamf.examples.guestbook
{
	/**
	 * Copyright (c) 2007-2009 The PyAMF Project.
	 * See LICENSE.txt for details.
	*/

	import flash.events.NetStatusEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.NetConnection;
	import flash.net.Responder;

	import mx.collections.ArrayCollection;
	import mx.core.Application;
	import mx.events.FlexEvent;
	import mx.utils.ObjectProxy;

	import org.pyamf.examples.guestbook.components.SubmitBox;
	import org.pyamf.examples.guestbook.events.SubmitEvent;
	import org.pyamf.examples.guestbook.vo.Message;

	/**
	 * Simple guestbook using PyAMF, Twisted and Flash.
	 *
	 * @since 0.3.0
	 */
	public class GuestbookExample extends Application
	{
		private var _gateway		: NetConnection;

		[Bindable]
		public var messages			: ArrayCollection;

		[Bindable]
		public var totalMessages	: String = "Loading...";

		[Bindable]
		public var loading			: Boolean = true;

		public var submit			: SubmitBox;

		public function GuestbookExample()
		{
			super();

			addEventListener( FlexEvent.APPLICATION_COMPLETE, onInitApp );
		}

		private function onInitApp( event:FlexEvent ): void
		{
			// setup connection
            _gateway = new NetConnection();
			_gateway.addEventListener( NetStatusEvent.NET_STATUS, 			onStatus );
			_gateway.addEventListener( SecurityErrorEvent.SECURITY_ERROR, 	onError );

            // Connect to gateway
            _gateway.connect( "http://localhost:8080/gateway" );

            // Set responder property to the object and methods that will receive the
            // result or fault condition that the service returns.
            var responder:Responder = new Responder( onLoadResult, onFault );

            // Call remote service to fetch data
            _gateway.call( "guestbook.getMessages", responder);
		}

		public function addMessage( event:SubmitEvent ): void
		{
			var message:Message = event.message;
			loading = true;

            // set responder property to the object and methods that will receive the
            // result or fault condition that the service returns.
            var responder:Responder = new Responder( onSaveResult, onFault );

            // call remote service to save guestbook message.
            _gateway.call( "guestbook.addMessage", responder, new ObjectProxy(event.message) );

            // wait for result.
            totalMessages = "Saving message...";
		}

		private function onLoadResult( result:* ): void
        {
        	loading = false;

        	// update list
           	messages = result;
           	totalMessages = "Loaded " + messages.length + " message(s).";
        }

        private function onSaveResult( result:* ): void
        {
            var message:Message = result;

            loading = false;

            // add message to list
            messages.addItemAt( message, 0 );
            totalMessages = "Loaded " + messages.length + " message(s).";
        }

        private function onStatus( event:NetStatusEvent ): void
		{
                        submit.status = event.info.description + "!";
		}

		private function onError( event:* ): void
		{
              		submit.status = event.error + "!";

		}

        private function onFault( error:* ): void
        {
            // notify the user of the problem
            //trace("Remoting error:");
            for ( var d:String in error ) {
               //trace("   " + d + ": " + error[d]);
            }

            totalMessages = "Loaded " + messages.length + " message(s).";

            if ( error.fault.description != null ) {
            	submit.status = error.fault.description + "!";
            } else {
            	submit.status = error + "!";
            }
        }

	}
}

fix compile error for missing import

fix compile error for missing import