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 _visible                    : Boolean;
        private var _computedVisibility         : Boolean;

		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;
        private var _visibilityChanged          : Signal;
        private var _computedVisibilityChanged  : Signal;

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

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

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

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

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

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

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

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

        final public function get scaleZ() : Number
		{
			return _transform.scaleZ;
		}
        final 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;
		}

        final public function get parent() : Group
		{
			return _parent;
		}
        final 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);
			}
		}

        final public function get scene() : Scene
        {
            return _root as Scene;
        }

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

        public function get visible() : Boolean
        {
            return _visible;
        }
        public function set visible(value : Boolean) : void
        {
            if (value != _visible)
            {
                _visible = value;
                _visibilityChanged.execute(this, value);
                updateComputedVisibility();
            }
        }

        public function get computedVisibility() : Boolean
        {
            return _computedVisibility;
        }

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

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

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

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

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

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

        final 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 get visibilityChanged() : Signal
        {
            return _visibilityChanged;
        }

        public function get computedVisibilityChanged() : Signal
        {
            return _computedVisibilityChanged;
        }

		public function AbstractSceneNode()
		{
			initialize();
		}

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

            _visible = true;
            _computedVisibility = true;

			_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');
            _visibilityChanged = new Signal('AbstractSceneNode.visibilityChanged');
            _computedVisibilityChanged = new Signal('AbstractSceneNode.computedVisibilityChanged');

			updateRoot();

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

			addController(new TransformController());
		}

		protected function addedHandler(child : ISceneNode, ancestor : Group) : void
		{
            // if ancestor == parent then the node was just added as a direct child of ancestor
            if (ancestor == _parent)
            {
                _parent.computedVisibilityChanged.add(parentComputedVisibilityChangedHandler);
                parentComputedVisibilityChangedHandler(_parent, _parent.computedVisibility);
            }

            updateRoot();
		}

		protected function removedHandler(child : ISceneNode, ancestor : Group) : void
		{
            // if parent is not set anymore, ancestor is not the direct parent of child anymore
            if (!_parent)
            {
                ancestor.computedVisibilityChanged.remove(parentComputedVisibilityChangedHandler);
                _computedVisibility = false;
            }

            updateRoot();
		}

        private function updateRoot() : void
        {
            var newRoot : ISceneNode    = _parent ? _parent.root : this;
            var oldRoot : ISceneNode    = _root;

            if (newRoot != oldRoot)
            {
                _root = newRoot;
                if (oldRoot is Scene)
                    _removedFromScene.execute(this, oldRoot);
                if (newRoot is Scene)
                    _addedToScene.execute(this, newRoot);
            }
        }

        protected function parentComputedVisibilityChangedHandler(parent        : Group,
                                                                  visibility    : Boolean) : void
        {
           updateComputedVisibility();
        }

        private function updateComputedVisibility() : void
        {
            var newComputedVisibility : Boolean = _visible
                && (!_parent || _parent.computedVisibility);

            if (newComputedVisibility != computedVisibility)
            {
                _computedVisibility = newComputedVisibility;
                _computedVisibilityChanged.execute(this, newComputedVisibility);
            }
        }

		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;
            var controllerId    : int   = _controllers.indexOf(controller);

            if (controllerId < 0)
                throw new Error('The controller is not on the node.');

			_controllers[controllerId] = _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 _visible                    : Boolean;
        private var _computedVisibility         : Boolean;

		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;
        private var _visibilityChanged          : Signal;
        private var _computedVisibilityChanged  : Signal;

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

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

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

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

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

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

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

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

        final public function get scaleZ() : Number
		{
			return _transform.scaleZ;
		}
        final 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;
		}

        final public function get parent() : Group
		{
			return _parent;
		}
        final 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);
			}
		}

        final public function get scene() : Scene
        {
            return _root as Scene;
        }

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

        public function get visible() : Boolean
        {
            return _visible;
        }
        public function set visible(value : Boolean) : void
        {
            if (value != _visible)
            {
                _visible = value;
                _visibilityChanged.execute(this, value);
                updateComputedVisibility();
            }
        }

        public function get computedVisibility() : Boolean
        {
            return _computedVisibility;
        }

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

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

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

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

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

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

        final 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 get visibilityChanged() : Signal
        {
            return _visibilityChanged;
        }

        public function get computedVisibilityChanged() : Signal
        {
            return _computedVisibilityChanged;
        }

		public function AbstractSceneNode()
		{
			initialize();
		}

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

            _visible = true;
            _computedVisibility = true;

			_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');
            _visibilityChanged = new Signal('AbstractSceneNode.visibilityChanged');
            _computedVisibilityChanged = new Signal('AbstractSceneNode.computedVisibilityChanged');

			updateRoot();

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

			addController(new TransformController());
		}

		protected function addedHandler(child : ISceneNode, ancestor : Group) : void
		{
            // if ancestor == parent then the node was just added as a direct child of ancestor
            if (ancestor == _parent)
            {
                _parent.computedVisibilityChanged.add(parentComputedVisibilityChangedHandler);
                parentComputedVisibilityChangedHandler(_parent, _parent.computedVisibility);
            }

            updateRoot();
		}

		protected function removedHandler(child : ISceneNode, ancestor : Group) : void
		{
            // if parent is not set anymore, ancestor is not the direct parent of child anymore
            if (!_parent)
            {
                ancestor.computedVisibilityChanged.remove(parentComputedVisibilityChangedHandler);
                _computedVisibility = false;
            }

            updateRoot();
		}

        private function updateRoot() : void
        {
            var newRoot : ISceneNode    = _parent ? _parent.root : this;
            var oldRoot : ISceneNode    = _root;

            if (newRoot != oldRoot)
            {
                _root = newRoot;
                if (oldRoot is Scene)
                    _removedFromScene.execute(this, oldRoot);
                if (newRoot is Scene)
                    _addedToScene.execute(this, newRoot);
            }
        }

        protected function parentComputedVisibilityChangedHandler(parent        : Group,
                                                                  visibility    : Boolean) : void
        {
           updateComputedVisibility();
        }

        private function updateComputedVisibility() : void
        {
            var newComputedVisibility : Boolean = _visible
                && (!_parent || _parent.computedVisibility);

            if (newComputedVisibility != computedVisibility)
            {
                _computedVisibility = newComputedVisibility;
                _computedVisibilityChanged.execute(this, newComputedVisibility);
            }
        }

		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;
            var controllerId    : int   = _controllers.indexOf(controller);

            if (controllerId < 0)
                throw new Error('The controller is not on the node.');

			_controllers[controllerId] = _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);
			}
		}
	}
}

Update src/aerys/minko/scene/node/AbstractSceneNode.as

BUG:scaleY


package org.mangui.chromeless {
    import flash.net.URLStream;

    import org.mangui.HLS.parsing.Level;
    import org.mangui.HLS.*;
    import org.mangui.HLS.utils.*;

    import flash.display.*;
    import flash.events.*;
    import flash.external.ExternalInterface;
    import flash.geom.Rectangle;
    import flash.media.Video;
    import flash.media.SoundTransform;
    import flash.media.StageVideo;
    import flash.media.StageVideoAvailability;
    import flash.utils.setTimeout;

    public class ChromelessPlayer extends Sprite {
        /** reference to the framework. **/
        private var _hls : HLS;
        /** Sheet to place on top of the video. **/
        private var _sheet : Sprite;
        /** Reference to the stage video element. **/
        private var _stageVideo : StageVideo = null;
        /** Reference to the video element. **/
        private var _video : Video = null;
        /** Video size **/
        private var _videoWidth : Number = 0;
        private var _videoHeight : Number = 0;
        /** current media position */
        private var _media_position : Number;

        /** Initialization. **/
        public function ChromelessPlayer() : void {
            // Set stage properties
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;
            stage.fullScreenSourceRect = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
            stage.addEventListener(StageVideoAvailabilityEvent.STAGE_VIDEO_AVAILABILITY, _onStageVideoState);
            stage.addEventListener(Event.RESIZE, _onStageResize);
            // Draw sheet for catching clicks
            _sheet = new Sprite();
            _sheet.graphics.beginFill(0x000000, 0);
            _sheet.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
            _sheet.addEventListener(MouseEvent.CLICK, _clickHandler);
            _sheet.buttonMode = true;
            addChild(_sheet);
            // Connect getters to JS.
            ExternalInterface.addCallback("getLevel", _getLevel);
            ExternalInterface.addCallback("getLevels", _getLevels);
            ExternalInterface.addCallback("getMetrics", _getMetrics);
            ExternalInterface.addCallback("getPosition", _getPosition);
            ExternalInterface.addCallback("getState", _getState);
            ExternalInterface.addCallback("getType", _getType);
            ExternalInterface.addCallback("getmaxBufferLength", _getmaxBufferLength);
            ExternalInterface.addCallback("getminBufferLength", _getminBufferLength);
            ExternalInterface.addCallback("getbufferLength", _getbufferLength);
            ExternalInterface.addCallback("getLogDebug", _getLogDebug);
            ExternalInterface.addCallback("getLogDebug2", _getLogDebug2);
            ExternalInterface.addCallback("getflushLiveURLCache", _getflushLiveURLCache);
            ExternalInterface.addCallback("getstartFromLowestLevel", _getstartFromLowestLevel);
            ExternalInterface.addCallback("getJSURLStream", _getJSURLStream);
            ExternalInterface.addCallback("getPlayerVersion", _getPlayerVersion);
            ExternalInterface.addCallback("getAudioTrackList", _getAudioTrackList);
            ExternalInterface.addCallback("getAudioTrackId", _getAudioTrackId);
            // Connect calls to JS.
            ExternalInterface.addCallback("playerLoad", _load);
            ExternalInterface.addCallback("playerPlay", _play);
            ExternalInterface.addCallback("playerPause", _pause);
            ExternalInterface.addCallback("playerResume", _resume);
            ExternalInterface.addCallback("playerSeek", _seek);
            ExternalInterface.addCallback("playerStop", _stop);
            ExternalInterface.addCallback("playerVolume", _volume);
            ExternalInterface.addCallback("playerSetLevel", _setLevel);
            ExternalInterface.addCallback("playerSetmaxBufferLength", _setmaxBufferLength);
            ExternalInterface.addCallback("playerSetminBufferLength", _setminBufferLength);
            ExternalInterface.addCallback("playerSetflushLiveURLCache", _setflushLiveURLCache);
            ExternalInterface.addCallback("playerSetstartFromLowestLevel", _setstartFromLowestLevel);
            ExternalInterface.addCallback("playerSetLogDebug", _setLogDebug);
            ExternalInterface.addCallback("playerSetLogDebug2", _setLogDebug2);
            ExternalInterface.addCallback("playerSetAudioTrack", _setAudioTrack);
            ExternalInterface.addCallback("playerSetJSURLStream", _setJSURLStream);

            setTimeout(_pingJavascript, 50);
        };

        /** Notify javascript the framework is ready. **/
        private function _pingJavascript() : void {
            ExternalInterface.call("onHLSReady", ExternalInterface.objectID);
        };

        /** Forward events from the framework. **/
        private function _completeHandler(event : HLSEvent) : void {
            if (ExternalInterface.available) {
                ExternalInterface.call("onComplete");
            }
        };

        private function _errorHandler(event : HLSEvent) : void {
            if (ExternalInterface.available) {
                ExternalInterface.call("onError", event.message);
            }
        };

        private function _fragmentHandler(event : HLSEvent) : void {
            if (ExternalInterface.available) {
                ExternalInterface.call("onFragment", event.metrics.bandwidth, event.metrics.level, stage.stageWidth);
            }
        };

        private function _manifestHandler(event : HLSEvent) : void {
            if (ExternalInterface.available) {
                ExternalInterface.call("onManifest", event.levels[0].duration);
            }
        };

        private function _mediaTimeHandler(event : HLSEvent) : void {
            if (ExternalInterface.available) {
                _media_position = event.mediatime.position;
                ExternalInterface.call("onPosition", event.mediatime.position, event.mediatime.duration, event.mediatime.live_sliding);
            }

            var videoWidth : Number = _video ? _video.videoWidth : _stageVideo.videoWidth;
            var videoHeight : Number = _video ? _video.videoHeight : _stageVideo.videoHeight;

            if (videoWidth && videoHeight) {
                var changed : Boolean = _videoWidth != videoWidth || _videoHeight != videoHeight;
                if (changed) {
                    _videoHeight = videoHeight;
                    _videoWidth = videoWidth;
                    _resize();
                    if (ExternalInterface.available) {
                        ExternalInterface.call("onVideoSize", _videoWidth, _videoHeight);
                    }
                }
            }
        };

        private function _stateHandler(event : HLSEvent) : void {
            if (ExternalInterface.available) {
                ExternalInterface.call("onState", event.state);
            }
        };

        private function _switchHandler(event : HLSEvent) : void {
            if (ExternalInterface.available) {
                ExternalInterface.call("onSwitch", event.level);
            }
        };

        private function _audioTracksListChange(event : HLSEvent) : void {
            if (ExternalInterface.available) {
                ExternalInterface.call("onAudioTracksListChange", _getAudioTrackList());
            }
        }

        private function _audioTrackChange(event : HLSEvent) : void {
            if (ExternalInterface.available) {
                ExternalInterface.call("onAudioTrackChange", event.audioTrack);
            }
        }

        /** Javascript getters. **/
        private function _getLevel() : Number {
            return _hls.level;
        };

        private function _getLevels() : Vector.<Level> {
            return _hls.levels;
        };

        private function _getMetrics() : Object {
            return _hls.metrics;
        };

        private function _getPosition() : Number {
            return _hls.position;
        };

        private function _getState() : String {
            return _hls.state;
        };

        private function _getType() : String {
            return _hls.type;
        };

        private function _getbufferLength() : Number {
            return _hls.bufferLength;
        };

        private function _getmaxBufferLength() : Number {
            return _hls.maxBufferLength;
        };

        private function _getminBufferLength() : Number {
            return _hls.minBufferLength;
        };

        private function _getflushLiveURLCache() : Boolean {
            return _hls.flushLiveURLCache;
        };

        private function _getstartFromLowestLevel() : Boolean {
            return _hls.startFromLowestLevel;
        };

        private function _getLogDebug() : Boolean {
            return Log.LOG_DEBUG_ENABLED;
        };

        private function _getLogDebug2() : Boolean {
            return Log.LOG_DEBUG2_ENABLED;
        };

        private function _getJSURLStream() : Boolean {
            return (_hls.URLstream is JSURLStream);
        };

        private function _getPlayerVersion() : Number {
            return 2;
        };

        private function _getAudioTrackList() : Array {
            var list : Array = [];
            var vec : Vector.<HLSAudioTrack> = _hls.audioTracks;
            for (var i : Object in vec) {
                list.push(vec[i]);
            }
            return list;
        };

        private function _getAudioTrackId() : Number {
            return _hls.audioTrack;
        };

        /** Javascript calls. **/
        private function _load(url : String) : void {
            _hls.load(url);
        };

        private function _play() : void {
            _hls.stream.play();
        };

        private function _pause() : void {
            _hls.stream.pause();
        };

        private function _resume() : void {
            _hls.stream.resume();
        };

        private function _seek(position : Number) : void {
            _hls.stream.seek(position);
        };

        private function _stop() : void {
            _hls.stream.close();
        };

        private function _volume(percent : Number) : void {
            _hls.stream.soundTransform = new SoundTransform(percent / 100);
        };

        private function _setLevel(level : Number) : void {
            _hls.level = level;
            if (!isNaN(_media_position)) {
                _hls.stream.seek(_media_position);
            }
        };

        private function _setmaxBufferLength(new_len : Number) : void {
            _hls.maxBufferLength = new_len;
        };

        private function _setminBufferLength(new_len : Number) : void {
            _hls.minBufferLength = new_len;
        };

        private function _setflushLiveURLCache(flushLiveURLCache : Boolean) : void {
            _hls.flushLiveURLCache = flushLiveURLCache;
        };

        private function _setstartFromLowestLevel(startFromLowestLevel : Boolean) : void {
            _hls.startFromLowestLevel = startFromLowestLevel;
        };

        private function _setLogDebug(debug : Boolean) : void {
            Log.LOG_DEBUG_ENABLED = debug;
        };

        private function _setLogDebug2(debug2 : Boolean) : void {
            Log.LOG_DEBUG2_ENABLED = debug2;
        };

        private function _setJSURLStream(jsURLstream : Boolean) : void {
            if (jsURLstream) {
                _hls.URLstream = JSURLStream as Class;
            } else {
                _hls.URLstream = URLStream as Class;
            }
        };

        private function _setAudioTrack(val : Number) : void {
            if (val == _hls.audioTrack) return;
            _hls.audioTrack = val;
            if (!isNaN(_media_position)) {
                _hls.stream.seek(_media_position);
            }
        };

        /** Mouse click handler. **/
        private function _clickHandler(event : MouseEvent) : void {
            if (stage.displayState == StageDisplayState.FULL_SCREEN_INTERACTIVE || stage.displayState == StageDisplayState.FULL_SCREEN) {
                stage.displayState = StageDisplayState.NORMAL;
            } else {
                stage.displayState = StageDisplayState.FULL_SCREEN;
            }
        };

        /** StageVideo detector. **/
        private function _onStageVideoState(event : StageVideoAvailabilityEvent) : void {
            var available : Boolean = (event.availability == StageVideoAvailability.AVAILABLE);
            _hls = new HLS();
            _hls.addEventListener(HLSEvent.PLAYBACK_COMPLETE, _completeHandler);
            _hls.addEventListener(HLSEvent.ERROR, _errorHandler);
            _hls.addEventListener(HLSEvent.FRAGMENT_LOADED, _fragmentHandler);
            _hls.addEventListener(HLSEvent.MANIFEST_LOADED, _manifestHandler);
            _hls.addEventListener(HLSEvent.MEDIA_TIME, _mediaTimeHandler);
            _hls.addEventListener(HLSEvent.STATE, _stateHandler);
            _hls.addEventListener(HLSEvent.QUALITY_SWITCH, _switchHandler);
            _hls.addEventListener(HLSEvent.AUDIO_TRACKS_LIST_CHANGE, _audioTracksListChange);
            _hls.addEventListener(HLSEvent.AUDIO_TRACK_CHANGE, _audioTrackChange);

            if (available && stage.stageVideos.length > 0) {
                _stageVideo = stage.stageVideos[0];
                _stageVideo.viewPort = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
                _stageVideo.attachNetStream(_hls.stream);
            } else {
                _video = new Video(stage.stageWidth, stage.stageHeight);
                addChild(_video);
                _video.smoothing = true;
                _video.attachNetStream(_hls.stream);
            }
        };

        private function _onStageResize(event : Event) : void {
            stage.fullScreenSourceRect = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
            _sheet.width = stage.stageWidth;
            _sheet.height = stage.stageHeight;
            _resize();
        };

        private function _resize() : void {
            var rect : Rectangle;
            rect = ScaleVideo.resizeRectangle(_videoWidth, _videoHeight, stage.stageWidth, stage.stageHeight);
            // resize video
            if (_video) {
                _video.width = rect.width;
                _video.height = rect.height;
                _video.x = rect.x;
                _video.y = rect.y;
            } else if (_stageVideo) {
                _stageVideo.viewPort = rect;
            }
        }
    }
}

package org.mangui.chromeless {
    import flash.net.URLStream;

    import org.mangui.HLS.parsing.Level;
    import org.mangui.HLS.*;
    import org.mangui.HLS.utils.*;

    import flash.display.*;
    import flash.events.*;
    import flash.external.ExternalInterface;
    import flash.geom.Rectangle;
    import flash.media.Video;
    import flash.media.SoundTransform;
    import flash.media.StageVideo;
    import flash.media.StageVideoAvailability;
    import flash.utils.setTimeout;

    public class ChromelessPlayer extends Sprite {
        /** reference to the framework. **/
        private var _hls : HLS;
        /** Sheet to place on top of the video. **/
        private var _sheet : Sprite;
        /** Reference to the stage video element. **/
        private var _stageVideo : StageVideo = null;
        /** Reference to the video element. **/
        private var _video : Video = null;
        /** Video size **/
        private var _videoWidth : Number = 0;
        private var _videoHeight : Number = 0;
        /** current media position */
        private var _media_position : Number;

        /** Initialization. **/
        public function ChromelessPlayer() : void {
            // Set stage properties
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;
            stage.fullScreenSourceRect = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
            stage.addEventListener(StageVideoAvailabilityEvent.STAGE_VIDEO_AVAILABILITY, _onStageVideoState);
            stage.addEventListener(Event.RESIZE, _onStageResize);
            // Draw sheet for catching clicks
            _sheet = new Sprite();
            _sheet.graphics.beginFill(0x000000, 0);
            _sheet.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
            _sheet.addEventListener(MouseEvent.CLICK, _clickHandler);
            _sheet.buttonMode = true;
            addChild(_sheet);
            // Connect getters to JS.
            ExternalInterface.addCallback("getLevel", _getLevel);
            ExternalInterface.addCallback("getLevels", _getLevels);
            ExternalInterface.addCallback("getMetrics", _getMetrics);
            ExternalInterface.addCallback("getPosition", _getPosition);
            ExternalInterface.addCallback("getState", _getState);
            ExternalInterface.addCallback("getType", _getType);
            ExternalInterface.addCallback("getmaxBufferLength", _getmaxBufferLength);
            ExternalInterface.addCallback("getminBufferLength", _getminBufferLength);
            ExternalInterface.addCallback("getbufferLength", _getbufferLength);
            ExternalInterface.addCallback("getLogDebug", _getLogDebug);
            ExternalInterface.addCallback("getLogDebug2", _getLogDebug2);
            ExternalInterface.addCallback("getflushLiveURLCache", _getflushLiveURLCache);
            ExternalInterface.addCallback("getstartFromLowestLevel", _getstartFromLowestLevel);
            ExternalInterface.addCallback("getJSURLStream", _getJSURLStream);
            ExternalInterface.addCallback("getPlayerVersion", _getPlayerVersion);
            ExternalInterface.addCallback("getAudioTrackList", _getAudioTrackList);
            ExternalInterface.addCallback("getAudioTrackId", _getAudioTrackId);
            // Connect calls to JS.
            ExternalInterface.addCallback("playerLoad", _load);
            ExternalInterface.addCallback("playerPlay", _play);
            ExternalInterface.addCallback("playerPause", _pause);
            ExternalInterface.addCallback("playerResume", _resume);
            ExternalInterface.addCallback("playerSeek", _seek);
            ExternalInterface.addCallback("playerStop", _stop);
            ExternalInterface.addCallback("playerVolume", _volume);
            ExternalInterface.addCallback("playerSetLevel", _setLevel);
            ExternalInterface.addCallback("playerSetmaxBufferLength", _setmaxBufferLength);
            ExternalInterface.addCallback("playerSetminBufferLength", _setminBufferLength);
            ExternalInterface.addCallback("playerSetflushLiveURLCache", _setflushLiveURLCache);
            ExternalInterface.addCallback("playerSetstartFromLowestLevel", _setstartFromLowestLevel);
            ExternalInterface.addCallback("playerSetLogDebug", _setLogDebug);
            ExternalInterface.addCallback("playerSetLogDebug2", _setLogDebug2);
            ExternalInterface.addCallback("playerSetAudioTrack", _setAudioTrack);
            ExternalInterface.addCallback("playerSetJSURLStream", _setJSURLStream);

            setTimeout(_pingJavascript, 50);
        };

        /** Notify javascript the framework is ready. **/
        private function _pingJavascript() : void {
            ExternalInterface.call("onHLSReady", ExternalInterface.objectID);
        };

        /** Forward events from the framework. **/
        private function _completeHandler(event : HLSEvent) : void {
            if (ExternalInterface.available) {
                ExternalInterface.call("onComplete");
            }
        };

        private function _errorHandler(event : HLSEvent) : void {
            if (ExternalInterface.available) {
                ExternalInterface.call("onError", event.message);
            }
        };

        private function _fragmentHandler(event : HLSEvent) : void {
            if (ExternalInterface.available) {
                ExternalInterface.call("onFragment", event.metrics.bandwidth, event.metrics.level, stage.stageWidth);
            }
        };

        private function _manifestHandler(event : HLSEvent) : void {
            if (ExternalInterface.available) {
                ExternalInterface.call("onManifest", event.levels[0].duration);
            }
        };

        private function _mediaTimeHandler(event : HLSEvent) : void {
            if (ExternalInterface.available) {
                _media_position = event.mediatime.position;
                ExternalInterface.call("onPosition", event.mediatime.position, event.mediatime.duration, event.mediatime.live_sliding);
            }

            var videoWidth : Number = _video ? _video.videoWidth : _stageVideo.videoWidth;
            var videoHeight : Number = _video ? _video.videoHeight : _stageVideo.videoHeight;

            if (videoWidth && videoHeight) {
                var changed : Boolean = _videoWidth != videoWidth || _videoHeight != videoHeight;
                if (changed) {
                    _videoHeight = videoHeight;
                    _videoWidth = videoWidth;
                    _resize();
                    if (ExternalInterface.available) {
                        ExternalInterface.call("onVideoSize", _videoWidth, _videoHeight);
                    }
                }
            }
        };

        private function _stateHandler(event : HLSEvent) : void {
            if (ExternalInterface.available) {
                ExternalInterface.call("onState", event.state);
            }
        };

        private function _switchHandler(event : HLSEvent) : void {
            if (ExternalInterface.available) {
                ExternalInterface.call("onSwitch", event.level);
            }
        };

        private function _audioTracksListChange(event : HLSEvent) : void {
            if (ExternalInterface.available) {
                ExternalInterface.call("onAudioTracksListChange", _getAudioTrackList());
            }
        }

        private function _audioTrackChange(event : HLSEvent) : void {
            if (ExternalInterface.available) {
                ExternalInterface.call("onAudioTrackChange", event.audioTrack);
            }
        }

        /** Javascript getters. **/
        private function _getLevel() : Number {
            return _hls.level;
        };

        private function _getLevels() : Vector.<Level> {
            return _hls.levels;
        };

        private function _getMetrics() : Object {
            return _hls.metrics;
        };

        private function _getPosition() : Number {
            return _hls.position;
        };

        private function _getState() : String {
            return _hls.state;
        };

        private function _getType() : String {
            return _hls.type;
        };

        private function _getbufferLength() : Number {
            return _hls.bufferLength;
        };

        private function _getmaxBufferLength() : Number {
            return _hls.maxBufferLength;
        };

        private function _getminBufferLength() : Number {
            return _hls.minBufferLength;
        };

        private function _getflushLiveURLCache() : Boolean {
            return _hls.flushLiveURLCache;
        };

        private function _getstartFromLowestLevel() : Boolean {
            return _hls.startFromLowestLevel;
        };

        private function _getLogDebug() : Boolean {
            return Log.LOG_DEBUG_ENABLED;
        };

        private function _getLogDebug2() : Boolean {
            return Log.LOG_DEBUG2_ENABLED;
        };

        private function _getJSURLStream() : Boolean {
            return (_hls.URLstream is JSURLStream);
        };

        private function _getPlayerVersion() : Number {
            return 2;
        };

        private function _getAudioTrackList() : Array {
            var list : Array = [];
            var vec : Vector.<HLSAudioTrack> = _hls.audioTracks;
            for (var i : Object in vec) {
                list.push(vec[i]);
            }
            return list;
        };

        private function _getAudioTrackId() : Number {
            return _hls.audioTrack;
        };

        /** Javascript calls. **/
        private function _load(url : String) : void {
            _hls.load(url);
        };

        private function _play() : void {
            _hls.stream.play();
        };

        private function _pause() : void {
            _hls.stream.pause();
        };

        private function _resume() : void {
            _hls.stream.resume();
        };

        private function _seek(position : Number) : void {
            _hls.stream.seek(position);
        };

        private function _stop() : void {
            _hls.stream.close();
        };

        private function _volume(percent : Number) : void {
            _hls.stream.soundTransform = new SoundTransform(percent / 100);
        };

        private function _setLevel(level : Number) : void {
            _hls.level = level;
            if (!isNaN(_media_position)) {
                _hls.stream.seek(_media_position);
            }
        };

        private function _setmaxBufferLength(new_len : Number) : void {
            _hls.maxBufferLength = new_len;
        };

        private function _setminBufferLength(new_len : Number) : void {
            _hls.minBufferLength = new_len;
        };

        private function _setflushLiveURLCache(flushLiveURLCache : Boolean) : void {
            _hls.flushLiveURLCache = flushLiveURLCache;
        };

        private function _setstartFromLowestLevel(startFromLowestLevel : Boolean) : void {
            _hls.startFromLowestLevel = startFromLowestLevel;
        };

        private function _setLogDebug(debug : Boolean) : void {
            Log.LOG_DEBUG_ENABLED = debug;
        };

        private function _setLogDebug2(debug2 : Boolean) : void {
            Log.LOG_DEBUG2_ENABLED = debug2;
        };

        private function _setJSURLStream(jsURLstream : Boolean) : void {
            if (jsURLstream) {
                _hls.URLstream = JSURLStream as Class;
            } else {
                _hls.URLstream = URLStream as Class;
            }
        };

        private function _setAudioTrack(val : Number) : void {
            if (val == _hls.audioTrack) return;
            _hls.audioTrack = val;
            if (!isNaN(_media_position)) {
                _hls.stream.seek(_media_position);
            }
        };

        /** Mouse click handler. **/
        private function _clickHandler(event : MouseEvent) : void {
            if (stage.displayState == StageDisplayState.FULL_SCREEN_INTERACTIVE || stage.displayState == StageDisplayState.FULL_SCREEN) {
                stage.displayState = StageDisplayState.NORMAL;
            } else {
                stage.displayState = StageDisplayState.FULL_SCREEN;
            }
        };

        /** StageVideo detector. **/
        private function _onStageVideoState(event : StageVideoAvailabilityEvent) : void {
            var available : Boolean = (event.availability == StageVideoAvailability.AVAILABLE);
            _hls = new HLS();
            _hls.addEventListener(HLSEvent.PLAYBACK_COMPLETE, _completeHandler);
            _hls.addEventListener(HLSEvent.ERROR, _errorHandler);
            _hls.addEventListener(HLSEvent.FRAGMENT_LOADED, _fragmentHandler);
            _hls.addEventListener(HLSEvent.MANIFEST_LOADED, _manifestHandler);
            _hls.addEventListener(HLSEvent.MEDIA_TIME, _mediaTimeHandler);
            _hls.addEventListener(HLSEvent.STATE, _stateHandler);
            _hls.addEventListener(HLSEvent.QUALITY_SWITCH, _switchHandler);
            _hls.addEventListener(HLSEvent.AUDIO_TRACKS_LIST_CHANGE, _audioTracksListChange);
            _hls.addEventListener(HLSEvent.AUDIO_TRACK_CHANGE, _audioTrackChange);

            if (available && stage.stageVideos.length > 0) {
                _stageVideo = stage.stageVideos[0];
                _stageVideo.viewPort = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
                _stageVideo.attachNetStream(_hls.stream);
            } else {
                _video = new Video(stage.stageWidth, stage.stageHeight);
                addChild(_video);
                _video.smoothing = true;
                _video.attachNetStream(_hls.stream);
            }
            stage.removeEventListener(StageVideoAvailabilityEvent.STAGE_VIDEO_AVAILABILITY, _onStageVideoState);
        };

        private function _onStageResize(event : Event) : void {
            stage.fullScreenSourceRect = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
            _sheet.width = stage.stageWidth;
            _sheet.height = stage.stageHeight;
            _resize();
        };

        private function _resize() : void {
            var rect : Rectangle;
            rect = ScaleVideo.resizeRectangle(_videoWidth, _videoHeight, stage.stageWidth, stage.stageHeight);
            // resize video
            if (_video) {
                _video.width = rect.width;
                _video.height = rect.height;
                _video.x = rect.x;
                _video.y = rect.y;
            } else if (_stageVideo) {
                _stageVideo.viewPort = rect;
            }
        }
    }
}

HLSProviderChromeless.swf:  fix NaN buffer reported when switching in fullscreen mode
when switching to FullScreen, sometimes StageVideoAvailabilityEvent.STAGE_VIDEO_AVAILABILITY listener is triggered.
remove this listener after its first trigger to avoid reinstanciating HLS instance


package dse{
	import com.hurlant.crypto.prng.Random;
	import com.hurlant.crypto.rsa.RSAKey;
	import com.hurlant.util.Hex;

	import flash.external.ExternalInterface;
	import flash.utils.ByteArray;
	public class KeyGenerator
	{
		public static function generateKeys():void{
			var exp:String = "10001";
			var rsa:RSAKey = RSAKey.generate(1024, exp);
			ExternalInterface.call("setvalue", "publickey", rsa.n.toString());
			ExternalInterface.call("setvalue", "d", rsa.d.toString());
			ExternalInterface.call("setvalue", "p", rsa.p.toString());
			ExternalInterface.call("setvalue", "q", rsa.q.toString());
			ExternalInterface.call("setvalue", "dmp", rsa.dmp1.toString());
			ExternalInterface.call("setvalue", "dmq", rsa.dmq1.toString());
			ExternalInterface.call("setvalue", "qinv", rsa.coeff.toString());

			var r:Random = new Random;
			var rankey:ByteArray = new ByteArray; var discard:ByteArray = new ByteArray;
			r.nextBytes(discard, 32);
			r.nextBytes(rankey, 32);
			ExternalInterface.call("setvalue", "rk", Hex.fromArray(rankey));
		}
	}
}

package dse{
	import com.hurlant.crypto.Crypto;
	import com.hurlant.crypto.hash.IHash;
	import com.hurlant.crypto.prng.Random;
	import com.hurlant.crypto.rsa.RSAKey;
	import com.hurlant.util.Hex;

	import flash.external.ExternalInterface;
	import flash.utils.ByteArray;

	public class KeyGenerator
	{
		public static function generateKeys(passphrase:String):void{
			var exp:String = "10001";
			var rsa:RSAKey = RSAKey.generate(1024, exp);
			ExternalInterface.call("setvalue", "publickey", rsa.n.toString());
			ExternalInterface.call("setvalue", "d", rsa.d.toString());
			ExternalInterface.call("setvalue", "p", rsa.p.toString());
			ExternalInterface.call("setvalue", "q", rsa.q.toString());
			ExternalInterface.call("setvalue", "dmp", rsa.dmp1.toString());
			ExternalInterface.call("setvalue", "dmq", rsa.dmq1.toString());
			ExternalInterface.call("setvalue", "qinv", rsa.coeff.toString());

			var r:Random = new Random;
			var rankey:ByteArray = new ByteArray; var discard:ByteArray = new ByteArray;

			//incorporate passphrase into seeding process
			var hash:IHash = Crypto.getHash("sha256");
			var p:ByteArray = hash.hash(Hex.toArray(Hex.fromString(passphrase)));
			r.autoSeed();
			while (p.bytesAvailable>=4) {
				r.seed(p.readUnsignedInt());
			}

			r.nextBytes(discard, 1024);
			r.nextBytes(rankey, 32);
			ExternalInterface.call("setvalue", "rk", Hex.fromArray(rankey));
		}
	}
}

improve randomness of random aes key generation by seeding with passphrase hash


package dolly.utils {

import dolly.core.dolly_internal;

import mx.collections.ArrayCollection;
import mx.collections.ArrayList;

use namespace dolly_internal;

public class PropertyUtil {

	dolly_internal static function copyArray(sourceObj:*, targetObj:*, propertyName:String):void {
		targetObj[propertyName] = sourceObj[propertyName].slice();
	}

	dolly_internal static function copyArrayList(sourceObj:*, targetObj:*, propertyName:String):void {
		targetObj[propertyName] = sourceObj[propertyName] ?
				new ArrayList(sourceObj[propertyName].source) :
				new ArrayList();
	}

	dolly_internal static function copyArrayCollection(targetObj:*, propertyName:String, sourceProperty:*):void {
		const arrayCollection:ArrayCollection = (sourceProperty as ArrayCollection);
		targetObj[propertyName] = arrayCollection.source ?
				new ArrayCollection(arrayCollection.source.slice()) :
				new ArrayCollection();
	}

	private static function copyObject(targetObj:*, propertyName:String, sourceProperty:*):void {
		targetObj[propertyName] = sourceProperty;
	}

	public static function copyProperty(sourceObj:*, targetObj:*, propertyName:String):void {
		const sourceProperty:* = sourceObj[propertyName];

		if (sourceProperty is Array) {
			copyArray(sourceObj, targetObj, propertyName);
			return;
		}

		if (sourceProperty is ArrayList) {
			copyArrayList(sourceObj, targetObj, propertyName);
			return;
		}

		if (sourceProperty is ArrayCollection) {
			copyArrayCollection(targetObj, propertyName, sourceProperty);
			return;
		}

		copyObject(targetObj, propertyName, sourceProperty);
	}

	public static function cloneProperty(sourceObj:*, targetObj:*, propertyName:String):void {
		const sourceProperty:* = sourceObj[propertyName];

		if (sourceProperty is Array) {
			copyArray(sourceObj, targetObj, propertyName);
			return;
		}

		if (sourceProperty is ArrayList) {
			copyArrayList(sourceObj, targetObj, propertyName);
			return;
		}

		if (sourceProperty is ArrayCollection) {
			copyArrayCollection(targetObj, propertyName, sourceProperty);
			return;
		}

		copyObject(targetObj, propertyName, sourceProperty);
	}
}
}

package dolly.utils {

import dolly.core.dolly_internal;

import mx.collections.ArrayCollection;
import mx.collections.ArrayList;

use namespace dolly_internal;

public class PropertyUtil {

	dolly_internal static function copyArray(sourceObj:*, targetObj:*, propertyName:String):void {
		targetObj[propertyName] = sourceObj[propertyName].slice();
	}

	dolly_internal static function copyArrayList(sourceObj:*, targetObj:*, propertyName:String):void {
		targetObj[propertyName] = sourceObj[propertyName] ?
				new ArrayList(sourceObj[propertyName].source) :
				new ArrayList();
	}

	dolly_internal static function copyArrayCollection(sourceObj:*, targetObj:*, propertyName:String):void {
		const arrayCollection:ArrayCollection = sourceObj[propertyName];
		targetObj[propertyName] = arrayCollection.source ?
				new ArrayCollection(arrayCollection.source.slice()) :
				new ArrayCollection();
	}

	private static function copyObject(targetObj:*, propertyName:String, sourceProperty:*):void {
		targetObj[propertyName] = sourceProperty;
	}

	public static function copyProperty(sourceObj:*, targetObj:*, propertyName:String):void {
		const sourceProperty:* = sourceObj[propertyName];

		if (sourceProperty is Array) {
			copyArray(sourceObj, targetObj, propertyName);
			return;
		}

		if (sourceProperty is ArrayList) {
			copyArrayList(sourceObj, targetObj, propertyName);
			return;
		}

		if (sourceProperty is ArrayCollection) {
			copyArrayCollection(sourceObj, targetObj, propertyName);
			return;
		}

		copyObject(targetObj, propertyName, sourceProperty);
	}

	public static function cloneProperty(sourceObj:*, targetObj:*, propertyName:String):void {
		const sourceProperty:* = sourceObj[propertyName];

		if (sourceProperty is Array) {
			copyArray(sourceObj, targetObj, propertyName);
			return;
		}

		if (sourceProperty is ArrayList) {
			copyArrayList(sourceObj, targetObj, propertyName);
			return;
		}

		if (sourceProperty is ArrayCollection) {
			copyArrayCollection(sourceObj, targetObj, propertyName);
			return;
		}

		copyObject(targetObj, propertyName, sourceProperty);
	}
}
}

Change signature of PropertyUtil.copyArrayCollection() method.


package aerys.minko.render.geometry.stream
{
	import aerys.minko.ns.minko_stream;
	import aerys.minko.render.resource.IndexBuffer3DResource;
	import aerys.minko.type.Signal;

	import flash.utils.ByteArray;
	import flash.utils.Endian;

	public final class IndexStream
	{
		use namespace minko_stream;

		minko_stream var _data			: ByteArray;
		minko_stream var _localDispose	: Boolean;

		private var _usage		: uint;
		private var _resource	: IndexBuffer3DResource;
		private var _length		: uint;

		private var _locked		: Boolean;

		private var _changed	: Signal;

		public function get usage() : uint
		{
			return _usage;
		}

		public function get resource() : IndexBuffer3DResource
		{
			return _resource;
		}

		public function get length() : uint
		{
			return _length;
		}

		public function set length(value : uint) : void
		{
			_data.length = value << 1;
			invalidate();
		}

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

		public function IndexStream(usage	: uint,
									data 	: ByteArray	= null,
									length	: uint		= 0)
		{
			super();

			initialize(data, length, usage);
		}

		minko_stream function invalidate() : void
		{
			_data.position = 0;
			_length = _data.length >>> 1;

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

		private function initialize(data	: ByteArray,
									length 	: uint,
									usage	: uint) : void
		{
			_changed = new Signal('IndexStream.changed');

			_usage = usage;
			_resource = new IndexBuffer3DResource(this);

			_data = new ByteArray();
			_data.endian = Endian.LITTLE_ENDIAN;
			if (data)
			{
				if (data.endian != Endian.LITTLE_ENDIAN)
					throw new Error('Endianness must be Endian.LITTLE_ENDIAN.');
				if (length == 0)
					length = data.bytesAvailable;
				if (length % 6 != 0)
					throw new Error();

				data.readBytes(_data, 0, length);
			}
			else
			{
				_data = dummyData(length);
			}

			_data.position = 0;

			invalidate();
		}

		public function get(index : uint) : uint
		{
			var value : uint = 0;

			checkReadUsage(this);

			_data.position = index << 1;
			value = _data.readUnsignedShort();
			_data.position = 0;

			return value;
		}

		public function set(index : uint, value : uint) : void
		{
			checkWriteUsage(this);

			_data.position = index << 1;
			_data.writeShort(value);
			_data.position = 0;

			invalidate();
		}

		public function deleteTriangle(triangleIndex : uint) : void
		{
			checkWriteUsage(this);

			_data.position = 0;
			_data.writeBytes(_data, triangleIndex * 12, 12);
			_data.length -= 12;
			_data.position = 0;

			invalidate();
		}

		public function clone(usage : uint = 0) : IndexStream
		{
			return new IndexStream(usage || _usage, _data);
		}

		public function toString() : String
		{
			return _data.toString();
		}

		public function concat(indexStream : IndexStream,
							   firstIndex	: uint	= 0,
							   count		: uint	= 0,
							   indexOffset	: uint 	= 0) : IndexStream
		{
			checkReadUsage(indexStream);
			checkWriteUsage(this);

			pushBytes(indexStream._data, firstIndex, count, indexOffset);
			indexStream._data.position = 0;

			return this;
		}

		public function pushBytes(bytes			: ByteArray,
								  firstIndex	: uint	= 0,
								  count			: uint	= 0,
								  indexOffset	: uint	= 0) : IndexStream
		{
			count ||= bytes.length >>> 1;

			_data.position = _data.length;

			if (indexOffset == 0)
				_data.writeBytes(bytes, firstIndex << 1, count << 1);
			else
			{
				bytes.position = firstIndex << 1;
				for (var i : uint = 0; i < count; ++i)
					_data.writeShort(bytes.readUnsignedShort() + indexOffset);
			}

			_data.position = 0;
			bytes.position = (firstIndex + count) << 1;

			invalidate();

			return this;
		}

		public function pushVector(indices 		: Vector.<uint>,
								   firstIndex	: uint	= 0,
								   count		: uint	= 0,
								   offset		: uint 	= 0) : IndexStream
		{
			checkWriteUsage(this);

			var numIndices : int = _data.length;

			count ||= indices.length;

			_data.position = _data.length;
			for (var i : int = 0; i < count; ++i)
				_data.writeShort(indices[int(firstIndex + i)] + offset);
			_data.position = 0;

			invalidate();

			return this;
		}

		public function pushTriangle(index1 : uint, index2 : uint, index3 : uint) : IndexStream
		{
			return setTriangle(length * 3, index1, index2, index3);
		}

		public function setTriangle(triangleIndex	: uint,
									index1 			: uint,
									index2 			: uint,
									index3 			: uint) : IndexStream
		{
			_data.position = triangleIndex << 1;
			_data.writeShort(index1);
			_data.writeShort(index2);
			_data.writeShort(index3);
			_data.position = 0;

			invalidate();

			return this;
		}

		public function disposeLocalData(waitForUpload : Boolean = true) : void
		{
			if (waitForUpload && _length != resource.numIndices)
				_localDispose = true;
			else
			{
				_data = null;
				_usage = StreamUsage.STATIC;
			}
		}

		public function dispose() : void
		{
			_resource.dispose();
		}

		public function lock() : ByteArray
		{
			checkReadUsage(this);

			_data.position = 0;
			_locked = true;

			return _data;
		}

		public function unlock(hasChanged : Boolean = true) : void
		{
			_data.position = 0;

			if (hasChanged)
				invalidate();
		}

		private static function checkReadUsage(stream : IndexStream) : void
		{
			if (!(stream._usage & StreamUsage.READ))
				throw new Error(
					'Unable to read from vertex stream: stream usage is not set to StreamUsage.READ.'
				);
		}

		private static function checkWriteUsage(stream : IndexStream) : void
		{
			if (!(stream._usage & StreamUsage.WRITE))
				throw new Error(
					'Unable to write in vertex stream: stream usage is not set to StreamUsage.WRITE.'
				);
		}

		public static function dummyData(size 	: uint,
										 offset : uint = 0) : ByteArray
		{
			var indices : ByteArray = new ByteArray();

			indices.endian = Endian.LITTLE_ENDIAN;
			for (var i : int = 0; i < size; ++i)
				indices.writeShort(i + offset);
			indices.position = 0;

			return indices;
		}

		public static function fromVector(usage : uint, data : Vector.<uint>) : IndexStream
		{
			var stream 		: IndexStream 	= new IndexStream(usage);
			var numIndices 	: uint 			= data.length;

			for (var i : uint = 0; i < numIndices; ++i)
				stream._data.writeShort(data[i]);
			stream._data.position = 0;
			stream._length = numIndices;

			return stream;
		}
	}
}

package aerys.minko.render.geometry.stream
{
	import aerys.minko.ns.minko_stream;
	import aerys.minko.render.resource.IndexBuffer3DResource;
	import aerys.minko.type.Signal;

	import flash.utils.ByteArray;
	import flash.utils.Endian;

	public final class IndexStream
	{
		use namespace minko_stream;

		minko_stream var _data			: ByteArray;
		minko_stream var _localDispose	: Boolean;

		private var _usage		: uint;
		private var _resource	: IndexBuffer3DResource;
		private var _length		: uint;

		private var _locked		: Boolean;

		private var _changed	: Signal;

		public function get usage() : uint
		{
			return _usage;
		}

		public function get resource() : IndexBuffer3DResource
		{
			return _resource;
		}

		public function get length() : uint
		{
			return _length;
		}

		public function set length(value : uint) : void
		{
			_data.length = value << 1;
			invalidate();
		}

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

		public function IndexStream(usage	: uint,
									data 	: ByteArray	= null,
									length	: uint		= 0)
		{
			super();

			initialize(data, length, usage);
		}

		minko_stream function invalidate() : void
		{
			_data.position = 0;
			_length = _data.length >>> 1;

            if (_length % 3 != 0)
                throw new Error('Invalid size');

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

		private function initialize(data	: ByteArray,
									length 	: uint,
									usage	: uint) : void
		{
			_changed = new Signal('IndexStream.changed');

			_usage = usage;
			_resource = new IndexBuffer3DResource(this);

			_data = new ByteArray();
			_data.endian = Endian.LITTLE_ENDIAN;
			if (data)
			{
				if (data.endian != Endian.LITTLE_ENDIAN)
					throw new Error('Endianness must be Endian.LITTLE_ENDIAN.');
				if (length == 0)
					length = data.bytesAvailable;
				if (length % 6 != 0)
					throw new Error('Invalid size');

				data.readBytes(_data, 0, length);
			}
			else
			{
				_data = dummyData(length);
			}

			_data.position = 0;

			invalidate();
		}

		public function get(index : uint) : uint
		{
			var value : uint = 0;

			checkReadUsage(this);

			_data.position = index << 1;
			value = _data.readUnsignedShort();
			_data.position = 0;

			return value;
		}

		public function set(index : uint, value : uint) : void
		{
			checkWriteUsage(this);

			_data.position = index << 1;
			_data.writeShort(value);
			_data.position = 0;

			invalidate();
		}

		public function deleteTriangle(triangleIndex : uint) : void
		{
			checkWriteUsage(this);

			_data.position = 0;
			_data.writeBytes(_data, triangleIndex * 12, 12);
			_data.length -= 12;
			_data.position = 0;

			invalidate();
		}

		public function clone(usage : uint = 0) : IndexStream
		{
			return new IndexStream(usage || _usage, _data);
		}

		public function toString() : String
		{
			return _data.toString();
		}

		public function concat(indexStream : IndexStream,
							   firstIndex	: uint	= 0,
							   count		: uint	= 0,
							   indexOffset	: uint 	= 0) : IndexStream
		{
			checkReadUsage(indexStream);
			checkWriteUsage(this);

			pushBytes(indexStream._data, firstIndex, count, indexOffset);
			indexStream._data.position = 0;

			return this;
		}

		public function pushBytes(bytes			: ByteArray,
								  firstIndex	: uint	= 0,
								  count			: uint	= 0,
								  indexOffset	: uint	= 0) : IndexStream
		{
			count ||= bytes.length >>> 1;

			_data.position = _data.length;

			if (indexOffset == 0)
				_data.writeBytes(bytes, firstIndex << 1, count << 1);
			else
			{
				bytes.position = firstIndex << 1;
				for (var i : uint = 0; i < count; ++i)
					_data.writeShort(bytes.readUnsignedShort() + indexOffset);
			}

			_data.position = 0;
			bytes.position = (firstIndex + count) << 1;

			invalidate();

			return this;
		}

		public function pushVector(indices 		: Vector.<uint>,
								   firstIndex	: uint	= 0,
								   count		: uint	= 0,
								   offset		: uint 	= 0) : IndexStream
		{
			checkWriteUsage(this);

			var numIndices : int = _data.length;

			count ||= indices.length;

			_data.position = _data.length;
			for (var i : int = 0; i < count; ++i)
				_data.writeShort(indices[int(firstIndex + i)] + offset);
			_data.position = 0;

			invalidate();

			return this;
		}

		public function pushTriangle(index1 : uint, index2 : uint, index3 : uint) : IndexStream
		{
			return setTriangle(length * 3, index1, index2, index3);
		}

		public function setTriangle(triangleIndex	: uint,
									index1 			: uint,
									index2 			: uint,
									index3 			: uint) : IndexStream
		{
			_data.position = triangleIndex << 1;
			_data.writeShort(index1);
			_data.writeShort(index2);
			_data.writeShort(index3);
			_data.position = 0;

			invalidate();

			return this;
		}

		public function disposeLocalData(waitForUpload : Boolean = true) : void
		{
			if (waitForUpload && _length != resource.numIndices)
				_localDispose = true;
			else
			{
				_data = null;
				_usage = StreamUsage.STATIC;
			}
		}

		public function dispose() : void
		{
			_resource.dispose();
		}

		public function lock() : ByteArray
		{
			checkReadUsage(this);

			_data.position = 0;
			_locked = true;

			return _data;
		}

		public function unlock(hasChanged : Boolean = true) : void
		{
			_data.position = 0;

			if (hasChanged)
				invalidate();
		}

		private static function checkReadUsage(stream : IndexStream) : void
		{
			if (!(stream._usage & StreamUsage.READ))
				throw new Error(
					'Unable to read from vertex stream: stream usage is not set to StreamUsage.READ.'
				);
		}

		private static function checkWriteUsage(stream : IndexStream) : void
		{
			if (!(stream._usage & StreamUsage.WRITE))
				throw new Error(
					'Unable to write in vertex stream: stream usage is not set to StreamUsage.WRITE.'
				);
		}

		public static function dummyData(size 	: uint,
										 offset : uint = 0) : ByteArray
		{
			var indices : ByteArray = new ByteArray();

			indices.endian = Endian.LITTLE_ENDIAN;
			for (var i : int = 0; i < size; ++i)
				indices.writeShort(i + offset);
			indices.position = 0;

			return indices;
		}

		public static function fromVector(usage : uint, data : Vector.<uint>) : IndexStream
		{
			var stream 		: IndexStream 	= new IndexStream(usage);
			var numIndices 	: uint 			= data.length;

			for (var i : uint = 0; i < numIndices; ++i)
				stream._data.writeShort(data[i]);
			stream._data.position = 0;
			stream._length = numIndices;

			return stream;
		}
	}
}

check IndexStream.length in IndexStream.invalidate() in order to fail early


package dolly.data {

[Cloneable]
public class CloneableSubclass extends CloneableClass {

	private var _writableField2:String;

	public var property4:String;
	public var property5:String;

	public function CloneableSubclass() {
		super();
	}

	public function get writableField2():String {
		return _writableField2;
	}

	public function set writableField2(value:String):void {
		_writableField2 = value;
	}

}
}

package dolly.data {

[Cloneable]
public class CloneableSubclass extends CloneableClass {

	public static var staticProperty1:String;
	public static var staticProperty2:String;
	public static var staticProperty3:String;

	private var _writableField2:String;

	public var property4:String;
	public var property5:String;

	public function CloneableSubclass() {
		super();
	}

	public function get writableField2():String {
		return _writableField2;
	}

	public function set writableField2(value:String):void {
		_writableField2 = value;
	}

}
}

Add static properties to CloneableSubclass.


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

import flash.events.Event;

public class IconFetchEvent extends Event
{
    public static const FETCH_COMPLETE:String = "FETCH_COMPLETE";

    private var _iconPath:String;

    public function IconFetchEvent(type:String, iconPath:String)
    {
        super(type, false, false);
        _iconPath = iconPath;
    }

    public function get iconPath():String
    {
        return _iconPath;
    }

    override public function clone():Event
    {
        return new IconFetchEvent(type, _iconPath);
    }
}
}

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

import flash.events.Event;

public class IconFetchEvent extends Event
{
    public static const FETCH_COMPLETE:String = "fetchComplete";

    private var _iconPath:String;

    public function IconFetchEvent(type:String, iconPath:String)
    {
        super(type, false, false);
        _iconPath = iconPath;
    }

    public function get iconPath():String
    {
        return _iconPath;
    }

    override public function clone():Event
    {
        return new IconFetchEvent(type, _iconPath);
    }
}
}

Change IconFetchEvent.COMPLETE value to camel case.


package aerys.minko.type.clone
{
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.controller.AnimationController;
	import aerys.minko.scene.controller.TransformController;
	import aerys.minko.scene.controller.camera.CameraController;
	import aerys.minko.scene.controller.mesh.VisibilityController;
	import aerys.minko.scene.controller.mesh.skinning.SkinningController;

	public class CloneOptions
	{
		private var _clonedControllerTypes		: Vector.<Class>	= new <Class>[];
		private var _ignoredControllerTypes		: Vector.<Class>	= new <Class>[];
		private var _reassignedControllerTypes	: Vector.<Class>	= new <Class>[];
		private var _defaultControllerAction	: uint				= ControllerCloneAction.REASSIGN;

		public function get defaultControllerAction() : uint
		{
			return _defaultControllerAction;
		}
		public function set defaultControllerAction(v : uint) : void
		{
			if (v != ControllerCloneAction.CLONE
				&& v != ControllerCloneAction.IGNORE
				&& v != ControllerCloneAction.REASSIGN)
				throw new Error('Unknown action type.');

			_defaultControllerAction = v;
		}

		public function CloneOptions()
		{
		}

		public static function get defaultOptions() : CloneOptions
		{
			var cloneOptions : CloneOptions = new CloneOptions();

			cloneOptions._clonedControllerTypes.push(
				AnimationController,
				SkinningController
			);
			cloneOptions._ignoredControllerTypes.push(
				VisibilityController,
				CameraController,
				TransformController
			);
			cloneOptions._defaultControllerAction = ControllerCloneAction.REASSIGN;

			return cloneOptions;
		}

		public static function get cloneAllOptions() : CloneOptions
		{
			var cloneOptions : CloneOptions = new CloneOptions();

			cloneOptions._ignoredControllerTypes.push(VisibilityController, CameraController);
			cloneOptions._defaultControllerAction = ControllerCloneAction.CLONE;

			return cloneOptions;
		}

		public function addControllerAction(controllerClass : Class, action : uint) : void
		{
			switch (action)
			{
				case ControllerCloneAction.CLONE:
					_clonedControllerTypes.push(controllerClass);
					break;

				case ControllerCloneAction.IGNORE:
					_ignoredControllerTypes.push(controllerClass);
					break;

				case ControllerCloneAction.REASSIGN:
					_reassignedControllerTypes.push(controllerClass);
					break;

				default:
					throw new Error('Unknown action type.');
			}
		}

		public function removeControllerAction(controllerClass : Class) : void
		{
			throw new Error('Implement me.');
		}

		public function getActionForController(controller : AbstractController) : uint
		{
			var numControllersToClone		: uint = _clonedControllerTypes.length;
			var numControllersToIgnore		: uint = _ignoredControllerTypes.length;
			var numControllersToReassign	: uint = _reassignedControllerTypes.length;
			var controllerId				: uint;

			for (controllerId = 0; controllerId < numControllersToClone; ++controllerId)
				if (controller is _clonedControllerTypes[controllerId])
					return ControllerCloneAction.CLONE;

			for (controllerId = 0; controllerId < numControllersToIgnore; ++controllerId)
				if (controller is _ignoredControllerTypes[controllerId])
					return ControllerCloneAction.IGNORE;

			for (controllerId = 0; controllerId < numControllersToReassign; ++controllerId)
				if (controller is _reassignedControllerTypes[controllerId])
					return ControllerCloneAction.REASSIGN;

			return _defaultControllerAction;
		}

	}
}

package aerys.minko.type.clone
{
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.controller.AnimationController;
	import aerys.minko.scene.controller.TransformController;
	import aerys.minko.scene.controller.camera.CameraController;
	import aerys.minko.scene.controller.mesh.VisibilityController;
	import aerys.minko.scene.controller.mesh.skinning.SkinningController;

	public class CloneOptions
	{
		private var _clonedControllerTypes		: Vector.<Class>	= new <Class>[];
		private var _ignoredControllerTypes		: Vector.<Class>	= new <Class>[];
		private var _reassignedControllerTypes	: Vector.<Class>	= new <Class>[];
		private var _defaultControllerAction	: uint				= ControllerCloneAction.REASSIGN;

		public function get defaultControllerAction() : uint
		{
			return _defaultControllerAction;
		}
		public function set defaultControllerAction(v : uint) : void
		{
			if (v != ControllerCloneAction.CLONE
				&& v != ControllerCloneAction.IGNORE
				&& v != ControllerCloneAction.REASSIGN)
				throw new Error('Unknown action type.');

			_defaultControllerAction = v;
		}

		public function CloneOptions()
		{
		}

		public static function get defaultOptions() : CloneOptions
		{
			var cloneOptions : CloneOptions = new CloneOptions();

			cloneOptions._clonedControllerTypes.push(
				AnimationController,
				SkinningController
			);
			cloneOptions._ignoredControllerTypes.push(
				VisibilityController,
				CameraController,
				TransformController
			);
			cloneOptions._defaultControllerAction = ControllerCloneAction.REASSIGN;

			return cloneOptions;
		}

		public static function get cloneAllOptions() : CloneOptions
		{
			var cloneOptions : CloneOptions = new CloneOptions();

			cloneOptions._ignoredControllerTypes.push(
				VisibilityController,
				CameraController,
				TransformController
			);
			cloneOptions._defaultControllerAction = ControllerCloneAction.CLONE;

			return cloneOptions;
		}

		public function addControllerAction(controllerClass : Class, action : uint) : void
		{
			switch (action)
			{
				case ControllerCloneAction.CLONE:
					_clonedControllerTypes.push(controllerClass);
					break;

				case ControllerCloneAction.IGNORE:
					_ignoredControllerTypes.push(controllerClass);
					break;

				case ControllerCloneAction.REASSIGN:
					_reassignedControllerTypes.push(controllerClass);
					break;

				default:
					throw new Error('Unknown action type.');
			}
		}

		public function removeControllerAction(controllerClass : Class) : void
		{
			throw new Error('Implement me.');
		}

		public function getActionForController(controller : AbstractController) : uint
		{
			var numControllersToClone		: uint = _clonedControllerTypes.length;
			var numControllersToIgnore		: uint = _ignoredControllerTypes.length;
			var numControllersToReassign	: uint = _reassignedControllerTypes.length;
			var controllerId				: uint;

			for (controllerId = 0; controllerId < numControllersToClone; ++controllerId)
				if (controller is _clonedControllerTypes[controllerId])
					return ControllerCloneAction.CLONE;

			for (controllerId = 0; controllerId < numControllersToIgnore; ++controllerId)
				if (controller is _ignoredControllerTypes[controllerId])
					return ControllerCloneAction.IGNORE;

			for (controllerId = 0; controllerId < numControllersToReassign; ++controllerId)
				if (controller is _reassignedControllerTypes[controllerId])
					return ControllerCloneAction.REASSIGN;

			return _defaultControllerAction;
		}

	}
}

fix CloneOptions.cloneAllOptions to exclude the TransformController from the list of controllers to clone


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

import com.esri.builder.supportClasses.URLUtil;
import com.esri.builder.model.Model;

import modules.IWidgetModel;

import mx.resources.ResourceManager;

[Bindable]
public final class PrintModel implements IWidgetModel
{
    public static const DEFAULT_DPI:Number = 96;

    private var _taskURL:String = Model.instance.printTaskURL;

    public function get taskURL():String
    {
        return _taskURL;
    }

    public function set taskURL(value:String):void
    {
        _taskURL = URLUtil.encode(value);
    }

    private var _dpi:Number = DEFAULT_DPI;

    public function get dpi():Number
    {
        return _dpi;
    }

    public function set dpi(value:Number):void
    {
        _dpi = isNaN(value) ? DEFAULT_DPI : value;
    }

    public var title:String = ResourceManager.getInstance().getString('BuilderStrings', 'print.defaultTitle');
    public var subtitle:String = ResourceManager.getInstance().getString('BuilderStrings', 'print.defaultSubtitle');
    public var copyright:String = ResourceManager.getInstance().getString('BuilderStrings', 'print.defaultCopyright');
    public var author:String = "";
    public var useScale:Boolean = true;
    public var submitLabel:String;
    public var defaultFormat:String = "";
    public var defaultLayoutTemplate:String = "";

    public var isTitleVisible:Boolean = true;
    public var isCopyrightVisible:Boolean = true;
    public var isAuthorVisible:Boolean = true;

    public var willUseExportWebMap:Boolean = false;
    public var useProxy:Boolean;

    public function importXML(doc:XML):void
    {
        if (doc.taskurl[0])
        {
            taskURL = doc.taskurl;
            willUseExportWebMap = true;
        }
        if (doc.title[0])
        {
            title = doc.title;
            isTitleVisible = (doc.title.@visible[0] != "false");
        }
        if (doc.author[0])
        {
            author = doc.author;
            isAuthorVisible = (doc.author.@visible[0] != "false");
        }
        if (doc.subtitle[0])
        {
            subtitle = doc.subtitle;
        }
        if (doc.copyright[0])
        {
            copyright = doc.copyright;
            isCopyrightVisible = (doc.copyright.@visible[0] != "false");
        }
        if (doc.usescale[0])
        {
            useScale = (doc.usescale.@visible == 'true');
        }
        if (doc.formats.@defaultvalue[0])
        {
            defaultFormat = doc.formats.@defaultvalue[0];
        }
        if (doc.layouttemplates.@defaultvalue[0])
        {
            defaultLayoutTemplate = doc.layouttemplates.@defaultvalue[0];
        }
        if(doc.useproxy[0] == "true")
        {
            useProxy = true;
        }
        if (doc.dpi[0])
        {
            dpi = parseFloat(doc.dpi[0]);
        }
    }

    public function exportXML():XML
    {
        if (willUseExportWebMap)
        {
            return createExportWebMapXML();
        }
        else
        {
            return createPrintScreenXML();
        }
    }

    private function createPrintScreenXML():XML
    {
        var configXML:XML = <configuration/>;

        if (title)
        {
            configXML.appendChild(<title>{title}</title>);
        }
        if (copyright)
        {
            configXML.appendChild(<copyright>{copyright}</copyright>);
        }
        if (subtitle)
        {
            configXML.appendChild(<subtitle>{subtitle}</subtitle>);
        }

        return configXML;
    }

    private function createExportWebMapXML():XML
    {
        var configXML:XML = <configuration/>;

        configXML.appendChild(<taskurl>{taskURL}</taskurl>);

        var titleXML:XML = <title>{title}</title>;
        titleXML.@visible = isTitleVisible;
        configXML.appendChild(titleXML);

        var copyrightXML:XML = <copyright>{copyright}</copyright>;
        copyrightXML.@visible = isCopyrightVisible;
        configXML.appendChild(copyrightXML);

        var authorXML:XML = <author>{author}</author>;
        authorXML.@visible = isAuthorVisible;
        configXML.appendChild(authorXML);

        configXML.appendChild(<dpi>{dpi}</dpi>);

        if (useScale)
        {
            configXML.appendChild(<usescale visible="true"/>);
        }

        if (defaultFormat)
        {
            configXML.appendChild(<formats defaultvalue={defaultFormat}/>)
        }

        if (defaultLayoutTemplate)
        {
            configXML.appendChild(<layouttemplates defaultvalue={defaultLayoutTemplate}/>)
        }

        if(useProxy)
        {
            configXML.appendChild(<useproxy>{useProxy}</useproxy>);
        }

        return configXML;
    }
}
}

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

import com.esri.builder.model.Model;
import com.esri.builder.supportClasses.URLUtil;

import modules.IWidgetModel;

import mx.resources.ResourceManager;

[Bindable]
public final class PrintModel implements IWidgetModel
{
    public static const DEFAULT_DPI:Number = 96;

    private var _taskURL:String = Model.instance.printTaskURL;

    public function get taskURL():String
    {
        return _taskURL;
    }

    public function set taskURL(value:String):void
    {
        _taskURL = URLUtil.encode(value);
    }

    private var _dpi:Number = DEFAULT_DPI;

    public function get dpi():Number
    {
        return _dpi;
    }

    public function set dpi(value:Number):void
    {
        _dpi = isNaN(value) ? DEFAULT_DPI : value;
    }

    public var title:String = ResourceManager.getInstance().getString('BuilderStrings', 'print.defaultTitle');
    public var subtitle:String = ResourceManager.getInstance().getString('BuilderStrings', 'print.defaultSubtitle');
    public var copyright:String = ResourceManager.getInstance().getString('BuilderStrings', 'print.defaultCopyright');
    public var author:String = "";
    public var useScale:Boolean = true;
    public var submitLabel:String;
    public var defaultFormat:String = "";
    public var defaultLayoutTemplate:String = "";

    public var isTitleVisible:Boolean = true;
    public var isCopyrightVisible:Boolean = true;
    public var isAuthorVisible:Boolean = true;

    public var willUseExportWebMap:Boolean = false;
    public var useProxy:Boolean;

    public function importXML(doc:XML):void
    {
        if (doc.taskurl[0])
        {
            taskURL = doc.taskurl;
            willUseExportWebMap = true;
        }
        if (doc.title[0])
        {
            title = doc.title;
            isTitleVisible = (doc.title.@visible[0] != "false");
        }
        if (doc.author[0])
        {
            author = doc.author;
            isAuthorVisible = (doc.author.@visible[0] != "false");
        }
        if (doc.subtitle[0])
        {
            subtitle = doc.subtitle;
        }
        if (doc.copyright[0])
        {
            copyright = doc.copyright;
            isCopyrightVisible = (doc.copyright.@visible[0] != "false");
        }
        if (doc.usescale[0])
        {
            useScale = (doc.usescale.@visible == 'true');
        }
        if (doc.formats.@defaultvalue[0])
        {
            defaultFormat = doc.formats.@defaultvalue[0];
        }
        if (doc.layouttemplates.@defaultvalue[0])
        {
            defaultLayoutTemplate = doc.layouttemplates.@defaultvalue[0];
        }
        if (doc.useproxy[0] == "true")
        {
            useProxy = true;
        }
        if (doc.dpi[0])
        {
            dpi = parseFloat(doc.dpi[0]);
        }
    }

    public function exportXML():XML
    {
        if (willUseExportWebMap)
        {
            return createExportWebMapXML();
        }
        else
        {
            return createPrintScreenXML();
        }
    }

    private function createPrintScreenXML():XML
    {
        var configXML:XML = <configuration/>;

        if (title)
        {
            configXML.appendChild(<title>{title}</title>);
        }
        if (copyright)
        {
            configXML.appendChild(<copyright>{copyright}</copyright>);
        }
        if (subtitle)
        {
            configXML.appendChild(<subtitle>{subtitle}</subtitle>);
        }

        return configXML;
    }

    private function createExportWebMapXML():XML
    {
        var configXML:XML = <configuration/>;

        configXML.appendChild(<taskurl>{taskURL}</taskurl>);

        var titleXML:XML = <title>{title}</title>;
        titleXML.@visible = isTitleVisible;
        configXML.appendChild(titleXML);

        var copyrightXML:XML = <copyright>{copyright}</copyright>;
        copyrightXML.@visible = isCopyrightVisible;
        configXML.appendChild(copyrightXML);

        var authorXML:XML = <author>{author}</author>;
        authorXML.@visible = isAuthorVisible;
        configXML.appendChild(authorXML);

        configXML.appendChild(<dpi>{dpi}</dpi>);

        if (useScale)
        {
            configXML.appendChild(<usescale visible="true"/>);
        }

        if (defaultFormat)
        {
            configXML.appendChild(<formats defaultvalue={defaultFormat}/>)
        }

        if (defaultLayoutTemplate)
        {
            configXML.appendChild(<layouttemplates defaultvalue={defaultLayoutTemplate}/>)
        }

        if (useProxy)
        {
            configXML.appendChild(<useproxy>{useProxy}</useproxy>);
        }

        return configXML;
    }
}
}

Apply formatting.

Apply formatting.