package aerys.minko.scene.controller
{
	import aerys.minko.ns.minko_scene;
	import aerys.minko.render.Viewport;
	import aerys.minko.scene.node.ISceneNode;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.type.Signal;

	import flash.display.BitmapData;
	import flash.utils.getQualifiedClassName;

	/**
	 * Controllers work on scene nodes to modify and update them. They offer the best
	 * way to add any kind of behavior on one or multiple scene nodes. They can be used
	 * to create animations, add physics, artificial intelligence...
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public class AbstractController
	{
		private var _targetType		: Class					= null;
		private var _targets		: Vector.<ISceneNode>	= new <ISceneNode>[];

		private var _ticked			: Signal				= new Signal('AbstractController.ticked');
		private var _targetAdded	: Signal				= new Signal('AbstractController.targetAdded');
		private var _targetRemoved	: Signal				= new Signal('AbstractController.targetRemoved');

		/**
		 * The number of scene nodes targeted by this very controller.
		 * @return
		 *
		 */
		public function get numTargets() : uint
		{
			return _targets.length;
		}

		/**
		 * The signal executed when a target is added to the controller.
		 * @return
		 *
		 */
		public function get targetAdded() : Signal
		{
			return _targetAdded;
		}

		/**
		 * The signal executed when a target is removed from the controller.
		 * @return
		 *
		 */
		public function get targetRemoved() : Signal
		{
			return _targetRemoved;
		}

		public function AbstractController(targetType 		: Class 	= null)
		{
			_targetType = targetType || ISceneNode;
		}

		/**
		 * Add a target to the controller.
		 * @param target
		 *
		 */
		minko_scene function addTarget(target : ISceneNode) : void
		{
			if (_targetType && !(target is _targetType))
			{
				throw new Error(
					"Controller '" + getQualifiedClassName(this)
					+ " cannot target objects from class '"
					+ getQualifiedClassName(target) + "'."
				);
			}

			_targets.push(target);

			_targetAdded.execute(this, target);
		}

		/**
		 * Remove a target from the controller.
		 * @param target
		 *
		 */
		minko_scene function removeTarget(target : ISceneNode) : void
		{
			var index : int = _targets.indexOf(target);
			var numTargets : int = _targets.length - 1;

			if (index < 0)
				throw new Error();

			_targets[index] = _targets[numTargets];
			_targets.length = numTargets;

			_targetRemoved.execute(this, target);
		}

		/**
		 * Get the target at the specified index.
		 * @param index
		 * @return
		 *
		 */
		public function getTarget(index : uint) : ISceneNode
		{
			return _targets[index];
		}

		public function clone() : AbstractController
		{
			throw new Error("The method AbstractController.clone() must be overriden.");
		}
	}
}

package aerys.minko.scene.controller
{
	import aerys.minko.ns.minko_scene;
	import aerys.minko.render.Viewport;
	import aerys.minko.scene.node.ISceneNode;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.type.Signal;

	import flash.display.BitmapData;
	import flash.utils.getQualifiedClassName;

	/**
	 * Controllers work on scene nodes to modify and update them. They offer the best
	 * way to add any kind of behavior on one or multiple scene nodes. They can be used
	 * to create animations, add physics, artificial intelligence...
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public class AbstractController
	{
		private var _targetType		: Class					= null;
		private var _targets		: Vector.<ISceneNode>	= new <ISceneNode>[];

		private var _targetAdded	: Signal				= new Signal('AbstractController.targetAdded');
		private var _targetRemoved	: Signal				= new Signal('AbstractController.targetRemoved');

		/**
		 * The number of scene nodes targeted by this very controller.
		 * @return
		 *
		 */
		public function get numTargets() : uint
		{
			return _targets.length;
		}

		/**
		 * The signal executed when a target is added to the controller.
		 * @return
		 *
		 */
		public function get targetAdded() : Signal
		{
			return _targetAdded;
		}

		/**
		 * The signal executed when a target is removed from the controller.
		 * @return
		 *
		 */
		public function get targetRemoved() : Signal
		{
			return _targetRemoved;
		}

		public function AbstractController(targetType 		: Class 	= null)
		{
			_targetType = targetType || ISceneNode;
		}

		/**
		 * Add a target to the controller.
		 * @param target
		 *
		 */
		minko_scene function addTarget(target : ISceneNode) : void
		{
			if (_targetType && !(target is _targetType))
			{
				throw new Error(
					"Controller '" + getQualifiedClassName(this)
					+ " cannot target objects from class '"
					+ getQualifiedClassName(target) + "'."
				);
			}

			_targets.push(target);

			_targetAdded.execute(this, target);
		}

		/**
		 * Remove a target from the controller.
		 * @param target
		 *
		 */
		minko_scene function removeTarget(target : ISceneNode) : void
		{
			var index : int = _targets.indexOf(target);
			var numTargets : int = _targets.length - 1;

			if (index < 0)
				throw new Error();

			_targets[index] = _targets[numTargets];
			_targets.length = numTargets;

			_targetRemoved.execute(this, target);
		}

		/**
		 * Get the target at the specified index.
		 * @param index
		 * @return
		 *
		 */
		public function getTarget(index : uint) : ISceneNode
		{
			return _targets[index];
		}

		public function clone() : AbstractController
		{
			throw new Error("The method AbstractController.clone() must be overriden.");
		}
	}
}

remove deprecated AbstractController._ticked : Signal


/*
 * Copyright 2008 Adobe Systems Inc., 2008 Google Inc.
 *
 * 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.
 *
 * Contributor(s):
 *   Zwetan Kjukov <zwetan@gmail.com>.
 *   Marc Alcaraz <ekameleon@gmail.com>.
 */

package com.google.analytics.utils
{
    import core.strings.userAgent;

    import com.google.analytics.core.ga_internal;
    import com.google.analytics.debug.DebugConfiguration;
    import com.google.analytics.external.HTMLDOM;

    import flash.system.Capabilities;
    import flash.system.Security;
    import flash.system.System;

    /**
     * Environment provides informations for the local environment.
     */
    public class Environment
    {
        private var _debug:DebugConfiguration;
        private var _dom:HTMLDOM;

        private var _protocol:Protocols;
        private var _appName:String;
        private var _appVersion:Version;
        private var _userAgent:String;
        private var _url:String;

        /**
         * Creates a new Environment instance.
         * @param url The URL of the SWF.
         * @param app The application name
         * @param version The application version
         * @param dom the HTMLDOM reference.
         */
        public function Environment( url:String = "", app:String = "", version:String = "",
                                     debug:DebugConfiguration = null, dom:HTMLDOM = null )
        {
            var v:Version;

            if( app == "" )
            {
                if( isAIR() )
                {
                    app = "AIR";
                }
                else
                {
                    app = "Flash";
                }
            }

            if( version == "" )
            {
                v = flashVersion;
            }
            else
            {
                v = Version.fromString( version );
            }

            _url        = url;
            _appName    = app;
            _appVersion = v;

            _debug      = debug;
            _dom        = dom;
        }

        /**
         * @private
         */
        private function _findProtocol():void
        {
            var p:Protocols = Protocols.none;

            if(_url != "")
            {
                // file://
                // http://
                // https://
                var URL:String = _url.toLowerCase();
                var test:String = URL.substr(0,5);

                switch( test )
                {
                    case "file:":
                    {
                        p = Protocols.file;
                        break;
                    }
                    case "http:":
                    {
                        p = Protocols.HTTP;
                        break;
                    }
                    case "https":
                    {
                        if(URL.charAt(5) == ":")
                        {
                            p = Protocols.HTTPS;
                        }
                        break;
                    }
                    default:
                    {
                        _protocol = Protocols.none;
                    }
                }
            }

            /*TODO:
              if _url is not found (if someone forgot to add the tracker to the display list)
              we could use the alternative to get the dom.location and find the protocol from that string
              off course only if we have access to ExternalInterface
            */

            var _proto:String = _dom.protocol;

            var proto:String = (p.toString()+":").toLowerCase();

            if( _proto && _proto != proto && _debug )
            {
                _debug.warning( "Protocol mismatch: SWF="+proto+", DOM="+_proto );
            }

            _protocol = p;
        }

        /**
         * Indicates the name of the application.
         */
        public function get appName():String
        {
            return _appName;
        }

        /**
         * @private
         */
        public function set appName( value:String ):void
        {
            _appName = value;
            _defineUserAgent();
        }

        /**
         * Indicates the version of the application.
         */
        public function get appVersion():Version
        {
            return _appVersion;
        }

        /**
         * @private
         */
        public function set appVersion( value:Version ):void
        {
            _appVersion = value;
            _defineUserAgent();

        }

        /**
         * Sets the stage reference value of the application.
         */
        ga_internal function set url( value:String ):void
        {
            _url = value;
        }

        /**
         * Indicates the location of swf.
         */
        public function get locationSWFPath():String
        {
            return _url;
        }

        /**
         * Indicates the referrer value.
         */
        public function get referrer():String
        {
            var _referrer:String = _dom.referrer;

            if( _referrer )
            {
                return _referrer;
            }

            if( protocol == Protocols.file )
            {
                return "localhost";
            }

            return "";
        }

        /**
         * Indicates the title of the document.
         */
        public function get documentTitle():String
        {
            var _title:String = _dom.title;

            if( _title )
            {
                return _title;
            }

            return "";
        }

        /**
         * Indicates the local domain name value.
         */
        public function get domainName():String
        {
            if( protocol == Protocols.HTTP ||
                protocol == Protocols.HTTPS )
            {
                var URL:String = _url.toLowerCase();
                var str:String;
                var end:int;

                if( protocol == Protocols.HTTP )
                {
                    str = URL.split( "http://" ).join( "" );
                }
                else if( protocol == Protocols.HTTPS )
                {
                    str = URL.split( "https://" ).join( "" );
                }

                end = str.indexOf( "/" );

                if( end > -1 )
                {
                    str = str.substring(0,end);
                }

                return str;
            }

            if( protocol == Protocols.file )
            {
                return "localhost";
            }

            return "";
        }

        /**
         * Indicates if the application is running in AIR.
         */
        public function isAIR():Boolean
        {
            //return (playerType == "Desktop") && (Security.sandboxType.toString() == "application");
            return Security.sandboxType == "application";
        }

        /**
         * Indicates if the SWF is embeded in an HTML page.
         * @return true if the SWF is embeded in an HTML page.
         */
        public function isInHTML():Boolean
        {
            return Capabilities.playerType == "PlugIn" ;
        }

        /**
         * Indicates the locationPath value.
         */
        public function get locationPath():String
        {
            var _pathname:String = _dom.pathname;

            if( _pathname )
            {
                return _pathname;
            }

            return "";
        }

        /**
         * Indicates the locationSearch value.
         */
        public function get locationSearch():String
        {
            var _search:String = _dom.search;

            if( _search )
            {
                return _search;
            }

            return "";
        }

        /**
         * Returns the flash version object representation of the application.
         *
This object contains the attributes major, minor, build and revision :

         *
Example :
         *

         * import com.google.analytics.utils.Environment ;
         *
         * var info:Environment = new Environment( "http://www.domain.com" ) ;
         * var version:Object = info.flashVersion ;
         *
         * trace( version.major    ) ; // 9
         * trace( version.minor    ) ; // 0
         * trace( version.build    ) ; // 124
         * trace( version.revision ) ; // 0
         *

         * @return the flash version object representation of the application.
         */
        public function get flashVersion():Version
        {
            var v:Version = Version.fromString( Capabilities.version.split( " " )[1], "," ) ;
            return v ;
        }

        /**
         * Returns the language string as a lowercase two-letter language code from ISO 639-1.
         * @see Capabilities.language
         */
        public function get language():String
        {
            var _lang:String = _dom.language;
            var lang:String  = Capabilities.language;

            if( _lang )
            {
                if( (_lang.length > lang.length) &&
                    (_lang.substr(0,lang.length) == lang) )
                {
                    lang = _lang;
                }
            }

            return lang;
        }

        /**
         * Returns the internal character set used by the flash player
         *
Logic : by default flash player use unicode internally so we return UTF-8.

         *
If the player use the system code page then we try to return the char set of the browser.

         * @return the internal character set used by the flash player
         */
        public function get languageEncoding():String
        {
            if( System.useCodePage )
            {
                var _charset:String = _dom.characterSet;
                if( _charset )
                {
                    return _charset;
                }
                return "-"; //not found
            }
            //default
            return "UTF-8" ;
        }

        /**
         * Returns the operating system string.
         *
Note: The flash documentation indicate those strings

         *
"Windows XP"

         *
"Windows 2000"

         *
"Windows NT"

         *
"Windows 98/ME"

         *
"Windows 95"

         *
"Windows CE" (available only in Flash Player SDK, not in the desktop version)

         *
"Linux"

         *
"MacOS"

         *
Other strings we can obtain ( not documented : "Mac OS 10.5.4" , "Windows Vista")

         * @return the operating system string.
         * @see Capabilities.os
         */
        public function get operatingSystem():String
        {
            return Capabilities.os ;
        }

        /**
         * Returns the player type.
         *
Note : The flash documentation indicate those strings.

         *
"ActiveX"    : for the Flash Player ActiveX control used by Microsoft Internet Explorer.

         *
"Desktop"    : for the Adobe AIR runtime (except for SWF content loaded by an HTML page, which has Capabilities.playerType set to "PlugIn").

         *
"External"   : for the external Flash Player "PlugIn" for the Flash Player browser plug-in (and for SWF content loaded by an HTML page in an AIR application).

         *
"StandAlone" : for the stand-alone Flash Player.

         * @return the player type.
         * @see Capabilities.playerType
         */
        public function get playerType():String
        {
            return Capabilities.playerType;
        }

        /**
         * Returns the platform, can be "Windows", "Macintosh" or "Linux"
         * @see Capabilities.manufacturer
         */
        public function get platform():String
        {
            var p:String = Capabilities.manufacturer;
            return p.split( "Adobe " )[1];
        }

        /**
         * Indicates the Protocols object of this local info.
         */
        public function get protocol():Protocols
        {
            if(!_protocol)
            {
                _findProtocol();
            }

            return _protocol;
        }

        /**
         * Indicates the height of the screen.
         * @see Capabilities.screenResolutionY
         */
        public function get screenHeight():Number
        {
            return Capabilities.screenResolutionY;
        }

        /**
         * Indicates the width of the screen.
         * @see Capabilities.screenResolutionX
         */
        public function get screenWidth():Number
        {
            return Capabilities.screenResolutionX;
        }

        /**
         * In AIR we can use flash.display.Screen to directly get the colorDepth property
         * in flash player we can only access screenColor in flash.system.Capabilities.
         *
Some ref : http://en.wikipedia.org/wiki/Color_depth

         *
"color" -> 16-bit or 24-bit or 32-bit

         *
"gray"  -> 2-bit

         *
"bw"    -> 1-bit

         */
        public function get screenColorDepth():String
        {
            var color:String;
            switch( Capabilities.screenColor )
            {
                case "bw":
                {
                    color = "1";
                    break;
                }
                case "gray":
                {
                    color = "2";
                    break;
                }
                /* note:
                   as we have no way to know if
                   we are in 16-bit, 24-bit or 32-bit
                   we gives 24-bit by default
                */
                case "color" :
                default      :
                {
                    color = "24" ;
                }
            }

            var _colorDepth:String = _dom.colorDepth;

            if( _colorDepth )
            {
                color = _colorDepth;
            }

            return color;
        }

        private function _defineUserAgent():void
        {
            _userAgent = core.strings.userAgent( appName + "/" + appVersion.toString(4) );
        }

        /**
         * Defines a custom user agent.
         *
For case where the user would want to define its own application name and version
         * it is possible to change appName and appVersion which are in sync with
         * applicationProduct and applicationVersion properties.

         */
        public function get userAgent():String
        {
            if( !_userAgent )
            {
                 _defineUserAgent();
            }

            return _userAgent;
        }

        /**
         * @private
         */
        public function set userAgent( custom:String ):void
        {
            _userAgent = custom;
        }

    }
}

fix comment for asdoc

fix comment for asdoc


package {

import flash.display.Sprite;
import flash.events.Event;
import flash.events.SampleDataEvent;
import flash.external.ExternalInterface;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.net.URLRequest;
import flash.utils.ByteArray;
import flash.utils.Endian;
import flash.utils.getQualifiedClassName;
import flash.system.Security;

/**
 * Audio main.
 */
public class SoundMain extends Sprite {

    private var ns:String;
    private var debug:Boolean;

    private var sounds:Array;

    /**
     * Constructor
     */
    public function SoundMain() {
        if (!ExternalInterface.available) {
            throw new Error("ExternalInterface not available");
        }

        ns = loaderInfo.parameters["namespace"] || getQualifiedClassName(this);
        debug = false;

        Security.allowDomain("*");

        sounds = [];

        /**
         * Javascript can call these
         */
        ExternalInterface.addCallback("__create", create);
        ExternalInterface.addCallback("__load", load);
        ExternalInterface.addCallback("__play", play);
        ExternalInterface.addCallback("__setDebug", setDebug);
        ExternalInterface.addCallback("__stop", stop);
        ExternalInterface.addCallback("__destroy", destroy);

        invoke("__onFlashInitialized");
    }

    private function setDebug(val:Boolean):void {
        invoke("__onLog", "setDebug");
        ExternalInterface.marshallExceptions = val;
        debug = val;
    }

    /**
     * Creates a new Audio
     */
    private function create(id:int):void {
        sounds[id] = {
            instance: new Sound(),
            channel: null
        };
    }

    /**
     * Loads audio from URL
     */
    private function load(id:int, uri:String):void {
        if (uri.substr(0, 4) == "data") {
            invoke("__onLog", "Data URI not supported");
            return;
        }
        sounds[id].instance.load(new URLRequest(uri));
    }

    /**
     * Plays audio
     */
    private function play(id:int, startTime:Number = 0, loops:int = 1):void {
        if (sounds[id].channel) {
            invoke("__onLog", "Already playing this sound");
            return;
        }
        var channel:SoundChannel = sounds[id].instance.play(startTime, loops);
        channel.addEventListener(Event.SOUND_COMPLETE, function(_:Event):void {
            if (id in sounds) sounds[id].channel = null;
        });
        sounds[id].channel = channel;
    }

    /**
     * Stops playing audio
     */
    private function stop(id:int):void {
        sounds[id].channel.stop();
    }

    /**
     * Cleans up resources
     */
    private function destroy(id:int):void {
        sounds[id].instance = null;
        if (sounds[id].channel) {
            sounds[id].channel.stop();
        }
        delete sounds[id];
    }

    /**
     * Conveniently invoke a function in Javascript.
     *
     * @param method String The method to call.
     */
    private function invoke(method:String, ...params):void {
        params = params || [];
        ExternalInterface.call.apply(ExternalInterface,
                [ns + "." + method].concat(params));
    }

}

}

package {

import flash.display.Sprite;
import flash.events.Event;
import flash.events.SampleDataEvent;
import flash.external.ExternalInterface;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.net.URLRequest;
import flash.utils.ByteArray;
import flash.utils.Endian;
import flash.utils.getQualifiedClassName;
import flash.system.Security;

/**
 * Audio main.
 */
public class SoundMain extends Sprite {

    private var ns:String;
    private var debug:Boolean;

    private var sounds:Array;

    /**
     * Constructor
     */
    public function SoundMain() {
        if (!ExternalInterface.available) {
            throw new Error("ExternalInterface not available");
        }

        ns = loaderInfo.parameters["namespace"] || getQualifiedClassName(this);
        debug = false;

        Security.allowDomain("*");

        sounds = [];

        /**
         * Javascript can call these
         */
        ExternalInterface.addCallback("__create", create);
        ExternalInterface.addCallback("__load", load);
        ExternalInterface.addCallback("__play", play);
        ExternalInterface.addCallback("__setDebug", setDebug);
        ExternalInterface.addCallback("__stop", stop);
        ExternalInterface.addCallback("__destroy", destroy);

        invoke("__onFlashInitialized");
    }

    private function setDebug(val:Boolean):void {
        invoke("__onLog", "setDebug");
        ExternalInterface.marshallExceptions = val;
        debug = val;
    }

    /**
     * Creates a new Audio
     */
    private function create(id:int):void {
        sounds[id] = {
            instance: new Sound(),
            channel: null
        };
    }

    /**
     * Loads audio from URL
     */
    private function load(id:int, uri:String):void {
        if (uri.substr(0, 4) == "data") {
            invoke("__onLog", "Data URI not supported");
            return;
        }
        sounds[id].instance.load(new URLRequest(uri));
    }

    /**
     * Plays audio
     */
    private function play(id:int, startTime:Number = 0, loops:int = 1):void {
        if (sounds[id].channel) {
            invoke("__onLog", "Already playing this sound");
            return;
        }
        var channel:SoundChannel = sounds[id].instance.play(startTime, loops);
        channel.addEventListener(Event.SOUND_COMPLETE, function(_:Event):void {
            if (id in sounds) sounds[id].channel = null;
        });
        sounds[id].channel = channel;
    }

    /**
     * Stops playing audio
     */
    private function stop(id:int):void {
        sounds[id].channel.stop();
        sounds[id].channel = null;
    }

    /**
     * Cleans up resources
     */
    private function destroy(id:int):void {
        sounds[id].instance = null;
        if (sounds[id].channel) {
            sounds[id].channel.stop();
        }
        delete sounds[id];
    }

    /**
     * Conveniently invoke a function in Javascript.
     *
     * @param method String The method to call.
     */
    private function invoke(method:String, ...params):void {
        params = params || [];
        ExternalInterface.call.apply(ExternalInterface,
                [ns + "." + method].concat(params));
    }

}

}

Set channel to null when sound stops playing


//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.desktop.NativeApplication;
import flash.display.NativeWindow;
import flash.display.Stage;
import flash.display.StageQuality;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filesystem.File;
import flash.net.SharedObject;

import com.adobe.crypto.MD5;

import deng.fzip.FZip;
import deng.fzip.FZipFile;

import flump.bytesToXML;
import flump.display.Movie;
import flump.executor.Executor;
import flump.executor.Future;
import flump.export.Ternary;
import flump.xfl.ParseError;
import flump.xfl.XflLibrary;
import flump.xfl.XflMovie;

import mx.collections.ArrayCollection;

import spark.components.DataGrid;
import spark.components.DropDownList;
import spark.components.List;
import spark.components.Window;
import spark.events.GridSelectionEvent;

import starling.display.Sprite;

import com.threerings.util.F;
import com.threerings.util.Log;
import com.threerings.util.StringUtil;

public class Exporter
{
    public static const NA :NativeApplication = NativeApplication.nativeApplication;

    protected static const IMPORT_ROOT :String = "IMPORT_ROOT";
    protected static const AUTHORED_RESOLUTION :String = "AUTHORED_RESOLUTION";

    public function Exporter (win :ExporterWindow) {
        _win = win;
        _errors = _win.errors;
        _libraries = _win.libraries;

        _authoredResolution = _win.authoredResolutionPopup;
        _authoredResolution.dataProvider = new ArrayCollection(DeviceType.values().map(
            function (type :DeviceType, ..._) :Object {
                return new DeviceSelection(type);
            }));
        var initialSelection :DeviceType = null;
        if (_settings.data.hasOwnProperty(AUTHORED_RESOLUTION)) {
            try {
                initialSelection = DeviceType.valueOf(_settings.data[AUTHORED_RESOLUTION]);
            } catch (e :Error) {}
        }
        if (initialSelection == null) {
            initialSelection = DeviceType.IPHONE_RETINA;
        }
        _authoredResolution.selectedIndex = DeviceType.values().indexOf(initialSelection);
        _authoredResolution.addEventListener(Event.CHANGE, function (..._) :void {
            var selectedType :DeviceType = DeviceSelection(_authoredResolution.selectedItem).type;
            _settings.data[AUTHORED_RESOLUTION] = selectedType.name();
        });

        function updateExportEnabled (..._) :void {
            _win.export.enabled = _exportChooser.dir != null && _libraries.selectionLength > 0 &&
              _libraries.selectedItems.some(function (status :DocStatus, ..._) :Boolean {
                return status.isValid;
            });
        }
        _libraries.addEventListener(GridSelectionEvent.SELECTION_CHANGE, function (..._) :void {
            log.info("Changed", "selected", _libraries.selectedIndices);
            updateExportEnabled();
            _win.preview.enabled = _libraries.selectedItem.isValid;
        });
        _win.reload.addEventListener(MouseEvent.CLICK, function (..._) :void {
            setImport(_importChooser.dir);
        });
        _win.export.addEventListener(MouseEvent.CLICK, function (..._) :void {
            for each (var status :DocStatus in _libraries.selectedItems) {
                exportFlashDocument(status);
            }
        });
        _win.preview.addEventListener(MouseEvent.CLICK, function (..._) :void {
            showPreviewWindow(_libraries.selectedItem.lib);
        });
        _importChooser =
            new DirChooser(_settings, "IMPORT_ROOT", _win.importRoot, _win.browseImport);
        _importChooser.changed.add(setImport);
        setImport(_importChooser.dir);
        _exportChooser =
            new DirChooser(_settings, "EXPORT_ROOT", _win.exportRoot, _win.browseExport);
        _exportChooser.changed.add(updateExportEnabled);
        function updatePublisher (..._) :void {
            if (_exportChooser.dir == null) _publisher = null;
            else {
                _publisher =
                    new Publisher(_exportChooser.dir, new XMLFormat(), new JSONFormat(), new StarlingFormat());
            }
        };
        _exportChooser.changed.add(updatePublisher);
        updatePublisher();
        _win.addEventListener(Event.CLOSE, function (..._) :void { NA.exit(0); });
    }

    protected function setImport (root :File) :void {
        _libraries.dataProvider.removeAll();
        _errors.dataProvider.removeAll();
        if (root == null) return;
        _rootLen = root.nativePath.length + 1;
        if (_docFinder != null) _docFinder.shutdownNow();
        _docFinder = new Executor(2);
        findFlashDocuments(root, _docFinder, true);
        _win.reload.enabled = true;
    }

    protected function showPreviewWindow (lib :XflLibrary) :void {
        if (_previewController == null || _previewWindow.closed || _previewControls.closed) {
            _previewWindow = new PreviewWindow();
            _previewControls = new PreviewControlsWindow();
            _previewWindow.started = function (container :Sprite) :void {
                _previewController = new PreviewController(lib, container, _previewControls);
            }

            _previewWindow.open();
            _previewControls.open();

            preventWindowClose(_previewWindow.nativeWindow);
            preventWindowClose(_previewControls.nativeWindow);

        } else {
            _previewController.lib = lib;
            _previewWindow.nativeWindow.visible = true;
            _previewControls.nativeWindow.visible = true;
        }
    }

    // Causes a window to be hidden, rather than closed, when its close box is clicked
    protected static function preventWindowClose (window :NativeWindow) :void {
        window.addEventListener(Event.CLOSING, function (e :Event) :void {
            e.preventDefault();
            window.visible = false;
        });
    }

    protected var _previewController :PreviewController;
    protected var _previewWindow :PreviewWindow;
    protected var _previewControls :PreviewControlsWindow;

    protected function findFlashDocuments (
            base :File, exec :Executor, ignoreXflAtBase :Boolean = false) :void {
        Files.list(base, exec).succeeded.add(function (files :Array) :void {
            if (exec.isShutdown) return;
            for each (var file :File in files) {
                if (Files.hasExtension(file, "xfl")) {
                    if (ignoreXflAtBase) {
                        _errors.dataProvider.addItem(new ParseError(base.nativePath,
                            ParseError.CRIT, "The import directory can't be an XFL directory, did you mean " +
                            base.parent.nativePath + "?"));
                    } else {
                        addFlashDocument(file.parent);
                    }
                    return;
                }
            }
            for each (file in files) {
                if (file.isDirectory) findFlashDocuments(file, exec);
                else if (Files.hasExtension(file, "fla")) addFlashDocument(file);
            }
        });
    }

    protected function addFlashDocument (file :File) :void {
        const status :DocStatus = new DocStatus(file, _rootLen, Ternary.UNKNOWN, Ternary.UNKNOWN, null);
        _libraries.dataProvider.addItem(status);
        loadFlashDocument(status);
    }

    protected function exportFlashDocument (status :DocStatus) :void {

        var stage :Stage = NA.activeWindow.stage;
        var prevQuality :String = stage.quality;

        stage.quality = StageQuality.BEST;
        _publisher.publish(status.lib, DeviceSelection(_authoredResolution.selectedItem).type);

        stage.quality = prevQuality;
        status.updateModified(Ternary.FALSE);
    }

    protected function loadFlashDocument (status :DocStatus) :void {
        if (Files.hasExtension(status.file, "xfl")) status.file = status.file.parent;
        if (status.file.isDirectory) {
            const name :String = status.file.nativePath
                .substring(_rootLen).replace(File.separator, "/");
            const load :Future = new XflLoader().load(name, status.file);
            load.succeeded.add(function (lib :XflLibrary) :void {
                status.lib = lib;
                status.updateModified(Ternary.of(_publisher == null || _publisher.modified(lib)));
                for each (var err :ParseError in lib.getErrors()) _errors.dataProvider.addItem(err);
                status.updateValid(Ternary.of(lib.valid));
            });
            load.failed.add(function (e :Error) :void {
                trace("Failed to load " + status.file.nativePath + ":" + e);
                status.updateValid(Ternary.FALSE);
                throw e;
            });
        } else loadFla(status.file);
    }

    protected function loadFla (file :File) :void {
        log.info("fla support not implemented", "path", file.nativePath);
        return;
        Files.load(file).succeeded.add(function (file :File) :void {
            const zip :FZip = new FZip();
            zip.loadBytes(file.data);
            const files :Array = [];
            for (var ii :int = 0; ii < zip.getFileCount(); ii++) files.push(zip.getFileAt(ii));
            const xmls :Array = F.filter(files, function (fz :FZipFile) :Boolean {
                return StringUtil.endsWith(fz.filename, ".xml");
            });
            const movies :Array = F.filter(xmls, function (fz :FZipFile) :Boolean {
                return StringUtil.startsWith(fz.filename, "LIBRARY/Animations/");
            });
            const textures :Array = F.filter(xmls, function (fz :FZipFile) :Boolean {
                return StringUtil.startsWith(fz.filename, "LIBRARY/Textures/");
            });
            function toFn (fz :FZipFile) :String { return fz.filename };
            log.info("Loaded", "bytes", file.data.length, "movies", F.map(movies, toFn),
                "textures", F.map(textures, toFn));
            for each (var fz :FZipFile in movies) {
                XflMovie.parse(null, bytesToXML(fz.content), MD5.hashBytes(fz.content));
            }
            NA.exit(0);
        });
    }

    protected var _rootLen :int;

    protected var _publisher :Publisher;
    protected var _docFinder :Executor;
    protected var _win :ExporterWindow;
    protected var _libraries :DataGrid;
    protected var _errors :DataGrid;
    protected var _exportChooser :DirChooser;
    protected var _importChooser :DirChooser;
    protected var _authoredResolution :DropDownList;
    protected const _settings :SharedObject = SharedObject.getLocal("flump/Exporter");

    private static const log :Log = Log.getLog(Exporter);
}
}
import flump.export.DeviceType;

class DeviceSelection {
    public var type :DeviceType;
    public function DeviceSelection (type :DeviceType) {
        this.type = type;
    }
    public function toString () :String {
        return type.displayName + " (" + type.resWidth + "x" + type.resHeight + ")";
    }
}
import flash.events.EventDispatcher;
import flash.filesystem.File;

import flump.export.Ternary;
import flump.xfl.XflLibrary;

import mx.core.IPropertyChangeNotifier;
import mx.events.PropertyChangeEvent;

class DocStatus extends EventDispatcher implements IPropertyChangeNotifier {
    public var path :String;
    public var modified :String;
    public var valid :String = QUESTION;
    public var file :File;
    public var lib :XflLibrary;

    public function DocStatus (file :File, rootLen :int, modified :Ternary, valid :Ternary, lib :XflLibrary) {
        this.file = file;
        this.lib = lib;
        path = file.nativePath.substring(rootLen);
        _uid = path;

        updateModified(modified);
        updateValid(valid);
    }

    public function updateValid (newValid :Ternary) :void {
        changeField("valid", function (..._) :void {
            if (newValid == Ternary.TRUE) valid = CHECK;
            else if (newValid == Ternary.FALSE) valid = FROWN;
            else valid = QUESTION;
        });
    }

    public function get isValid () :Boolean { return valid == CHECK; }

    public function updateModified (newModified :Ternary) :void {
        changeField("modified", function (..._) :void {
            if (newModified == Ternary.TRUE) modified = CHECK;
            else if (newModified == Ternary.FALSE) modified = " ";
            else modified = QUESTION;
        });
    }

    protected function changeField(fieldName :String, modifier :Function) :void {
        const oldValue :Object = this[fieldName];
        modifier();
        const newValue :Object = this[fieldName];
        dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, fieldName, oldValue, newValue));
    }

    public function get uid () :String { return _uid; }
    public function set uid (uid :String) :void { _uid = uid; }

    protected var _uid :String;

    protected static const QUESTION :String = "?";
    protected static const FROWN :String = "☹";
    protected static const CHECK :String = "✓";
}

//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.desktop.NativeApplication;
import flash.display.NativeWindow;
import flash.display.Stage;
import flash.display.StageQuality;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filesystem.File;
import flash.net.SharedObject;

import com.adobe.crypto.MD5;

import deng.fzip.FZip;
import deng.fzip.FZipFile;

import flump.bytesToXML;
import flump.display.Movie;
import flump.executor.Executor;
import flump.executor.Future;
import flump.export.Ternary;
import flump.xfl.ParseError;
import flump.xfl.XflLibrary;
import flump.xfl.XflMovie;

import mx.collections.ArrayCollection;

import spark.components.DataGrid;
import spark.components.DropDownList;
import spark.components.List;
import spark.components.Window;
import spark.events.GridSelectionEvent;

import starling.display.Sprite;

import com.threerings.util.F;
import com.threerings.util.Log;
import com.threerings.util.StringUtil;

public class Exporter
{
    public static const NA :NativeApplication = NativeApplication.nativeApplication;

    protected static const IMPORT_ROOT :String = "IMPORT_ROOT";
    protected static const AUTHORED_RESOLUTION :String = "AUTHORED_RESOLUTION";

    public function Exporter (win :ExporterWindow) {
        Log.setLevel("", Log.INFO);
        _win = win;
        _errors = _win.errors;
        _libraries = _win.libraries;

        _authoredResolution = _win.authoredResolutionPopup;
        _authoredResolution.dataProvider = new ArrayCollection(DeviceType.values().map(
            function (type :DeviceType, ..._) :Object {
                return new DeviceSelection(type);
            }));
        var initialSelection :DeviceType = null;
        if (_settings.data.hasOwnProperty(AUTHORED_RESOLUTION)) {
            try {
                initialSelection = DeviceType.valueOf(_settings.data[AUTHORED_RESOLUTION]);
            } catch (e :Error) {}
        }
        if (initialSelection == null) {
            initialSelection = DeviceType.IPHONE_RETINA;
        }
        _authoredResolution.selectedIndex = DeviceType.values().indexOf(initialSelection);
        _authoredResolution.addEventListener(Event.CHANGE, function (..._) :void {
            var selectedType :DeviceType = DeviceSelection(_authoredResolution.selectedItem).type;
            _settings.data[AUTHORED_RESOLUTION] = selectedType.name();
        });

        function updateExportEnabled (..._) :void {
            _win.export.enabled = _exportChooser.dir != null && _libraries.selectionLength > 0 &&
              _libraries.selectedItems.some(function (status :DocStatus, ..._) :Boolean {
                return status.isValid;
            });
        }
        _libraries.addEventListener(GridSelectionEvent.SELECTION_CHANGE, function (..._) :void {
            log.info("Changed", "selected", _libraries.selectedIndices);
            updateExportEnabled();
            _win.preview.enabled = _libraries.selectedItem.isValid;
        });
        _win.reload.addEventListener(MouseEvent.CLICK, function (..._) :void {
            setImport(_importChooser.dir);
        });
        _win.export.addEventListener(MouseEvent.CLICK, function (..._) :void {
            for each (var status :DocStatus in _libraries.selectedItems) {
                exportFlashDocument(status);
            }
        });
        _win.preview.addEventListener(MouseEvent.CLICK, function (..._) :void {
            showPreviewWindow(_libraries.selectedItem.lib);
        });
        _importChooser =
            new DirChooser(_settings, "IMPORT_ROOT", _win.importRoot, _win.browseImport);
        _importChooser.changed.add(setImport);
        setImport(_importChooser.dir);
        _exportChooser =
            new DirChooser(_settings, "EXPORT_ROOT", _win.exportRoot, _win.browseExport);
        _exportChooser.changed.add(updateExportEnabled);
        function updatePublisher (..._) :void {
            if (_exportChooser.dir == null) _publisher = null;
            else {
                _publisher =
                    new Publisher(_exportChooser.dir, new XMLFormat(), new JSONFormat(), new StarlingFormat());
            }
        };
        _exportChooser.changed.add(updatePublisher);
        updatePublisher();
        _win.addEventListener(Event.CLOSE, function (..._) :void { NA.exit(0); });
    }

    protected function setImport (root :File) :void {
        _libraries.dataProvider.removeAll();
        _errors.dataProvider.removeAll();
        if (root == null) return;
        _rootLen = root.nativePath.length + 1;
        if (_docFinder != null) _docFinder.shutdownNow();
        _docFinder = new Executor(2);
        findFlashDocuments(root, _docFinder, true);
        _win.reload.enabled = true;
    }

    protected function showPreviewWindow (lib :XflLibrary) :void {
        if (_previewController == null || _previewWindow.closed || _previewControls.closed) {
            _previewWindow = new PreviewWindow();
            _previewControls = new PreviewControlsWindow();
            _previewWindow.started = function (container :Sprite) :void {
                _previewController = new PreviewController(lib, container, _previewControls);
            }

            _previewWindow.open();
            _previewControls.open();

            preventWindowClose(_previewWindow.nativeWindow);
            preventWindowClose(_previewControls.nativeWindow);

        } else {
            _previewController.lib = lib;
            _previewWindow.nativeWindow.visible = true;
            _previewControls.nativeWindow.visible = true;
        }
    }

    // Causes a window to be hidden, rather than closed, when its close box is clicked
    protected static function preventWindowClose (window :NativeWindow) :void {
        window.addEventListener(Event.CLOSING, function (e :Event) :void {
            e.preventDefault();
            window.visible = false;
        });
    }

    protected var _previewController :PreviewController;
    protected var _previewWindow :PreviewWindow;
    protected var _previewControls :PreviewControlsWindow;

    protected function findFlashDocuments (
            base :File, exec :Executor, ignoreXflAtBase :Boolean = false) :void {
        Files.list(base, exec).succeeded.add(function (files :Array) :void {
            if (exec.isShutdown) return;
            for each (var file :File in files) {
                if (Files.hasExtension(file, "xfl")) {
                    if (ignoreXflAtBase) {
                        _errors.dataProvider.addItem(new ParseError(base.nativePath,
                            ParseError.CRIT, "The import directory can't be an XFL directory, did you mean " +
                            base.parent.nativePath + "?"));
                    } else {
                        addFlashDocument(file.parent);
                    }
                    return;
                }
            }
            for each (file in files) {
                if (file.isDirectory) findFlashDocuments(file, exec);
                else if (Files.hasExtension(file, "fla")) addFlashDocument(file);
            }
        });
    }

    protected function addFlashDocument (file :File) :void {
        const status :DocStatus = new DocStatus(file, _rootLen, Ternary.UNKNOWN, Ternary.UNKNOWN, null);
        _libraries.dataProvider.addItem(status);
        loadFlashDocument(status);
    }

    protected function exportFlashDocument (status :DocStatus) :void {

        var stage :Stage = NA.activeWindow.stage;
        var prevQuality :String = stage.quality;

        stage.quality = StageQuality.BEST;
        _publisher.publish(status.lib, DeviceSelection(_authoredResolution.selectedItem).type);

        stage.quality = prevQuality;
        status.updateModified(Ternary.FALSE);
    }

    protected function loadFlashDocument (status :DocStatus) :void {
        if (Files.hasExtension(status.file, "xfl")) status.file = status.file.parent;
        if (status.file.isDirectory) {
            const name :String = status.file.nativePath
                .substring(_rootLen).replace(File.separator, "/");
            const load :Future = new XflLoader().load(name, status.file);
            load.succeeded.add(function (lib :XflLibrary) :void {
                status.lib = lib;
                status.updateModified(Ternary.of(_publisher == null || _publisher.modified(lib)));
                for each (var err :ParseError in lib.getErrors()) _errors.dataProvider.addItem(err);
                status.updateValid(Ternary.of(lib.valid));
            });
            load.failed.add(function (e :Error) :void {
                trace("Failed to load " + status.file.nativePath + ":" + e);
                status.updateValid(Ternary.FALSE);
                throw e;
            });
        } else loadFla(status.file);
    }

    protected function loadFla (file :File) :void {
        log.info("fla support not implemented", "path", file.nativePath);
        return;
        Files.load(file).succeeded.add(function (file :File) :void {
            const zip :FZip = new FZip();
            zip.loadBytes(file.data);
            const files :Array = [];
            for (var ii :int = 0; ii < zip.getFileCount(); ii++) files.push(zip.getFileAt(ii));
            const xmls :Array = F.filter(files, function (fz :FZipFile) :Boolean {
                return StringUtil.endsWith(fz.filename, ".xml");
            });
            const movies :Array = F.filter(xmls, function (fz :FZipFile) :Boolean {
                return StringUtil.startsWith(fz.filename, "LIBRARY/Animations/");
            });
            const textures :Array = F.filter(xmls, function (fz :FZipFile) :Boolean {
                return StringUtil.startsWith(fz.filename, "LIBRARY/Textures/");
            });
            function toFn (fz :FZipFile) :String { return fz.filename };
            log.info("Loaded", "bytes", file.data.length, "movies", F.map(movies, toFn),
                "textures", F.map(textures, toFn));
            for each (var fz :FZipFile in movies) {
                XflMovie.parse(null, bytesToXML(fz.content), MD5.hashBytes(fz.content));
            }
            NA.exit(0);
        });
    }

    protected var _rootLen :int;

    protected var _publisher :Publisher;
    protected var _docFinder :Executor;
    protected var _win :ExporterWindow;
    protected var _libraries :DataGrid;
    protected var _errors :DataGrid;
    protected var _exportChooser :DirChooser;
    protected var _importChooser :DirChooser;
    protected var _authoredResolution :DropDownList;
    protected const _settings :SharedObject = SharedObject.getLocal("flump/Exporter");

    private static const log :Log = Log.getLog(Exporter);
}
}
import flump.export.DeviceType;

class DeviceSelection {
    public var type :DeviceType;
    public function DeviceSelection (type :DeviceType) {
        this.type = type;
    }
    public function toString () :String {
        return type.displayName + " (" + type.resWidth + "x" + type.resHeight + ")";
    }
}
import flash.events.EventDispatcher;
import flash.filesystem.File;

import flump.export.Ternary;
import flump.xfl.XflLibrary;

import mx.core.IPropertyChangeNotifier;
import mx.events.PropertyChangeEvent;

class DocStatus extends EventDispatcher implements IPropertyChangeNotifier {
    public var path :String;
    public var modified :String;
    public var valid :String = QUESTION;
    public var file :File;
    public var lib :XflLibrary;

    public function DocStatus (file :File, rootLen :int, modified :Ternary, valid :Ternary, lib :XflLibrary) {
        this.file = file;
        this.lib = lib;
        path = file.nativePath.substring(rootLen);
        _uid = path;

        updateModified(modified);
        updateValid(valid);
    }

    public function updateValid (newValid :Ternary) :void {
        changeField("valid", function (..._) :void {
            if (newValid == Ternary.TRUE) valid = CHECK;
            else if (newValid == Ternary.FALSE) valid = FROWN;
            else valid = QUESTION;
        });
    }

    public function get isValid () :Boolean { return valid == CHECK; }

    public function updateModified (newModified :Ternary) :void {
        changeField("modified", function (..._) :void {
            if (newModified == Ternary.TRUE) modified = CHECK;
            else if (newModified == Ternary.FALSE) modified = " ";
            else modified = QUESTION;
        });
    }

    protected function changeField(fieldName :String, modifier :Function) :void {
        const oldValue :Object = this[fieldName];
        modifier();
        const newValue :Object = this[fieldName];
        dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, fieldName, oldValue, newValue));
    }

    public function get uid () :String { return _uid; }
    public function set uid (uid :String) :void { _uid = uid; }

    protected var _uid :String;

    protected static const QUESTION :String = "?";
    protected static const FROWN :String = "☹";
    protected static const CHECK :String = "✓";
}

Cut logging back to INFO by default

Cut logging back to INFO by default


package aerys.minko.scene.controller
{
	import aerys.minko.ns.minko_math;
	import aerys.minko.render.Viewport;
	import aerys.minko.scene.node.Group;
	import aerys.minko.scene.node.ISceneNode;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.type.math.Matrix4x4;

	import flash.display.BitmapData;
	import flash.utils.Dictionary;

	use namespace minko_math;

	/**
	 * The TransformController handles the batched update of all the local to world matrices
	 * of a sub-scene. As such, it will only be active on the root node of a sub-scene and will
	 * automatically disable itself on other nodes.
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public final class TransformController extends AbstractController
	{
		private var _target								: ISceneNode;

		private var _invalidList						: Boolean;

		private var _nodeToId							: Dictionary;
		private var _idToNode							: Vector.<ISceneNode>
		private var _transforms							: Vector.<Matrix4x4>;
		private var _localToWorldTransformsInitialized	: Vector.<Boolean>;
		private var _localToWorldTransforms 			: Vector.<Matrix4x4>;
        private var _worldToLocalTransforms 			: Vector.<Matrix4x4>;
		private var _numChildren						: Vector.<uint>;
		private var _firstChildId						: Vector.<uint>;
		private var _parentId							: Vector.<int>;

		public function TransformController()
		{
			super();

			targetAdded.add(targetAddedHandler);
			targetRemoved.add(targetRemovedHandler);
		}

		private function renderingBeginHandler(scene			: Scene,
											   viewport		: Viewport,
											   destination	: BitmapData,
											   time			: Number) : void
		{
			if (_invalidList)
				updateTransformsList();

			if (_transforms.length)
				updateLocalToWorld();
		}

		private function updateLocalToWorld(nodeId : uint = 0) : void
		{
			var numNodes 			: uint 			= _transforms.length;
			var childrenOffset		: uint			= 1;
			var rootLocalToWorld	: Matrix4x4		= _localToWorldTransforms[nodeId];
			var rootTransform		: Matrix4x4		= _transforms[nodeId];
			var root				: ISceneNode	= _idToNode[childId];

			if (rootTransform._hasChanged || !_localToWorldTransformsInitialized[nodeId])
			{
				rootLocalToWorld.copyFrom(rootTransform);

				if (nodeId != 0)
					rootLocalToWorld.append(_localToWorldTransforms[_parentId[nodeId]]);

				rootTransform._hasChanged = false;
				_localToWorldTransformsInitialized[nodeId] = true;
				root.localToWorldTransformChanged.execute(root, rootLocalToWorld);
			}

			for (; nodeId < numNodes; ++nodeId)
			{
				var localToWorld 	: Matrix4x4	= _localToWorldTransforms[nodeId];
				var numChildren		: uint		= _numChildren[nodeId];
				var firstChildId	: uint		= _firstChildId[nodeId];
				var lastChildId		: uint		= firstChildId + numChildren;
				var isDirty			: Boolean	= localToWorld._hasChanged ||
												  !_localToWorldTransformsInitialized[nodeId];

				localToWorld._hasChanged = false;
				_localToWorldTransformsInitialized[nodeId] = true;

				for (var childId : uint = firstChildId; childId < lastChildId; ++childId)
				{
					var childTransform		: Matrix4x4		= _transforms[childId];
					var childLocalToWorld	: Matrix4x4		= _localToWorldTransforms[childId];
					var childIsDirty		: Boolean		= isDirty || childTransform._hasChanged
						|| !_localToWorldTransformsInitialized[childId];

					if (childIsDirty || _localToWorldTransformsInitialized[childId])
					{
						var child	: ISceneNode	= _idToNode[childId];

						childLocalToWorld
							.copyFrom(childTransform)
							.append(localToWorld);

						childTransform._hasChanged = false;
						_localToWorldTransformsInitialized[childId] = true;
						child.localToWorldTransformChanged.execute(child, childLocalToWorld);
					}
				}
			}
		}

        private function getDirtyRoot(nodeId : int) : int
        {
            var dirtyRoot : int = -1;

            while (nodeId >= 0)
            {
                if ((_transforms[nodeId] as Matrix4x4)._hasChanged ||
					!_localToWorldTransformsInitialized[nodeId])
                    dirtyRoot = nodeId;

                nodeId = _parentId[nodeId];
            }

            return dirtyRoot;
        }

		private function targetAddedHandler(ctrl	: TransformController,
											target	: ISceneNode) : void
		{
			if (_target)
				throw new Error('The TransformController cannot have more than one target.');

			_target = target;
			_invalidList = true;

			if (target is Scene)
			{
				(target as Scene).renderingBegin.add(renderingBeginHandler);
				return;
			}

			if (target is Group)
			{
				var targetGroup : Group = target as Group;

				targetGroup.descendantAdded.add(descendantAddedHandler);
				targetGroup.descendantRemoved.add(descendantRemovedHandler);
			}

			target.added.add(addedHandler);
		}

		private function targetRemovedHandler(ctrl		: TransformController,
											  target	: ISceneNode) : void
		{
			target.added.remove(addedHandler);

			if (target is Group)
			{
				var targetGroup : Group = target as Group;

				targetGroup.descendantAdded.remove(descendantAddedHandler);
				targetGroup.descendantRemoved.remove(descendantRemovedHandler);
			}

			_invalidList = false;
			_target = null;

			_nodeToId = null;
			_transforms = null;
			_localToWorldTransformsInitialized = null;
			_localToWorldTransforms = null;
            _worldToLocalTransforms = null;
			_numChildren = null;
			_idToNode = null;
			_parentId = null;
		}

		private function addedHandler(target : ISceneNode, ancestor : Group) : void
		{
			// the controller will remove itself from the node when it's not its own root anymore
			// but it will watch for the 'removed' signal to add itself back if the node becomes
			// its own root again
			_target.removed.add(removedHandler);
			_target.removeController(this);
		}

		private function removedHandler(target : ISceneNode, ancestor : Group) : void
		{
			if (target.root == target)
			{
				target.removed.remove(removedHandler);
				target.addController(this);
			}
		}

		private function descendantAddedHandler(root		: Group,
												descendant	: ISceneNode) : void
		{
			_invalidList = true;
		}

		private function descendantRemovedHandler(root			: Group,
												  descendant	: ISceneNode) : void
		{
			_invalidList = true;
		}

		private function updateTransformsList() : void
		{
			var root 	: ISceneNode 			= _target.root;
			var nodes 	: Vector.<ISceneNode> 	= new <ISceneNode>[root];
			var nodeId 	: uint 					= 0;

			_nodeToId = new Dictionary(true);
			_transforms = new <Matrix4x4>[];
			_localToWorldTransformsInitialized = new <Boolean>[];
			_localToWorldTransforms = new <Matrix4x4>[];
            _worldToLocalTransforms = new <Matrix4x4>[];
			_numChildren = new <uint>[];
			_firstChildId = new <uint>[];
			_idToNode = new <ISceneNode>[];
			_parentId = new <int>[-1];

			while (nodes.length)
			{
				var node 	: ISceneNode 	= nodes.shift();
				var group 	: Group 		= node as Group;

				_nodeToId[node] = nodeId;
				_idToNode[nodeId] = node;
				_transforms[nodeId] = node.transform;
				_localToWorldTransforms[nodeId] = new Matrix4x4().lock();
				_localToWorldTransformsInitialized[nodeId] = false;

				if (group)
				{
					var numChildren 	: uint = group.numChildren;
					var firstChildId 	: uint = nodeId + nodes.length + 1;

					_numChildren[nodeId] = numChildren;
					_firstChildId[nodeId] = firstChildId;
					for (var childId : uint = 0; childId < numChildren; ++childId)
					{
						_parentId[uint(firstChildId + childId)] = nodeId;
						nodes.push(group.getChildAt(childId));
					}
				}
				else
				{
					_numChildren[nodeId] = 0;
					_firstChildId[nodeId] = 0;
				}

				++nodeId;
			}

            _worldToLocalTransforms.length = _localToWorldTransforms.length;
			_invalidList = false;
		}

		public function getLocalToWorldTransform(node 			: ISceneNode,
												 forceUpdate 	: Boolean = false) : Matrix4x4
		{
			if (_invalidList || _nodeToId[node] == undefined)
				updateTransformsList();

			var nodeId : uint = _nodeToId[node];

			if (forceUpdate)
            {
                var dirtyRoot : int = getDirtyRoot(nodeId);

                if (dirtyRoot >= 0)
                    updateLocalToWorld(dirtyRoot);
            }

			return _localToWorldTransforms[nodeId];
		}

        public function getWorldToLocalTransform(node           : ISceneNode,
                                                 forceUpdate    : Boolean   = false) : Matrix4x4
        {
            if (_invalidList || _nodeToId[node] == undefined)
                updateTransformsList();

            var nodeId                  : uint      = _nodeToId[node];
            var worldToLocalTransform   : Matrix4x4 = _worldToLocalTransforms[nodeId];

            if (!worldToLocalTransform)
            {
                _worldToLocalTransforms[nodeId] = worldToLocalTransform = new Matrix4x4();
                if (!forceUpdate)
                    worldToLocalTransform.copyFrom(_localToWorldTransforms[nodeId]).invert();
            }

            if (forceUpdate)
            {
                var dirtyRoot : int = getDirtyRoot(nodeId);

                if (dirtyRoot >= 0)
                {
                    updateLocalToWorld(dirtyRoot);

                    worldToLocalTransform
                        .copyFrom(_localToWorldTransforms[nodeId])
                        .invert();
                }
            }

            return worldToLocalTransform;
        }
	}
}

package aerys.minko.scene.controller
{
	import aerys.minko.ns.minko_math;
	import aerys.minko.render.Viewport;
	import aerys.minko.scene.node.Group;
	import aerys.minko.scene.node.ISceneNode;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.type.math.Matrix4x4;

	import flash.display.BitmapData;
	import flash.utils.Dictionary;

	use namespace minko_math;

	/**
	 * The TransformController handles the batched update of all the local to world matrices
	 * of a sub-scene. As such, it will only be active on the root node of a sub-scene and will
	 * automatically disable itself on other nodes.
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public final class TransformController extends AbstractController
	{
		private var _target								: ISceneNode;

		private var _invalidList						: Boolean;

		private var _nodeToId							: Dictionary;
		private var _idToNode							: Vector.<ISceneNode>
		private var _transforms							: Vector.<Matrix4x4>;
		private var _localToWorldTransformsInitialized	: Vector.<Boolean>;
		private var _localToWorldTransforms 			: Vector.<Matrix4x4>;
        private var _worldToLocalTransforms 			: Vector.<Matrix4x4>;
		private var _numChildren						: Vector.<uint>;
		private var _firstChildId						: Vector.<uint>;
		private var _parentId							: Vector.<int>;

		public function TransformController()
		{
			super();

			targetAdded.add(targetAddedHandler);
			targetRemoved.add(targetRemovedHandler);
		}

		private function renderingBeginHandler(scene			: Scene,
											   viewport		: Viewport,
											   destination	: BitmapData,
											   time			: Number) : void
		{
			if (_invalidList)
				updateTransformsList();

			if (_transforms.length)
				updateLocalToWorld();
		}

		private function updateLocalToWorld(nodeId : uint = 0) : void
		{
			var numNodes 			: uint 			= _transforms.length;
			var childrenOffset		: uint			= 1;
			var rootLocalToWorld	: Matrix4x4		= _localToWorldTransforms[nodeId];
			var rootTransform		: Matrix4x4		= _transforms[nodeId];
			var root				: ISceneNode	= _idToNode[childId];

			if (rootTransform._hasChanged || !_localToWorldTransformsInitialized[nodeId])
			{
				rootLocalToWorld.copyFrom(rootTransform);

				if (nodeId != 0)
					rootLocalToWorld.append(_localToWorldTransforms[_parentId[nodeId]]);

				rootTransform._hasChanged = false;
				_localToWorldTransformsInitialized[nodeId] = true;
				root.localToWorldTransformChanged.execute(root, rootLocalToWorld);
			}

			for (; nodeId < numNodes; ++nodeId)
			{
				var localToWorld 	: Matrix4x4	= _localToWorldTransforms[nodeId];
				var numChildren		: uint		= _numChildren[nodeId];
				var firstChildId	: uint		= _firstChildId[nodeId];
				var lastChildId		: uint		= firstChildId + numChildren;
				var isDirty			: Boolean	= localToWorld._hasChanged;

                localToWorld._hasChanged = false;

				for (var childId : uint = firstChildId; childId < lastChildId; ++childId)
				{
					var childTransform		: Matrix4x4		= _transforms[childId];
					var childLocalToWorld	: Matrix4x4		= _localToWorldTransforms[childId];
					var childIsDirty		: Boolean		= isDirty || childTransform._hasChanged
						|| !_localToWorldTransformsInitialized[childId];

					if (childIsDirty)
					{
						var child	: ISceneNode	= _idToNode[childId];

						childLocalToWorld
							.copyFrom(childTransform)
							.append(localToWorld);

						childTransform._hasChanged = false;
						_localToWorldTransformsInitialized[childId] = true;
						child.localToWorldTransformChanged.execute(child, childLocalToWorld);
					}
				}
			}
		}

        private function getDirtyRoot(nodeId : int) : int
        {
            var dirtyRoot : int = -1;

            while (nodeId >= 0)
            {
                if ((_transforms[nodeId] as Matrix4x4)._hasChanged ||
					!_localToWorldTransformsInitialized[nodeId])
                    dirtyRoot = nodeId;

                nodeId = _parentId[nodeId];
            }

            return dirtyRoot;
        }

		private function targetAddedHandler(ctrl	: TransformController,
											target	: ISceneNode) : void
		{
			if (_target)
				throw new Error('The TransformController cannot have more than one target.');

			_target = target;
			_invalidList = true;

			if (target is Scene)
			{
				(target as Scene).renderingBegin.add(renderingBeginHandler);
				return;
			}

			if (target is Group)
			{
				var targetGroup : Group = target as Group;

				targetGroup.descendantAdded.add(descendantAddedHandler);
				targetGroup.descendantRemoved.add(descendantRemovedHandler);
			}

			target.added.add(addedHandler);
		}

		private function targetRemovedHandler(ctrl		: TransformController,
											  target	: ISceneNode) : void
		{
			target.added.remove(addedHandler);

			if (target is Group)
			{
				var targetGroup : Group = target as Group;

				targetGroup.descendantAdded.remove(descendantAddedHandler);
				targetGroup.descendantRemoved.remove(descendantRemovedHandler);
			}

			_invalidList = false;
			_target = null;

			_nodeToId = null;
			_transforms = null;
			_localToWorldTransformsInitialized = null;
			_localToWorldTransforms = null;
            _worldToLocalTransforms = null;
			_numChildren = null;
			_idToNode = null;
			_parentId = null;
		}

		private function addedHandler(target : ISceneNode, ancestor : Group) : void
		{
			// the controller will remove itself from the node when it's not its own root anymore
			// but it will watch for the 'removed' signal to add itself back if the node becomes
			// its own root again
			_target.removed.add(removedHandler);
			_target.removeController(this);
		}

		private function removedHandler(target : ISceneNode, ancestor : Group) : void
		{
			if (target.root == target)
			{
				target.removed.remove(removedHandler);
				target.addController(this);
			}
		}

		private function descendantAddedHandler(root		: Group,
												descendant	: ISceneNode) : void
		{
			_invalidList = true;
		}

		private function descendantRemovedHandler(root			: Group,
												  descendant	: ISceneNode) : void
		{
			_invalidList = true;
		}

		private function updateTransformsList() : void
		{
			var root 	: ISceneNode 			= _target.root;
			var nodes 	: Vector.<ISceneNode> 	= new <ISceneNode>[root];
			var nodeId 	: uint 					= 0;

			_nodeToId = new Dictionary(true);
			_transforms = new <Matrix4x4>[];
			_localToWorldTransformsInitialized = new <Boolean>[];
			_localToWorldTransforms = new <Matrix4x4>[];
            _worldToLocalTransforms = new <Matrix4x4>[];
			_numChildren = new <uint>[];
			_firstChildId = new <uint>[];
			_idToNode = new <ISceneNode>[];
			_parentId = new <int>[-1];

			while (nodes.length)
			{
				var node 	: ISceneNode 	= nodes.shift();
				var group 	: Group 		= node as Group;

				_nodeToId[node] = nodeId;
				_idToNode[nodeId] = node;
				_transforms[nodeId] = node.transform;
				_localToWorldTransforms[nodeId] = new Matrix4x4().lock();
				_localToWorldTransformsInitialized[nodeId] = false;

				if (group)
				{
					var numChildren 	: uint = group.numChildren;
					var firstChildId 	: uint = nodeId + nodes.length + 1;

					_numChildren[nodeId] = numChildren;
					_firstChildId[nodeId] = firstChildId;
					for (var childId : uint = 0; childId < numChildren; ++childId)
					{
						_parentId[uint(firstChildId + childId)] = nodeId;
						nodes.push(group.getChildAt(childId));
					}
				}
				else
				{
					_numChildren[nodeId] = 0;
					_firstChildId[nodeId] = 0;
				}

				++nodeId;
			}

            _worldToLocalTransforms.length = _localToWorldTransforms.length;
			_invalidList = false;
		}

		public function getLocalToWorldTransform(node 			: ISceneNode,
												 forceUpdate 	: Boolean = false) : Matrix4x4
		{
			if (_invalidList || _nodeToId[node] == undefined)
				updateTransformsList();

			var nodeId : uint = _nodeToId[node];

			if (forceUpdate)
            {
                var dirtyRoot : int = getDirtyRoot(nodeId);

                if (dirtyRoot >= 0)
                    updateLocalToWorld(dirtyRoot);
            }

			return _localToWorldTransforms[nodeId];
		}

        public function getWorldToLocalTransform(node           : ISceneNode,
                                                 forceUpdate    : Boolean   = false) : Matrix4x4
        {
            if (_invalidList || _nodeToId[node] == undefined)
                updateTransformsList();

            var nodeId                  : uint      = _nodeToId[node];
            var worldToLocalTransform   : Matrix4x4 = _worldToLocalTransforms[nodeId];

            if (!worldToLocalTransform)
            {
                _worldToLocalTransforms[nodeId] = worldToLocalTransform = new Matrix4x4();
                if (!forceUpdate)
                    worldToLocalTransform.copyFrom(_localToWorldTransforms[nodeId]).invert();
            }

            if (forceUpdate)
            {
                var dirtyRoot : int = getDirtyRoot(nodeId);

                if (dirtyRoot >= 0)
                {
                    updateLocalToWorld(dirtyRoot);

                    worldToLocalTransform
                        .copyFrom(_localToWorldTransforms[nodeId])
                        .invert();
                }
            }

            return worldToLocalTransform;
        }
	}
}

fix TransformController.updateLocalToWorld() to use !_localToWorldTransformsInitialized[childId] instead of _localToWorldTransformsInitialized[childId] to check if the child is dirty


////////////////////////////////////////////////////////////////////////////////
//
//  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 mx.utils
{
	import flash.display.DisplayObject;
	import flash.system.Capabilities;

	import mx.core.mx_internal;

	[Mixin]
	public class AndroidPlatformVersionOverride
	{
		public static function init(root:DisplayObject):void
		{
			var c:Class = Capabilities;
			//Set this override value on if we are
			// a. on the AIR Simulator
			// b. simulating Android
			if(c.version.indexOf("AND") > -1 && c.manufacturer != "Android Linux")
			{
				Platform.mx_internal::androidVersionOverride =  "4.1.2";
			}
		}
	}
}

Add Apache license header

Add Apache license header


package aerys.minko.type.loader
{
	import aerys.minko.render.resource.texture.TextureResource;
	import aerys.minko.scene.node.AbstractSceneNode;
	import aerys.minko.scene.node.Group;
	import aerys.minko.scene.node.ISceneNode;
	import aerys.minko.type.Signal;
	import aerys.minko.type.loader.parser.IParser;
	import aerys.minko.type.loader.parser.ParserOptions;

	import flash.events.Event;
	import flash.events.ProgressEvent;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;
	import flash.utils.getQualifiedClassName;

	public class SceneLoader implements ILoader
	{
		private static const REGISTERED_PARSERS : Vector.<Class> = new <Class>[];

		private static const STATE_IDLE		: uint = 0;
		private static const STATE_LOADING	: uint = 1;
		private static const STATE_PARSING	: uint = 2;
		private static const STATE_COMPLETE	: uint = 3;

		private var _currentState			: int;

		private var _progress				: Signal;
		private var _complete				: Signal;
		private var _error					: Signal;

		private var _data					: ISceneNode;
		private var _parser					: IParser;
		private var _numDependencies		: uint;
		private var _dependencies			: Vector.<ILoader>;
		private var _parserOptions			: ParserOptions;

		private var _currentProgress		: Number;
		private var _currentProgressChanged : Boolean;
		private var _isComplete				: Boolean;

		public function get error() : Signal
		{
			return _error;
		}

		public function get progress() : Signal
		{
			return _progress;
		}

		public function get complete() : Signal
		{
			return _complete;
		}

		public function get isComplete() : Boolean
		{
			return _isComplete;
		}

		public function get data() : ISceneNode
		{
			return _data;
		}

		public static function registerParser(parserClass : Class) : void
		{
			if (REGISTERED_PARSERS.indexOf(parserClass) != -1)
				return;

			if (!(new parserClass(new ParserOptions()) is IParser))
				throw new Error('Parsers must implement the IParser interface.');

			REGISTERED_PARSERS.push(parserClass);
		}

		public function SceneLoader(parserOptions : ParserOptions = null)
		{
			_currentState	= STATE_IDLE;

			_progress		= new Signal('SceneLoader.progress');
			_complete		= new Signal('SceneLoader.complete');
			_data			= null;
			_isComplete		= false;

			_parserOptions	= parserOptions || new ParserOptions();
		}

		public function load(urlRequest : URLRequest) : void
		{
			if (_currentState != STATE_IDLE)
				throw new Error('This controller is already loading an asset.');

			_currentState = STATE_LOADING;

			var urlLoader : URLLoader = new URLLoader();
			urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
			urlLoader.addEventListener(ProgressEvent.PROGRESS, loadProgressHandler);
			urlLoader.addEventListener(Event.COMPLETE, loadCompleteHandler);
			urlLoader.load(urlRequest);
		}

		private function loadProgressHandler(e : ProgressEvent) : void
		{
			_progress.execute(this, 0.5 * e.bytesLoaded / e.bytesTotal);
		}

		private function loadCompleteHandler(e : Event) : void
		{
			_currentState = STATE_IDLE;

			loadBytes(URLLoader(e.currentTarget).data);
		}

		public function loadClass(classObject : Class) : void
		{
			loadBytes(new classObject());
		}

		public function loadBytes(byteArray : ByteArray) : void
		{
			var startPosition : uint = byteArray.position;

			if (_currentState != STATE_IDLE)
				throw new Error('This loader is already loading an asset.');

			_currentState = STATE_PARSING;
			_progress.execute(this, 0.5);

			if (_parserOptions != null && _parserOptions.parser != null)
			{
				_parser = new (_parserOptions.parser)(_parserOptions);

				if (!_parser.isParsable(byteArray))
					throw new Error('Invalid datatype for this parser.');
			}
			else
			{
				// search a parser by testing registered parsers.
				var numRegisteredParser : uint = REGISTERED_PARSERS.length;
				for (var parserId : uint = 0; parserId < numRegisteredParser; ++parserId)
				{
					_parser = new REGISTERED_PARSERS[parserId](_parserOptions);
					byteArray.position = startPosition;
					if (_parser.isParsable(byteArray))
						break;
				}

				if (parserId == numRegisteredParser)
					throw new Error('No parser could be found for this datatype.');
			}

			byteArray.position = startPosition;

			_dependencies	 = _parser.getDependencies(byteArray);
			_numDependencies = 0;

			if (_dependencies != null)
				for each (var dependency : ILoader in _dependencies)
					if (!dependency.isComplete)
					{
						dependency.error.add(decrementDependencyCounter);
						dependency.complete.add(decrementDependencyCounter);

						_numDependencies++;
					}

			if (_numDependencies == 0)
				parse();
		}

		private function decrementDependencyCounter(...args) : void
		{
			--_numDependencies;

			if (_numDependencies == 0)
				parse();
		}

		private function parse() : void
		{
			_parser.error.add(onParseError);
			_parser.progress.add(onParseProgress);
			_parser.complete.add(onParseComplete);
			_parser.parse();
		}

		private function onParseError(parser : IParser) : void
		{
			_isComplete = true;
		}

		private function onParseProgress(parser : IParser, progress : Number) : void
		{
			_progress.execute(this, 0.5 * (1 + progress));
		}

		private function onParseComplete(parser : IParser, loadedData : ISceneNode) : void
		{
			_isComplete = true;
			_data = loadedData;
			_complete.execute(this, loadedData);
		}
	}
}

package aerys.minko.type.loader
{
	import aerys.minko.render.resource.texture.TextureResource;
	import aerys.minko.scene.node.AbstractSceneNode;
	import aerys.minko.scene.node.Group;
	import aerys.minko.scene.node.ISceneNode;
	import aerys.minko.type.Signal;
	import aerys.minko.type.loader.parser.IParser;
	import aerys.minko.type.loader.parser.ParserOptions;

	import flash.events.Event;
	import flash.events.ProgressEvent;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;
	import flash.utils.getQualifiedClassName;
	import flash.utils.setTimeout;

	public class SceneLoader implements ILoader
	{
		private static const REGISTERED_PARSERS : Vector.<Class> = new <Class>[];

		private static const STATE_IDLE		: uint = 0;
		private static const STATE_LOADING	: uint = 1;
		private static const STATE_PARSING	: uint = 2;
		private static const STATE_COMPLETE	: uint = 3;

		private var _currentState			: int;

		private var _progress				: Signal;
		private var _complete				: Signal;
		private var _error					: Signal;

		private var _data					: ISceneNode;
		private var _parser					: IParser;
		private var _numDependencies		: uint;
		private var _dependencies			: Vector.<ILoader>;
		private var _parserOptions			: ParserOptions;

		private var _currentProgress		: Number;
		private var _currentProgressChanged : Boolean;
		private var _isComplete				: Boolean;

		public function get error() : Signal
		{
			return _error;
		}

		public function get progress() : Signal
		{
			return _progress;
		}

		public function get complete() : Signal
		{
			return _complete;
		}

		public function get isComplete() : Boolean
		{
			return _isComplete;
		}

		public function get data() : ISceneNode
		{
			return _data;
		}

		public static function registerParser(parserClass : Class) : void
		{
			if (REGISTERED_PARSERS.indexOf(parserClass) != -1)
				return;

			if (!(new parserClass(new ParserOptions()) is IParser))
				throw new Error('Parsers must implement the IParser interface.');

			REGISTERED_PARSERS.push(parserClass);
		}

		public function SceneLoader(parserOptions : ParserOptions = null)
		{
			_currentState	= STATE_IDLE;

			_progress		= new Signal('SceneLoader.progress');
			_complete		= new Signal('SceneLoader.complete');
			_data			= null;
			_isComplete		= false;

			_parserOptions	= parserOptions || new ParserOptions();
		}

		public function load(urlRequest : URLRequest) : void
		{
			if (_currentState != STATE_IDLE)
				throw new Error('This controller is already loading an asset.');

			_currentState = STATE_LOADING;

			var urlLoader : URLLoader = new URLLoader();
			urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
			urlLoader.addEventListener(ProgressEvent.PROGRESS, loadProgressHandler);
			urlLoader.addEventListener(Event.COMPLETE, loadCompleteHandler);
			urlLoader.load(urlRequest);
		}

		private function loadProgressHandler(e : ProgressEvent) : void
		{
			_progress.execute(this, 0.5 * e.bytesLoaded / e.bytesTotal);
		}

		private function loadCompleteHandler(e : Event) : void
		{
			_currentState = STATE_IDLE;

			loadBytes(URLLoader(e.currentTarget).data);
		}

		public function loadClass(classObject : Class) : void
		{
			loadBytes(new classObject());
		}

		public function loadBytes(byteArray : ByteArray) : void
		{
			var startPosition : uint = byteArray.position;

			if (_currentState != STATE_IDLE)
				throw new Error('This loader is already loading an asset.');

			_currentState = STATE_PARSING;
			_progress.execute(this, 0.5);

			if (_parserOptions != null && _parserOptions.parser != null)
			{
				_parser = new (_parserOptions.parser)(_parserOptions);

				if (!_parser.isParsable(byteArray))
					throw new Error('Invalid datatype for this parser.');
			}
			else
			{
				// search a parser by testing registered parsers.
				var numRegisteredParser : uint = REGISTERED_PARSERS.length;
				for (var parserId : uint = 0; parserId < numRegisteredParser; ++parserId)
				{
					_parser = new REGISTERED_PARSERS[parserId](_parserOptions);
					byteArray.position = startPosition;
					if (_parser.isParsable(byteArray))
						break;
				}

				if (parserId == numRegisteredParser)
					throw new Error('No parser could be found for this datatype.');
			}

			byteArray.position = startPosition;

			_dependencies	 = _parser.getDependencies(byteArray);
			_numDependencies = 0;

			if (_dependencies != null)
				for each (var dependency : ILoader in _dependencies)
					if (!dependency.isComplete)
					{
						dependency.error.add(decrementDependencyCounter);
						dependency.complete.add(decrementDependencyCounter);

						_numDependencies++;
					}

			if (_numDependencies == 0)
				parse();
		}

		private function decrementDependencyCounter(...args) : void
		{
			--_numDependencies;

			if (_numDependencies == 0)
				parse();
		}

		private function parse() : void
		{
			_parser.error.add(parseErrorHandler);
			_parser.progress.add(parseProgressHandler);
			_parser.complete.add(parseCompleteHandler);
			_parser.parse();
		}

		private function parseErrorHandler(parser : IParser) : void
		{
			_isComplete = true;
		}

		private function parseProgressHandler(parser : IParser, progress : Number) : void
		{
			_progress.execute(this, 0.5 * (1 + progress));
		}

		private function parseCompleteHandler(parser : IParser, loadedData : ISceneNode) : void
		{
			_isComplete = true;
			_data = loadedData;

			// call later to make sure the loading is always seen as asynchronous
			setTimeout(callLaterComplete, 0, loadedData);
		}

		private function callLaterComplete(loadedData : ISceneNode) : void
		{
			_complete.execute(this, loadedData);
		}
	}
}

update SceneLoader.parseCompleteHandler() to use setTimeout() and enforce asynchronous-like signals even when loading/parsing is synchronous for the sake of consistency


import mx.events.EventDispatcher;
import mx.utils.Delegate;
import mx.transitions.easing.*;
import flash.filters.GlowFilter;
import com.mosesSupposes.fuse.*;

class com.segonquart.Entrar extends MovieClip
{
	public var click_mc:MovieClip;
	public var entrar_mc:MovieClip;
	public var down:MovieClip;
	public var ok_mc:MovieClip;
	public var v1, v2, v3, b1, b2:MovieClip;
	public var m01:MovieClip;
	public var m02:MovieClip;
	public var botiga_mc:MovieClip;
	public var marcMenu_mc:MovieClip;
	public var addEventListener:Function;
	public var removeEventListener:Function;
	public function Entrar ()
	{
		mx.events.EventDispatcher.initialize (this);
	}
	private function initAppFrame1 ()
	{
		var m= enter_mc;
		this.m = m;
		m.timeToEnter();
		this.onRollOver = this.eOver;
		this.onRollOut = this.eOut;
		this.onPress = this.ePress;

	}
	private function eOver (m:MovieClip)
	{
		click_mc.tintTo ("#4A8618", 100, "easeOutSine");
		m.scaleTo (110, 2, 'easeOutBounce');
		m.DropShadow_distanceTo (3, .9, "easeOutBounce");
		addEventListener (this, "onPress");
	}
	private function eOut (m:MovieClip)
	{
		click_mc.tintTo ("#FF0000", 100, "easeOutElastic");
		m.scaleTo (100, 1, 'easeInBack');
		m.DropShadow_distanceTo (0, 2, "easeOutBounce");
	}
	private function ePress (m:MovieClip)
	{
		m.Blur_blur = 0;
		m.Blur_blurXTo ('100', .25, 'easeOutSine', {cycles:1});
		m.alphaTo (0, 0.3, 'easeInOutQuint', .5);
		down.tintTo ("#DCEECA", 100, "easeOutSine", .3);
		v2.tintTo ("#95C60D", 100, "easeOutSine");
		marcMenu_mc.fadeIn ();
		titol_mcM.fadeOut () + 10000;
	}
	function timeToEnter (m:MovieClip)
	{
		var entrar:Number = getTimer () + 1500;
		m.onRelease = function ()
		{
			if (getTimer () > entrar)
			{
				nextFrame ();
			}
			else
			{
				delete this.onEnterFrame;
			}
		};
	}
}

import mx.events.EventDispatcher;
import mx.utils.Delegate;
import mx.transitions.easing.*;
import flash.filters.GlowFilter;
import com.mosesSupposes.fuse.*;

class com.segonquart.Entrar extends MovieClip
{
	public var click_mc:MovieClip;
	public var entrar_mc:MovieClip;
	public var down:MovieClip;
	public var ok_mc:MovieClip;
	public var v1, v2, v3, b1, b2:MovieClip;
	public var m01:MovieClip;
	public var m02:MovieClip;
	public var botiga_mc:MovieClip;
	public var marcMenu_mc:MovieClip;
	public var addEventListener:Function;
	public var removeEventListener:Function;
	public function Entrar ()
	{
		mx.events.EventDispatcher.initialize (this);
	}
	private function initAppFrame1 ()
	{
		var m= enter_mc;
		this.m = m;
		m.timeToEnter();
		this.onRollOver = this.eOver;
		this.onRollOut = this.eOut;
		this.onPress = this.ePress;

	}
	private function eOver (m:MovieClip)
	{
		click_mc.tintTo ("#4A8618", 100, "easeOutSine");
		m.scaleTo (110, 2, 'easeOutBounce');
		m.DropShadow_distanceTo (3, .9, "easeOutBounce");
		addEventListener (this, "onPress");
	}
	private function eOut (m:MovieClip)
	{
		click_mc.tintTo ("#FF0000", 100, "easeOutElastic");
		m.scaleTo (100, 1, 'easeInBack');
		m.DropShadow_distanceTo (0, 2, "easeOutBounce");
	}
	private function ePress (m:MovieClip)
	{
		m.Blur_blur = 0;
		m.Blur_blurXTo ('100', .25, 'easeOutSine', {cycles:1});
		m.alphaTo (0, 0.3, 'easeInOutQuint', .5);
		down.tintTo ("#DCEECA", 100, "easeOutSine", .3);
		v2.tintTo ("#95C60D", 100, "easeOutSine");
		marcMenu_mc.fadeIn ();
		titol_mcM.fadeOut () + 10000;
		removeEventListener (this, "onPress");
	}
      private function timeToEnter (m:MovieClip)
	{
		var entrar:Number = getTimer () + 1500;
		m.onRelease = function ()
		{
			if (getTimer () > entrar)
			{
				nextFrame ();
			}
			else
			{
				this.onEnterFrame = null;
			}
		};
	}
}

refactor v2

refactor v2


// Used by TemporalRenderer_FeatureCollection.mxml
package com.esri.ags.samples
{

import com.esri.ags.Graphic;
import com.esri.ags.Map;
import com.esri.ags.TimeExtent;
import com.esri.ags.components.TimeSlider;
import com.esri.ags.events.ExtentEvent;
import com.esri.ags.geometry.MapPoint;
import com.esri.ags.layers.FeatureLayer;
import com.esri.ags.utils.GraphicUtil;
import com.esri.ags.utils.WebMercatorUtil;

import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;

public class GPXFeed
{
    // constants
    private static const GPX_NS:Namespace = new Namespace("http://www.topografix.com/GPX/1/1");

    // constructor
    public function GPXFeed()
    {
        _loader = new URLLoader();
        _loader.addEventListener(Event.COMPLETE, loader_completeHandler);
        _loader.addEventListener(IOErrorEvent.IO_ERROR, loader_ioErrorHandler);
        _loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, loader_securityErrorHandler);
    }

    // variables
    private var _loader:URLLoader;

    // properties
    public var featureLayer:FeatureLayer;
    public var map:Map;
    public var timeSlider:TimeSlider; // optional
    public var url:String;

    // methods
    public function fetch():void
    {
        var request:URLRequest = new URLRequest();
        request.url = url;

        _loader.load(request);
    }

    private function parseDate(value:String):Date
    {
        // assume value is in the form 2009-07-15T14:13:35.000Z
        value = value.replace("T", " ");
        value = value.replace(/-/g, "/");
        value = value.replace(".000Z", " UTC");
        // value should now be in the form 2009/07/15 14:13:35 UTC
        return new Date(value);
    }

    // event handlers
    private function loader_completeHandler(event:Event):void
    {
        //trace(event);
        var gpxXML:XML = new XML(_loader.data);
        default xml namespace = GPX_NS;
        var trkpts:XMLList = gpxXML..trkpt;

        var timeExtent:TimeExtent = new TimeExtent();
        var features:Array = [];
        for each (var trkpt:XML in trkpts)
        {
            //trace(trkpt.@lon, trkpt.@lat, parseDate(trkpt.time).toUTCString());
            var point:MapPoint = new MapPoint(trkpt.@lon, trkpt.@lat);
            point = WebMercatorUtil.geographicToWebMercator(point) as MapPoint;
            var time:Date = parseDate(trkpt.time);
            var feature:Graphic = new Graphic(point, null, { "time": time });
            features.push(feature);
            // find startTime and endTime
            if (!timeExtent.startTime || timeExtent.startTime.time > time.time)
            {
                timeExtent.startTime = time;
            }
            if (!timeExtent.endTime || timeExtent.endTime.time < time.time)
            {
                timeExtent.endTime = time;
            }
        }

        if (features.length > 0)
        {
            featureLayer.applyEdits(features, null, null);

            map.addEventListener(ExtentEvent.EXTENT_CHANGE, map_extentChangeHandler);
            map.extent = GraphicUtil.getGraphicsExtent(features);

            function map_extentChangeHandler(event:ExtentEvent):void
            {
                map.removeEventListener(ExtentEvent.EXTENT_CHANGE, map_extentChangeHandler);
                if (timeExtent.startTime !== timeExtent.endTime)
                {
                    if (timeSlider)
                    {
                        timeSlider.createTimeStopsByCount(timeExtent, 15);
                    }
                    else
                    {
                        map.timeExtent = timeExtent;
                    }
                }
            }
        }
    }

    private function loader_ioErrorHandler(event:IOErrorEvent):void
    {
        trace(event);
    }

    private function loader_securityErrorHandler(event:SecurityErrorEvent):void
    {
        trace(event);
    }
}

}

// Used by TemporalRenderer_FeatureCollection.mxml
package com.esri.ags.samples
{

import com.esri.ags.Graphic;
import com.esri.ags.Map;
import com.esri.ags.TimeExtent;
import com.esri.ags.components.TimeSlider;
import com.esri.ags.events.ExtentEvent;
import com.esri.ags.geometry.MapPoint;
import com.esri.ags.layers.FeatureLayer;
import com.esri.ags.utils.GraphicUtil;
import com.esri.ags.utils.WebMercatorUtil;

import flash.events.Event;
import flash.events.HTTPStatusEvent;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;

import mx.controls.Alert;

public class GPXFeed
{
    // constants
    private static const GPX_NS:Namespace = new Namespace("http://www.topografix.com/GPX/1/1");

    // constructor
    public function GPXFeed()
    {
        _loader = new URLLoader();
        _loader.addEventListener(Event.COMPLETE, loader_completeHandler);
        _loader.addEventListener(IOErrorEvent.IO_ERROR, loader_ioErrorHandler);
        _loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, loader_securityErrorHandler);
        _loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, loader_httpStatusHandler);
    }

    // variables
    private var _loader:URLLoader;

    // properties
    public var featureLayer:FeatureLayer;
    public var map:Map;
    public var timeSlider:TimeSlider; // optional
    public var url:String;

    // methods
    public function fetch():void
    {
        var request:URLRequest = new URLRequest();
        request.url = url;

        _loader.load(request);
    }

    private function parseDate(value:String):Date
    {
        // assume value is in the form 2009-07-15T14:13:35.000Z
        value = value.replace("T", " ");
        value = value.replace(/-/g, "/");
        value = value.replace(".000Z", " UTC");
        // value should now be in the form 2009/07/15 14:13:35 UTC
        return new Date(value);
    }

    // event handlers
    private function loader_completeHandler(event:Event):void
    {
        //trace(event);
        var gpxXML:XML = new XML(_loader.data);
        default xml namespace = GPX_NS;
        var trkpts:XMLList = gpxXML..trkpt;

        var timeExtent:TimeExtent = new TimeExtent();
        var features:Array = [];
        for each (var trkpt:XML in trkpts)
        {
            //trace(trkpt.@lon, trkpt.@lat, parseDate(trkpt.time).toUTCString());
            var point:MapPoint = new MapPoint(trkpt.@lon, trkpt.@lat);
            point = WebMercatorUtil.geographicToWebMercator(point) as MapPoint;
            var time:Date = parseDate(trkpt.time);
            var feature:Graphic = new Graphic(point, null, { "time": time });
            features.push(feature);
            // find startTime and endTime
            if (!timeExtent.startTime || timeExtent.startTime.time > time.time)
            {
                timeExtent.startTime = time;
            }
            if (!timeExtent.endTime || timeExtent.endTime.time < time.time)
            {
                timeExtent.endTime = time;
            }
        }

        if (features.length > 0)
        {
            featureLayer.applyEdits(features, null, null);

            map.addEventListener(ExtentEvent.EXTENT_CHANGE, map_extentChangeHandler);
            map.extent = GraphicUtil.getGraphicsExtent(features);

            function map_extentChangeHandler(event:ExtentEvent):void
            {
                map.removeEventListener(ExtentEvent.EXTENT_CHANGE, map_extentChangeHandler);
                if (timeExtent.startTime !== timeExtent.endTime)
                {
                    if (timeSlider)
                    {
                        timeSlider.createTimeStopsByCount(timeExtent, 15);
                    }
                    else
                    {
                        map.timeExtent = timeExtent;
                    }
                }
            }
        }
    }

    private function loader_ioErrorHandler(event:IOErrorEvent):void
    {
        Alert.show(event.text, "Application IOError");
    }

    private function loader_securityErrorHandler(event:SecurityErrorEvent):void
    {
        Alert.show(event.text, "Application Security Error");
    }

    protected function loader_httpStatusHandler(event:HTTPStatusEvent):void
    {
        if (event.status == 404)
        {
            Alert.show("Unable to load the following resource \n" + url, "http error");
        }
    }
}

}

Add alert messages when errors occur loading the file resource.