package aerys.minko.scene
{
	import aerys.minko.scene.node.Group;
	import aerys.minko.scene.node.ISceneNode;
	import aerys.minko.type.binding.DataBindings;

	import avmplus.getQualifiedClassName;

	import flash.utils.Dictionary;
	import flash.utils.Proxy;
	import flash.utils.describeType;
	import flash.utils.flash_proxy;
	import flash.utils.getQualifiedClassName;

	public dynamic class SceneIterator extends Proxy
	{
		private static const TYPE_CACHE	: Dictionary		= new Dictionary(true);
		private static const OPERATORS	: Vector.<String>	= new <String>[
			'//', '/', '[', ']', '..', '.', '~=', '?=', '=', '@', '*', '(', ')',
			'>=', '>', '<=', '<', '==', '='
		];
		private static const REGEX_TRIM	: RegExp			= /^\s+|\s+$/;

		private var _path		: String				= null;
		private var _selection	: Vector.<ISceneNode>	= null;
		private var _modifier	: String				= null;

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

		public function SceneIterator(path 		: String,
									  selection : Vector.<ISceneNode>,
									  modifier	: String	= "")
		{
			super();

			_modifier = modifier;

			initialize(path, selection);
		}

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

//		override flash_proxy function setProperty(name : *, value : *):void
//		{
//			var propertyName : String = name;
//
//			for each (var node : ISceneNode in _selection)
//				getValueObject(node, _modifier)[propertyName] = value;
//		}

		override flash_proxy function getProperty(name : *) : *
		{
			var index : int = parseInt(name);

			if (index == name)
				return index < _selection.length ? _selection[index] : null;
			else
			{
				throw new Error(
					'Unable to get a property on a set of objects. '
					+ 'You must use the [] operator to fetch one of the objects.'
				);
			}
		}

		override flash_proxy function nextNameIndex(index : int) : int
		{
			return index < _selection.length ? index + 1 : 0;
		}

		override flash_proxy function nextName(index : int) : String
		{
			return String(index - 1);
		}

		override flash_proxy function nextValue(index : int) : *
		{
			return _selection[int(index - 1)];
		}

//		override flash_proxy function callProperty(name:*, ...parameters):*
//		{
//			var methodName : String = name;
//
//			for each (var node : ISceneNode in _selection)
//			{
//				var method : Function = getValueObject(node, _modifier)[methodName];
//
//				method.apply(null, parameters);
//			}
//
//			return this;
//		}

		private function initialize(path : String, selection : Vector.<ISceneNode>) : void
		{
			_path = path;

			// update root
			var token : String = getToken();

			_selection = selection.slice();
			if (token == "/")
			{
				selectRoots();
				nextToken(token);
			}

			// parse
			while (token = getToken())
			{
				switch (token)
				{
					case '//' :
						nextToken(token);
						selectDescendants();
						break ;
					case '/' :
						nextToken(token);
						selectChildren();
						break ;
					default :
						nextToken(token);
						parseNodeType(token);
						break ;
				}
			}
		}

		private function getToken(doNext : Boolean = false) : String
		{
			var token	: String	= null;

			if (!_path)
				return null;

			_path = _path.replace(/^\s+/, '');

			var nextOpIndex : int = int.MAX_VALUE;

			for each (var op : String in OPERATORS)
			{
				var opIndex : int = _path.indexOf(op);

				if (opIndex > 0 && opIndex < nextOpIndex)
					nextOpIndex = opIndex;

				if (opIndex == 0)
				{
					token = op;
					break ;
				}
			}

			if (!token)
				token = _path.substring(0, nextOpIndex);

			if (doNext)
				nextToken(token);

			return token;
		}

		private function getValueToken() : Object
		{
			var value : Object	= null;

			_path = _path.replace(/^\s+/, '');

			if (_path.charAt(0) == "'")
			{
				var endOfStringIndex : int = _path.indexOf("'", 1);

				if (endOfStringIndex < 0)
					throw new Error("Unterminated string expression.");

				var stringValue	: String	=  _path.substring(1, endOfStringIndex);

				_path = _path.substring(endOfStringIndex + 1);

				value = stringValue;
			}
			else
			{
				var token : String	= getToken(true);

				if (token == 'true')
					value = true;
				else if (token == 'false')
					value = false;
				else if (token.indexOf('0x') == 0)
					value = parseInt(token, 16);
			}

			return value;
		}

		private function nextToken(token : String) : void
		{
			_path = _path.substring(_path.indexOf(token) + token.length);
		}

		private function selectChildren(typeName : String = null) : void
		{
			var selection : Vector.<ISceneNode> = _selection.slice();

			if (typeName != null)
				typeName = typeName.toLowerCase();

			_selection.length = 0;
			for each (var node : ISceneNode in selection)
			{
				if (node is Group)
				{
					var group 		: Group = node as Group;
					var numChildren : uint 	= group.numChildren;

					for (var i : uint = 0; i < numChildren; ++i)
					{
						var child 		: ISceneNode 	= group.getChildAt(i);
						var className	: String		= getQualifiedClassName(child)
						var childType 	: String 		= className.substr(className.lastIndexOf(':') + 1);

						if (typeName == null || childType.toLowerCase() == typeName)
							_selection.push(child);
					}
				}
			}
		}

		private function selectRoots() : void
		{
			var selection	: Vector.<ISceneNode>	= _selection.slice();

			_selection.length = 0;
			for each (var node : ISceneNode in selection)
				if (_selection.indexOf(node.root) < 0)
					_selection.push(node);
		}

		private function selectDescendants() : void
		{
			var selection : Vector.<ISceneNode> = _selection.slice();

			_selection.length = 0;
			for each (var node : ISceneNode in selection)
			{
				_selection.push(node);
				if (node is Group)
					(node as Group).getDescendantsByType(ISceneNode, _selection);
			}
		}

		private function selectParents() : void
		{
			var selection : Vector.<ISceneNode> = _selection.slice();

			_selection.length = 0;
			for each (var node : ISceneNode in selection)
			{
				if (node.parent)
					_selection.push(node.parent);
				else
					_selection.push(node);
			}
		}

		private function parseNodeType(nodeType : String) : void
		{
			if (nodeType == '.')
			{
				// nothing
			}
			if (nodeType == '..')
				selectParents();
			else if (nodeType == '*')
				selectChildren();
			else
				selectChildren(nodeType);

			// apply predicates
			var token : String = getToken();

			while (token == '[')
			{
				nextToken(token);
				parsePredicate();

				token = getToken();
			}
		}

		private function parsePredicate() : void
		{
			var propertyName	: String	= getToken(true);
			var isBinding		: Boolean	= propertyName == '@';

			if (isBinding)
				propertyName = getToken(true);

			var index	: int	= parseInt(propertyName);

			if (propertyName == 'hasController')
				filterOnController();
			if (propertyName == 'hasProperty')
				filterOnProperty();
			else if (propertyName == 'position')
				filterOnPosition();
			else if (propertyName == 'last')
				filterLast();
			else if (propertyName == 'first')
				filterFirst();
			else if (index.toString() == propertyName)
			{
				if (index < _selection.length)
				{
					_selection[0] = _selection[index];
					_selection.length = 1;
				}
				else
					_selection.length = 0;
			}
			else
				filterOnValue(propertyName, isBinding);

			checkNextToken(']');
		}

		private function filterLast() : void
		{
			checkNextToken('(');
			checkNextToken(')');

			_selection[0] = _selection[uint(_selection.length - 1)];
			_selection.length = 1;
		}

		private function filterFirst() : void
		{
			checkNextToken('(');
			checkNextToken(')');

			_selection.length = 1;
		}

		private function filterOnValue(propertyName : String, isBinding : Boolean = false) : void
		{
			var operator	: String	= getToken(true);
			var chunks		: Array		= [propertyName];

			while (operator == '.')
			{
				chunks.push(getToken(true));
				operator = getToken(true);
			}

			var value		: Object	= getValueToken();
			var numNodes	: uint		= _selection.length;

			for (var i : int = numNodes - 1; i >= 0; --i)
			{
				var node		: ISceneNode	= _selection[i];
				var nodeValue 	: Object 		= null;

				if (isBinding && (node['bindings'] is DataBindings))
					nodeValue = (node['bindings'] as DataBindings).getProperty(propertyName);
				else
				{
					try
					{
						nodeValue = getValueObject(node, chunks);
						if (!compare(operator, nodeValue, value))
							removeFromSelection(i);
					}
					catch (e : Error)
					{
						removeFromSelection(i);
					}
				}

			}
		}

		private function compare(operator : String, a : Object, b : Object) : Boolean
		{
			switch (operator)
			{
				case '>' :
					return a > b;
				case '>=' :
					return a >= b;
				case '<' :
					return a >= b;
				case '<=' :
					return a <= b;
				case '=' :
				case '==' :
					return a == b;
				case '~=' :
					var matches	: Array	= String(a).match(b);

					return matches && matches.length != 0;
				default:
					throw new Error('Unknown comparison operator \'' + operator + '\'');
			}
		}

		private function filterOnController() : Object
		{
			checkNextToken('(');
			var controllerName : String = getToken(true);
			checkNextToken(')');

			var numNodes	: uint	= _selection.length;

			for (var i : int = numNodes - 1; i >= 0; --i)
			{
				var node			: ISceneNode	= _selection[i];
				var numControllers	: uint			= node.numControllers;
				var keepSceneNode	: Boolean		= false;

				for (var controllerId : uint = 0; controllerId < numControllers; ++controllerId)
				{
					var controllerType : String = getQualifiedClassName(node.getController(controllerId));
					controllerType = controllerType.substr(controllerType.lastIndexOf(':') + 1);

					if (controllerType == controllerName)
					{
						keepSceneNode = true;
						break;
					}
				}

				if (!keepSceneNode)
					removeFromSelection(i);
			}

			return null;
		}

		private function filterOnPosition() : void
		{
			checkNextToken('(');
			checkNextToken(')');

			var operator 	: String 	= getToken(true);
			var value 		: uint 		= uint(parseInt(getToken(true)));

			switch (operator)
			{
				case '>':
					++value;
				case '>=':
					_selection = _selection.slice(value);
					break;
				case '<':
					--value;
				case '<=':
					_selection = _selection.slice(0, value);
					break;
				case '=':
				case '==':
					_selection[0] = _selection[value];
					_selection.length = 1;
				default:
					throw new Error('Unknown comparison operator \'' + operator + '\'');
			}
		}

		private function filterOnProperty() : void
		{
			checkNextToken('(');

			var chunks		: Array 	= [getToken(true)];
			var operator	: String 	= getToken(true);

			while (operator == '.')
			{
				chunks.push(operator);
				operator = getToken(true);
			}

			if (operator != ')')
				throwParseError(')', operator);

			var numNodes : uint	= _selection.length;
			for (var i : int = numNodes - 1; i >= 0; --i)
			{
				try
				{
					getValueObject(_selection[i], chunks);
				}
				catch (e : Error)
				{
					removeFromSelection(i);
				}
			}
		}

		private function getValueObject(source : Object, chunks : Array) : Object
		{
			if (chunks)
				for each (var chunk : String in chunks)
					source = source[chunk];

			return source;
		}

		private function removeFromSelection(index : uint) : void
		{
			var numNodes : uint = _selection.length - 1;

			_selection[index] = _selection[numNodes];
			_selection.length = numNodes;
		}

		private function checkNextToken(expected : String) : void
		{
			var token : String = getToken(true);

			if (token != expected)
				throwParseError(expected, token);
		}

		private function throwParseError(expected	: String,
										 got		: String) : void
		{
			throw new Error(
				'Parse error: expected \'' + expected + '\', got \'' + got + '\'.'
			);
		}
	}
}

package aerys.minko.scene
{
	import aerys.minko.scene.node.Group;
	import aerys.minko.scene.node.ISceneNode;
	import aerys.minko.type.binding.DataBindings;

	import flash.utils.Dictionary;
	import flash.utils.Proxy;
	import flash.utils.describeType;
	import flash.utils.flash_proxy;
	import flash.utils.getQualifiedClassName;

	public dynamic class SceneIterator extends Proxy
	{
		private static const TYPE_CACHE	: Dictionary		= new Dictionary(true);
		private static const OPERATORS	: Vector.<String>	= new <String>[
			'//', '/', '[', ']', '..', '.', '~=', '?=', '=', '@', '*', '(', ')',
			'>=', '>', '<=', '<', '==', '='
		];
		private static const REGEX_TRIM	: RegExp			= /^\s+|\s+$/;

		private var _path		: String				= null;
		private var _selection	: Vector.<ISceneNode>	= null;
		private var _modifier	: String				= null;

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

		public function SceneIterator(path 		: String,
									  selection : Vector.<ISceneNode>,
									  modifier	: String	= "")
		{
			super();

			_modifier = modifier;

			initialize(path, selection);
		}

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

//		override flash_proxy function setProperty(name : *, value : *):void
//		{
//			var propertyName : String = name;
//
//			for each (var node : ISceneNode in _selection)
//				getValueObject(node, _modifier)[propertyName] = value;
//		}

		override flash_proxy function getProperty(name : *) : *
		{
			var index : int = parseInt(name);

			if (index == name)
				return index < _selection.length ? _selection[index] : null;
			else
			{
				throw new Error(
					'Unable to get a property on a set of objects. '
					+ 'You must use the [] operator to fetch one of the objects.'
				);
			}
		}

		override flash_proxy function nextNameIndex(index : int) : int
		{
			return index < _selection.length ? index + 1 : 0;
		}

		override flash_proxy function nextName(index : int) : String
		{
			return String(index - 1);
		}

		override flash_proxy function nextValue(index : int) : *
		{
			return _selection[int(index - 1)];
		}

//		override flash_proxy function callProperty(name:*, ...parameters):*
//		{
//			var methodName : String = name;
//
//			for each (var node : ISceneNode in _selection)
//			{
//				var method : Function = getValueObject(node, _modifier)[methodName];
//
//				method.apply(null, parameters);
//			}
//
//			return this;
//		}

		private function initialize(path : String, selection : Vector.<ISceneNode>) : void
		{
			_path = path;

			// update root
			var token : String = getToken();

			_selection = selection.slice();
			if (token == "/")
			{
				selectRoots();
				nextToken(token);
			}

			// parse
			while (token = getToken())
			{
				switch (token)
				{
					case '//' :
						nextToken(token);
						selectDescendants();
						break ;
					case '/' :
						nextToken(token);
						selectChildren();
						break ;
					default :
						nextToken(token);
						parseNodeType(token);
						break ;
				}
			}
		}

		private function getToken(doNext : Boolean = false) : String
		{
			var token	: String	= null;

			if (!_path)
				return null;

			_path = _path.replace(/^\s+/, '');

			var nextOpIndex : int = int.MAX_VALUE;

			for each (var op : String in OPERATORS)
			{
				var opIndex : int = _path.indexOf(op);

				if (opIndex > 0 && opIndex < nextOpIndex)
					nextOpIndex = opIndex;

				if (opIndex == 0)
				{
					token = op;
					break ;
				}
			}

			if (!token)
				token = _path.substring(0, nextOpIndex);

			if (doNext)
				nextToken(token);

			return token;
		}

		private function getValueToken() : Object
		{
			var value : Object	= null;

			_path = _path.replace(/^\s+/, '');

			if (_path.charAt(0) == "'")
			{
				var endOfStringIndex : int = _path.indexOf("'", 1);

				if (endOfStringIndex < 0)
					throw new Error("Unterminated string expression.");

				var stringValue	: String	=  _path.substring(1, endOfStringIndex);

				_path = _path.substring(endOfStringIndex + 1);

				value = stringValue;
			}
			else
			{
				var token : String	= getToken(true);

				if (token == 'true')
					value = true;
				else if (token == 'false')
					value = false;
				else if (token.indexOf('0x') == 0)
					value = parseInt(token, 16);
			}

			return value;
		}

		private function nextToken(token : String) : void
		{
			_path = _path.substring(_path.indexOf(token) + token.length);
		}

		private function selectChildren(typeName : String = null) : void
		{
			var selection : Vector.<ISceneNode> = _selection.slice();

			if (typeName != null)
				typeName = typeName.toLowerCase();

			_selection.length = 0;
			for each (var node : ISceneNode in selection)
			{
				if (node is Group)
				{
					var group 		: Group = node as Group;
					var numChildren : uint 	= group.numChildren;

					for (var i : uint = 0; i < numChildren; ++i)
					{
						var child 		: ISceneNode 	= group.getChildAt(i);
						var className	: String		= getQualifiedClassName(child)
						var childType 	: String 		= className.substr(className.lastIndexOf(':') + 1);

						if (typeName == null || childType.toLowerCase() == typeName)
							_selection.push(child);
					}
				}
			}
		}

		private function selectRoots() : void
		{
			var selection	: Vector.<ISceneNode>	= _selection.slice();

			_selection.length = 0;
			for each (var node : ISceneNode in selection)
				if (_selection.indexOf(node.root) < 0)
					_selection.push(node);
		}

		private function selectDescendants() : void
		{
			var selection : Vector.<ISceneNode> = _selection.slice();

			_selection.length = 0;
			for each (var node : ISceneNode in selection)
			{
				_selection.push(node);
				if (node is Group)
					(node as Group).getDescendantsByType(ISceneNode, _selection);
			}
		}

		private function selectParents() : void
		{
			var selection : Vector.<ISceneNode> = _selection.slice();

			_selection.length = 0;
			for each (var node : ISceneNode in selection)
			{
				if (node.parent)
					_selection.push(node.parent);
				else
					_selection.push(node);
			}
		}

		private function parseNodeType(nodeType : String) : void
		{
			if (nodeType == '.')
			{
				// nothing
			}
			if (nodeType == '..')
				selectParents();
			else if (nodeType == '*')
				selectChildren();
			else
				selectChildren(nodeType);

			// apply predicates
			var token : String = getToken();

			while (token == '[')
			{
				nextToken(token);
				parsePredicate();

				token = getToken();
			}
		}

		private function parsePredicate() : void
		{
			var propertyName	: String	= getToken(true);
			var isBinding		: Boolean	= propertyName == '@';

			if (isBinding)
				propertyName = getToken(true);

			var index	: int	= parseInt(propertyName);

			if (propertyName == 'hasController')
				filterOnController();
			if (propertyName == 'hasProperty')
				filterOnProperty();
			else if (propertyName == 'position')
				filterOnPosition();
			else if (propertyName == 'last')
				filterLast();
			else if (propertyName == 'first')
				filterFirst();
			else if (index.toString() == propertyName)
			{
				if (index < _selection.length)
				{
					_selection[0] = _selection[index];
					_selection.length = 1;
				}
				else
					_selection.length = 0;
			}
			else
				filterOnValue(propertyName, isBinding);

			checkNextToken(']');
		}

		private function filterLast() : void
		{
			checkNextToken('(');
			checkNextToken(')');

			_selection[0] = _selection[uint(_selection.length - 1)];
			_selection.length = 1;
		}

		private function filterFirst() : void
		{
			checkNextToken('(');
			checkNextToken(')');

			_selection.length = 1;
		}

		private function filterOnValue(propertyName : String, isBinding : Boolean = false) : void
		{
			var operator	: String	= getToken(true);
			var chunks		: Array		= [propertyName];

			while (operator == '.')
			{
				chunks.push(getToken(true));
				operator = getToken(true);
			}

			var value		: Object	= getValueToken();
			var numNodes	: uint		= _selection.length;

			for (var i : int = numNodes - 1; i >= 0; --i)
			{
				var node		: ISceneNode	= _selection[i];
				var nodeValue 	: Object 		= null;

				if (isBinding && (node['bindings'] is DataBindings))
					nodeValue = (node['bindings'] as DataBindings).getProperty(propertyName);
				else
				{
					try
					{
						nodeValue = getValueObject(node, chunks);
						if (!compare(operator, nodeValue, value))
							removeFromSelection(i);
					}
					catch (e : Error)
					{
						removeFromSelection(i);
					}
				}

			}
		}

		private function compare(operator : String, a : Object, b : Object) : Boolean
		{
			switch (operator)
			{
				case '>' :
					return a > b;
				case '>=' :
					return a >= b;
				case '<' :
					return a >= b;
				case '<=' :
					return a <= b;
				case '=' :
				case '==' :
					return a == b;
				case '~=' :
					var matches	: Array	= String(a).match(b);

					return matches && matches.length != 0;
				default:
					throw new Error('Unknown comparison operator \'' + operator + '\'');
			}
		}

		private function filterOnController() : Object
		{
			checkNextToken('(');
			var controllerName : String = getToken(true);
			checkNextToken(')');

			var numNodes	: uint	= _selection.length;

			for (var i : int = numNodes - 1; i >= 0; --i)
			{
				var node			: ISceneNode	= _selection[i];
				var numControllers	: uint			= node.numControllers;
				var keepSceneNode	: Boolean		= false;

				for (var controllerId : uint = 0; controllerId < numControllers; ++controllerId)
				{
					var controllerType : String = getQualifiedClassName(node.getController(controllerId));
					controllerType = controllerType.substr(controllerType.lastIndexOf(':') + 1);

					if (controllerType == controllerName)
					{
						keepSceneNode = true;
						break;
					}
				}

				if (!keepSceneNode)
					removeFromSelection(i);
			}

			return null;
		}

		private function filterOnPosition() : void
		{
			checkNextToken('(');
			checkNextToken(')');

			var operator 	: String 	= getToken(true);
			var value 		: uint 		= uint(parseInt(getToken(true)));

			switch (operator)
			{
				case '>':
					++value;
				case '>=':
					_selection = _selection.slice(value);
					break;
				case '<':
					--value;
				case '<=':
					_selection = _selection.slice(0, value);
					break;
				case '=':
				case '==':
					_selection[0] = _selection[value];
					_selection.length = 1;
				default:
					throw new Error('Unknown comparison operator \'' + operator + '\'');
			}
		}

		private function filterOnProperty() : void
		{
			checkNextToken('(');

			var chunks		: Array 	= [getToken(true)];
			var operator	: String 	= getToken(true);

			while (operator == '.')
			{
				chunks.push(operator);
				operator = getToken(true);
			}

			if (operator != ')')
				throwParseError(')', operator);

			var numNodes : uint	= _selection.length;
			for (var i : int = numNodes - 1; i >= 0; --i)
			{
				try
				{
					getValueObject(_selection[i], chunks);
				}
				catch (e : Error)
				{
					removeFromSelection(i);
				}
			}
		}

		private function getValueObject(source : Object, chunks : Array) : Object
		{
			if (chunks)
				for each (var chunk : String in chunks)
					source = source[chunk];

			return source;
		}

		private function removeFromSelection(index : uint) : void
		{
			var numNodes : uint = _selection.length - 1;

			_selection[index] = _selection[numNodes];
			_selection.length = numNodes;
		}

		private function checkNextToken(expected : String) : void
		{
			var token : String = getToken(true);

			if (token != expected)
				throwParseError(expected, token);
		}

		private function throwParseError(expected	: String,
										 got		: String) : void
		{
			throw new Error(
				'Parse error: expected \'' + expected + '\', got \'' + got + '\'.'
			);
		}
	}
}

fix ambiguous reference to getQualifiedClassName()


package aerys.minko.scene.node
{
	import aerys.minko.ns.minko_scene;
	import aerys.minko.scene.SceneIterator;
	import aerys.minko.type.Signal;
	import aerys.minko.type.Sort;
	import aerys.minko.type.loader.ILoader;
	import aerys.minko.type.loader.SceneLoader;
	import aerys.minko.type.loader.parser.ParserOptions;
	import aerys.minko.type.math.Ray;

	import flash.net.URLRequest;
	import flash.utils.ByteArray;
	import flash.utils.getQualifiedClassName;

	use namespace minko_scene;

	/**
	 * Group objects can contain other scene nodes and applies a 3D
	 * transformation to its descendants.
	 *
	 * @author Jean-Marc Le Roux
	 */
	public class Group extends AbstractVisibleSceneNode
	{
		minko_scene var _children		: Vector.<ISceneNode>;
		minko_scene var _numChildren	: uint;

		private var _numDescendants		: uint;

		private var _descendantAdded	: Signal;
		private var _descendantRemoved	: Signal;

		/**
		 * The number of children of the Group.
		 */
		public function get numChildren() : uint
		{
			return _numChildren;
		}

		/**
		 * The number of descendants of the Group.
		 *
		 * @return
		 *
		 */
		public function get numDescendants() : uint
		{
			return _numDescendants;
		}

		/**
		 * The signal executed when a descendant is added to the Group.
		 * Callbacks for this signal must accept the following arguments:
		 *

		 *
newParent : Group, the Group the descendant was actually added to

		 *
descendant : ISceneNode, the descendant that was just added

		 *

		 *
		 * @return
		 *
		 */
		public function get descendantAdded() : Signal
		{
			return _descendantAdded
		}

		/**
		 * The signal executed when a descendant is removed from the Group.
		 * Callbacks for this signal must accept the following arguments:
		 *

		 *
oldParent : Group, the Group the descendant was actually removed from

		 *
descendant : ISceneNode, the descendant that was just removed

		 *

		 *
		 * @return
		 *
		 */
		public function get descendantRemoved() : Signal
		{
			return _descendantRemoved;
		}

		public function Group(...children)
		{
			super();

			initializeChildren(children);
		}

		override protected function initializeSignals() : void
		{
			super.initializeSignals();

            _descendantAdded = new Signal('Group.descendantAdded');
            _descendantRemoved = new Signal('Group.descendantRemoved');
		}

		override protected function initializeSignalHandlers() : void
		{
			super.initializeSignalHandlers();

			_descendantAdded.add(descendantAddedHandler);
			_descendantRemoved.add(descendantRemovedHandler);

			added.add(addedHandler);
			removed.add(removedHandler);
		}

		protected function initializeChildren(children : Array) : void
		{
			_children = new <ISceneNode>[];

			while (children.length == 1 && children[0] is Array)
				children = children[0];

			var childrenNum : uint = children.length;

			for (var childrenIndex : uint = 0; childrenIndex < childrenNum; ++childrenIndex)
				addChild(ISceneNode(children[childrenIndex]));
		}

		private function descendantAddedHandler(group : Group, child : ISceneNode) : void
		{
			if (group == this)
			{
				var childGroup : Group = child as Group;

				if (childGroup)
				{
					childGroup.descendantAdded.add(_descendantAdded.execute);
					childGroup.descendantRemoved.add(_descendantRemoved.execute);
				}
			}

			_numDescendants += (child is Group) ? (child as Group)._numDescendants + 1 : 1;
		}

		private function descendantRemovedHandler(group : Group, child : ISceneNode) : void
		{
			if (group == this)
			{
				var childGroup : Group = child as Group;

				if (childGroup)
				{
					childGroup.descendantAdded.remove(_descendantAdded.execute);
					childGroup.descendantRemoved.remove(_descendantRemoved.execute);
				}
			}

			_numDescendants -= (child is Group) ? (child as Group)._numDescendants + 1 : 1;
		}

        private function addedHandler(child : ISceneNode, ancestor : Group) : void
        {
            var numChildren : uint = this.numChildren;

            for (var childId : uint = 0; childId < numChildren; ++childId)
            {
                var child : ISceneNode = _children[childId];

                child.added.execute(child, ancestor);
            }
        }

        private function removedHandler(child : ISceneNode, ancestor : Group) : void
        {
            var numChildren : uint = this.numChildren;

            for (var childId : uint = 0; childId < numChildren; ++childId)
            {
                var child : ISceneNode = _children[childId];

                child.removed.execute(child, ancestor);
            }
        }

		/**
		 * Return true if the specified scene node is a child of the Group, false otherwise.
		 *
		 * @param scene
		 * @return
		 *
		 */
		public function contains(scene : ISceneNode) : Boolean
		{
			return getChildIndex(scene) >= 0;
		}

		/**
		 * Return the index of the speficied scene node or -1 if it is not in the Group.
		 *
		 * @param child
		 * @return
		 *
		 */
		public function getChildIndex(child : ISceneNode) : int
		{
			if (child == null)
				throw new Error('The \'child\' parameter cannot be null.');

			for (var i : int = 0; i < _numChildren; i++)
				if (_children[i] === child)
					return i;

			return -1;
		}

		public function getChildByName(name : String) : ISceneNode
		{
			for (var i : int = 0; i < _numChildren; i++)
				if (_children[i].name === name)
					return _children[i];

			return null;
		}

		/**
		 * Add a child to the group.
		 *
		 * @param	scene The child to add.
		 */
		public function addChild(node : ISceneNode) : Group
		{
			return addChildAt(node, _numChildren);
		}

		/**
		 * Add a child to the group at the specified position.
		 *
		 * @param node
		 * @param position
		 * @return
		 *
		 */
		public function addChildAt(node : ISceneNode, position : uint) : Group
		{
			if (!node)
				throw new Error('Parameter \'scene\' must not be null.');

			node.parent = this;

			for (var i : int = _numChildren - 1; i > position; --i)
				_children[i] = _children[int(i - 1)];

			_children[position] = node;

			return this;
		}

		/**
		 * Remove a child from the container.
		 *
		 * @param	myChild The child to remove.
		 * @return Whether the child was actually removed or not.
		 */
		public function removeChild(child : ISceneNode) : Group
		{
			return removeChildAt(getChildIndex(child));
		}

		public function removeChildAt(position : uint) : Group
		{
			if (position >= _numChildren || position < 0)
				throw new Error('The scene node is not a child of the caller.');

			(_children[position] as ISceneNode).parent = null;

			return this;
		}

		/**
		 * Remove all the children.
		 *
		 * @return
		 *
		 */
		public function removeAllChildren() : Group
		{
			while (_numChildren)
				removeChildAt(0);

			return this;
		}

		/**
		 * Return the child at the specified position.
		 *
		 * @param position
		 * @return
		 *
		 */
		public function getChildAt(position : uint) : ISceneNode
		{
			return position < _numChildren ? _children[position] : null;
		}

		/**
		 * Returns the list of descendant scene nodes that have the specified type.
		 *
		 * @param type
		 * @param descendants
		 * @return
		 *
		 */
		public function getDescendantsByType(type 			: Class,
											 descendants 	: Vector.<ISceneNode> = null) : Vector.<ISceneNode>
		{
			descendants ||= new Vector.<ISceneNode>();

			for (var i : int = 0; i < _numChildren; ++i)
			{
				var child	: ISceneNode	= _children[i];
				var group 	: Group 		= child as Group;

				if (child is type)
					descendants.push(child);

				if (group)
					group.getDescendantsByType(type, descendants);
			}

			return descendants;
		}

		public function toString() : String
		{
			return '[' + getQualifiedClassName(this) + ' ' + name + ']';
		}

		/**
		 * Load the 3D scene corresponding to the specified URLRequest object
		 * and add it directly to the group.
		 *
		 * @param request
		 * @param options
		 * @return
		 *
		 */
		public function load(request	: URLRequest,
							 options	: ParserOptions	= null) : ILoader
		{
			var loader	: SceneLoader	= new SceneLoader(options);

			loader.complete.add(loaderCompleteHandler);
			loader.load(request);

			return loader;
		}

		/**
		 * Load the 3D scene corresponding to the specified Class object
		 * and add it directly to the group.
		 *
		 * @param classObject
		 * @param options
		 * @return
		 */
		public function loadClass(classObject	: Class,
								  options		: ParserOptions	= null) : SceneLoader
		{
			var loader : SceneLoader = new SceneLoader(options);

			loader.complete.add(loaderCompleteHandler);
			loader.loadClass(classObject);

			return loader;
		}

		/**
		 * Load the 3D scene corresponding to the specified ByteArray object
		 * and add it directly to the group.
		 *
		 * @param bytes
		 * @param options
		 * @return
		 *
		 */
		public function loadBytes(bytes		: ByteArray,
								  options	: ParserOptions	= null) : ILoader
		{
			var loader	: SceneLoader	= new SceneLoader(options);

			loader.complete.add(loaderCompleteHandler);
			loader.loadBytes(bytes);

			return loader;
		}

		/**
		 * Return the set of nodes matching the specified XPath query.
		 *
		 * @param xpath
		 * @return
		 *
		 */
		public function get(xpath : String) : SceneIterator
		{
			return new SceneIterator(xpath, new <ISceneNode>[this]);
		}

		private function loaderCompleteHandler(loader	: ILoader,
											   scene	: ISceneNode) : void
		{
			addChild(scene);
		}

		/**
		 * Return all the Mesh objects hit by the specified ray.
		 *
		 * @param ray
		 * @param maxDistance
		 * @return
		 *
		 */
		public function cast(ray : Ray, maxDistance : Number = Number.POSITIVE_INFINITY) : SceneIterator
		{
			var meshes		: Vector.<ISceneNode> 	= getDescendantsByType(Mesh);
			var numMeshes	: uint					= meshes.length;
			var hit			: Array					= [];
			var depth		: Vector.<Number>		= new <Number>[];
			var numItems	: uint					= 0;

			for (var i : uint = 0; i < numMeshes; ++i)
			{
				var mesh 		: Mesh		= meshes[i] as Mesh;
				var hitDepth	: Number	= mesh.cast(ray, maxDistance);

				if (hitDepth >= 0.0)
				{
					hit[numItems] = mesh;
					depth[numItems] = hitDepth;
					++numItems;
				}
			}

			if (numItems > 1)
				Sort.flashSort(depth, hit, numItems);

			return new SceneIterator(null, Vector.<ISceneNode>(hit));
		}

		override minko_scene function cloneNode() : AbstractSceneNode
		{
			var clone : Group = new Group();

			clone.name = name;
			clone.transform.copyFrom(transform);

			for (var childId : uint = 0; childId < _numChildren; ++childId)
			{
				var child		: AbstractSceneNode = AbstractSceneNode(_children[childId]);
				var clonedChild	: AbstractSceneNode = AbstractSceneNode(child.cloneNode());

				clone.addChild(clonedChild);
			}

			return clone;
		}
	}
}

package aerys.minko.scene.node
{
	import aerys.minko.ns.minko_scene;
	import aerys.minko.scene.SceneIterator;
	import aerys.minko.type.Signal;
	import aerys.minko.type.Sort;
	import aerys.minko.type.loader.ILoader;
	import aerys.minko.type.loader.SceneLoader;
	import aerys.minko.type.loader.parser.ParserOptions;
	import aerys.minko.type.math.Ray;

	import flash.net.URLRequest;
	import flash.utils.ByteArray;
	import flash.utils.getQualifiedClassName;

	use namespace minko_scene;

	/**
	 * Group objects can contain other scene nodes and applies a 3D
	 * transformation to its descendants.
	 *
	 * @author Jean-Marc Le Roux
	 */
	public class Group extends AbstractVisibleSceneNode
	{
		minko_scene var _children		: Vector.<ISceneNode>;
		minko_scene var _numChildren	: uint;

		private var _numDescendants		: uint;

		private var _descendantAdded	: Signal;
		private var _descendantRemoved	: Signal;

		/**
		 * The number of children of the Group.
		 */
		public function get numChildren() : uint
		{
			return _numChildren;
		}

		/**
		 * The number of descendants of the Group.
		 *
		 * @return
		 *
		 */
		public function get numDescendants() : uint
		{
			return _numDescendants;
		}

		/**
		 * The signal executed when a descendant is added to the Group.
		 * Callbacks for this signal must accept the following arguments:
		 *

		 *
newParent : Group, the Group the descendant was actually added to

		 *
descendant : ISceneNode, the descendant that was just added

		 *

		 *
		 * @return
		 *
		 */
		public function get descendantAdded() : Signal
		{
			return _descendantAdded
		}

		/**
		 * The signal executed when a descendant is removed from the Group.
		 * Callbacks for this signal must accept the following arguments:
		 *

		 *
oldParent : Group, the Group the descendant was actually removed from

		 *
descendant : ISceneNode, the descendant that was just removed

		 *

		 *
		 * @return
		 *
		 */
		public function get descendantRemoved() : Signal
		{
			return _descendantRemoved;
		}

		public function Group(...children)
		{
			super();

			initializeChildren(children);
		}

		override protected function initializeSignals() : void
		{
			super.initializeSignals();

            _descendantAdded = new Signal('Group.descendantAdded');
            _descendantRemoved = new Signal('Group.descendantRemoved');
		}

		override protected function initializeSignalHandlers() : void
		{
			super.initializeSignalHandlers();

			_descendantAdded.add(descendantAddedHandler);
			_descendantRemoved.add(descendantRemovedHandler);

			added.add(addedHandler);
			removed.add(removedHandler);
		}

		protected function initializeChildren(children : Array) : void
		{
			_children = new <ISceneNode>[];

			while (children.length == 1 && children[0] is Array)
				children = children[0];

			var childrenNum : uint = children.length;

			for (var childrenIndex : uint = 0; childrenIndex < childrenNum; ++childrenIndex)
				addChild(ISceneNode(children[childrenIndex]));
		}

		private function descendantAddedHandler(group : Group, child : ISceneNode) : void
		{
			if (group == this)
			{
				var childGroup : Group = child as Group;

				if (childGroup)
				{
					childGroup.descendantAdded.add(_descendantAdded.execute);
					childGroup.descendantRemoved.add(_descendantRemoved.execute);
				}
			}

			_numDescendants += (child is Group) ? (child as Group)._numDescendants + 1 : 1;
		}

		private function descendantRemovedHandler(group : Group, child : ISceneNode) : void
		{
			if (group == this)
			{
				var childGroup : Group = child as Group;

				if (childGroup)
				{
					childGroup.descendantAdded.remove(_descendantAdded.execute);
					childGroup.descendantRemoved.remove(_descendantRemoved.execute);
				}
			}

			_numDescendants -= (child is Group) ? (child as Group)._numDescendants + 1 : 1;
		}

        private function addedHandler(child : ISceneNode, ancestor : Group) : void
        {
            var numChildren : uint = this.numChildren;

            for (var childId : uint = 0; childId < numChildren; ++childId)
            {
                var child : ISceneNode = _children[childId];

                child.added.execute(child, ancestor);
            }
        }

        private function removedHandler(child : ISceneNode, ancestor : Group) : void
        {
            var numChildren : uint = this.numChildren;

            for (var childId : uint = 0; childId < numChildren; ++childId)
            {
                var child : ISceneNode = _children[childId];

                child.removed.execute(child, ancestor);
            }
        }

		/**
		 * Return true if the specified scene node is a child of the Group, false otherwise.
		 *
		 * @param scene
		 * @return
		 *
		 */
		public function contains(scene : ISceneNode) : Boolean
		{
			return getChildIndex(scene) >= 0;
		}

		/**
		 * Return the index of the speficied scene node or -1 if it is not in the Group.
		 *
		 * @param child
		 * @return
		 *
		 */
		public function getChildIndex(child : ISceneNode) : int
		{
			if (child == null)
				throw new Error('The \'child\' parameter cannot be null.');

			for (var i : int = 0; i < _numChildren; i++)
				if (_children[i] === child)
					return i;

			return -1;
		}

		public function getChildByName(name : String) : ISceneNode
		{
			for (var i : int = 0; i < _numChildren; i++)
				if (_children[i].name === name)
					return _children[i];

			return null;
		}

		/**
		 * Add a child to the group.
		 *
		 * @param	scene The child to add.
		 */
		public function addChild(node : ISceneNode) : Group
		{
			return addChildAt(node, _numChildren);
		}

		/**
		 * Add a child to the group at the specified position.
		 *
		 * @param node
		 * @param position
		 * @return
		 *
		 */
		public function addChildAt(node : ISceneNode, position : uint) : Group
		{
			if (!node)
				throw new Error('Parameter \'scene\' must not be null.');

			node.parent = this;

			for (var i : int = _numChildren - 1; i > position; --i)
				_children[i] = _children[int(i - 1)];

			_children[position] = node;

			return this;
		}

		/**
		 * Remove a child from the container.
		 *
		 * @param	myChild The child to remove.
		 * @return Whether the child was actually removed or not.
		 */
		public function removeChild(child : ISceneNode) : Group
		{
			return removeChildAt(getChildIndex(child));
		}

		public function removeChildAt(position : uint) : Group
		{
			if (position >= _numChildren)
				throw new Error('The scene node is not a child of the caller.');

			(_children[position] as ISceneNode).parent = null;

			return this;
		}

		/**
		 * Remove all the children.
		 *
		 * @return
		 *
		 */
		public function removeAllChildren() : Group
		{
			while (_numChildren)
				removeChildAt(0);

			return this;
		}

		/**
		 * Return the child at the specified position.
		 *
		 * @param position
		 * @return
		 *
		 */
		public function getChildAt(position : uint) : ISceneNode
		{
			return position < _numChildren ? _children[position] : null;
		}

		/**
		 * Returns the list of descendant scene nodes that have the specified type.
		 *
		 * @param type
		 * @param descendants
		 * @return
		 *
		 */
		public function getDescendantsByType(type 			: Class,
											 descendants 	: Vector.<ISceneNode> = null) : Vector.<ISceneNode>
		{
			descendants ||= new Vector.<ISceneNode>();

			for (var i : int = 0; i < _numChildren; ++i)
			{
				var child	: ISceneNode	= _children[i];
				var group 	: Group 		= child as Group;

				if (child is type)
					descendants.push(child);

				if (group)
					group.getDescendantsByType(type, descendants);
			}

			return descendants;
		}

		public function toString() : String
		{
			return '[' + getQualifiedClassName(this) + ' ' + name + ']';
		}

		/**
		 * Load the 3D scene corresponding to the specified URLRequest object
		 * and add it directly to the group.
		 *
		 * @param request
		 * @param options
		 * @return
		 *
		 */
		public function load(request	: URLRequest,
							 options	: ParserOptions	= null) : ILoader
		{
			var loader	: SceneLoader	= new SceneLoader(options);

			loader.complete.add(loaderCompleteHandler);
			loader.load(request);

			return loader;
		}

		/**
		 * Load the 3D scene corresponding to the specified Class object
		 * and add it directly to the group.
		 *
		 * @param classObject
		 * @param options
		 * @return
		 */
		public function loadClass(classObject	: Class,
								  options		: ParserOptions	= null) : SceneLoader
		{
			var loader : SceneLoader = new SceneLoader(options);

			loader.complete.add(loaderCompleteHandler);
			loader.loadClass(classObject);

			return loader;
		}

		/**
		 * Load the 3D scene corresponding to the specified ByteArray object
		 * and add it directly to the group.
		 *
		 * @param bytes
		 * @param options
		 * @return
		 *
		 */
		public function loadBytes(bytes		: ByteArray,
								  options	: ParserOptions	= null) : ILoader
		{
			var loader	: SceneLoader	= new SceneLoader(options);

			loader.complete.add(loaderCompleteHandler);
			loader.loadBytes(bytes);

			return loader;
		}

		/**
		 * Return the set of nodes matching the specified XPath query.
		 *
		 * @param xpath
		 * @return
		 *
		 */
		public function get(xpath : String) : SceneIterator
		{
			return new SceneIterator(xpath, new <ISceneNode>[this]);
		}

		private function loaderCompleteHandler(loader	: ILoader,
											   scene	: ISceneNode) : void
		{
			addChild(scene);
		}

		/**
		 * Return all the Mesh objects hit by the specified ray.
		 *
		 * @param ray
		 * @param maxDistance
		 * @return
		 *
		 */
		public function cast(ray : Ray, maxDistance : Number = Number.POSITIVE_INFINITY) : SceneIterator
		{
			var meshes		: Vector.<ISceneNode> 	= getDescendantsByType(Mesh);
			var numMeshes	: uint					= meshes.length;
			var hit			: Array					= [];
			var depth		: Vector.<Number>		= new <Number>[];
			var numItems	: uint					= 0;

			for (var i : uint = 0; i < numMeshes; ++i)
			{
				var mesh 		: Mesh		= meshes[i] as Mesh;
				var hitDepth	: Number	= mesh.cast(ray, maxDistance);

				if (hitDepth >= 0.0)
				{
					hit[numItems] = mesh;
					depth[numItems] = hitDepth;
					++numItems;
				}
			}

			if (numItems > 1)
				Sort.flashSort(depth, hit, numItems);

			return new SceneIterator(null, Vector.<ISceneNode>(hit));
		}

		override minko_scene function cloneNode() : AbstractSceneNode
		{
			var clone : Group = new Group();

			clone.name = name;
			clone.transform.copyFrom(transform);

			for (var childId : uint = 0; childId < _numChildren; ++childId)
			{
				var child		: AbstractSceneNode = AbstractSceneNode(_children[childId]);
				var clonedChild	: AbstractSceneNode = AbstractSceneNode(child.cloneNode());

				clone.addChild(clonedChild);
			}

			return clone;
		}
	}
}

remove useless position < 0 test in Group.removeChildAt() since the specified position is uint


package aerys.minko.scene.node
{
	import aerys.minko.ns.minko_scene;
	import aerys.minko.scene.SceneIterator;
	import aerys.minko.type.Signal;
	import aerys.minko.type.Sort;
	import aerys.minko.type.loader.ILoader;
	import aerys.minko.type.loader.SceneLoader;
	import aerys.minko.type.loader.parser.ParserOptions;
	import aerys.minko.type.math.Ray;

	import flash.net.URLRequest;
	import flash.utils.ByteArray;
	import flash.utils.getQualifiedClassName;

	use namespace minko_scene;

	/**
	 * Group objects can contain other scene nodes and applies a 3D
	 * transformation to its descendants.
	 *
	 * @author Jean-Marc Le Roux
	 */
	public class Group extends AbstractVisibleSceneNode
	{
		minko_scene var _children		: Vector.<ISceneNode>;
		minko_scene var _numChildren	: uint;

		private var _numDescendants		: uint;

		private var _descendantAdded	: Signal;
		private var _descendantRemoved	: Signal;

		/**
		 * The number of children of the Group.
		 */
		public function get numChildren() : uint
		{
			return _numChildren;
		}

		/**
		 * The number of descendants of the Group.
		 *
		 * @return
		 *
		 */
		public function get numDescendants() : uint
		{
			return _numDescendants;
		}

		/**
		 * The signal executed when a descendant is added to the Group.
		 * Callbacks for this signal must accept the following arguments:
		 *

		 *
newParent : Group, the Group the descendant was actually added to

		 *
descendant : ISceneNode, the descendant that was just added

		 *

		 *
		 * @return
		 *
		 */
		public function get descendantAdded() : Signal
		{
			return _descendantAdded
		}

		/**
		 * The signal executed when a descendant is removed from the Group.
		 * Callbacks for this signal must accept the following arguments:
		 *

		 *
oldParent : Group, the Group the descendant was actually removed from

		 *
descendant : ISceneNode, the descendant that was just removed

		 *

		 *
		 * @return
		 *
		 */
		public function get descendantRemoved() : Signal
		{
			return _descendantRemoved;
		}

		public function Group(...children)
		{
			super();

			initializeChildren(children);
		}

		override protected function initializeSignals() : void
		{
			super.initializeSignals();

            _descendantAdded = new Signal('Group.descendantAdded');
            _descendantRemoved = new Signal('Group.descendantRemoved');
		}

		override protected function initializeSignalHandlers() : void
		{
			super.initializeSignalHandlers();

			_descendantAdded.add(descendantAddedHandler);
			_descendantRemoved.add(descendantRemovedHandler);

			added.add(addedHandler);
			removed.add(removedHandler);
		}

		protected function initializeChildren(children : Array) : void
		{
			_children = new <ISceneNode>[];

			while (children.length == 1 && children[0] is Array)
				children = children[0];

			var childrenNum : uint = children.length;

			for (var childrenIndex : uint = 0; childrenIndex < childrenNum; ++childrenIndex)
				addChild(ISceneNode(children[childrenIndex]));
		}

		private function descendantAddedHandler(group : Group, child : ISceneNode) : void
		{
			if (group == this)
			{
				var childGroup : Group = child as Group;

				if (childGroup)
				{
					childGroup.descendantAdded.add(_descendantAdded.execute);
					childGroup.descendantRemoved.add(_descendantRemoved.execute);
				}
			}

			_numDescendants += (child is Group) ? (child as Group)._numDescendants + 1 : 1;
		}

		private function descendantRemovedHandler(group : Group, child : ISceneNode) : void
		{
			if (group == this)
			{
				var childGroup : Group = child as Group;

				if (childGroup)
				{
					childGroup.descendantAdded.remove(_descendantAdded.execute);
					childGroup.descendantRemoved.remove(_descendantRemoved.execute);
				}
			}

			_numDescendants -= (child is Group) ? (child as Group)._numDescendants + 1 : 1;
		}

        private function addedHandler(child : ISceneNode, ancestor : Group) : void
        {
            var numChildren : uint = this.numChildren;

            for (var childId : uint = 0; childId < numChildren; ++childId)
            {
                var child : ISceneNode = _children[childId];

                child.added.execute(child, ancestor);
            }
        }

        private function removedHandler(child : ISceneNode, ancestor : Group) : void
        {
            var numChildren : uint = this.numChildren;

            for (var childId : uint = 0; childId < numChildren; ++childId)
            {
                var child : ISceneNode = _children[childId];

                child.removed.execute(child, ancestor);
            }
        }

		/**
		 * Return true if the specified scene node is a child of the Group, false otherwise.
		 *
		 * @param scene
		 * @return
		 *
		 */
		public function contains(scene : ISceneNode) : Boolean
		{
			return getChildIndex(scene) >= 0;
		}

		/**
		 * Return the index of the speficied scene node or -1 if it is not in the Group.
		 *
		 * @param child
		 * @return
		 *
		 */
		public function getChildIndex(child : ISceneNode) : int
		{
			if (child == null)
				throw new Error('The \'child\' parameter cannot be null.');

			for (var i : int = 0; i < _numChildren; i++)
				if (_children[i] === child)
					return i;

			return -1;
		}

		public function getChildByName(name : String) : ISceneNode
		{
			for (var i : int = 0; i < _numChildren; i++)
				if (_children[i].name === name)
					return _children[i];

			return null;
		}

		/**
		 * Add a child to the group.
		 *
		 * @param	scene The child to add.
		 */
		public function addChild(node : ISceneNode) : Group
		{
			return addChildAt(node, _numChildren);
		}

		/**
		 * Add a child to the group at the specified position.
		 *
		 * @param node
		 * @param position
		 * @return
		 *
		 */
		public function addChildAt(node : ISceneNode, position : uint) : Group
		{
			if (!node)
				throw new Error('Parameter \'scene\' must not be null.');

			node.parent = this;

			for (var i : int = _numChildren - 1; i > position; --i)
				_children[i] = _children[int(i - 1)];

			_children[position] = node;

			return this;
		}

		/**
		 * Remove a child from the container.
		 *
		 * @param	myChild The child to remove.
		 * @return Whether the child was actually removed or not.
		 */
		public function removeChild(child : ISceneNode) : Group
		{
			return removeChildAt(getChildIndex(child));
		}

		public function removeChildAt(position : uint) : Group
		{
			if (position >= _numChildren)
				throw new Error('The scene node is not a child of the caller.');

			(_children[position] as ISceneNode).parent = null;

			return this;
		}

		/**
		 * Remove all the children.
		 *
		 * @return
		 *
		 */
		public function removeAllChildren() : Group
		{
			while (_numChildren)
				removeChildAt(0);

			return this;
		}

		/**
		 * Return the child at the specified position.
		 *
		 * @param position
		 * @return
		 *
		 */
		public function getChildAt(position : uint) : ISceneNode
		{
			return position < _numChildren ? _children[position] : null;
		}

		/**
		 * Returns the list of descendant scene nodes that have the specified type.
		 *
		 * @param type
		 * @param descendants
		 * @return
		 *
		 */
		public function getDescendantsByType(type 			: Class,
											 descendants 	: Vector.<ISceneNode> = null) : Vector.<ISceneNode>
		{
			descendants ||= new Vector.<ISceneNode>();

			for (var i : int = 0; i < _numChildren; ++i)
			{
				var child	: ISceneNode	= _children[i];
				var group 	: Group 		= child as Group;

				if (child is type)
					descendants.push(child);

				if (group)
					group.getDescendantsByType(type, descendants);
			}

			return descendants;
		}

		public function toString() : String
		{
			return '[' + getQualifiedClassName(this) + ' ' + name + ']';
		}

		/**
		 * Load the 3D scene corresponding to the specified URLRequest object
		 * and add it directly to the group.
		 *
		 * @param request
		 * @param options
		 * @return
		 *
		 */
		public function load(request	: URLRequest,
							 options	: ParserOptions	= null) : ILoader
		{
			if (options != null && scene != null && options.assets == null)
				options.assets = scene.assets;

			var loader	: SceneLoader	= new SceneLoader(options);

			loader.complete.add(loaderCompleteHandler);
			loader.load(request);

			return loader;
		}

		/**
		 * Load the 3D scene corresponding to the specified Class object
		 * and add it directly to the group.
		 *
		 * @param classObject
		 * @param options
		 * @return
		 */
		public function loadClass(classObject	: Class,
								  options		: ParserOptions	= null) : SceneLoader
		{
			if (options != null && scene != null && options.assets == null)
				options.assets = scene.assets;

			var loader : SceneLoader = new SceneLoader(options);

			loader.complete.add(loaderCompleteHandler);
			loader.loadClass(classObject);

			return loader;
		}

		/**
		 * Load the 3D scene corresponding to the specified ByteArray object
		 * and add it directly to the group.
		 *
		 * @param bytes
		 * @param options
		 * @return
		 *
		 */
		public function loadBytes(bytes		: ByteArray,
								  options	: ParserOptions	= null) : ILoader
		{
			if (options != null && scene != null && options.assets == null)
				options.assets = scene.assets;

			var loader	: SceneLoader	= new SceneLoader(options);

			loader.complete.add(loaderCompleteHandler);
			loader.loadBytes(bytes);

			return loader;
		}

		/**
		 * Return the set of nodes matching the specified XPath query.
		 *
		 * @param xpath
		 * @return
		 *
		 */
		public function get(xpath : String) : SceneIterator
		{
			return new SceneIterator(xpath, new <ISceneNode>[this]);
		}

		private function loaderCompleteHandler(loader	: ILoader,
											   scene	: ISceneNode) : void
		{
			addChild(scene);
		}

		/**
		 * Return all the Mesh objects hit by the specified ray.
		 *
		 * @param ray
		 * @param maxDistance
		 * @return
		 *
		 */
		public function cast(ray : Ray, maxDistance : Number = Number.POSITIVE_INFINITY, tag : uint = 1) : SceneIterator
		{
			var meshes		: Vector.<ISceneNode> 	= getDescendantsByType(Mesh);
			var numMeshes	: uint					= meshes.length;
			var hit			: Array					= [];
			var depth		: Vector.<Number>		= new <Number>[];
			var numItems	: uint					= 0;

			for (var i : uint = 0; i < numMeshes; ++i)
			{
				var mesh 		: Mesh		= meshes[i] as Mesh;
				var hitDepth	: Number	= mesh.cast(ray, maxDistance, tag);

				if (hitDepth >= 0.0)
				{
					hit[numItems] = mesh;
					depth[numItems] = hitDepth;
					++numItems;
				}
			}

			if (numItems > 1)
				Sort.flashSort(depth, hit, numItems);

			return new SceneIterator(null, Vector.<ISceneNode>(hit));
		}

		override minko_scene function cloneNode() : AbstractSceneNode
		{
			var clone : Group = new Group();

			clone.name = name;
			clone.transform.copyFrom(transform);

			for (var childId : uint = 0; childId < _numChildren; ++childId)
			{
				var child		: AbstractSceneNode = AbstractSceneNode(_children[childId]);
				var clonedChild	: AbstractSceneNode = AbstractSceneNode(child.cloneNode());

				clone.addChild(clonedChild);
			}

			return clone;
		}
	}
}

package aerys.minko.scene.node
{
	import aerys.minko.ns.minko_scene;
	import aerys.minko.scene.SceneIterator;
	import aerys.minko.type.Signal;
	import aerys.minko.type.Sort;
	import aerys.minko.type.loader.ILoader;
	import aerys.minko.type.loader.SceneLoader;
	import aerys.minko.type.loader.parser.ParserOptions;
	import aerys.minko.type.math.Ray;

	import flash.net.URLRequest;
	import flash.utils.ByteArray;
	import flash.utils.getQualifiedClassName;

	use namespace minko_scene;

	/**
	 * Group objects can contain other scene nodes and applies a 3D
	 * transformation to its descendants.
	 *
	 * @author Jean-Marc Le Roux
	 */
	public class Group extends AbstractVisibleSceneNode
	{
		minko_scene var _children		: Vector.<ISceneNode>;
		minko_scene var _numChildren	: uint;

		private var _numDescendants		: uint;

		private var _descendantAdded	: Signal;
		private var _descendantRemoved	: Signal;

		/**
		 * The number of children of the Group.
		 */
		public function get numChildren() : uint
		{
			return _numChildren;
		}

		/**
		 * The number of descendants of the Group.
		 *
		 * @return
		 *
		 */
		public function get numDescendants() : uint
		{
			return _numDescendants;
		}

		/**
		 * The signal executed when a descendant is added to the Group.
		 * Callbacks for this signal must accept the following arguments:
		 *

		 *
newParent : Group, the Group the descendant was actually added to

		 *
descendant : ISceneNode, the descendant that was just added

		 *

		 *
		 * @return
		 *
		 */
		public function get descendantAdded() : Signal
		{
			return _descendantAdded
		}

		/**
		 * The signal executed when a descendant is removed from the Group.
		 * Callbacks for this signal must accept the following arguments:
		 *

		 *
oldParent : Group, the Group the descendant was actually removed from

		 *
descendant : ISceneNode, the descendant that was just removed

		 *

		 *
		 * @return
		 *
		 */
		public function get descendantRemoved() : Signal
		{
			return _descendantRemoved;
		}

		public function Group(...children)
		{
			super();

			initializeChildren(children);
		}

		override protected function initializeSignals() : void
		{
			super.initializeSignals();

            _descendantAdded = new Signal('Group.descendantAdded');
            _descendantRemoved = new Signal('Group.descendantRemoved');
		}

		override protected function initializeSignalHandlers() : void
		{
			super.initializeSignalHandlers();

			_descendantAdded.add(descendantAddedHandler);
			_descendantRemoved.add(descendantRemovedHandler);

			added.add(addedHandler);
			removed.add(removedHandler);
		}

		protected function initializeChildren(children : Array) : void
		{
			_children = new <ISceneNode>[];

			while (children.length == 1 && children[0] is Array)
				children = children[0];

			var childrenNum : uint = children.length;

			for (var childrenIndex : uint = 0; childrenIndex < childrenNum; ++childrenIndex)
				addChild(ISceneNode(children[childrenIndex]));
		}

		private function descendantAddedHandler(group : Group, child : ISceneNode) : void
		{
			if (group == this)
			{
				var childGroup : Group = child as Group;

				if (childGroup)
				{
					childGroup.descendantAdded.add(_descendantAdded.execute);
					childGroup.descendantRemoved.add(_descendantRemoved.execute);
				}
			}

			_numDescendants += (child is Group) ? (child as Group)._numDescendants + 1 : 1;
		}

		private function descendantRemovedHandler(group : Group, child : ISceneNode) : void
		{
			if (group == this)
			{
				var childGroup : Group = child as Group;

				if (childGroup)
				{
					childGroup.descendantAdded.remove(_descendantAdded.execute);
					childGroup.descendantRemoved.remove(_descendantRemoved.execute);
				}
			}

			_numDescendants -= (child is Group) ? (child as Group)._numDescendants + 1 : 1;
		}

        private function addedHandler(child : ISceneNode, ancestor : Group) : void
        {
            var numChildren : uint = this.numChildren;

            for (var childId : uint = 0; childId < numChildren; ++childId)
            {
                var child : ISceneNode = _children[childId];

                child.added.execute(child, ancestor);
            }
        }

        private function removedHandler(child : ISceneNode, ancestor : Group) : void
        {
            var numChildren : uint = this.numChildren;

            for (var childId : uint = 0; childId < numChildren; ++childId)
            {
                var child : ISceneNode = _children[childId];

                child.removed.execute(child, ancestor);
            }
        }

		/**
		 * Return true if the specified scene node is a child of the Group, false otherwise.
		 *
		 * @param scene
		 * @return
		 *
		 */
		public function contains(scene : ISceneNode) : Boolean
		{
			return getChildIndex(scene) >= 0;
		}

		/**
		 * Return the index of the speficied scene node or -1 if it is not in the Group.
		 *
		 * @param child
		 * @return
		 *
		 */
		public function getChildIndex(child : ISceneNode) : int
		{
			if (child == null)
				throw new Error('The \'child\' parameter cannot be null.');

			for (var i : int = 0; i < _numChildren; i++)
				if (_children[i] === child)
					return i;

			return -1;
		}

		public function getChildByName(name : String) : ISceneNode
		{
			for (var i : int = 0; i < _numChildren; i++)
				if (_children[i].name === name)
					return _children[i];

			return null;
		}

		/**
		 * Add a child to the group.
		 *
		 * @param	scene The child to add.
		 */
		public function addChild(node : ISceneNode) : Group
		{
			return addChildAt(node, _numChildren);
		}

		/**
		 * Add a child to the group at the specified position.
		 *
		 * @param node
		 * @param position
		 * @return
		 *
		 */
		public function addChildAt(node : ISceneNode, position : uint) : Group
		{
			if (!node)
				throw new Error('Parameter \'node\' must not be null.');

			node.parent = this;

			for (var i : int = _numChildren - 1; i > position; --i)
				_children[i] = _children[int(i - 1)];

			_children[position] = node;

			return this;
		}

		/**
		 * Remove a child from the container.
		 *
		 * @param	myChild The child to remove.
		 * @return Whether the child was actually removed or not.
		 */
		public function removeChild(child : ISceneNode) : Group
		{
			return removeChildAt(getChildIndex(child));
		}

		public function removeChildAt(position : uint) : Group
		{
			if (position >= _numChildren)
				throw new Error('The scene node is not a child of the caller.');

			(_children[position] as ISceneNode).parent = null;

			return this;
		}

		/**
		 * Remove all the children.
		 *
		 * @return
		 *
		 */
		public function removeAllChildren() : Group
		{
			while (_numChildren)
				removeChildAt(0);

			return this;
		}

		/**
		 * Return the child at the specified position.
		 *
		 * @param position
		 * @return
		 *
		 */
		public function getChildAt(position : uint) : ISceneNode
		{
			return position < _numChildren ? _children[position] : null;
		}

		/**
		 * Returns the list of descendant scene nodes that have the specified type.
		 *
		 * @param type
		 * @param descendants
		 * @return
		 *
		 */
		public function getDescendantsByType(type 			: Class,
											 descendants 	: Vector.<ISceneNode> = null) : Vector.<ISceneNode>
		{
			descendants ||= new Vector.<ISceneNode>();

			for (var i : int = 0; i < _numChildren; ++i)
			{
				var child	: ISceneNode	= _children[i];
				var group 	: Group 		= child as Group;

				if (child is type)
					descendants.push(child);

				if (group)
					group.getDescendantsByType(type, descendants);
			}

			return descendants;
		}

		public function toString() : String
		{
			return '[' + getQualifiedClassName(this) + ' ' + name + ']';
		}

		/**
		 * Load the 3D scene corresponding to the specified URLRequest object
		 * and add it directly to the group.
		 *
		 * @param request
		 * @param options
		 * @return
		 *
		 */
		public function load(request	: URLRequest,
							 options	: ParserOptions	= null) : ILoader
		{
			if (options != null && scene != null && options.assets == null)
				options.assets = scene.assets;

			var loader	: SceneLoader	= new SceneLoader(options);

			loader.complete.add(loaderCompleteHandler);
			loader.load(request);

			return loader;
		}

		/**
		 * Load the 3D scene corresponding to the specified Class object
		 * and add it directly to the group.
		 *
		 * @param classObject
		 * @param options
		 * @return
		 */
		public function loadClass(classObject	: Class,
								  options		: ParserOptions	= null) : SceneLoader
		{
			if (options != null && scene != null && options.assets == null)
				options.assets = scene.assets;

			var loader : SceneLoader = new SceneLoader(options);

			loader.complete.add(loaderCompleteHandler);
			loader.loadClass(classObject);

			return loader;
		}

		/**
		 * Load the 3D scene corresponding to the specified ByteArray object
		 * and add it directly to the group.
		 *
		 * @param bytes
		 * @param options
		 * @return
		 *
		 */
		public function loadBytes(bytes		: ByteArray,
								  options	: ParserOptions	= null) : ILoader
		{
			if (options != null && scene != null && options.assets == null)
				options.assets = scene.assets;

			var loader	: SceneLoader	= new SceneLoader(options);

			loader.complete.add(loaderCompleteHandler);
			loader.loadBytes(bytes);

			return loader;
		}

		/**
		 * Return the set of nodes matching the specified XPath query.
		 *
		 * @param xpath
		 * @return
		 *
		 */
		public function get(xpath : String) : SceneIterator
		{
			return new SceneIterator(xpath, new <ISceneNode>[this]);
		}

		private function loaderCompleteHandler(loader	: ILoader,
											   scene	: ISceneNode) : void
		{
			addChild(scene);
		}

		/**
		 * Return all the Mesh objects hit by the specified ray.
		 *
		 * @param ray
		 * @param maxDistance
		 * @return
		 *
		 */
		public function cast(ray : Ray, maxDistance : Number = Number.POSITIVE_INFINITY, tag : uint = 1) : SceneIterator
		{
			var meshes		: Vector.<ISceneNode> 	= getDescendantsByType(Mesh);
			var numMeshes	: uint					= meshes.length;
			var hit			: Array					= [];
			var depth		: Vector.<Number>		= new <Number>[];
			var numItems	: uint					= 0;

			for (var i : uint = 0; i < numMeshes; ++i)
			{
				var mesh 		: Mesh		= meshes[i] as Mesh;
				var hitDepth	: Number	= mesh.cast(ray, maxDistance, tag);

				if (hitDepth >= 0.0)
				{
					hit[numItems] = mesh;
					depth[numItems] = hitDepth;
					++numItems;
				}
			}

			if (numItems > 1)
				Sort.flashSort(depth, hit, numItems);

			return new SceneIterator(null, Vector.<ISceneNode>(hit));
		}

		override minko_scene function cloneNode() : AbstractSceneNode
		{
			var clone : Group = new Group();

			clone.name = name;
			clone.transform.copyFrom(transform);

			for (var childId : uint = 0; childId < _numChildren; ++childId)
			{
				var child		: AbstractSceneNode = AbstractSceneNode(_children[childId]);
				var clonedChild	: AbstractSceneNode = AbstractSceneNode(child.cloneNode());

				clone.addChild(clonedChild);
			}

			return clone;
		}
	}
}

fix typo in error message

fix typo in error message


/**
 * Created by vizoli on 4/9/16.
 */
package ageofai.home.model
{
    import ageofai.cost.constant.CUnitCost;
    import ageofai.home.ai.HomeAI;
    import ageofai.home.constant.CHome;
    import ageofai.home.event.HomeEvent;
    import ageofai.home.vo.HomeVO;
    import ageofai.villager.vo.VillagerVO;

    import caurina.transitions.Tweener;

    import common.mvc.model.base.BaseModel;

    import flash.events.TimerEvent;
    import flash.utils.Timer;

    public class HomeModel extends BaseModel implements IHomeModel
    {
        private var _homes:Vector.<HomeVO>;
        private var _homeAI:HomeAI;

        public function HomeModel()
        {
            this._homeAI = new HomeAI();
        }

        public function tick():void
        {
            this.calculateVillagerCreation();
        }

        private function calculateVillagerCreation():void
        {
            for ( var i:int = 0; i < this._homes.length; i++ )
            {
                if ( !this._homes[ i ].villagerIsCreating )
                {
                    if ( this._homeAI.isNewVillagerAvailable( this._homes[ i ].food, this._homes[ i ].villagers.length ) )
                    {
                        this._homes[ i ].villagerIsCreating = true;

                        this.updateFoodAmount( this._homes[ i ], this._homes[ i ].food - CUnitCost.VILLAGER.food );

                        this._homes[ i ].food -= CUnitCost.VILLAGER.food;

                        var home:HomeVO = this._homes[ i ];

                        var creationTimer:Timer = new Timer( CHome.VILLAGER_CREATION_TIME / CHome.VILLAGER_CREATION_TIMELY, CHome.VILLAGER_CREATION_TIMELY );
                        creationTimer.addEventListener( TimerEvent.TIMER, function ():void
                        {
                            var homeEvent:HomeEvent = new HomeEvent( HomeEvent.VILLAGER_CREATION_IN_PROGRESS );
                            homeEvent.progressPercentage = creationTimer.currentCount * CHome.VILLAGER_CREATION_TIMELY;
                            homeEvent.homeVO = home;

                            dispatch( homeEvent );
                        } );

                        Tweener.addTween( this, {
                            time: 2,
                            onComplete: creationTimerCompleteHandler,
                            onCompleteParams: [ home ]
                        } );

                        creationTimer.start();
                    }
                }
            }
        }

        private function creationTimerCompleteHandler( homeVO:HomeVO ):void
        {
            homeVO.villagerIsCreating = false;

            trace( '@@@@@===============>>>>>', homeVO.id );
            var homeEvent:HomeEvent = new HomeEvent( HomeEvent.REQUEST_TO_CREATE_VILLAGER );
            homeEvent.homeVO = homeVO;

            this.dispatch( homeEvent );
        }

        public function setInitHomes( homes:Vector.<HomeVO> ):void
        {
            this._homes = homes;

            this.setHomeVOIds();
        }

        private function setHomeVOIds():void
        {
            for ( var i:int = 0; i < this._homes.length; i++ )
            {
                this._homes[ i ].id = i;
            }
        }

        public function addVillager( homeVO:HomeVO, villagerVO:VillagerVO ):void
        {
            homeVO.villagers.push( villagerVO );
        }

        public function updateFoodAmount( homeVO:HomeVO, amount:int ):void
        {
            homeVO.food = amount;

            var event:HomeEvent = new HomeEvent( HomeEvent.FOOD_AMOUNT_UPDATED );
            event.homeVO = homeVO;

            this.dispatch( event );
        }

        public function updateWoodAmount( homeVO:HomeVO, amount:int ):void
        {
            homeVO.wood = amount;

            var event:HomeEvent = new HomeEvent( HomeEvent.WOOD_AMOUNT_UPDATED );
            event.homeVO = homeVO;

            this.dispatch( event );
        }

        public function getHomeByVillager( villagerVO:VillagerVO ):HomeVO
        {
            for ( var i:int = 0; i < this._homes.length; i++ )
            {
                for ( var j:int = 0; j < this._homes[ i ].villagers.length; j++ )
                {
                    if ( this._homes[ i ].villagers[ j ] == villagerVO )
                    {
                        return this._homes[ i ];
                    }
                }
            }

            return null;
        }
    }
}

/**
 * Created by vizoli on 4/9/16.
 */
package ageofai.home.model
{
    import ageofai.cost.constant.CUnitCost;
    import ageofai.home.ai.HomeAI;
    import ageofai.home.constant.CHome;
    import ageofai.home.event.HomeEvent;
    import ageofai.home.vo.HomeVO;
    import ageofai.villager.vo.VillagerVO;
    import flash.utils.Dictionary;

    import caurina.transitions.Tweener;

    import common.mvc.model.base.BaseModel;

    import flash.events.TimerEvent;
    import flash.utils.Timer;

    public class HomeModel extends BaseModel implements IHomeModel
    {
        private var _homes:Vector.<HomeVO>;
        private var _homeAI:HomeAI;

        private var _progressDic:Dictionary = new Dictionary(true);

        public function HomeModel()
        {
            this._homeAI = new HomeAI();
        }

        public function tick():void
        {
            this.calculateVillagerCreation();
        }

        private function calculateVillagerCreation():void
        {
            for ( var i:int = 0; i < this._homes.length; i++ )
            {
                if ( !this._homes[ i ].villagerIsCreating )
                {
                    if ( this._homeAI.isNewVillagerAvailable( this._homes[ i ].food, this._homes[ i ].villagers.length ) )
                    {
                        this._homes[ i ].villagerIsCreating = true;

                        this.updateFoodAmount( this._homes[ i ], this._homes[ i ].food - CUnitCost.VILLAGER.food );

                        this._homes[ i ].food -= CUnitCost.VILLAGER.food;

                        var home:HomeVO = this._homes[ i ];

                        var creationTimer:Timer = new Timer( CHome.VILLAGER_CREATION_TIME / CHome.VILLAGER_CREATION_TIMELY, CHome.VILLAGER_CREATION_TIMELY );
                        creationTimer.addEventListener( TimerEvent.TIMER, creationTimerHandler );
                        _progressDic[creationTimer] = home;

                        Tweener.addTween( this, {
                            time: 2,
                            onComplete: creationTimerCompleteHandler,
                            onCompleteParams: [ home ]
                        } );

                        creationTimer.start();
                    }
                }
            }
        }

        private function creationTimerHandler(e:TimerEvent):void
        {
            var home:HomeVO = _progressDic[e.currentTarget];
            var homeEvent:HomeEvent = new HomeEvent( HomeEvent.VILLAGER_CREATION_IN_PROGRESS );
            homeEvent.progressPercentage = e.currentTarget.currentCount * CHome.VILLAGER_CREATION_TIMELY;
            homeEvent.homeVO = home;

            dispatch( homeEvent );
        }

        private function creationTimerCompleteHandler( homeVO:HomeVO ):void
        {
            homeVO.villagerIsCreating = false;

            trace( '@@@@@===============>>>>>', homeVO.id );
            var homeEvent:HomeEvent = new HomeEvent( HomeEvent.REQUEST_TO_CREATE_VILLAGER );
            homeEvent.homeVO = homeVO;

            this.dispatch( homeEvent );
        }

        public function setInitHomes( homes:Vector.<HomeVO> ):void
        {
            this._homes = homes;

            this.setHomeVOIds();
        }

        private function setHomeVOIds():void
        {
            for ( var i:int = 0; i < this._homes.length; i++ )
            {
                this._homes[ i ].id = i;
            }
        }

        public function addVillager( homeVO:HomeVO, villagerVO:VillagerVO ):void
        {
            homeVO.villagers.push( villagerVO );
        }

        public function updateFoodAmount( homeVO:HomeVO, amount:int ):void
        {
            homeVO.food = amount;

            var event:HomeEvent = new HomeEvent( HomeEvent.FOOD_AMOUNT_UPDATED );
            event.homeVO = homeVO;

            this.dispatch( event );
        }

        public function updateWoodAmount( homeVO:HomeVO, amount:int ):void
        {
            homeVO.wood = amount;

            var event:HomeEvent = new HomeEvent( HomeEvent.WOOD_AMOUNT_UPDATED );
            event.homeVO = homeVO;

            this.dispatch( event );
        }

        public function getHomeByVillager( villagerVO:VillagerVO ):HomeVO
        {
            for ( var i:int = 0; i < this._homes.length; i++ )
            {
                for ( var j:int = 0; j < this._homes[ i ].villagers.length; j++ )
                {
                    if ( this._homes[ i ].villagers[ j ] == villagerVO )
                    {
                        return this._homes[ i ];
                    }
                }
            }

            return null;
        }
    }
}

fix creation progress

fix creation progress


package org.mangui.osmf.plugins
{
	import flash.display.Sprite;
	import flash.system.Security;

	import org.mangui.osmf.plugins.HLSPlugin;
	import org.osmf.media.PluginInfo;

	public class HLSDynamicPlugin extends Sprite
	{
		private var _pluginInfo:PluginInfo;

		public function HLSDynamicPlugin()
		{
			super();
			Security.allowDomain("*");
			_pluginInfo = new HLSPlugin();
		}

		public function get pluginInfo():PluginInfo{
			return _pluginInfo;
		}
	}
}

package org.mangui.osmf.plugins
{
	import flash.display.Sprite;
	import flash.system.Security;
	import org.osmf.media.PluginInfo;

	public class HLSDynamicPlugin extends Sprite
	{
		private var _pluginInfo:PluginInfo;

		public function HLSDynamicPlugin()
		{
			super();
			Security.allowDomain("*");
			_pluginInfo = new HLSPlugin();
		}

		public function get pluginInfo():PluginInfo{
			return _pluginInfo;
		}
	}
}

remove unused import

remove unused import


                                                        -*- shell-script -*-
URBI_INIT

me=$as_me
medir=$(echo "$as_me" | sed -e 's/\..*//').dir
rm -rf $medir
mkdir $medir
cd $medir
xrun "--help"    urbi-send --help
xrun "--version" urbi-send --version

                                                        -*- shell-script -*-
URBI_INIT

me=$as_me
medir=$(absolute "$0").dir
rm -rf $medir
mkdir -p $medir
cd $medir
xrun "--help"    urbi-send --help
xrun "--version" urbi-send --version

Fix clean rules.

Fix clean rules.

	* src/tests/examples/urbi-send.as (medir): Fix its value.


//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2008 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

package com.threerings.bureau.data {

import com.threerings.presents.dobj.DObject;

public class AgentObject extends DObject
{
    // AUTO-GENERATED: FIELDS START
    /** The field name of the bureauId field. */
    public static const BUREAU_ID :String = "bureauId";

    /** The field name of the bureauType field. */
    public static const BUREAU_TYPE :String = "bureauType";

    /** The field name of the agentCode field. */
    public static const AGENT_CODE :String = "agentCode";
    // AUTO-GENERATED: FIELDS END

    /** The id of the bureau the agent is running in. This is normally a unique id corresponding
     *  to the game or item that requires some server-side processing. */
    public var bureauId :String;

    /** The type of bureau that the agent is running in. This is normally derived from the kind
     *  of media that the game or item has specified for its code and determines the method of
     *  launching the bureau when the first agent is requested. */
    public var bureauType :String;

    /** The location of the code for the agent. This could be a URL to an action script file or
     *  some other description that the bureau can use to load and execute the agent's code. */
    public var agentCode :String;

    // AUTO-GENERATED: METHODS START
    /**
     * Requests that the bureauId field be set to the
     * specified value. The local value will be updated immediately and an
     * event will be propagated through the system to notify all listeners
     * that the attribute did change. Proxied copies of this object (on
     * clients) will apply the value change when they received the
     * attribute changed notification.
     */
    public function setBureauId (value :String) :void
    {
        var ovalue :String = this.bureauId;
        requestAttributeChange(
            BUREAU_ID, value, ovalue);
        this.bureauId = value;
    }

    /**
     * Requests that the bureauType field be set to the
     * specified value. The local value will be updated immediately and an
     * event will be propagated through the system to notify all listeners
     * that the attribute did change. Proxied copies of this object (on
     * clients) will apply the value change when they received the
     * attribute changed notification.
     */
    public function setBureauType (value :String) :void
    {
        var ovalue :String = this.bureauType;
        requestAttributeChange(
            BUREAU_TYPE, value, ovalue);
        this.bureauType = value;
    }

    /**
     * Requests that the agentCode field be set to the
     * specified value. The local value will be updated immediately and an
     * event will be propagated through the system to notify all listeners
     * that the attribute did change. Proxied copies of this object (on
     * clients) will apply the value change when they received the
     * attribute changed notification.
     */
    public function setAgentCode (value :String) :void
    {
        var ovalue :String = this.agentCode;
        requestAttributeChange(
            AGENT_CODE, value, ovalue);
        this.agentCode = value;
    }
    // AUTO-GENERATED: METHODS END
}
}

//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2008 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

package com.threerings.bureau.data {

import com.threerings.io.ObjectInputStream;
import com.threerings.presents.dobj.DObject;

public class AgentObject extends DObject
{
    // AUTO-GENERATED: FIELDS START
    /** The field name of the bureauId field. */
    public static const BUREAU_ID :String = "bureauId";

    /** The field name of the bureauType field. */
    public static const BUREAU_TYPE :String = "bureauType";

    /** The field name of the agentCode field. */
    public static const AGENT_CODE :String = "agentCode";
    // AUTO-GENERATED: FIELDS END

    /** The id of the bureau the agent is running in. This is normally a unique id corresponding
     *  to the game or item that requires some server-side processing. */
    public var bureauId :String;

    /** The type of bureau that the agent is running in. This is normally derived from the kind
     *  of media that the game or item has specified for its code and determines the method of
     *  launching the bureau when the first agent is requested. */
    public var bureauType :String;

    /** The location of the code for the agent. This could be a URL to an action script file or
     *  some other description that the bureau can use to load and execute the agent's code. */
    public var agentCode :String;

    // AUTO-GENERATED: METHODS START
    /**
     * Requests that the bureauId field be set to the
     * specified value. The local value will be updated immediately and an
     * event will be propagated through the system to notify all listeners
     * that the attribute did change. Proxied copies of this object (on
     * clients) will apply the value change when they received the
     * attribute changed notification.
     */
    public function setBureauId (value :String) :void
    {
        var ovalue :String = this.bureauId;
        requestAttributeChange(
            BUREAU_ID, value, ovalue);
        this.bureauId = value;
    }

    /**
     * Requests that the bureauType field be set to the
     * specified value. The local value will be updated immediately and an
     * event will be propagated through the system to notify all listeners
     * that the attribute did change. Proxied copies of this object (on
     * clients) will apply the value change when they received the
     * attribute changed notification.
     */
    public function setBureauType (value :String) :void
    {
        var ovalue :String = this.bureauType;
        requestAttributeChange(
            BUREAU_TYPE, value, ovalue);
        this.bureauType = value;
    }

    /**
     * Requests that the agentCode field be set to the
     * specified value. The local value will be updated immediately and an
     * event will be propagated through the system to notify all listeners
     * that the attribute did change. Proxied copies of this object (on
     * clients) will apply the value change when they received the
     * attribute changed notification.
     */
    public function setAgentCode (value :String) :void
    {
        var ovalue :String = this.agentCode;
        requestAttributeChange(
            AGENT_CODE, value, ovalue);
        this.agentCode = value;
    }
    // AUTO-GENERATED: METHODS END

    // from interface Streamable
    override public function readObject (ins :ObjectInputStream) :void
    {
        super.readObject(ins);
        bureauId = ins.readField(String) as String;
        bureauType = ins.readField(String) as String;
        agentCode = ins.readField(String) as String;
    }
}
}

Configure the AgentObject from the stream.

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


package classes
{
	/**
	 AGORA - an interactive and web-based argument mapping tool that stimulates reasoning,
	 reflection, critique, deliberation, and creativity in individual argument construction
	 and in collaborative or adversarial settings.
	 Copyright (C) 2011 Georgia Institute of Technology

	 This program is free software: you can redistribute it and/or modify
	 it under the terms of the GNU Affero General Public License as
	 published by the Free Software Foundation, either version 3 of the
	 License, or (at your option) any later version.

	 This program is distributed in the hope that it will be useful,
	 but WITHOUT ANY WARRANTY; without even the implied warranty of
	 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	 GNU Affero General Public License for more details.

	 You should have received a copy of the GNU Affero General Public License
	 along with this program.  If not, see <http://www.gnu.org/licenses/>.

	 */
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;

	import mx.controls.Alert;

	import org.osmf.layout.AbsoluteLayoutFacet;

	public class Language
	{
		//I will set the language to either GERMAN, RUSSIAN or ENGLISH
		//based on this, you could read the values into the variables
		//by default, the language is EN-US

		public static const GERMAN:String = "GER";
		public static const ENGLISH:String = "EN-US";
		public static const RUSSIAN:String = "RUS";
		public static var language:String = GERMAN;

		public static var xml:XML;
		private static var ready:Boolean=false;

		public static function init():void
		{
			[Embed(source="../../../translation.xml", mimeType="application/octet-stream")]
			const MyData:Class;
			var byteArray:ByteArray = new MyData() as ByteArray;
			var x:XML = new XML(byteArray.readUTFBytes(byteArray.length));
			xml = x;
			ready=true;
		}

		/**The key function. Use this to look up a label from the translation document according to the set language.*/

		public static function lookup(label:String):String{
			if(!ready){
				init();
			}
			trace("Now looking up:" + label);
			var lbl:XMLList = xml.descendants(label);
			var lang:XMLList = lbl.descendants(language);
			var output:String = lang.attribute("text");
			if(!output){
				output = "error | ошибка | fehler --- There was a problem getting the text for this item. The label was: " + label;
			}
			trace("Output is: " + output);
			return output;
		}
	}
}

package classes
{
	/**
	 AGORA - an interactive and web-based argument mapping tool that stimulates reasoning,
	 reflection, critique, deliberation, and creativity in individual argument construction
	 and in collaborative or adversarial settings.
	 Copyright (C) 2011 Georgia Institute of Technology

	 This program is free software: you can redistribute it and/or modify
	 it under the terms of the GNU Affero General Public License as
	 published by the Free Software Foundation, either version 3 of the
	 License, or (at your option) any later version.

	 This program is distributed in the hope that it will be useful,
	 but WITHOUT ANY WARRANTY; without even the implied warranty of
	 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	 GNU Affero General Public License for more details.

	 You should have received a copy of the GNU Affero General Public License
	 along with this program.  If not, see <http://www.gnu.org/licenses/>.

	 */
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;

	import mx.controls.Alert;

	import org.osmf.layout.AbsoluteLayoutFacet;

	public class Language
	{
		//I will set the language to either GERMAN, RUSSIAN or ENGLISH
		//based on this, you could read the values into the variables
		//by default, the language is EN-US

		public static const GERMAN:String = "GER";
		public static const ENGLISH:String = "EN-US";
		public static const RUSSIAN:String = "RUS";
		public static var language:String = ENGLISH;

		public static var xml:XML;
		private static var ready:Boolean=false;

		public static function init():void
		{
			[Embed(source="../../../translation.xml", mimeType="application/octet-stream")]
			const MyData:Class;
			var byteArray:ByteArray = new MyData() as ByteArray;
			var x:XML = new XML(byteArray.readUTFBytes(byteArray.length));
			xml = x;
			ready=true;
		}

		/**The key function. Use this to look up a label from the translation document according to the set language.*/

		public static function lookup(label:String):String{
			if(!ready){
				init();
			}
			trace("Now looking up:" + label);
			var lbl:XMLList = xml.descendants(label);
			var lang:XMLList = lbl.descendants(language);
			var output:String = lang.attribute("text");
			if(!output){
				output = "error | ошибка | fehler --- There was a problem getting the text for this item. The label was: " + label;
			}
			trace("Output is: " + output);
			return output;
		}
	}
}

Move default to English once more

Move default to English once more