package com.thedevstop.asfac
{
	import avmplus.getQualifiedClassName;
	import flash.errors.IllegalOperationError;
	import flash.utils.describeType;
	import flash.utils.Dictionary;
	import flash.utils.getDefinitionByName;

	/**
	 * The default AsFactory allows for registering instances, types, or callbacks
	 */
	public class AsFactory
	{
		private var _registrations:Dictionary;
		private var _descriptions:Dictionary;

		/**
		 * Constructs a new AsFactory
		 */
		public function AsFactory()
		{
			_registrations = new Dictionary();
			_descriptions = new Dictionary();
		}

		/**
		 * Registers a concrete instance to be returned whenever the target type is requested
		 * @param	instance the concrete instance to be returned
		 * @param	type the target type for which the instance should be returned at resolution time
		 */
		public function registerInstance(instance:Object, type:Class):void
		{
			var returnInstance:Function = function():Object
			{
				return instance;
			};

			registerCallback(returnInstance, type, false);
		}

		/**
		 * Registers a type to be returned whenever the target type is requested
		 * @param	instanceType the type to construct at resolution time
		 * @param	type the type being requested
		 * @param	asSingleton If true, only one instance will be created and returned on each request. If false (default), a new instance
		 * is created and returned at each resolution request
		 */
		public function registerType(instanceType:Class, type:Class, asSingleton:Boolean=false):void
		{
			if (!instanceType)
				throw new IllegalOperationError("InstanceType cannot be null when registering a type");

			var resolveType:Function = function():Object
			{
				return resolveByClass(instanceType);
			};

			registerCallback(resolveType, type, asSingleton);
		}

		/**
		 * Registers a callback to be executed, the result of which is returned whenever the target type is requested
		 * @param	callback the callback to execute
		 * @param	type the type being requested
		 * @param	asSingleton If true, callback is only invoked once and the result is returned on each request. If false (default),
		 * callback is invoked on each resolution request
		 */
		public function registerCallback(callback:Function, type:Class, asSingleton:Boolean=false):void
		{
			if (!type)
				throw new IllegalOperationError("Type cannot be null when registering a callback");

			if (callback == null)
				throw new IllegalOperationError("Callback cannot be null when registering a type");

			if (!isValid(callback))
				throw new IllegalOperationError("Callback function registered for {0} must have no arguments or a single AsFactory argument".replace("{0}", getQualifiedClassName(type)));

			if (asSingleton)
				_registrations[type] = (function(callback:Function):Function
				{
					var instance:Object = null;

					return function():Object
					{
						if (!instance)
							instance = callback(this);

						return instance;
					};
				})(callback);
			else
				_registrations[type] = callback;
		}

		/**
		 * Returns an instance for the target type, using prior registrations to fulfill constructor parameters
		 * @param	type the type being requested
		 * @return resolved instance
		 */
		public function resolve(type:Class):*
		{
			if (_registrations[type] !== undefined)
				return _registrations[type](this);

			return resolveByClass(type);
		}

		/**
		 * Resolves the desired type using prior registrations
		 * @param	type the type being requested
		 * @return the resolved instance
		 */
		private function resolveByClass(type:Class):*
		{
			if (!type)
				throw new IllegalOperationError("Type cannot be null when resolving.");

			var parameters:Array = [];
			var description:XML;

			if (_descriptions[type] !== undefined)
				description = _descriptions[type];
			else
				description = _descriptions[type] = describeType(type);

			var constructor:XMLList = description.factory.constructor;

			if (constructor.length() === 0)
				throw new IllegalOperationError("Interface {0} must be registered before it can be resolved.".replace("{0}", description.@name.toString()));

			for each (var parameter:XML in constructor.parameter)
			{
				if (parameter.@optional.toString() != "false")
					break;

				var parameterType:Class = Class(getDefinitionByName(parameter.@type.toString()));
				parameters.push(resolve(parameterType));
			}
			return createObject(type, parameters);
		}

		/**
		 * Creates a new instance of the type, using the specified parameters as the constructor parameters
		 * @param	type the type being created
		 * @param	parameters the parameters to supply to the constructor
		 * @return new instance of type
		 */
		private function createObject(type:Class, parameters:Array):*
		{
			switch (parameters.length)
			{
				case 0 : return new type();
				case 1 : return new type(parameters[0]);
				case 2 : return new type(parameters[0], parameters[1]);
				case 3 : return new type(parameters[0], parameters[1], parameters[2]);
				case 4 : return new type(parameters[0], parameters[1], parameters[2], parameters[3]);
				case 5 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4]);
				case 6 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5]);
				case 7 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6]);
				case 8 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7]);
				case 9 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8]);
				case 10 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9]);
				case 11 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9], parameters[10]);
				case 12 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9], parameters[10], parameters[11]);
				case 13 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9], parameters[10], parameters[11], parameters[12]);
				case 14 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9], parameters[10], parameters[11], parameters[12], parameters[13]);
				case 15 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9], parameters[10], parameters[11], parameters[12], parameters[13], parameters[14]);
				default : throw new Error("Too many constructor parameters for createObject");
			}
		}

		/**
		 * Confirms that a callback is valid for registration. Currently the callback must accept no arguments, or a single AsFactory argument
		 * @param	callback the callback being tested
		 */
		private function isValid(callback:Function):Boolean
		{
			// TODO: How to check type?
			return callback.length < 2;
		}
	}
}

package com.thedevstop.asfac
{
	import avmplus.getQualifiedClassName;
	import flash.errors.IllegalOperationError;
	import flash.utils.describeType;
	import flash.utils.Dictionary;
	import flash.utils.getDefinitionByName;

	/**
	 * The default AsFactory allows for registering instances, types, or callbacks
	 */
	public class AsFactory
	{
		private var _registrations:Dictionary;
		private var _descriptions:Dictionary;

		/**
		 * Constructs a new AsFactory
		 */
		public function AsFactory()
		{
			_registrations = new Dictionary();
			_descriptions = new Dictionary();
		}

		/**
		 * Registers a concrete instance to be returned whenever the target type is requested
		 * @param	instance the concrete instance to be returned
		 * @param	type the target type for which the instance should be returned at resolution time
		 */
		public function registerInstance(instance:Object, type:Class):void
		{
			var returnInstance:Function = function():Object
			{
				return instance;
			};

			registerCallback(returnInstance, type, false);
		}

		/**
		 * Registers a type to be returned whenever the target type is requested
		 * @param	instanceType the type to construct at resolution time
		 * @param	type the type being requested
		 * @param	asSingleton If true, only one instance will be created and returned on each request. If false (default), a new instance
		 * is created and returned at each resolution request
		 */
		public function registerType(instanceType:Class, type:Class, asSingleton:Boolean=false):void
		{
			if (!instanceType)
				throw new IllegalOperationError("InstanceType cannot be null when registering a type");

			var resolveType:Function = function():Object
			{
				return resolveByClass(instanceType);
			};

			registerCallback(resolveType, type, asSingleton);
		}

		/**
		 * Registers a callback to be executed, the result of which is returned whenever the target type is requested
		 * @param	callback the callback to execute
		 * @param	type the type being requested
		 * @param	asSingleton If true, callback is only invoked once and the result is returned on each request. If false (default),
		 * callback is invoked on each resolution request
		 */
		public function registerCallback(callback:Function, type:Class, asSingleton:Boolean=false):void
		{
			if (!type)
				throw new IllegalOperationError("Type cannot be null when registering a callback");

			validateCallback(callback);

			if (asSingleton)
				_registrations[type] = (function(callback:Function):Function
				{
					var instance:Object = null;

					return function():Object
					{
						if (!instance)
							instance = callback(this);

						return instance;
					};
				})(callback);
			else
				_registrations[type] = callback;
		}

		/**
		 * Returns an instance for the target type, using prior registrations to fulfill constructor parameters
		 * @param	type the type being requested
		 * @return resolved instance
		 */
		public function resolve(type:Class):*
		{
			if (_registrations[type] !== undefined)
				return _registrations[type](this);

			return resolveByClass(type);
		}

		/**
		 * Resolves the desired type using prior registrations
		 * @param	type the type being requested
		 * @return the resolved instance
		 */
		private function resolveByClass(type:Class):*
		{
			if (!type)
				throw new IllegalOperationError("Type cannot be null when resolving.");

			var parameters:Array = [];
			var description:XML;

			if (_descriptions[type] !== undefined)
				description = _descriptions[type];
			else
				description = _descriptions[type] = describeType(type);

			var constructor:XMLList = description.factory.constructor;

			if (constructor.length() === 0)
				throw new IllegalOperationError("Interface {0} must be registered before it can be resolved.".replace("{0}", description.@name.toString()));

			for each (var parameter:XML in constructor.parameter)
			{
				if (parameter.@optional.toString() != "false")
					break;

				var parameterType:Class = Class(getDefinitionByName(parameter.@type.toString()));
				parameters.push(resolve(parameterType));
			}
			return createObject(type, parameters);
		}

		/**
		 * Creates a new instance of the type, using the specified parameters as the constructor parameters
		 * @param	type the type being created
		 * @param	parameters the parameters to supply to the constructor
		 * @return new instance of type
		 */
		private function createObject(type:Class, parameters:Array):*
		{
			switch (parameters.length)
			{
				case 0 : return new type();
				case 1 : return new type(parameters[0]);
				case 2 : return new type(parameters[0], parameters[1]);
				case 3 : return new type(parameters[0], parameters[1], parameters[2]);
				case 4 : return new type(parameters[0], parameters[1], parameters[2], parameters[3]);
				case 5 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4]);
				case 6 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5]);
				case 7 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6]);
				case 8 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7]);
				case 9 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8]);
				case 10 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9]);
				case 11 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9], parameters[10]);
				case 12 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9], parameters[10], parameters[11]);
				case 13 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9], parameters[10], parameters[11], parameters[12]);
				case 14 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9], parameters[10], parameters[11], parameters[12], parameters[13]);
				case 15 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9], parameters[10], parameters[11], parameters[12], parameters[13], parameters[14]);
				default : throw new Error("Too many constructor parameters for createObject");
			}
		}

		/**
		 * Confirms that a callback is valid for registration. Currently the callback must accept no arguments, or a single AsFactory argument
		 * @param	callback the callback being tested
		 */
		private function validateCallback(callback:Function):void
		{
			if (callback == null)
				throw new IllegalOperationError("Callback cannot be null when registering a type");

			// TODO: How to check type?
			if (callback.length > 1)
				throw new IllegalOperationError("Callback function must have no arguments or a single AsFactory argument");
		}
	}
}

Refactor callback checks to validateCallback


/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mangui.hls {

    import flash.display.Stage;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.net.NetConnection;
    import flash.net.NetStream;
    import flash.net.URLLoader;
    import flash.net.URLStream;
    import org.mangui.hls.controller.AudioTrackController;
    import org.mangui.hls.controller.LevelController;
    import org.mangui.hls.event.HLSEvent;
    import org.mangui.hls.loader.AltAudioLevelLoader;
    import org.mangui.hls.loader.LevelLoader;
    import org.mangui.hls.model.AudioTrack;
    import org.mangui.hls.model.Level;
    import org.mangui.hls.playlist.AltAudioTrack;
    import org.mangui.hls.stream.HLSNetStream;
    import org.mangui.hls.stream.StreamBuffer;

    CONFIG::LOGGING {
        import org.mangui.hls.utils.Log;
    }
    /** Class that manages the streaming process. **/
    public class HLS extends EventDispatcher {
        private var _levelLoader : LevelLoader;
        private var _altAudioLevelLoader : AltAudioLevelLoader;
        private var _audioTrackController : AudioTrackController;
        private var _levelController : LevelController;
        private var _streamBuffer : StreamBuffer;
        /** HLS NetStream **/
        private var _hlsNetStream : HLSNetStream;
        /** HLS URLStream/URLLoader **/
        private var _hlsURLStream : Class;
        private var _hlsURLLoader : Class;
        private var _client : Object = {};
        private var _stage : Stage;
        /* level handling */
        private var _level : int;
        /* overrided quality_manual_level level */
        private var _manual_level : int = -1;

        /** Create and connect all components. **/
        public function HLS() {
            var connection : NetConnection = new NetConnection();
            connection.connect(null);
            _levelLoader = new LevelLoader(this);
            _altAudioLevelLoader = new AltAudioLevelLoader(this);
            _audioTrackController = new AudioTrackController(this);
            _levelController = new LevelController(this);
            _streamBuffer = new StreamBuffer(this, _audioTrackController, _levelController);
            _hlsURLStream = URLStream as Class;
            _hlsURLLoader = URLLoader as Class;
            // default loader
            _hlsNetStream = new HLSNetStream(connection, this, _streamBuffer);
            this.addEventListener(HLSEvent.LEVEL_SWITCH, _levelSwitchHandler);
        };

        /** Forward internal errors. **/
        override public function dispatchEvent(event : Event) : Boolean {
            if (event.type == HLSEvent.ERROR) {
                CONFIG::LOGGING {
                    Log.error((event as HLSEvent).error);
                }
                _hlsNetStream.close();
            }
            return super.dispatchEvent(event);
        };

        private function _levelSwitchHandler(event : HLSEvent) : void {
            _level = event.level;
        };

        public function dispose() : void {
            this.removeEventListener(HLSEvent.LEVEL_SWITCH, _levelSwitchHandler);
            _levelLoader.dispose();
            _altAudioLevelLoader.dispose();
            _audioTrackController.dispose();
            _levelController.dispose();
            _hlsNetStream.dispose_();
            _streamBuffer.dispose();
            _levelLoader = null;
            _altAudioLevelLoader = null;
            _audioTrackController = null;
            _levelController = null;
            _hlsNetStream = null;
            _client = null;
            _stage = null;
            _hlsNetStream = null;
        }

        /** Return index of first quality level referenced in Manifest  **/
        public function get firstlevel() : int {
            return _levelController.firstlevel;
        };

        /** Return the quality level used when starting a fresh playback **/
        public function get startlevel() : int {
            return _levelController.startlevel;
        };

        /** Return the quality level used after a seek operation **/
        public function get seeklevel() : int {
            return _levelController.seeklevel;
        };

        /** Return the quality level of the currently played fragment **/
        public function get playbacklevel() : int {
            return _hlsNetStream.playbackLevel;
        };

        /** Return the quality level of last loaded fragment **/
        public function get level() : int {
            return _level;
        };

        /*  set quality level for next loaded fragment (-1 for automatic level selection) */
        public function set level(level : int) : void {
            _manual_level = level;
        };

        /* check if we are in automatic level selection mode */
        public function get autolevel() : Boolean {
            return (_manual_level == -1);
        };

        /* return manual level */
        public function get manuallevel() : int {
            return _manual_level;
        };

        /** Return a Vector of quality level **/
        public function get levels() : Vector.<Level> {
            return _levelLoader.levels;
        };

        /** Return the current playback position. **/
        public function get position() : Number {
            return _streamBuffer.position;
        };

        /** Return the current playback state. **/
        public function get playbackState() : String {
            return _hlsNetStream.playbackState;
        };

        /** Return the current seek state. **/
        public function get seekState() : String {
            return _hlsNetStream.seekState;
        };

        /** Return the type of stream (VOD/LIVE). **/
        public function get type() : String {
            return _levelLoader.type;
        };

        /** Load and parse a new HLS URL **/
        public function load(url : String) : void {
            _hlsNetStream.close();
            _levelLoader.load(url);
        };

        /** return HLS NetStream **/
        public function get stream() : NetStream {
            return _hlsNetStream;
        }

        public function get client() : Object {
            return _client;
        }

        public function set client(value : Object) : void {
            _client = value;
        }

        /** get current Buffer Length  **/
        public function get bufferLength() : Number {
            return _hlsNetStream.bufferLength;
        };

        /** get current back buffer Length  **/
        public function get backBufferLength() : Number {
            return _hlsNetStream.backBufferLength;
        };

        /** get audio tracks list**/
        public function get audioTracks() : Vector.<AudioTrack> {
            return _audioTrackController.audioTracks;
        };

        /** get alternate audio tracks list from playlist **/
        public function get altAudioTracks() : Vector.<AltAudioTrack> {
            return _levelLoader.altAudioTracks;
        };

        /** get index of the selected audio track (index in audio track lists) **/
        public function get audioTrack() : int {
            return _audioTrackController.audioTrack;
        };

        /** select an audio track, based on its index in audio track lists**/
        public function set audioTrack(val : int) : void {
            _audioTrackController.audioTrack = val;
        }

        /* set stage */
        public function set stage(stage : Stage) : void {
            _stage = stage;
        }

        /* get stage */
        public function get stage() : Stage {
            return _stage;
        }

        /* set URL stream loader */
        public function set URLstream(urlstream : Class) : void {
            _hlsURLStream = urlstream;
        }

        /* retrieve URL stream loader */
        public function get URLstream() : Class {
            return _hlsURLStream;
        }

        /* set URL stream loader */
        public function set URLloader(urlloader : Class) : void {
            _hlsURLLoader = urlloader;
        }

        /* retrieve URL stream loader */
        public function get URLloader() : Class {
            return _hlsURLLoader;
        }
    }
}

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mangui.hls {

    import flash.display.Stage;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.net.NetConnection;
    import flash.net.NetStream;
    import flash.net.URLLoader;
    import flash.net.URLStream;
    import org.mangui.hls.controller.AudioTrackController;
    import org.mangui.hls.controller.LevelController;
    import org.mangui.hls.event.HLSEvent;
    import org.mangui.hls.loader.AltAudioLevelLoader;
    import org.mangui.hls.loader.LevelLoader;
    import org.mangui.hls.model.AudioTrack;
    import org.mangui.hls.model.Level;
    import org.mangui.hls.playlist.AltAudioTrack;
    import org.mangui.hls.stream.HLSNetStream;
    import org.mangui.hls.stream.StreamBuffer;

    CONFIG::LOGGING {
        import org.mangui.hls.utils.Log;
    }
    /** Class that manages the streaming process. **/
    public class HLS extends EventDispatcher {
        private var _levelLoader : LevelLoader;
        private var _altAudioLevelLoader : AltAudioLevelLoader;
        private var _audioTrackController : AudioTrackController;
        private var _levelController : LevelController;
        private var _streamBuffer : StreamBuffer;
        /** HLS NetStream **/
        private var _hlsNetStream : HLSNetStream;
        /** HLS URLStream/URLLoader **/
        private var _hlsURLStream : Class;
        private var _hlsURLLoader : Class;
        private var _client : Object = {};
        private var _stage : Stage;
        /* level handling */
        private var _level : int;
        /* overrided quality_manual_level level */
        private var _manual_level : int = -1;

        /** Create and connect all components. **/
        public function HLS() {
            var connection : NetConnection = new NetConnection();
            connection.connect(null);
            _levelLoader = new LevelLoader(this);
            _altAudioLevelLoader = new AltAudioLevelLoader(this);
            _audioTrackController = new AudioTrackController(this);
            _levelController = new LevelController(this);
            _streamBuffer = new StreamBuffer(this, _audioTrackController, _levelController);
            _hlsURLStream = URLStream as Class;
            _hlsURLLoader = URLLoader as Class;
            // default loader
            _hlsNetStream = new HLSNetStream(connection, this, _streamBuffer);
            this.addEventListener(HLSEvent.LEVEL_SWITCH, _levelSwitchHandler);
        };

        /** Forward internal errors. **/
        override public function dispatchEvent(event : Event) : Boolean {
            if (event.type == HLSEvent.ERROR) {
                CONFIG::LOGGING {
                    Log.error((event as HLSEvent).error);
                }
                _hlsNetStream.close();
            }
            return super.dispatchEvent(event);
        };

        private function _levelSwitchHandler(event : HLSEvent) : void {
            _level = event.level;
        };

        public function dispose() : void {
            this.removeEventListener(HLSEvent.LEVEL_SWITCH, _levelSwitchHandler);
            _levelLoader.dispose();
            _altAudioLevelLoader.dispose();
            _audioTrackController.dispose();
            _levelController.dispose();
            _hlsNetStream.dispose_();
            _streamBuffer.dispose();
            _levelLoader = null;
            _altAudioLevelLoader = null;
            _audioTrackController = null;
            _levelController = null;
            _hlsNetStream = null;
            _client = null;
            _stage = null;
            _hlsNetStream = null;
        }

        /** Return index of first quality level referenced in Manifest  **/
        public function get firstlevel() : int {
            return _levelController.firstlevel;
        };

        /** Return the quality level used when starting a fresh playback **/
        public function get startlevel() : int {
            return _levelController.startlevel;
        };

        /** Return the quality level used after a seek operation **/
        public function get seeklevel() : int {
            return _levelController.seeklevel;
        };

        /** Return the quality level of the currently played fragment **/
        public function get playbacklevel() : int {
            return _hlsNetStream.playbackLevel;
        };

        /** Return the quality level of last loaded fragment **/
        public function get level() : int {
            return _level;
        };

        /*  set quality level for next loaded fragment (-1 for automatic level selection) */
        public function set level(level : int) : void {
            _manual_level = level;
        };

        /* check if we are in automatic level selection mode */
        public function get autolevel() : Boolean {
            return (_manual_level == -1);
        };

        /* return manual level */
        public function get manuallevel() : int {
            return _manual_level;
        };

        /** Return a Vector of quality level **/
        public function get levels() : Vector.<Level> {
            return _levelLoader.levels;
        };

        /** Return the current playback position. **/
        public function get position() : Number {
            return _streamBuffer.position;
        };

        /** Return the current playback state. **/
        public function get playbackState() : String {
            return _hlsNetStream.playbackState;
        };

        /** Return the current seek state. **/
        public function get seekState() : String {
            return _hlsNetStream.seekState;
        };

        /** Return the type of stream (VOD/LIVE). **/
        public function get type() : String {
            return _levelLoader.type;
        };

        /** Load and parse a new HLS URL **/
        public function load(url : String) : void {
            _level = 0;
            _hlsNetStream.close();
            _levelLoader.load(url);
        };

        /** return HLS NetStream **/
        public function get stream() : NetStream {
            return _hlsNetStream;
        }

        public function get client() : Object {
            return _client;
        }

        public function set client(value : Object) : void {
            _client = value;
        }

        /** get current Buffer Length  **/
        public function get bufferLength() : Number {
            return _hlsNetStream.bufferLength;
        };

        /** get current back buffer Length  **/
        public function get backBufferLength() : Number {
            return _hlsNetStream.backBufferLength;
        };

        /** get audio tracks list**/
        public function get audioTracks() : Vector.<AudioTrack> {
            return _audioTrackController.audioTracks;
        };

        /** get alternate audio tracks list from playlist **/
        public function get altAudioTracks() : Vector.<AltAudioTrack> {
            return _levelLoader.altAudioTracks;
        };

        /** get index of the selected audio track (index in audio track lists) **/
        public function get audioTrack() : int {
            return _audioTrackController.audioTrack;
        };

        /** select an audio track, based on its index in audio track lists**/
        public function set audioTrack(val : int) : void {
            _audioTrackController.audioTrack = val;
        }

        /* set stage */
        public function set stage(stage : Stage) : void {
            _stage = stage;
        }

        /* get stage */
        public function get stage() : Stage {
            return _stage;
        }

        /* set URL stream loader */
        public function set URLstream(urlstream : Class) : void {
            _hlsURLStream = urlstream;
        }

        /* retrieve URL stream loader */
        public function get URLstream() : Class {
            return _hlsURLStream;
        }

        /* set URL stream loader */
        public function set URLloader(urlloader : Class) : void {
            _hlsURLLoader = urlloader;
        }

        /* retrieve URL stream loader */
        public function get URLloader() : Class {
            return _hlsURLLoader;
        }
    }
}

reset level upon hls.load(url)

reset level upon hls.load(url)


package aerys.minko.type.math
{
	import aerys.minko.ns.minko_math;
	import aerys.minko.type.Factory;
	import aerys.minko.type.Signal;
	import aerys.minko.type.binding.IWatchable;

	import flash.geom.Vector3D;

	public class Vector4 implements IWatchable
	{
		use namespace minko_math;

		public static const X_AXIS				: Vector4	= new Vector4(1., 0., 0.);
		public static const Y_AXIS				: Vector4	= new Vector4(0., 1., 0.);
		public static const Z_AXIS				: Vector4	= new Vector4(0., 0., 1.);
		public static const ZERO				: Vector4	= new Vector4(0., 0., 0., 0.);
		public static const ONE					: Vector4	= new Vector4(1., 1., 1., 1.);
		public static const FORWARD				: Vector4	= Z_AXIS;
		public static const BACKWARD			: Vector4	= new Vector4(0., 0., -1.);
		public static const LEFT				: Vector4	= new Vector4(-1, 0., 0.);
		public static const RIGHT				: Vector4	= new Vector4(1, 0., 0.);
		public static const UP					: Vector4	= Y_AXIS;
		public static const DOWN				: Vector4	= new Vector4(0, -1., 0.);

		private static const FACTORY			: Factory	= Factory.getFactory(Vector4);

		private static const UPDATE_NONE		: uint		= 0;
		private static const UPDATE_LENGTH		: uint		= 1;
		private static const UPDATE_LENGTH_SQ	: uint		= 2;
		private static const UPDATE_ALL			: uint		= UPDATE_LENGTH | UPDATE_LENGTH_SQ;

		private static const DATA_DESCRIPTOR	: Object	= {
			'x'	: 'x',
			'y'	: 'y',
			'z'	: 'z',
			'w'	: 'w'
		}

		minko_math var _vector	: Vector3D	= new Vector3D();

		private var _update		: uint		= 0;

		private var _length		: Number	= 0.;
		private var _lengthSq	: Number	= 0.;

		private var _locked		: Boolean	= false;
		private var _changed	: Signal	= new Signal('Vector4.changed');

		public function get x()	: Number
		{
			return _vector.x;
		}
		public function set x(value : Number) : void
		{
			if (value != _vector.x)
			{
				_vector.x = value;
				_update = UPDATE_ALL;

				if (!_locked)
					_changed.execute(this);
			}
		}

		public function get y()	: Number
		{
			return _vector.y;
		}
		public function set y(value : Number) : void
		{
			if (value != _vector.y)
			{
				_vector.y = value;
				_update = UPDATE_ALL;

				if (!_locked)
					_changed.execute(this);
			}
		}

		public function get z() : Number
		{
			return _vector.z;
		}
		public function set z(value : Number) : void
		{
			if (value != _vector.z)
			{
				_vector.z = value;
				_update = UPDATE_ALL;

				if (!_locked)
					_changed.execute(this);
			}
		}

		public function get w()	: Number
		{
			return _vector.w;
		}
		public function set w(value : Number) : void
		{
			if (value != _vector.w)
			{
				_vector.w = value;
				_update = UPDATE_ALL;

				if (!_locked)
					_changed.execute(this);
			}
		}

		public function get lengthSquared()	: Number
		{
			if (_update & UPDATE_LENGTH_SQ)
			{
				_update ^= UPDATE_LENGTH_SQ;
				_lengthSq = _vector.x * _vector.x + _vector.y * _vector.y
							+ _vector.z * _vector.z;
			}

			return _lengthSq;
		}

		public function get length() : Number
		{
			if (_update & UPDATE_LENGTH)
			{
				_update ^= UPDATE_LENGTH;
				_length = Math.sqrt(lengthSquared);
			}

			return _length;
		}

		public function get locked() : Boolean
		{
			return _locked;
		}

		public function get changed() : Signal
		{
			return _changed;
		}

		public function Vector4(x 	: Number	= 0.,
								y	: Number	= 0.,
								z	: Number	= 0.,
								w 	: Number	= 1)
		{
			_vector.x = x;
			_vector.y = y;
			_vector.z = z;
			_vector.w = w;

			_update = UPDATE_ALL;
		}

		public static function add(u 	: Vector4,
								   v 	: Vector4,
								   out	: Vector4 = null) : Vector4
		{
			out = copy(u, out);

			return out.incrementBy(v);
		}

		public static function subtract(u 	: Vector4,
										v 	: Vector4,
										out : Vector4 = null) : Vector4
		{
			out = copy(u, out);

			return out.decrementBy(v);
		}

		public static function dotProduct(u : Vector4, v : Vector4) : Number
		{
			return u._vector.dotProduct(v._vector);
		}

		public static function crossProduct(u : Vector4, v : Vector4) : Vector4
		{
			return new Vector4(
				u._vector.y * v._vector.z - v._vector.y * u._vector.z,
				u._vector.z * v._vector.x - v._vector.z * u._vector.x,
				u._vector.x * v._vector.y - v._vector.x * u._vector.y
			);
		}

		public function compareTo(v : Vector4, allFour : Boolean = false) : Boolean
		{
			return _vector.x == v._vector.x
				   && _vector.y == v._vector.y
				   && _vector.z == v._vector.z
				   && (!allFour || (_vector.w == v._vector.w));
		}

		public static function distance(u : Vector4, v : Vector4) : Number
		{
			return Vector3D.distance(u._vector, v._vector);
		}

		public static function copy(source : Vector4, target : Vector4 = null) : Vector4
		{
			target ||= FACTORY.create() as Vector4;
			target.set(source.x, source.y, source.z, source.w);

			return target;
		}

		public function incrementBy(vector : Vector4) : Vector4
		{
			_vector.incrementBy(vector._vector);

			_update = UPDATE_ALL;
			_changed.execute(this);

			return this;
		}

		public function decrementBy(vector : Vector4) : Vector4
		{
			_vector.decrementBy(vector._vector);

			_update = UPDATE_ALL;
			_changed.execute(this);

			return this;
		}

		public function scaleBy(scale : Number) : Vector4
		{
			_vector.scaleBy(scale);

			_update = UPDATE_ALL;
			_changed.execute(this);

			return this;
		}

		public function project() : Vector4
		{
			_vector.x /= _vector.w;
			_vector.y /= _vector.w;
			_vector.z /= _vector.w;

			_update = UPDATE_ALL;
			_changed.execute(this);

			return this;
		}

		public function normalize() : Vector4
		{
			var l : Number = length;

			if (l != 0.)
			{
				_vector.x /= l;
				_vector.y /= l;
				_vector.z /= l;

				_length = 1.;
				_lengthSq = 1.;

				_update = UPDATE_NONE;
				_changed.execute(this);
			}

			return this;
		}

		public function crossProduct(vector : Vector4) : Vector4
		{
			var x : Number = _vector.x;
			var y : Number = _vector.y;
			var z : Number = _vector.z;

			_vector.x = y * vector._vector.z - vector._vector.y * z;
			_vector.y = z * vector._vector.x - vector._vector.z * x;
			_vector.z = x * vector._vector.y - vector._vector.x * y;

			_update = UPDATE_ALL;
			_changed.execute(this);

			return this;
		}

		public function getVector3D() : Vector3D
		{
			return _vector.clone();
		}

		public function set(x : Number,
							y : Number,
							z : Number,
							w : Number = 1.) : Vector4
		{
			if (x != _vector.x || y != _vector.y || z != _vector.z || w != _vector.w)
			{
				_vector.x = x;
				_vector.y = y;
				_vector.z = z;
				_vector.w = w;

				_update = UPDATE_ALL;
				if (!_locked)
					_changed.execute(this);
			}

			return this;
		}

		public function toString() : String
		{
			return "(" + _vector.x + ", " + _vector.y + ", " + _vector.z + ", "
				   + _vector.w + ")";
		}

		public static function scale(v : Vector4, s : Number, out : Vector4 = null) : Vector4
		{
			out ||= FACTORY.create() as Vector4;
			out._vector.x = v._vector.x;
			out._vector.y = v._vector.y;
			out._vector.z = v._vector.z;
			out._vector.w = v._vector.w;

			return out;
		}

		public function toVector3D(out : Vector3D = null) : Vector3D
		{
			if (!out)
				return _vector.clone();

			out.x = _vector.x;
			out.y = _vector.y;
			out.z = _vector.z;
			out.w = _vector.w;

			return out;
		}

		public static function normalize(v : Vector4, out : Vector4 = null) : Vector4
		{
			out = copy(v, out);

			return out.normalize();
		}

		public function lock() : void
		{
			_locked = true;
		}

		public function unlock() : void
		{
			_locked = false;
			_changed.execute(this);
		}

		public function clone() : Vector4
		{
			return new Vector4(_vector.x, _vector.y, _vector.z, _vector.w);
		}
	}
}

package aerys.minko.type.math
{
	import aerys.minko.ns.minko_math;
	import aerys.minko.type.Factory;
	import aerys.minko.type.Signal;
	import aerys.minko.type.binding.IWatchable;

	import flash.geom.Vector3D;

	public class Vector4 implements IWatchable
	{
		use namespace minko_math;

		public static const X_AXIS				: Vector4	= new Vector4(1., 0., 0.);
		public static const Y_AXIS				: Vector4	= new Vector4(0., 1., 0.);
		public static const Z_AXIS				: Vector4	= new Vector4(0., 0., 1.);
		public static const ZERO				: Vector4	= new Vector4(0., 0., 0., 0.);
		public static const ONE					: Vector4	= new Vector4(1., 1., 1., 1.);
		public static const FORWARD				: Vector4	= Z_AXIS;
		public static const BACKWARD			: Vector4	= new Vector4(0., 0., -1.);
		public static const LEFT				: Vector4	= new Vector4(-1, 0., 0.);
		public static const RIGHT				: Vector4	= new Vector4(1, 0., 0.);
		public static const UP					: Vector4	= Y_AXIS;
		public static const DOWN				: Vector4	= new Vector4(0, -1., 0.);

		private static const FACTORY			: Factory	= Factory.getFactory(Vector4);

		private static const UPDATE_NONE		: uint		= 0;
		private static const UPDATE_LENGTH		: uint		= 1;
		private static const UPDATE_LENGTH_SQ	: uint		= 2;
		private static const UPDATE_ALL			: uint		= 3; // UPDATE_LENGTH | UPDATE_LENGTH_SQ;

		private static const DATA_DESCRIPTOR	: Object	= {
			'x'	: 'x',
			'y'	: 'y',
			'z'	: 'z',
			'w'	: 'w'
		}

		minko_math var _vector	: Vector3D	= new Vector3D();

		private var _update		: uint		= 0;

		private var _length		: Number	= 0.;
		private var _lengthSq	: Number	= 0.;

		private var _locked		: Boolean	= false;
		private var _changed	: Signal	= new Signal('Vector4.changed');

		public function get x()	: Number
		{
			return _vector.x;
		}
		public function set x(value : Number) : void
		{
			if (value != _vector.x)
			{
				_vector.x = value;
				_update = UPDATE_ALL;

				if (!_locked)
					_changed.execute(this);
			}
		}

		public function get y()	: Number
		{
			return _vector.y;
		}
		public function set y(value : Number) : void
		{
			if (value != _vector.y)
			{
				_vector.y = value;
				_update = UPDATE_ALL;

				if (!_locked)
					_changed.execute(this);
			}
		}

		public function get z() : Number
		{
			return _vector.z;
		}
		public function set z(value : Number) : void
		{
			if (value != _vector.z)
			{
				_vector.z = value;
				_update = UPDATE_ALL;

				if (!_locked)
					_changed.execute(this);
			}
		}

		public function get w()	: Number
		{
			return _vector.w;
		}
		public function set w(value : Number) : void
		{
			if (value != _vector.w)
			{
				_vector.w = value;
				_update = UPDATE_ALL;

				if (!_locked)
					_changed.execute(this);
			}
		}

		public function get lengthSquared()	: Number
		{
			if (_update & UPDATE_LENGTH_SQ)
			{
				_update ^= UPDATE_LENGTH_SQ;
				_lengthSq = _vector.x * _vector.x + _vector.y * _vector.y
							+ _vector.z * _vector.z;
			}

			return _lengthSq;
		}

		public function get length() : Number
		{
			if (_update & UPDATE_LENGTH)
			{
				_update ^= UPDATE_LENGTH;
				_length = Math.sqrt(lengthSquared);
			}

			return _length;
		}

		public function get locked() : Boolean
		{
			return _locked;
		}

		public function get changed() : Signal
		{
			return _changed;
		}

		public function Vector4(x 	: Number	= 0.,
								y	: Number	= 0.,
								z	: Number	= 0.,
								w 	: Number	= 1.)
		{
			_vector.x = x;
			_vector.y = y;
			_vector.z = z;
			_vector.w = w;

			_update = UPDATE_ALL;
		}

		public static function add(u 	: Vector4,
								   v 	: Vector4,
								   out	: Vector4 = null) : Vector4
		{
			out = copy(u, out);

			return out.incrementBy(v);
		}

		public static function subtract(u 	: Vector4,
										v 	: Vector4,
										out : Vector4 = null) : Vector4
		{
			out = copy(u, out);

			return out.decrementBy(v);
		}

		public static function dotProduct(u : Vector4, v : Vector4) : Number
		{
			return u._vector.dotProduct(v._vector);
		}

		public static function crossProduct(u : Vector4, v : Vector4) : Vector4
		{
			return new Vector4(
				u._vector.y * v._vector.z - v._vector.y * u._vector.z,
				u._vector.z * v._vector.x - v._vector.z * u._vector.x,
				u._vector.x * v._vector.y - v._vector.x * u._vector.y
			);
		}

		public function compareTo(v : Vector4, allFour : Boolean = false) : Boolean
		{
			return _vector.x == v._vector.x
				   && _vector.y == v._vector.y
				   && _vector.z == v._vector.z
				   && (!allFour || (_vector.w == v._vector.w));
		}

		public static function distance(u : Vector4, v : Vector4) : Number
		{
			return Vector3D.distance(u._vector, v._vector);
		}

		public static function copy(source : Vector4, target : Vector4 = null) : Vector4
		{
			target ||= FACTORY.create() as Vector4;
			target.set(source.x, source.y, source.z, source.w);

			return target;
		}

		public function incrementBy(vector : Vector4) : Vector4
		{
			_vector.incrementBy(vector._vector);

			_update = UPDATE_ALL;
			_changed.execute(this);

			return this;
		}

		public function decrementBy(vector : Vector4) : Vector4
		{
			_vector.decrementBy(vector._vector);

			_update = UPDATE_ALL;
			_changed.execute(this);

			return this;
		}

		public function scaleBy(scale : Number) : Vector4
		{
			_vector.scaleBy(scale);

			_update = UPDATE_ALL;
			_changed.execute(this);

			return this;
		}

		public function project() : Vector4
		{
			_vector.x /= _vector.w;
			_vector.y /= _vector.w;
			_vector.z /= _vector.w;

			_update = UPDATE_ALL;
			_changed.execute(this);

			return this;
		}

		public function normalize() : Vector4
		{
			var l : Number = length;

			if (l != 0.)
			{
				_vector.x /= l;
				_vector.y /= l;
				_vector.z /= l;

				_length = 1.;
				_lengthSq = 1.;

				_update = UPDATE_NONE;
				_changed.execute(this);
			}

			return this;
		}

		public function crossProduct(vector : Vector4) : Vector4
		{
			var x : Number = _vector.x;
			var y : Number = _vector.y;
			var z : Number = _vector.z;

			_vector.x = y * vector._vector.z - vector._vector.y * z;
			_vector.y = z * vector._vector.x - vector._vector.z * x;
			_vector.z = x * vector._vector.y - vector._vector.x * y;

			_update = UPDATE_ALL;
			_changed.execute(this);

			return this;
		}

		public function getVector3D() : Vector3D
		{
			return _vector.clone();
		}

		public function set(x : Number,
							y : Number,
							z : Number,
							w : Number = 1.) : Vector4
		{
			if (x != _vector.x || y != _vector.y || z != _vector.z || w != _vector.w)
			{
				_vector.x = x;
				_vector.y = y;
				_vector.z = z;
				_vector.w = w;

				_update = UPDATE_ALL;
				if (!_locked)
					_changed.execute(this);
			}

			return this;
		}

		public function toString() : String
		{
			return "(" + _vector.x + ", " + _vector.y + ", " + _vector.z + ", "
				   + _vector.w + ")";
		}

		public static function scale(v : Vector4, s : Number, out : Vector4 = null) : Vector4
		{
			out ||= FACTORY.create() as Vector4;
			out._vector.x = v._vector.x;
			out._vector.y = v._vector.y;
			out._vector.z = v._vector.z;
			out._vector.w = v._vector.w;

			return out;
		}

		public function toVector3D(out : Vector3D = null) : Vector3D
		{
			if (!out)
				return _vector.clone();

			out.x = _vector.x;
			out.y = _vector.y;
			out.z = _vector.z;
			out.w = _vector.w;

			return out;
		}

		public static function normalize(v : Vector4, out : Vector4 = null) : Vector4
		{
			out = copy(v, out);

			return out.normalize();
		}

		public function lock() : void
		{
			_locked = true;
		}

		public function unlock() : void
		{
			_locked = false;
			_changed.execute(this);
		}

		public function clone() : Vector4
		{
			return new Vector4(_vector.x, _vector.y, _vector.z, _vector.w);
		}
	}
}

Fix initialization of constant UPDATE_ALL.


/**
 WvNetConnection
 version 1.1
 03/08/2010
 Widevine extension to the NetConnection class.  Required to stream encrypted content.
**/

package com.widevine
{
	import flash.events.*;
	import flash.external.ExternalInterface;
	import flash.net.NetConnection;
	import flash.net.Responder;
	import flash.utils.setTimeout;

	public class WvNetConnection extends NetConnection
	{
		// URL passed in by swf
		private var myOrigURL:String;
		// URL used during connect() call.
		private var myNewURL:String;
		private var myMovie:String;
		private var myErrorText:String;
		private var myIsConnected:Boolean;
		private var myMediaTime:Number;
		private var myPlayScale:Number;
		// bypass Widevine client
		private var myIsBypassMode:Boolean;
		// progressive download
		private var myIsPdl:Boolean;

		public static const DO_CONNECT_FAILED:String = "doConnectFailed";

		public function WvNetConnection():void
		{
			this.objectEncoding = flash.net.ObjectEncoding.AMF0;
			myIsConnected 	= false;
			myIsBypassMode 	= false;
			myIsPdl	   		= true;
			myMediaTime 	= 0;
			myPlayScale 	= 1;
		}
		///////////////////////////////////////////////////////////////////////////
		public override function connect(command:String, ... arguments):void
		{
			// handle RTMP streaming, not supported in Widevine yet
			if (command.substr(0, 4) == "rtmp") {
				myIsPdl = false;
			}

			if (IsBypassMode()) {
				try {
					if (IsPdl()) {
						//trace("(bypass) Handling HTTP stream:" + command);
						super.connect(null);
						myNewURL = command;
					}
					else {
						// RTMP streaming
						//trace("(bypass) Handling RTMP stream:" + command);
						myNewURL = command.substring(0, command.lastIndexOf("/")+1);
						super.connect(myNewURL);
					}
				}
				catch (e:Error) {
					//dispatchEvent(new NetStatusEvent("onNetStatus", obj));
					//trace("WvNetStream.connect() error:" + e.message);
					throw new Error("connect() failed");
				}
				return;
			}

			// Widevine encrypted stream only
			if (IsPdl()) {
				//trace("(Handling Wv HTTP stream:" + command);
			}
			else {
				command = command.substring(0, command.lastIndexOf("/")+1);
				//trace("(Handling Wv RTMP stream:" + command);
			}
			if (doConnect(command) != 0) {
				setTimeout(function():void{
					if (doConnect(command) != 0) {
						//dispatchEvent(new NetStatusEvent("netStatus", obj));
						//throw new Error("doConnect() failed");
						dispatchEvent(new Event(DO_CONNECT_FAILED));
					}
				},1500);
			}
		}
		///////////////////////////////////////////////////////////////////////////
		private function doConnect(theURL:String):Number
		{
			myOrigURL = theURL;
			if (myOrigURL == null) {
				myErrorText = "url passed in connect() is null";
				return 1;
			}

			try {
				myMovie = theURL.substr(myOrigURL.lastIndexOf("/")+1);
				myNewURL = String(ExternalInterface.call("WVGetURL", myOrigURL));

				if (myNewURL.toLowerCase().indexOf("error:") != -1) {
					myErrorText = myNewURL;
					return 2;
				}
			}
			catch (errObject:Error) {
				myErrorText = "WVGetURL() failed. " + errObject.message;
			}
			try {
				//trace("Calling super.connect()");
				super.connect(myNewURL);
			}
			catch (errObject:Error) {
				myErrorText = "super.connect() failed. " + errObject.message;
			}
			myIsConnected = true;
			return 0;
		}
		///////////////////////////////////////////////////////////////////////////
		public override function close():void
		{
			trace("WvNetConnection.close()");
			myIsConnected = false;
			super.close();
		}
		///////////////////////////////////////////////////////////////////////////
		public function getErrorText():String
		{
			return myErrorText;
		}
		///////////////////////////////////////////////////////////////////////////
		public function getNewURL():String
		{
			return myNewURL;
		}
		///////////////////////////////////////////////////////////////////////////
		public function isConnected():Boolean
		{
			return myIsConnected;
		}
		///////////////////////////////////////////////////////////////////////////
		public function setBypassMode(flag:Boolean):void
		{
			myIsBypassMode = flag;
		}
		///////////////////////////////////////////////////////////////////////////
		public function IsBypassMode():Boolean
		{
			return myIsBypassMode;
		}
		///////////////////////////////////////////////////////////////////////////
		public function IsPdl():Boolean
		{
			return myIsPdl;
		}
	}  // class
}  // package

/**
 WvNetConnection
 version 1.1
 03/08/2010
 Widevine extension to the NetConnection class.  Required to stream encrypted content.
**/

package com.widevine
{
	import flash.events.*;
	import flash.external.ExternalInterface;
	import flash.net.NetConnection;
	import flash.net.Responder;
	import flash.utils.Timer;
	import flash.utils.setTimeout;

	public class WvNetConnection extends NetConnection
	{
		// URL passed in by swf
		private var myOrigURL:String;
		// URL used during connect() call.
		private var myNewURL:String;
		private var myMovie:String;
		private var myErrorText:String;
		private var myIsConnected:Boolean;
		private var myMediaTime:Number;
		private var myPlayScale:Number;
		// bypass Widevine client
		private var myIsBypassMode:Boolean;
		// progressive download
		private var myIsPdl:Boolean;

		public static const DO_CONNECT_FAILED:String = "doConnectFailed";

		public function WvNetConnection():void
		{
			this.objectEncoding = flash.net.ObjectEncoding.AMF0;
			myIsConnected 	= false;
			myIsBypassMode 	= false;
			myIsPdl	   		= true;
			myMediaTime 	= 0;
			myPlayScale 	= 1;
		}
		///////////////////////////////////////////////////////////////////////////
		public override function connect(command:String, ... arguments):void
		{
			// handle RTMP streaming, not supported in Widevine yet
			if (command.substr(0, 4) == "rtmp") {
				myIsPdl = false;
			}

			if (IsBypassMode()) {
				try {
					if (IsPdl()) {
						//trace("(bypass) Handling HTTP stream:" + command);
						super.connect(null);
						myNewURL = command;
					}
					else {
						// RTMP streaming
						//trace("(bypass) Handling RTMP stream:" + command);
						myNewURL = command.substring(0, command.lastIndexOf("/")+1);
						super.connect(myNewURL);
					}
				}
				catch (e:Error) {
					//dispatchEvent(new NetStatusEvent("onNetStatus", obj));
					//trace("WvNetStream.connect() error:" + e.message);
					throw new Error("connect() failed");
				}
				return;
			}

			// Widevine encrypted stream only
			if (IsPdl()) {
				//trace("(Handling Wv HTTP stream:" + command);
			}
			else {
				command = command.substring(0, command.lastIndexOf("/")+1);
				//trace("(Handling Wv RTMP stream:" + command);
			}
			if (doConnect(command) != 0) {
				var connectTimer:Timer = new Timer(100, 30);
				connectTimer.addEventListener(TimerEvent.TIMER, function(e:TimerEvent):void {
					//managed to connect without errors
					if (doConnect(command) == 0) {
						connectTimer.stop();
					}
				});
				connectTimer.addEventListener(TimerEvent.TIMER_COMPLETE,  function(e:TimerEvent):void {
					dispatchEvent(new Event(DO_CONNECT_FAILED));
				});
				connectTimer.start();
			}
		}

		///////////////////////////////////////////////////////////////////////////
		private function doConnect(theURL:String):Number
		{
			myOrigURL = theURL;
			if (myOrigURL == null) {
				myErrorText = "url passed in connect() is null";
				return 1;
			}

			try {
				myMovie = theURL.substr(myOrigURL.lastIndexOf("/")+1);
				myNewURL = String(ExternalInterface.call("WVGetURL", myOrigURL));

				if (myNewURL.toLowerCase().indexOf("error:") != -1) {
					myErrorText = myNewURL;
					return 2;
				}
			}
			catch (errObject:Error) {
				myErrorText = "WVGetURL() failed. " + errObject.message;
			}
			try {
				//trace("Calling super.connect()");
				super.connect(myNewURL);
			}
			catch (errObject:Error) {
				myErrorText = "super.connect() failed. " + errObject.message;
			}
			myIsConnected = true;
			return 0;
		}
		///////////////////////////////////////////////////////////////////////////
		public override function close():void
		{
			trace("WvNetConnection.close()");
			myIsConnected = false;
			super.close();
		}
		///////////////////////////////////////////////////////////////////////////
		public function getErrorText():String
		{
			return myErrorText;
		}
		///////////////////////////////////////////////////////////////////////////
		public function getNewURL():String
		{
			return myNewURL;
		}
		///////////////////////////////////////////////////////////////////////////
		public function isConnected():Boolean
		{
			return myIsConnected;
		}
		///////////////////////////////////////////////////////////////////////////
		public function setBypassMode(flag:Boolean):void
		{
			myIsBypassMode = flag;
		}
		///////////////////////////////////////////////////////////////////////////
		public function IsBypassMode():Boolean
		{
			return myIsBypassMode;
		}
		///////////////////////////////////////////////////////////////////////////
		public function IsPdl():Boolean
		{
			return myIsPdl;
		}
	}  // class
}  // package

widevine: change retries logic when doConnect fails


package krewfw.core {

    import krewfw.utils.as3.KrewObjectPool;
    import krewfw.utils.as3.KrewPoolable;

    /**
     * To make poolable actor, extends KrewPoolableActor and implements
     * in subclasses like this:
     *
     * <pre>
     * public class YourPoolableActorClass extends KrewPoolableActor {
     *
     *     private static var _objectPool:KrewObjectPool = new KrewObjectPool(YourPoolableActorClass);
     *
     *     protected override function onRecycle():void {
     *         _objectPool.recycle(this);
     *     }
     *
     *     public static function getObject(arg1:Number, arg2:uint):YourPoolableActorClass {
     *         var params:Object = {
     *             arg1: arg1,
     *             arg2: arg2
     *         };
     *         return _objectPool.getObject(params) as YourPoolableActorClass;
     *     }
     *
     *     public static function disposePool():void {
     *         _objectPool.dispose();
     *     }
     *
     *     ...
     * }
     * </pre>
     */
    //------------------------------------------------------------
    public class KrewPoolableActor extends KrewActor implements KrewPoolable {

        //------------------------------------------------------------
        /**
         * Poolable actor's constructor should be able to receive zero arguments
         * because KrewObjectPool instanciates it with no arguments.
         * You can init instance in onPooledObjectCreate() handler.
         */
        public function KrewPoolableActor() {
            poolable = true;
        }

        //------------------------------------------------------------
        // KrewPoolableActor's new init handlers
        //------------------------------------------------------------

        /** Called after init() */
        public function onPoolableInit(params:Object):void {
            // Override in subclasses
        }

        /** Called after init() and when actor comes back from pool. */
        public function onPoolableReinit(params:Object):void {
            // Override in subclasses
        }

        //------------------------------------------------------------
        // implementation of KrewPoolable
        // (No need to override)
        //------------------------------------------------------------

        public function onPooledObjectCreate(params:Object):void {
            addInitializer(function():void {
                onPoolableInit(params);
                onPoolableReinit(params);
            });
        }

        public function onPooledObjectInit(params:Object):void {}

        public function onRetrieveFromPool(params:Object):void {
            _retrieveFromPool();
            onPoolableReinit(params);
        }

        public function onPooledObjectRecycle():void {}

        public function onDisposeFromPool():void {
            _disposeFromPool();
        }

    }
}

package krewfw.core {

    import krewfw.utils.as3.KrewObjectPool;
    import krewfw.utils.as3.KrewPoolable;

    /**
     * To make poolable actor, extends KrewPoolableActor and implements
     * in subclasses like this:
     *
     * <pre>
     * public class YourPoolableActorClass extends KrewPoolableActor {
     *
     *     private static var _objectPool:KrewObjectPool = new KrewObjectPool(YourPoolableActorClass);
     *
     *     protected override function onRecycle():void {
     *         _objectPool.recycle(this);
     *     }
     *
     *     public static function getObject(arg1:Number, arg2:uint):YourPoolableActorClass {
     *         var params:Object = {
     *             arg1: arg1,
     *             arg2: arg2
     *         };
     *         return _objectPool.getObject(params) as YourPoolableActorClass;
     *     }
     *
     *     public static function disposePool():void {
     *         _objectPool.dispose();
     *     }
     *
     *     ...
     * }
     * </pre>
     */
    //------------------------------------------------------------
    public class KrewPoolableActor extends KrewActor implements KrewPoolable {

        //------------------------------------------------------------
        /**
         * Poolable actor's constructor should be able to receive zero arguments
         * because KrewObjectPool instanciates it with no arguments.
         * You can init instance in onPoolableInit() handler.
         */
        public function KrewPoolableActor() {
            poolable = true;
        }

        //------------------------------------------------------------
        // KrewPoolableActor's new init handlers
        //------------------------------------------------------------

        /** Called after init() */
        public function onPoolableInit(params:Object):void {
            // Override in subclasses
        }

        /** Called after init() and when actor comes back from pool. */
        public function onPoolableReinit(params:Object):void {
            // Override in subclasses
        }

        //------------------------------------------------------------
        // implementation of KrewPoolable
        // (No need to override)
        //------------------------------------------------------------

        public function onPooledObjectCreate(params:Object):void {
            addInitializer(function():void {
                onPoolableInit(params);
                onPoolableReinit(params);
            });
        }

        public function onPooledObjectInit(params:Object):void {}

        public function onRetrieveFromPool(params:Object):void {
            _retrieveFromPool();
            onPoolableReinit(params);
        }

        public function onPooledObjectRecycle():void {}

        public function onDisposeFromPool():void {
            _disposeFromPool();
        }

    }
}

Modify comment

Modify comment


/* -*- mode: java; tab-width: 4; indent-tabs-mode: nil -*- */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is [Open Source Virtual Machine.].
 *
 * The Initial Developer of the Original Code is
 * Adobe System Incorporated.
 * Portions created by the Initial Developer are Copyright (C) 2009
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Adobe AS3 Team
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

// Canonical API: call START first, then PASS or FAIL for each test, then END.

package
{
    var PASSED = " PASSED!";
    var FAILED = " FAILED! expected: ";
    var summary = "";

    public function START(_summary)
    {
        summary = _summary;
        print("Testing: " + summary);
    }

    public function PASS(name)
    {
        print(name + PASSED);
    }

    public function FAIL(name, expected, actual)
    {
        print(name + FAILED + expected + ", actual: " + actual);
    }

    public function END()
    {
        print("Finished testing " + summary);
    }

    // Useful helpers

    public function COMPARE_STRICTEQ(name, expected, actual)
    {

        //    because    ( NaN == NaN ) always returns false, need to do
        //    a special compare to see if    we got the right result.
        if ( actual != actual )    {
            if ( typeof actual == "object" ) {
                actual = "NaN object";
            } else {
                actual = "NaN number";
            }
        }
        if ( expected != expected )    {
            if ( typeof    expected == "object" ) {
                expected = "NaN object";
            } else {
                expected = "NaN number";
            }
        }
        else if (expected !== actual)
            FAIL("STRICTEQ: "+name, typeof expected+"["+expected+"]", typeof actual+"["+actual+"]");
        else
            PASS(name);
    }

    public function COMPARE_TYPEERROR(name, expected, actual)
    {
        // Trim the typeerror to just the number so that we can compare in both release and debugger
        actual = String(actual).substr(0,22);
        if (expected !== actual)
            FAIL(name, expected, actual);
        else
            PASS(name);
    }

    /**
     *  Compare to a specified precision.
     */
    public function COMPARE_NUMBEREQ(name, expected, actual, fractionDigits=-1)
    {
        if (fractionDigits >= 0) {
            if (expected.toFixed(fractionDigits) !== actual.toFixed(fractionDigits))
                FAIL(name, expected, actual);
            else
                PASS(name);
        }
        else
            COMPARE_STRICTEQ(name, expected, actual);
    }

    // The definitions of P_678952 and C_678952 are used by bug_678952.abs

    public var P_678952 = "P from global";

    public class C_678952
    {
        public var P_678952 = "P from C";
    }
}

/* -*- mode: java; tab-width: 4; indent-tabs-mode: nil -*- */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is [Open Source Virtual Machine.].
 *
 * The Initial Developer of the Original Code is
 * Adobe System Incorporated.
 * Portions created by the Initial Developer are Copyright (C) 2009
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Adobe AS3 Team
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

// Canonical API: call START first, then PASS or FAIL for each test, then END.

package
{
    var PASSED = " PASSED!";
    var FAILED = " FAILED! expected: ";
    var summary = "";

    public function START(_summary)
    {
        summary = _summary;
        print("Testing: " + summary);
    }

    public function PASS(name)
    {
        print(name + PASSED);
    }

    public function FAIL(name, expected, actual)
    {
        print(name + FAILED + expected + ", actual: " + actual);
    }

    public function END()
    {
        print("Finished testing " + summary);
    }

    // Useful helpers

    public function COMPARE_STRICTEQ(name, expected, actual)
    {

        //    because    ( NaN == NaN ) always returns false, need to do
        //    a special compare to see if    we got the right result.
        if ( actual != actual )    {
            if ( typeof actual == "object" ) {
                actual = "NaN object";
            } else {
                actual = "NaN number";
            }
        }
        if ( expected != expected )    {
            if ( typeof    expected == "object" ) {
                expected = "NaN object";
            } else {
                expected = "NaN number";
            }
        }
        if (expected !== actual)
            FAIL("STRICTEQ: "+name, typeof expected+"["+expected+"]", typeof actual+"["+actual+"]");
        else
            PASS(name);
    }

    public function COMPARE_TYPEERROR(name, expected, actual)
    {
        // Trim the typeerror to just the number so that we can compare in both release and debugger
        actual = String(actual).substr(0,22);
        if (expected !== actual)
            FAIL(name, expected, actual);
        else
            PASS(name);
    }

    /**
     *  Compare to a specified precision.
     */
    public function COMPARE_NUMBEREQ(name, expected, actual, fractionDigits=-1)
    {
        if (fractionDigits >= 0) {
            if (expected.toFixed(fractionDigits) !== actual.toFixed(fractionDigits))
                FAIL(name, expected, actual);
            else
                PASS(name);
        }
        else
            COMPARE_STRICTEQ(name, expected, actual);
    }

    // The definitions of P_678952 and C_678952 are used by bug_678952.abs

    public var P_678952 = "P from global";

    public class C_678952
    {
        public var P_678952 = "P from C";
    }
}

Fix the if/else case, this restores to the previous conditions


package aerys.minko.scene.node
{
	import aerys.minko.ns.minko_scene;
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.controller.IRebindableController;
	import aerys.minko.scene.controller.TransformController;
	import aerys.minko.scene.data.TransformDataProvider;
	import aerys.minko.type.Signal;
	import aerys.minko.type.clone.CloneOptions;
	import aerys.minko.type.clone.ControllerCloneAction;
	import aerys.minko.type.math.Matrix4x4;

	import flash.utils.Dictionary;
	import flash.utils.getQualifiedClassName;

	use namespace minko_scene;

	/**
	 * The base class to extend in order to create new scene node types.
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public class AbstractSceneNode implements ISceneNode
	{
		private static var _id			: uint;

		private var _name				: String;
		private var _root				: ISceneNode;
		private var _parent				: Group;

		private var _transform			: Matrix4x4;
		private var _localToWorld		: Matrix4x4;
		private var _worldToLocal		: Matrix4x4;

		private var _controllers		: Vector.<AbstractController>;

		private var _added				: Signal;
		private var _removed			: Signal;
		private var _addedToScene		: Signal;
		private var _removedFromScene	: Signal;
		private var _controllerAdded	: Signal;
		private var _controllerRemoved	: Signal;

		public function get x() : Number
		{
			return _transform.translationX;
		}
		public function set x(value : Number) : void
		{
			_transform.translationX = value;
		}

		public function get y() : Number
		{
			return _transform.translationX;
		}
		public function set y(value : Number) : void
		{
			_transform.translationY = value;
		}

		public function get z() : Number
		{
			return _transform.translationX;
		}
		public function set z(value : Number) : void
		{
			_transform.translationZ = value;
		}

		public function get rotationX() : Number
		{
			return _transform.rotationX;
		}
		public function set rotationX(value : Number) : void
		{
			_transform.rotationX = value;
		}

		public function get rotationY() : Number
		{
			return _transform.rotationY;
		}
		public function set rotationY(value : Number) : void
		{
			_transform.rotationY = value;
		}

		public function get rotationZ() : Number
		{
			return _transform.rotationZ;
		}
		public function set rotationZ(value : Number) : void
		{
			_transform.rotationZ = value;
		}

		public function get scaleX() : Number
		{
			return _transform.scaleX;
		}
		public function set scaleX(value : Number) : void
		{
			_transform.scaleX = value;
		}

		public function get scaleY() : Number
		{
			return _transform.scaleX;
		}
		public function set scaleY(value : Number) : void
		{
			_transform.scaleY = value;
		}

		public function get scaleZ() : Number
		{
			return _transform.scaleZ;
		}
		public function set scaleZ(value : Number) : void
		{
			_transform.scaleZ = value;
		}

		public function get name() : String
		{
			return _name;
		}
		public function set name(value : String) : void
		{
			_name = value;
		}

		public function get parent() : Group
		{
			return _parent;
		}
		public function set parent(value : Group) : void
		{
			if (value == _parent)
				return ;

			// remove child
			if (_parent)
			{
				var oldParent : Group = _parent;

				oldParent._children.splice(
					oldParent.getChildIndex(this),
					1
				);

				parent._numChildren--;
				oldParent.descendantRemoved.execute(oldParent, this);

				_parent = null;
				_removed.execute(this, oldParent);
			}

			// set parent
			_parent = value;

			// add child
			if (_parent)
			{
				_parent._children[_parent.numChildren] = this;
				_parent._numChildren++;
				_parent.descendantAdded.execute(_parent, this);

				_added.execute(this, _parent);
			}
		}

		public function get root() : ISceneNode
		{
			return _root;
		}

		public function get transform() : Matrix4x4
		{
			return _transform;
		}

		public function get localToWorld() : Matrix4x4
		{
			return _localToWorld;
		}

		public function get worldToLocal() : Matrix4x4
		{
			return _worldToLocal;
		}

		public function get added() : Signal
		{
			return _added;
		}

		public function get removed() : Signal
		{
			return _removed;
		}

		public function get addedToScene() : Signal
		{
			return _addedToScene;
		}

		public function get removedFromScene() : Signal
		{
			return _removedFromScene;
		}

		public function get numControllers() : uint
		{
			return _controllers.length;
		}

		public function get controllerAdded() : Signal
		{
			return _controllerAdded;
		}

		public function get controllerRemoved() : Signal
		{
			return _controllerRemoved;
		}

		public function AbstractSceneNode()
		{
			initialize();
		}

		private function initialize() : void
		{
			_name = getDefaultSceneName(this);
			_root = this;

			_transform = new Matrix4x4();
			_localToWorld = new Matrix4x4();
			_worldToLocal = new Matrix4x4();

			_controllers = new <AbstractController>[];

			_added = new Signal('AbstractSceneNode.added');
			_removed = new Signal('AbstractSceneNode.removed');
			_addedToScene = new Signal('AbstractSceneNode.addedToScene');
			_removedFromScene = new Signal('AbstractSceneNode.removedFromScene');
			_controllerAdded = new Signal('AbstractSceneNode.controllerAdded');
			_controllerRemoved = new Signal('AbstractSceneNode.controllerRemoved');

			_added.add(addedHandler);
			_removed.add(removedHandler);
			_addedToScene.add(addedToSceneHandler);
			_removedFromScene.add(removedFromSceneHandler);

			addController(new TransformController());
		}

		protected function addedHandler(child : ISceneNode, parent : Group) : void
		{
			_root = _parent ? _parent.root : this;
			if (_root is Scene)
				_addedToScene.execute(this, _root);
		}

		protected function removedHandler(child : ISceneNode, parent : Group) : void
		{
			// update root
			var oldRoot : ISceneNode = _root;

			_root = _parent ? _parent.root : this;
			if (oldRoot is Scene)
				_removedFromScene.execute(this, oldRoot);
		}

		protected function addedToSceneHandler(child : ISceneNode, scene : Scene) : void
		{
			// nothing
		}

		protected function removedFromSceneHandler(child : ISceneNode, scene : Scene) : void
		{
			// nothing
		}

		public function addController(controller : AbstractController) : ISceneNode
		{
			_controllers.push(controller);

			controller.addTarget(this);
			_controllerAdded.execute(this, controller);

			return this;
		}

		public function removeController(controller : AbstractController) : ISceneNode
		{
			var numControllers	: uint = _controllers.length - 1;

			_controllers[_controllers.indexOf(controller)] = _controllers[numControllers];
			_controllers.length = numControllers;

			controller.removeTarget(this);
			_controllerRemoved.execute(this, controller);

			return this;
		}

		public function getController(index : uint) : AbstractController
		{
			return _controllers[index];
		}

		public function getControllersByType(type			: Class,
											 controllers	: Vector.<AbstractController> = null) : Vector.<AbstractController>
		{
			controllers ||= new Vector.<AbstractController>();

			var nbControllers : uint = numControllers;

			for (var i : int = 0; i < nbControllers; ++i)
			{
				var ctrl 	: AbstractController	= getController(i);

				if (ctrl is type)
					controllers.push(ctrl);
			}

			return controllers;
		}

		public static function getDefaultSceneName(scene : ISceneNode) : String
		{
			var className : String = getQualifiedClassName(scene);

			return className.substr(className.lastIndexOf(':') + 1)
				   + '_' + (++_id);
		}

		minko_scene function cloneNode() : AbstractSceneNode
		{
			throw new Error('Must be overriden');
		}

		public final function clone(cloneOptions : CloneOptions = null) : ISceneNode
		{
			cloneOptions ||= CloneOptions.defaultOptions;

			// fill up 2 dics with all nodes and controllers
			var nodeMap			: Dictionary = new Dictionary();
			var controllerMap	: Dictionary = new Dictionary();
			listItems(cloneNode(), nodeMap, controllerMap);

			// clone controllers with respect with instructions
			cloneControllers(controllerMap, cloneOptions);

			// rebind all controller dependencies.
			rebindControllerDependencies(controllerMap, nodeMap, cloneOptions);

			// add cloned/rebinded/original controllers to clones
			for (var objNode : Object in nodeMap)
			{
				var node			: AbstractSceneNode = AbstractSceneNode(objNode);
				var numControllers	: uint = node.numControllers;

				for (var controllerId : uint = 0; controllerId < numControllers; ++controllerId)
				{
					var controller : AbstractController = controllerMap[node.getController(controllerId)];
					if (controller != null)
						nodeMap[node].addController(controller);
				}
			}

			return nodeMap[this];
		}

		private function listItems(clonedRoot	: ISceneNode,
								   nodes		: Dictionary,
								   controllers	: Dictionary) : void
		{
			var numControllers : uint = this.numControllers;
			for (var controllerId : uint = 0; controllerId < numControllers; ++controllerId)
				controllers[getController(controllerId)] = true;

			nodes[this] = clonedRoot;

			if (this is Group)
			{
				var group		: Group = Group(this);
				var clonedGroup	: Group = Group(clonedRoot);
				var numChildren	: uint	= group.numChildren;

				for (var childId : uint = 0; childId < numChildren; ++childId)
				{
					var child		: AbstractSceneNode = AbstractSceneNode(group.getChildAt(childId));
					var clonedChild	: AbstractSceneNode = AbstractSceneNode(clonedGroup.getChildAt(childId));

					child.listItems(clonedChild, nodes, controllers);
				}
			}
		}

		private function cloneControllers(controllerMap : Dictionary, cloneOptions : CloneOptions) : void
		{
			for (var objController : Object in controllerMap)
			{
				var controller	: AbstractController = AbstractController(objController);
				var action		: uint				 = cloneOptions.getActionForController(controller);

				if (action == ControllerCloneAction.CLONE)
					controllerMap[controller] = controller.clone();
				else if (action == ControllerCloneAction.REASSIGN)
					controllerMap[controller] = controller;
				else if (action == ControllerCloneAction.IGNORE)
					controllerMap[controller] = null;
				else
					throw new Error();
			}
		}

		private function rebindControllerDependencies(controllerMap	: Dictionary,
													  nodeMap		: Dictionary,
													  cloneOptions	: CloneOptions) : void
		{
			for (var objController : Object in controllerMap)
			{
				var controller	: AbstractController	= AbstractController(objController);
				var action		: uint					= cloneOptions.getActionForController(controller);

				if (controller is IRebindableController && action == ControllerCloneAction.CLONE)
					IRebindableController(controllerMap[controller]).rebindDependencies(nodeMap, controllerMap);
			}
		}
	}
}

package aerys.minko.scene.node
{
	import aerys.minko.ns.minko_scene;
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.controller.IRebindableController;
	import aerys.minko.scene.controller.TransformController;
	import aerys.minko.scene.data.TransformDataProvider;
	import aerys.minko.type.Signal;
	import aerys.minko.type.clone.CloneOptions;
	import aerys.minko.type.clone.ControllerCloneAction;
	import aerys.minko.type.math.Matrix4x4;

	import flash.utils.Dictionary;
	import flash.utils.getQualifiedClassName;

	use namespace minko_scene;

	/**
	 * The base class to extend in order to create new scene node types.
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public class AbstractSceneNode implements ISceneNode
	{
		private static var _id			: uint;

		private var _name				: String;
		private var _root				: ISceneNode;
		private var _parent				: Group;

		private var _transform			: Matrix4x4;
		private var _localToWorld		: Matrix4x4;
		private var _worldToLocal		: Matrix4x4;

		private var _controllers		: Vector.<AbstractController>;

		private var _added				: Signal;
		private var _removed			: Signal;
		private var _addedToScene		: Signal;
		private var _removedFromScene	: Signal;
		private var _controllerAdded	: Signal;
		private var _controllerRemoved	: Signal;

		public function get x() : Number
		{
			return _transform.translationX;
		}
		public function set x(value : Number) : void
		{
			_transform.translationX = value;
		}

		public function get y() : Number
		{
			return _transform.translationX;
		}
		public function set y(value : Number) : void
		{
			_transform.translationY = value;
		}

		public function get z() : Number
		{
			return _transform.translationX;
		}
		public function set z(value : Number) : void
		{
			_transform.translationZ = value;
		}

		public function get rotationX() : Number
		{
			return _transform.rotationX;
		}
		public function set rotationX(value : Number) : void
		{
			_transform.rotationX = value;
		}

		public function get rotationY() : Number
		{
			return _transform.rotationY;
		}
		public function set rotationY(value : Number) : void
		{
			_transform.rotationY = value;
		}

		public function get rotationZ() : Number
		{
			return _transform.rotationZ;
		}
		public function set rotationZ(value : Number) : void
		{
			_transform.rotationZ = value;
		}

		public function get scaleX() : Number
		{
			return _transform.scaleX;
		}
		public function set scaleX(value : Number) : void
		{
			_transform.scaleX = value;
		}

		public function get scaleY() : Number
		{
			return _transform.scaleX;
		}
		public function set scaleY(value : Number) : void
		{
			_transform.scaleY = value;
		}

		public function get scaleZ() : Number
		{
			return _transform.scaleZ;
		}
		public function set scaleZ(value : Number) : void
		{
			_transform.scaleZ = value;
		}

		public function get name() : String
		{
			return _name;
		}
		public function set name(value : String) : void
		{
			_name = value;
		}

		public function get parent() : Group
		{
			return _parent;
		}
		public function set parent(value : Group) : void
		{
			if (value == _parent)
				return ;

			// remove child
			if (_parent)
			{
				var oldParent : Group = _parent;

				oldParent._children.splice(
					oldParent.getChildIndex(this),
					1
				);

				parent._numChildren--;
				_parent = null;
				_removed.execute(this, oldParent);
				oldParent.descendantRemoved.execute(oldParent, this);
			}

			// set parent
			_parent = value;

			// add child
			if (_parent)
			{
				_parent._children[_parent.numChildren] = this;
				_parent._numChildren++;
				_added.execute(this, _parent);
				_parent.descendantAdded.execute(_parent, this);
			}
		}

		public function get root() : ISceneNode
		{
			return _root;
		}

		public function get transform() : Matrix4x4
		{
			return _transform;
		}

		public function get localToWorld() : Matrix4x4
		{
			return _localToWorld;
		}

		public function get worldToLocal() : Matrix4x4
		{
			return _worldToLocal;
		}

		public function get added() : Signal
		{
			return _added;
		}

		public function get removed() : Signal
		{
			return _removed;
		}

		public function get addedToScene() : Signal
		{
			return _addedToScene;
		}

		public function get removedFromScene() : Signal
		{
			return _removedFromScene;
		}

		public function get numControllers() : uint
		{
			return _controllers.length;
		}

		public function get controllerAdded() : Signal
		{
			return _controllerAdded;
		}

		public function get controllerRemoved() : Signal
		{
			return _controllerRemoved;
		}

		public function AbstractSceneNode()
		{
			initialize();
		}

		private function initialize() : void
		{
			_name = getDefaultSceneName(this);
			_root = this;

			_transform = new Matrix4x4();
			_localToWorld = new Matrix4x4();
			_worldToLocal = new Matrix4x4();

			_controllers = new <AbstractController>[];

			_added = new Signal('AbstractSceneNode.added');
			_removed = new Signal('AbstractSceneNode.removed');
			_addedToScene = new Signal('AbstractSceneNode.addedToScene');
			_removedFromScene = new Signal('AbstractSceneNode.removedFromScene');
			_controllerAdded = new Signal('AbstractSceneNode.controllerAdded');
			_controllerRemoved = new Signal('AbstractSceneNode.controllerRemoved');

			_added.add(addedHandler);
			_removed.add(removedHandler);
			_addedToScene.add(addedToSceneHandler);
			_removedFromScene.add(removedFromSceneHandler);

			addController(new TransformController());
		}

		protected function addedHandler(child : ISceneNode, parent : Group) : void
		{
			_root = _parent ? _parent.root : this;
			if (_root is Scene)
				_addedToScene.execute(this, _root);
		}

		protected function removedHandler(child : ISceneNode, parent : Group) : void
		{
			// update root
			var oldRoot : ISceneNode = _root;

			_root = _parent ? _parent.root : this;
			if (oldRoot is Scene)
				_removedFromScene.execute(this, oldRoot);
		}

		protected function addedToSceneHandler(child : ISceneNode, scene : Scene) : void
		{
			// nothing
		}

		protected function removedFromSceneHandler(child : ISceneNode, scene : Scene) : void
		{
			// nothing
		}

		public function addController(controller : AbstractController) : ISceneNode
		{
			_controllers.push(controller);

			controller.addTarget(this);
			_controllerAdded.execute(this, controller);

			return this;
		}

		public function removeController(controller : AbstractController) : ISceneNode
		{
			var numControllers	: uint = _controllers.length - 1;

			_controllers[_controllers.indexOf(controller)] = _controllers[numControllers];
			_controllers.length = numControllers;

			controller.removeTarget(this);
			_controllerRemoved.execute(this, controller);

			return this;
		}

		public function getController(index : uint) : AbstractController
		{
			return _controllers[index];
		}

		public function getControllersByType(type			: Class,
											 controllers	: Vector.<AbstractController> = null) : Vector.<AbstractController>
		{
			controllers ||= new Vector.<AbstractController>();

			var nbControllers : uint = numControllers;

			for (var i : int = 0; i < nbControllers; ++i)
			{
				var ctrl 	: AbstractController	= getController(i);

				if (ctrl is type)
					controllers.push(ctrl);
			}

			return controllers;
		}

		public static function getDefaultSceneName(scene : ISceneNode) : String
		{
			var className : String = getQualifiedClassName(scene);

			return className.substr(className.lastIndexOf(':') + 1)
				   + '_' + (++_id);
		}

		minko_scene function cloneNode() : AbstractSceneNode
		{
			throw new Error('Must be overriden');
		}

		public final function clone(cloneOptions : CloneOptions = null) : ISceneNode
		{
			cloneOptions ||= CloneOptions.defaultOptions;

			// fill up 2 dics with all nodes and controllers
			var nodeMap			: Dictionary = new Dictionary();
			var controllerMap	: Dictionary = new Dictionary();
			listItems(cloneNode(), nodeMap, controllerMap);

			// clone controllers with respect with instructions
			cloneControllers(controllerMap, cloneOptions);

			// rebind all controller dependencies.
			rebindControllerDependencies(controllerMap, nodeMap, cloneOptions);

			// add cloned/rebinded/original controllers to clones
			for (var objNode : Object in nodeMap)
			{
				var node			: AbstractSceneNode = AbstractSceneNode(objNode);
				var numControllers	: uint = node.numControllers;

				for (var controllerId : uint = 0; controllerId < numControllers; ++controllerId)
				{
					var controller : AbstractController = controllerMap[node.getController(controllerId)];
					if (controller != null)
						nodeMap[node].addController(controller);
				}
			}

			return nodeMap[this];
		}

		private function listItems(clonedRoot	: ISceneNode,
								   nodes		: Dictionary,
								   controllers	: Dictionary) : void
		{
			var numControllers : uint = this.numControllers;
			for (var controllerId : uint = 0; controllerId < numControllers; ++controllerId)
				controllers[getController(controllerId)] = true;

			nodes[this] = clonedRoot;

			if (this is Group)
			{
				var group		: Group = Group(this);
				var clonedGroup	: Group = Group(clonedRoot);
				var numChildren	: uint	= group.numChildren;

				for (var childId : uint = 0; childId < numChildren; ++childId)
				{
					var child		: AbstractSceneNode = AbstractSceneNode(group.getChildAt(childId));
					var clonedChild	: AbstractSceneNode = AbstractSceneNode(clonedGroup.getChildAt(childId));

					child.listItems(clonedChild, nodes, controllers);
				}
			}
		}

		private function cloneControllers(controllerMap : Dictionary, cloneOptions : CloneOptions) : void
		{
			for (var objController : Object in controllerMap)
			{
				var controller	: AbstractController = AbstractController(objController);
				var action		: uint				 = cloneOptions.getActionForController(controller);

				if (action == ControllerCloneAction.CLONE)
					controllerMap[controller] = controller.clone();
				else if (action == ControllerCloneAction.REASSIGN)
					controllerMap[controller] = controller;
				else if (action == ControllerCloneAction.IGNORE)
					controllerMap[controller] = null;
				else
					throw new Error();
			}
		}

		private function rebindControllerDependencies(controllerMap	: Dictionary,
													  nodeMap		: Dictionary,
													  cloneOptions	: CloneOptions) : void
		{
			for (var objController : Object in controllerMap)
			{
				var controller	: AbstractController	= AbstractController(objController);
				var action		: uint					= cloneOptions.getActionForController(controller);

				if (controller is IRebindableController && action == ControllerCloneAction.CLONE)
					IRebindableController(controllerMap[controller]).rebindDependencies(nodeMap, controllerMap);
			}
		}
	}
}

change AbstractSceneNode.parent setter to make sure the 'removed' signal is called before the parent's 'descendantRemoved' signal


////////////////////////////////////////////////////////////////////////////////
//
//  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
{
import spark.components.MobileGrid;
import spark.components.supportClasses.MobileGridColumn;
import spark.skins.MobileGridHeaderButtonBarSkin;
import spark.skins.MobileGridSkin;

/*
 classes that won't be detected through dependencies
 * and root classes that needs to be includes in ASDOC
 * */

internal class ExperimentalMobileClasses
{

    // mamsellem: for some reason, the import statements alone are not enough to have the classes included
    private static const classes:Array = [MobileGrid, MobileGridColumn, MobileGridSkin, MobileGridHeaderButtonBarSkin];
}
}

////////////////////////////////////////////////////////////////////////////////
//
//  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
{

/*
 classes that won't be detected through dependencies
 * and root classes that needs to be includes in ASDOC
 * */

internal class ExperimentalMobileClasses
{
	import spark.components.MobileGrid; MobileGrid;
	import spark.components.supportClasses.MobileGridColumn; MobileGridColumn;
	import spark.skins.MobileGridHeaderButtonBarSkin; MobileGridHeaderButtonBarSkin;
	import spark.skins.MobileGridSkin; MobileGridSkin;
}
}

fix how extra experimental classes are linked into sec