/*
    Weave (Web-based Analysis and Visualization Environment)
    Copyright (C) 2008-2011 University of Massachusetts Lowell

    This file is a part of Weave.

    Weave is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License, Version 3,
    as published by the Free Software Foundation.

    Weave 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 General Public License for more details.

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

package weave.core
{
	import flash.utils.Dictionary;
	import flash.utils.getQualifiedClassName;

	import mx.utils.StringUtil;

	import weave.api.WeaveAPI;
	import weave.api.core.ILinkableHashMap;
	import weave.api.getCallbackCollection;
	import weave.api.reportError;
	import weave.compiler.Compiler;
	import weave.compiler.ICompiledObject;
	import weave.compiler.ProxyObject;
	import weave.compiler.StandardLib;

	/**
	 * LinkableFunction allows a function to be defined by a String that can use macros defined in the static macros hash map.
	 * Libraries listed in macroLibraries variable will be included when compiling the function.
	 *
	 * @author adufilie
	 */
	public class LinkableFunction extends LinkableString
	{
		/**
		 * Debug mode.
		 */
		public static var debug:Boolean = false;

		/**
		 * @param defaultValue The default function definition.
		 * @param ignoreRuntimeErrors If this is true, errors thrown during evaluation of the function will be caught and values of undefined will be returned.
		 * @param useThisScope When true, variable lookups will be evaluated as if the function were in the scope of the thisArg passed to the apply() function.
		 * @param paramNames An Array of parameter names that can be used in the function definition.
		 */
		public function LinkableFunction(defaultValue:String = null, ignoreRuntimeErrors:Boolean = false, useThisScope:Boolean = false, paramNames:Array = null)
		{
			super(unIndent(defaultValue));
			_allLinkableFunctions[this] = true; // register this instance so the callbacks will trigger when the libraries change
			_ignoreRuntimeErrors = ignoreRuntimeErrors;
			_useThisScope = useThisScope;
			_paramNames = paramNames && paramNames.concat();
			getCallbackCollection(this).addImmediateCallback(this, handleChange);
		}

		private var _ignoreRuntimeErrors:Boolean = false;
		private var _useThisScope:Boolean = false;
		private var _compiledMethod:Function = null;
		private var _paramNames:Array = null;
		private var _isFunctionDefinition:Boolean = false;

		/**
		 * This is called whenever the session state changes.
		 */
		private function handleChange():void
		{
			// do not compile immediately because we don't want to throw an error at this time.
			_compiledMethod = null;
		}

		/**
		 * This is used as a placeholder to prevent re-compiling erroneous code.
		 */
		private static function RETURN_UNDEFINED(..._):* { return undefined; }

		/**
		 * This will attempt to compile the function.  An Error will be thrown if this fails.
		 */
		public function validate():void
		{
			if (_compiledMethod == null)
			{
				// in case compile fails, prevent re-compiling erroneous code
				_compiledMethod = RETURN_UNDEFINED;
				_isFunctionDefinition = false;

				if (_macroProxy == null)
					_macroProxy = new ProxyObject(_hasMacro, _getMacro, null, evaluateMacro); // allows evaluating macros but not setting them
				var object:ICompiledObject = _compiler.compileToObject(value);
				_isFunctionDefinition = _compiler.compiledObjectIsFunction(object);
				_compiledMethod = _compiler.compileObjectToFunction(object, _macroProxy, errorHandler, _useThisScope, _paramNames);
			}
		}

		private function errorHandler(e:*):Boolean
		{
			if (debug)
				reportError(e);

			if (_ignoreRuntimeErrors || debug)
				return true;
			throw e;
		}

		/**
		 * This gets the length property of the generated Function.
		 */
		public function get length():int
		{
			if (_compiledMethod == null)
				validate();
			return _compiledMethod.length;
		}

		/**
		 * This will evaluate the function with the specified parameters.
		 * @param thisArg The value of 'this' to be used when evaluating the function.
		 * @param argArray An Array of arguments to be passed to the compiled function.
		 * @return The result of evaluating the function.
		 */
		public function apply(thisArg:* = null, argArray:Array = null):*
		{
			if (_compiledMethod == null)
				validate();
			return _compiledMethod.apply(thisArg, argArray);
		}

		/**
		 * This will evaluate the function with the specified parameters.
		 * @param thisArg The value of 'this' to be used when evaluating the function.
		 * @param args Arguments to be passed to the compiled function.
		 * @return The result of evaluating the function.
		 */
		public function call(thisArg:* = null, ...args):*
		{
			if (_compiledMethod == null)
				validate();
			return _compiledMethod.apply(thisArg, args);
		}

		/////////////////////////////////////////////////////////////////////////////////////////////
		// static section

		/**
		 * This is a proxy object for use as a symbol table for the compiler.
		 */
		private static var _macroProxy:ProxyObject = null;

		/**
		 * This function checks if a macro exists.
		 * @param macroName The name of a macro to check.
		 * @return A value of true if the specified macro exists, or false if it does not.
		 */
		private static function _hasMacro(macroName:String):Boolean
		{
			return macros.getObject(macroName) != null;
		}

		private static function _getMacro(macroName:String):*
		{
			var lf:LinkableFunction = macros.getObject(macroName) as LinkableFunction;
			if (!lf)
				return undefined;
			if (lf._isFunctionDefinition)
				return lf;
			return lf.apply();
		}

		/**
		 * This function evaluates a macro specified in the macros hash map.
		 * @param macroName The name of the macro to evaluate.
		 * @param params The parameters to pass to the macro.
		 * @return The result of evaluating the macro.
		 */
		public static function evaluateMacro(macroName:String, ...params):*
		{
			var lf:LinkableFunction = macros.getObject(macroName) as LinkableFunction;
			return lf ? lf.apply(null, params) : undefined;
		}

		/**
		 * This is a list of macros that can be used in any LinkableFunction expression.
		 */
		public static const macros:ILinkableHashMap = new LinkableHashMap(LinkableFunction);

		/**
		 * This is a list of libraries to include in the static compiler for macros.
		 */
		public static const macroLibraries:LinkableString = new LinkableString();

		/**
		 * This function will add a library to the static list of macro libraries if it is not already added.
		 * @param libraryQName A library to add to the list of static libraries.
		 */
		public static function includeMacroLibrary(libraryQName:String):void
		{
			var rows:Array = WeaveAPI.CSVParser.parseCSV(macroLibraries.value);
			for each (var row:Array in rows)
				if (row.indexOf(libraryQName) >= 0)
					return;
			rows.push([libraryQName]);
			macroLibraries.value = WeaveAPI.CSVParser.createCSV(rows);
		}

		staticInit();

		/**
		 * This function will initialize static variables.
		 */
		private static function staticInit():void
		{
			// when the libraries change, we need to update the compiler
			macroLibraries.addImmediateCallback(null, handleLibrariesChange);
			macroLibraries.value = getQualifiedClassName(WeaveAPI);
		}

		/**
		 * This is the static compiler to be used by every LinkableFunction.
		 */
		private static var _compiler:Compiler = null;
		private static var _allLinkableFunctions:Dictionary = new Dictionary(true); // the keys in this are LinkableFunction instances

		/**
		 * This function will update the static compiler when the static libraries change.
		 */
		private static function handleLibrariesChange():void
		{
			_compiler = _getNewCompiler(true);
			for (var linkableFunction:Object in _allLinkableFunctions)
			{
				var lf:LinkableFunction = linkableFunction as LinkableFunction;
				if (!lf.wasDisposed)
					lf.triggerCallbacks();
			}
		}

		/**
		 * This function returns a new compiler initialized with the libraries specified by the public static libraries variable.
		 * @param reportErrors If this is true, errors will be reported through WeaveAPI.ErrorManager.
		 * @return A new initialized compiler.
		 */
		private static function _getNewCompiler(reportErrors:Boolean):Compiler
		{
			var compiler:Compiler = new Compiler();
			for each (var row:Array in WeaveAPI.CSVParser.parseCSV(macroLibraries.value))
			{
				try
				{
					compiler.includeLibraries.apply(null, row);
				}
				catch (e:Error)
				{
					if (reportErrors)
						reportError(e);
				}
			}
			return compiler;
		}

//		/**
//		 * This function returns a new compiler initialized with the libraries specified by the public static libraries variable.
//		 * @return A new initialized compiler.
//		 */
//		public static function getNewCompiler():Compiler
//		{
//			return _getNewCompiler(false);
//		}

		/**
		 * Takes a script where all lines have been indented, removes the common indentation from all lines and replaces each tab with four spaces.
		 * The common indentation is naively assumed to be the same as the first non-blank line in the script.
		 * @param script A script.
		 * @return The modified script.
		 */
		public static function unIndent(script:String):String
		{
			if (script == null)
				return null;
			script = StandardLib.replace(script, '\r\n','\n','\r','\n');
			while (StringUtil.isWhitespace(script.substr(-1)))
				script = script.substr(0, -1);
			var lines:Array = script.split('\n');
			while (!lines[0])
				lines.shift();
			var indent:int = 0;
			var line:String = lines[0];
			while (line.charAt(indent) == '\t')
				indent++;
			lines.forEach(
				function(line:String, index:int, lines:Array):void
				{
					var i:int = 0;
					var spaces:String = '';
					while (line.charAt(i) == '\t')
						if (i++ >= indent)
							spaces += '    ';

					lines[index] = spaces + line.substr(i);
				}
			);
			return lines.join('\n') + '\n';
		}
	}
}

/*
    Weave (Web-based Analysis and Visualization Environment)
    Copyright (C) 2008-2011 University of Massachusetts Lowell

    This file is a part of Weave.

    Weave is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License, Version 3,
    as published by the Free Software Foundation.

    Weave 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 General Public License for more details.

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

package weave.core
{
	import flash.utils.Dictionary;
	import flash.utils.getQualifiedClassName;

	import mx.utils.StringUtil;

	import weave.api.WeaveAPI;
	import weave.api.core.ILinkableHashMap;
	import weave.api.getCallbackCollection;
	import weave.api.reportError;
	import weave.compiler.Compiler;
	import weave.compiler.ICompiledObject;
	import weave.compiler.ProxyObject;
	import weave.compiler.StandardLib;

	/**
	 * LinkableFunction allows a function to be defined by a String that can use macros defined in the static macros hash map.
	 * Libraries listed in macroLibraries variable will be included when compiling the function.
	 *
	 * @author adufilie
	 */
	public class LinkableFunction extends LinkableString
	{
		/**
		 * Debug mode.
		 */
		public static var debug:Boolean = false;

		/**
		 * @param defaultValue The default function definition.
		 * @param ignoreRuntimeErrors If this is true, errors thrown during evaluation of the function will be caught and values of undefined will be returned.
		 * @param useThisScope When true, variable lookups will be evaluated as if the function were in the scope of the thisArg passed to the apply() function.
		 * @param paramNames An Array of parameter names that can be used in the function definition.
		 */
		public function LinkableFunction(defaultValue:String = null, ignoreRuntimeErrors:Boolean = false, useThisScope:Boolean = false, paramNames:Array = null)
		{
			super(unIndent(defaultValue));
			_allLinkableFunctions[this] = true; // register this instance so the callbacks will trigger when the libraries change
			_ignoreRuntimeErrors = ignoreRuntimeErrors;
			_useThisScope = useThisScope;
			_paramNames = paramNames && paramNames.concat();
			getCallbackCollection(this).addImmediateCallback(this, handleChange);
		}

		private var _ignoreRuntimeErrors:Boolean = false;
		private var _useThisScope:Boolean = false;
		private var _compiledMethod:Function = null;
		private var _paramNames:Array = null;
		private var _isFunctionDefinition:Boolean = false;

		/**
		 * This is called whenever the session state changes.
		 */
		private function handleChange():void
		{
			// do not compile immediately because we don't want to throw an error at this time.
			_compiledMethod = null;
		}

		/**
		 * This is used as a placeholder to prevent re-compiling erroneous code.
		 */
		private static function RETURN_UNDEFINED(..._):* { return undefined; }

		/**
		 * This will attempt to compile the function.  An Error will be thrown if this fails.
		 */
		public function validate():void
		{
			if (_compiledMethod == null)
			{
				// in case compile fails, prevent re-compiling erroneous code
				_compiledMethod = RETURN_UNDEFINED;
				_isFunctionDefinition = false;

				if (_macroProxy == null)
					_macroProxy = new ProxyObject(_hasMacro, _getMacro, null, evaluateMacro); // allows evaluating macros but not setting them
				var object:ICompiledObject = _compiler.compileToObject(value);
				_isFunctionDefinition = _compiler.compiledObjectIsFunction(object);
				_compiledMethod = _compiler.compileObjectToFunction(object, _macroProxy, errorHandler, _useThisScope, _paramNames);
			}
		}

		private function errorHandler(e:*):Boolean
		{
			if (debug)
				reportError(e);

			if (_ignoreRuntimeErrors || debug)
				return true;
			throw e;
		}

		/**
		 * This gets the length property of the generated Function.
		 */
		public function get length():int
		{
			if (_compiledMethod == null)
				validate();
			return _compiledMethod.length;
		}

		/**
		 * This will evaluate the function with the specified parameters.
		 * @param thisArg The value of 'this' to be used when evaluating the function.
		 * @param argArray An Array of arguments to be passed to the compiled function.
		 * @return The result of evaluating the function.
		 */
		public function apply(thisArg:* = null, argArray:Array = null):*
		{
			if (_compiledMethod == null)
				validate();
			return _compiledMethod.apply(thisArg, argArray);
		}

		/**
		 * This will evaluate the function with the specified parameters.
		 * @param thisArg The value of 'this' to be used when evaluating the function.
		 * @param args Arguments to be passed to the compiled function.
		 * @return The result of evaluating the function.
		 */
		public function call(thisArg:* = null, ...args):*
		{
			if (_compiledMethod == null)
				validate();
			return _compiledMethod.apply(thisArg, args);
		}

		/////////////////////////////////////////////////////////////////////////////////////////////
		// static section

		/**
		 * This is a proxy object for use as a symbol table for the compiler.
		 */
		private static var _macroProxy:ProxyObject = null;

		/**
		 * This function checks if a macro exists.
		 * @param macroName The name of a macro to check.
		 * @return A value of true if the specified macro exists, or false if it does not.
		 */
		private static function _hasMacro(macroName:String):Boolean
		{
			return macros.getObject(macroName) != null;
		}

		private static function _getMacro(macroName:String):*
		{
			var lf:LinkableFunction = macros.getObject(macroName) as LinkableFunction;
			if (!lf)
				return undefined;
			if (lf._isFunctionDefinition)
				return lf;
			return lf.apply();
		}

		/**
		 * This function evaluates a macro specified in the macros hash map.
		 * @param macroName The name of the macro to evaluate.
		 * @param params The parameters to pass to the macro.
		 * @return The result of evaluating the macro.
		 */
		public static function evaluateMacro(macroName:String, ...params):*
		{
			var lf:LinkableFunction = macros.getObject(macroName) as LinkableFunction;
			return lf ? lf.apply(null, params) : undefined;
		}

		/**
		 * This is a list of macros that can be used in any LinkableFunction expression.
		 */
		public static const macros:ILinkableHashMap = new LinkableHashMap(LinkableFunction);

		/**
		 * This is a list of libraries to include in the static compiler for macros.
		 */
		public static const macroLibraries:LinkableString = new LinkableString();

		/**
		 * This function will add a library to the static list of macro libraries if it is not already added.
		 * @param libraryQName A library to add to the list of static libraries.
		 */
		public static function includeMacroLibrary(libraryQName:String):void
		{
			var rows:Array = WeaveAPI.CSVParser.parseCSV(macroLibraries.value);
			for each (var row:Array in rows)
				if (row.indexOf(libraryQName) >= 0)
					return;
			rows.push([libraryQName]);
			macroLibraries.value = WeaveAPI.CSVParser.createCSV(rows);
		}

		staticInit();

		/**
		 * This function will initialize static variables.
		 */
		private static function staticInit():void
		{
			// when the libraries change, we need to update the compiler
			macroLibraries.addImmediateCallback(null, handleLibrariesChange);
			macroLibraries.value = getQualifiedClassName(WeaveAPI);
		}

		/**
		 * This is the static compiler to be used by every LinkableFunction.
		 */
		private static var _compiler:Compiler = null;
		private static var _allLinkableFunctions:Dictionary = new Dictionary(true); // the keys in this are LinkableFunction instances

		/**
		 * This function will update the static compiler when the static libraries change.
		 */
		private static function handleLibrariesChange():void
		{
			_compiler = _getNewCompiler(true);
			for (var linkableFunction:Object in _allLinkableFunctions)
			{
				var lf:LinkableFunction = linkableFunction as LinkableFunction;
				if (!lf.wasDisposed)
					lf.triggerCallbacks();
			}
		}

		/**
		 * This function returns a new compiler initialized with the libraries specified by the public static libraries variable.
		 * @param reportErrors If this is true, errors will be reported through WeaveAPI.ErrorManager.
		 * @return A new initialized compiler.
		 */
		private static function _getNewCompiler(reportErrors:Boolean):Compiler
		{
			var compiler:Compiler = new Compiler();
			for each (var row:Array in WeaveAPI.CSVParser.parseCSV(macroLibraries.value))
			{
				try
				{
					compiler.includeLibraries.apply(null, row);
				}
				catch (e:Error)
				{
					if (reportErrors)
						reportError(e);
				}
			}
			return compiler;
		}

//		/**
//		 * This function returns a new compiler initialized with the libraries specified by the public static libraries variable.
//		 * @return A new initialized compiler.
//		 */
//		public static function getNewCompiler():Compiler
//		{
//			return _getNewCompiler(false);
//		}

		/**
		 * Takes a script where all lines have been indented, removes the common indentation from all lines and replaces each tab with four spaces.
		 * The common indentation is naively assumed to be the same as the first non-blank line in the script.
		 * @param script A script.
		 * @return The modified script.
		 */
		public static function unIndent(script:String):String
		{
			if (script == null)
				return null;
			script = StandardLib.replace(script, '\r\n','\n','\r','\n');
			while (StringUtil.isWhitespace(script.substr(-1)))
				script = script.substr(0, -1);
			var lines:Array = script.split('\n');
			while (!lines[0])
				lines.shift();
			var indent:int = 0;
			var line:String = lines[0];
			while (line.charAt(indent) == '\t')
				indent++;
			for (var i:int = 0; i < lines.length; i++)
			{
				var line:String = lines[i];
				var t:int = 0;
				var spaces:String = '';
				while (line.charAt(t) == '\t')
					if (t++ >= indent)
						spaces += '    ';

				lines[i] = spaces + line.substr(t);
			}
			return lines.join('\n') + '\n';
		}
	}
}

rewrite for loop

rewrite for loop


package aerys.minko.scene.controller.mesh
{
	import aerys.minko.render.geometry.Geometry;
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.controller.TransformController;
	import aerys.minko.scene.node.Group;
	import aerys.minko.scene.node.Mesh;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.type.binding.DataProvider;
	import aerys.minko.type.enum.DataProviderUsage;
	import aerys.minko.type.math.Matrix4x4;

	public final class MeshController extends AbstractController
	{
		private var _data 			: DataProvider;

		private var _geometry		: Geometry;
		private var _frame			: uint;
        private var _localToWorld   : Matrix4x4;
		private var _worldToLocal 	: Matrix4x4;

		public function get geometry() : Geometry
		{
			return _geometry;
		}
		public function set geometry(value : Geometry) : void
		{
			_geometry = value;
			if (_data)
				_data.setProperty('geometry', value);
		}

		public function get frame() : uint
		{
			return _frame;
		}
		public function set frame(value : uint) : void
		{
			_frame = value;
			if (_data)
				_data.setProperty('frame', value);
		}

		public function MeshController()
		{
			super(Mesh);

			initialize();
		}

		private function initialize() : void
		{
			targetAdded.add(targetAddedHandler);
		}

		private function targetAddedHandler(ctrl	: MeshController,
											target	: Mesh) : void
		{
			target.added.add(addedHandler);
			target.removed.add(removedHandler);
		}

		private function addedHandler(target	: Mesh,
									  ancestor	: Group) : void
		{
			if (!target.scene)
				return ;

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

            var transformController : TransformController = target.scene.getControllersByType(TransformController)[0]
                as TransformController;

//            transformController.setSharedLocalToWorldTransformReference(target, _localToWorld);
//            transformController.setSharedWorldToLocalTransformReference(target, _worldToLocal);
            _localToWorld = transformController.getLocalToWorldTransform(target, true);
            _worldToLocal = transformController.getWorldToLocalTransform(target, true);
            transformController.synchronizeTransforms(target, true);
            transformController.lockTransformsBeforeUpdate(target, true);

			_data = new DataProvider(
				null, target.name + '_transforms', DataProviderUsage.EXCLUSIVE
			);
			_data.setProperty('geometry', _geometry);
			_data.setProperty('frame', _frame);
			_data.setProperty('localToWorld', _localToWorld);
			_data.setProperty('worldToLocal', _worldToLocal);

			target.bindings.addProvider(_data);
		}

		private function removedHandler(target		: Mesh,
										ancestor	: Group) : void
		{
			if (!ancestor.scene)
				return ;

			target.bindings.removeProvider(_data);
			_data.dispose();
			_data = null;

            _localToWorld = null;
            _worldToLocal = null;
		}
	}
}

package aerys.minko.scene.controller.mesh
{
	import aerys.minko.render.geometry.Geometry;
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.controller.TransformController;
	import aerys.minko.scene.node.Group;
	import aerys.minko.scene.node.Mesh;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.type.binding.DataProvider;
	import aerys.minko.type.enum.DataProviderUsage;
	import aerys.minko.type.math.Matrix4x4;

	public final class MeshController extends AbstractController
	{
		private var _data 			: DataProvider;

		private var _geometry		: Geometry;
		private var _frame			: uint;
        private var _localToWorld   : Matrix4x4;
		private var _worldToLocal 	: Matrix4x4;

		public function get geometry() : Geometry
		{
			return _geometry;
		}
		public function set geometry(value : Geometry) : void
		{
			_geometry = value;
			if (_data)
				_data.setProperty('geometry', value);
		}

		public function get frame() : uint
		{
			return _frame;
		}
		public function set frame(value : uint) : void
		{
			_frame = value;
			if (_data)
				_data.setProperty('frame', value);
		}

		public function MeshController()
		{
			super(Mesh);

			initialize();
		}

		private function initialize() : void
		{
			targetAdded.add(targetAddedHandler);
		}

		private function targetAddedHandler(ctrl	: MeshController,
											target	: Mesh) : void
		{
			target.added.add(addedHandler);
			target.removed.add(removedHandler);
		}

		private function addedHandler(target	: Mesh,
									  ancestor	: Group) : void
		{
			if (!target.scene)
				return ;

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

            var transformController : TransformController = target.scene.getControllersByType(TransformController)[0]
                as TransformController;

            _localToWorld = transformController.getLocalToWorldTransform(target, true);
            _worldToLocal = transformController.getWorldToLocalTransform(target, true);
            transformController.synchronizeTransforms(target, true);
            transformController.lockTransformsBeforeUpdate(target, true);

			_data = new DataProvider(
				null, target.name + '_transforms', DataProviderUsage.EXCLUSIVE
			);
			_data.setProperty('geometry', _geometry);
			_data.setProperty('frame', _frame);
			_data.setProperty('localToWorld', _localToWorld);
			_data.setProperty('worldToLocal', _worldToLocal);

			target.bindings.addProvider(_data);
		}

		private function removedHandler(target		: Mesh,
										ancestor	: Group) : void
		{
			if (!ancestor.scene)
				return ;

			target.bindings.removeProvider(_data);
			_data.dispose();
			_data = null;

            _localToWorld = null;
            _worldToLocal = null;
		}
	}
}

remove dead code

remove dead code


package aerys.minko.scene.node.light
{
	import aerys.minko.ns.minko_scene;
	import aerys.minko.render.resource.texture.CubeTextureResource;
	import aerys.minko.render.resource.texture.ITextureResource;
	import aerys.minko.render.resource.texture.TextureResource;
	import aerys.minko.scene.controller.light.PointLightController;
	import aerys.minko.scene.node.AbstractSceneNode;
	import aerys.minko.scene.node.ISceneNode;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.type.binding.DataBindings;
	import aerys.minko.type.enum.ShadowMappingType;
	import aerys.minko.type.math.Matrix4x4;
	import aerys.minko.type.math.Vector4;

	use namespace minko_scene;

	/**
	 *
	 * @author Romain Gilliotte
	 * @author Jean-Marc Le Roux
	 *
	 */
	public class PointLight extends AbstractLight
	{
		public static const LIGHT_TYPE : uint = 2;

		private static const MAP_NAMES : Vector.<String> = new <String>[
			'shadowMapCube',
			'shadowMapDPFront',
			'shadowMapDPBack'
		];

		private static const TMP_VECTOR		: Vector4 = new Vector4();

		private var _shadowMapSize	: uint;

		public function get diffuse() : Number
		{
			return lightData.getLightProperty('diffuse') as Number;
		}
		public function set diffuse(v : Number)	: void
		{
			lightData.setLightProperty('diffuse', v);

			if (lightData.getLightProperty('diffuseEnabled') != (v != 0))
				lightData.setLightProperty('diffuseEnabled', v != 0);
		}

		public function get specular() : Number
		{
			return lightData.getLightProperty('specular') as Number;
		}
		public function set specular(v : Number) : void
		{
			lightData.setLightProperty('specular', v);

			if (lightData.getLightProperty('specularEnabled') != (v != 0))
				lightData.setLightProperty('specularEnabled', v != 0);
		}

		public function get shininess() : Number
		{
			return lightData.getLightProperty('shininess') as Number;
		}
		public function set shininess(v : Number) : void
		{
			lightData.setLightProperty('shininess', v);
		}

		public function get attenuationDistance() : Number
		{
			return lightData.getLightProperty('attenuationDistance') as Number;
		}
		public function set attenuationDistance(v : Number) : void
		{
			lightData.setLightProperty('attenuationDistance', v);

			if (lightData.getLightProperty('attenuationEnabled') != (v != 0))
				lightData.setLightProperty('attenuationEnabled', v != 0);
		}

		public function get shadowMapSize() : uint
		{
			return _shadowMapSize;
		}
		public function set shadowMapSize(v : uint) : void
		{
			_shadowMapSize = v;

			this.shadowCastingType = this.shadowCastingType
		}

		public function get shadowZNear() : Number
		{
			return lightData.getLightProperty('shadowZNear');
		}
		public function set shadowZNear(v : Number) : void
		{
			lightData.setLightProperty('shadowZNear', v);
		}

		public function get shadowZFar() : Number
		{
			return lightData.getLightProperty('shadowZFar');
		}
		public function set shadowZFar(v : Number) : void
		{
			lightData.setLightProperty('shadowZFar', v);
		}

		override public function set shadowCastingType(v : uint) : void
		{
			var shadowMap : ITextureResource;

			// start by clearing current shadow maps.
			for each (var mapName : String in MAP_NAMES)
			{
				shadowMap = lightData.getLightProperty(mapName) as ITextureResource;
				if (shadowMap !== null)
				{
					shadowMap.dispose();
					lightData.removeProperty(mapName);
				}
			}

			switch (v)
			{
				case ShadowMappingType.NONE:
					lightData.setLightProperty('shadowCastingType', ShadowMappingType.NONE);
					break;

				case ShadowMappingType.DUAL_PARABOLOID:
					if (!((_shadowMapSize & (~_shadowMapSize + 1)) == _shadowMapSize
						&& _shadowMapSize <= 2048))
						throw new Error(_shadowMapSize + ' is an invalid size for dual paraboloid shadow maps');

					// set textures and shadowmaptype
					shadowMap = new TextureResource(_shadowMapSize, _shadowMapSize);
					lightData.setLightProperty('shadowMapDPFront', shadowMap);
					shadowMap = new TextureResource(_shadowMapSize, _shadowMapSize);
					lightData.setLightProperty('shadowMapDPBack', shadowMap);
					lightData.setLightProperty('shadowCastingType', ShadowMappingType.DUAL_PARABOLOID);
					break;

				case ShadowMappingType.CUBE:
					if (!((_shadowMapSize & (~_shadowMapSize + 1)) == _shadowMapSize
						&& _shadowMapSize <= 1024))
						throw new Error(_shadowMapSize + ' is an invalid size for cubic shadow maps');

					shadowMap = new CubeTextureResource(_shadowMapSize);
					lightData.setLightProperty('shadowMapCube', shadowMap);
					lightData.setLightProperty('shadowCastingType', ShadowMappingType.CUBE);
					break;

				default:
					throw new ArgumentError('Invalid shadow casting type.');
			}
		}

		public function PointLight(color				: uint		= 0xFFFFFFFF,
								   diffuse				: Number	= .6,
								   specular				: Number	= .8,
								   shininess			: Number	= 64,
								   attenuationDistance	: Number	= 0,
								   emissionMask			: uint		= 0x1,
								   shadowCastingType	: uint		= 0,
								   shadowMapSize		: uint		= 512,
								   shadowMapZNear		: Number	= 0.1,
								   shadowMapZFar		: Number	= 1000)
		{
			_shadowMapSize				= shadowMapSize;

			super(
				new PointLightController(),
				LIGHT_TYPE,
				color,
				emissionMask,
				shadowCastingType
			);

			this.diffuse				= diffuse;
			this.specular				= specular;
			this.shininess				= shininess;
			this.attenuationDistance	= attenuationDistance;
			this.shadowZNear			= shadowMapZNear;
			this.shadowZFar			= shadowMapZFar;

			if ([ShadowMappingType.NONE,
				 ShadowMappingType.DUAL_PARABOLOID,
				 ShadowMappingType.CUBE].indexOf(shadowCastingType) == -1)
				throw new Error('Invalid ShadowMappingType.');
		}

		override minko_scene function cloneNode() : AbstractSceneNode
		{
			var light : PointLight = new PointLight(
				color, diffuse, specular, shininess,
				attenuationDistance, emissionMask,
				shadowCastingType, shadowMapSize
			);

			light.name = this.name;
			light.transform.copyFrom(this.transform);

			return light;
		}
	}
}

fix coding style

fix coding style


package {

	public class @@project_name@@{

		public function @@project_name@@(){

		}

	}

}

package{

	import flash.display.Sprite;

	public class @@project_name@@ extends Sprite{

		public function @@project_name@@(){

		}

	}

}

fix : the main class need to extend Sprite


package aerys.minko.scene.controller.debug
{
	import aerys.minko.render.geometry.Geometry;
	import aerys.minko.render.geometry.primitive.LineGeometry;
	import aerys.minko.render.geometry.stream.iterator.TriangleIterator;
	import aerys.minko.render.geometry.stream.iterator.TriangleReference;
	import aerys.minko.render.material.line.LineMaterial;
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.node.Group;
	import aerys.minko.scene.node.ISceneNode;
	import aerys.minko.scene.node.Mesh;
	import aerys.minko.type.math.Matrix4x4;

	import flash.utils.Dictionary;

	public final class WireframeDebugController extends AbstractController
	{
		private static var _wireframeMaterial	: LineMaterial;

		private var _targetToWireframe	: Dictionary	= new Dictionary();
		private var _geometryToMesh		: Dictionary 	= new Dictionary();
		private var _visible 			: Boolean 		= true;

		public function get material() : LineMaterial
		{
			return _wireframeMaterial
				|| (_wireframeMaterial = new LineMaterial({diffuseColor : 0x509dc7ff, lineThickness	: 1.}));
		}

		public function set visible(value : Boolean) : void
		{
			_visible = value;

			for each (var wireframe : Mesh in _targetToWireframe)
				wireframe.visible = value;
		}

		public function get visible() : Boolean
		{
			return _visible;
		}

		public function WireframeDebugController()
		{
			super(Mesh);

			initialize();
		}

		private function initialize() : void
		{
			targetAdded.add(targetAddedHandler);
			targetRemoved.add(targetRemovedHandler);
		}

		private function targetAddedHandler(ctrl	: WireframeDebugController,
											target	: Mesh) : void
		{
			if (target.scene)
				addedHandler(target, target.parent);
			else
				target.added.add(addedHandler);
			target.removed.add(removedHandler);
		}

		private function addedHandler(target 	: Mesh,
									  ancestor	: Group) : void
		{
			if (!target.scene || target.geometry == null)
				return ;

			var triangles	: TriangleIterator = new TriangleIterator(
				target.geometry.getVertexStream(),
				target.geometry.indexStream
			);
			var linesGeom	: LineGeometry		= new LineGeometry();
			for each (var triangle : TriangleReference in triangles)
			{
				linesGeom.moveTo(triangle.v0.x, triangle.v0.y, triangle.v0.z)
					.lineTo(triangle.v1.x, triangle.v1.y, triangle.v1.z)
					.lineTo(triangle.v2.x, triangle.v2.y, triangle.v2.z)
					.lineTo(triangle.v0.x, triangle.v0.y, triangle.v0.z);
			}

			var lines		: Mesh				= new Mesh(linesGeom, this.material);
			lines.visible 	= _visible;
			_targetToWireframe[target] = lines;

			target.localToWorldTransformChanged.add(updateTransform);
			updateTransform(target, target.getLocalToWorldTransform());
			target.scene.addChild(lines);
		}

		private function updateTransform(child : ISceneNode, childLocalToWorld : Matrix4x4) : void
		{
			var lineMesh : Mesh = _targetToWireframe[child];

			if (lineMesh == null)
				child.localToWorldTransformChanged.remove(updateTransform);
			else
				lineMesh.transform.copyFrom(childLocalToWorld);
		}

		private function removeWireframes(target : Mesh) : void
		{
			if (_targetToWireframe[target])
				_targetToWireframe[target].parent = null;
			_targetToWireframe[target] = null;
		}

		private function targetRemovedHandler(ctrl		: WireframeDebugController,
											  target	: Mesh) : void
		{
			if (target.added.hasCallback(addedHandler))
				target.added.remove(addedHandler);
			target.removed.remove(removedHandler);
			if (target.localToWorldTransformChanged.hasCallback(updateTransform))
				target.localToWorldTransformChanged.remove(updateTransform);
			removeWireframes(target);
		}

		private function removedHandler(target : Mesh, ancestor : Group) : void
		{
			removeWireframes(target);
		}

		override public function clone():AbstractController
		{
			return null;
		}
	}
}

package aerys.minko.scene.controller.debug
{
	import aerys.minko.render.geometry.Geometry;
	import aerys.minko.render.geometry.primitive.LineGeometry;
	import aerys.minko.render.geometry.stream.iterator.TriangleIterator;
	import aerys.minko.render.geometry.stream.iterator.TriangleReference;
	import aerys.minko.render.material.line.LineMaterial;
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.node.Group;
	import aerys.minko.scene.node.ISceneNode;
	import aerys.minko.scene.node.Mesh;
	import aerys.minko.type.math.Matrix4x4;

	import flash.utils.Dictionary;

	public final class WireframeDebugController extends AbstractController
	{
		private static var _wireframeMaterial	: LineMaterial;

		private var _targetToWireframe	: Dictionary	= new Dictionary();
		private var _geometryToMesh		: Dictionary 	= new Dictionary();
		private var _visible 			: Boolean 		= true;

		public function get material() : LineMaterial
		{
			return _wireframeMaterial
				|| (_wireframeMaterial = new LineMaterial({diffuseColor : 0x509dc7ff, lineThickness	: 1.}));
		}

		public function set visible(value : Boolean) : void
		{
			_visible = value;

			for each (var wireframe : Mesh in _targetToWireframe)
				wireframe.visible = value;
		}

		public function get visible() : Boolean
		{
			return _visible;
		}

		public function WireframeDebugController()
		{
			super(Mesh);

			initialize();
		}

		private function initialize() : void
		{
			targetAdded.add(targetAddedHandler);
			targetRemoved.add(targetRemovedHandler);
		}

		private function targetAddedHandler(ctrl	: WireframeDebugController,
											target	: Mesh) : void
		{
			if (target.scene)
				addedHandler(target, target.parent);
			else
				target.added.add(addedHandler);
			target.removed.add(removedHandler);
		}

		private function addedHandler(target 	: Mesh,
									  ancestor	: Group) : void
		{
			if (!target.scene || target.geometry == null)
				return ;

			var triangles	: TriangleIterator = new TriangleIterator(
				target.geometry.getVertexStream(),
				target.geometry.indexStream
			);
			var linesGeom	: LineGeometry		= new LineGeometry();
			for each (var triangle : TriangleReference in triangles)
			{
				linesGeom.moveTo(triangle.v0.x, triangle.v0.y, triangle.v0.z)
					.lineTo(triangle.v1.x, triangle.v1.y, triangle.v1.z)
					.lineTo(triangle.v2.x, triangle.v2.y, triangle.v2.z)
					.lineTo(triangle.v0.x, triangle.v0.y, triangle.v0.z);
			}

			var lines		: Mesh				= new Mesh(linesGeom, this.material);
			lines.visible 	= _visible;
			_targetToWireframe[target] = lines;

			if (!target.localToWorldTransformChanged.hasCallback(updateTransform))
				target.localToWorldTransformChanged.add(updateTransform);

			updateTransform(target, target.getLocalToWorldTransform());
			target.scene.addChild(lines);
		}

		private function updateTransform(child : ISceneNode, childLocalToWorld : Matrix4x4) : void
		{
			var lineMesh : Mesh = _targetToWireframe[child];

			if (lineMesh == null)
				child.localToWorldTransformChanged.remove(updateTransform);
			else
				lineMesh.transform.copyFrom(childLocalToWorld);
		}

		private function removeWireframes(target : Mesh) : void
		{
			if (_targetToWireframe[target])
				_targetToWireframe[target].parent = null;
			_targetToWireframe[target] = null;
		}

		private function targetRemovedHandler(ctrl		: WireframeDebugController,
											  target	: Mesh) : void
		{
			if (target.added.hasCallback(addedHandler))
				target.added.remove(addedHandler);
			target.removed.remove(removedHandler);
			if (target.localToWorldTransformChanged.hasCallback(updateTransform))
				target.localToWorldTransformChanged.remove(updateTransform);
			removeWireframes(target);
		}

		private function removedHandler(target : Mesh, ancestor : Group) : void
		{
			removeWireframes(target);
		}

		override public function clone():AbstractController
		{
			return null;
		}
	}
}

Fix bug when a callback was already listened


//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.geom.Rectangle;

import flump.xfl.XflLibrary;
import flump.xfl.XflTexture;

import com.threerings.util.Comparators;

public class Packer
{
    public static const BIN_SIZES :Vector.<int> = new <int>[8, 16, 32, 64, 128, 256, 512, 1024];

    public const atlases :Vector.<Atlas> = new Vector.<Atlas>();

    public function Packer (lib :XflLibrary) {
        for each (var tex :XflTexture in lib.textures) {
            _unpacked.push(new PackedTexture(tex, lib));
        }
        _unpacked.sort(Comparators.createReverse(Comparators.createFields(["a", "w", "h"])));
        var minBin :int = findOptimalMinBin();
        atlases.push(new Atlas(lib.location + "/atlas0", minBin, minBin));
        while (_unpacked.length > 0) pack(_unpacked.shift());
    }

    protected function pack (tex :PackedTexture) :void {
        for each (var atlas :Atlas in atlases) {
            for each (var bin :Rectangle in atlas.bins) {
                if (tex.w <= bin.width && tex.h <= bin.height) {
                    atlas.place(tex, bin, false);
                    return;
                } else if (tex.h <= bin.width && tex.w <= bin.height) {
                    atlas.place(tex, bin, true);
                    return;
                }
            }
        }
        // TODO - allocate another atlas
        throw new Error("Doesn't fit " + tex);
    }

    protected function findOptimalMinBin () :int {
        var area :int = 0;
        var maxExtent :int = 0;
        for each (var tex :PackedTexture in _unpacked) {
            area += tex.a;
            maxExtent = Math.max(maxExtent, tex.w, tex.h);
        }
        for each (var size :int in BIN_SIZES) {
            if (size >= maxExtent && size * size >= area) return size;
        }
        return BIN_SIZES[BIN_SIZES.length -1];
    }

    protected var _unpacked :Vector.<PackedTexture> = new Vector.<PackedTexture>();
}
}

//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.geom.Rectangle;

import flump.xfl.XflLibrary;
import flump.xfl.XflTexture;

import com.threerings.util.Comparators;

public class Packer
{
    public const atlases :Vector.<Atlas> = new Vector.<Atlas>();

    public function Packer (lib :XflLibrary) {
        _lib = lib;
        for each (var tex :XflTexture in _lib.textures) {
            _unpacked.push(new PackedTexture(tex, _lib));
        }
        _unpacked.sort(Comparators.createReverse(Comparators.createFields(["a", "w", "h"])));
        while (_unpacked.length > 0) pack();
    }

    protected function pack () :void {
        const tex :PackedTexture = _unpacked[0];
        if (tex.w > LARGEST_BIN || tex.h > LARGEST_BIN) throw new Error("Too large to fit in bin");
        for each (var atlas :Atlas in atlases) {
            for each (var bin :Rectangle in atlas.bins) {
                if (tex.w <= bin.width && tex.h <= bin.height) {
                    atlas.place(_unpacked.shift(), bin, false);
                    return;
                } else if (tex.h <= bin.width && tex.w <= bin.height) {
                    atlas.place(_unpacked.shift(), bin, true);
                    return;
                }
            }
        }
        var minBin :int = findOptimalMinBin();
        atlases.push(new Atlas(_lib.location + "/atlas" + atlases.length, minBin, minBin));
        pack();
    }

    protected function findOptimalMinBin () :int {
        var area :int = 0;
        var maxExtent :int = 0;
        for each (var tex :PackedTexture in _unpacked) {
            area += tex.a;
            maxExtent = Math.max(maxExtent, tex.w, tex.h);
        }
        for each (var size :int in BIN_SIZES) {
            if (size >= maxExtent && size * size >= area) return size;
        }
        return LARGEST_BIN;
    }

    protected var _unpacked :Vector.<PackedTexture> = new Vector.<PackedTexture>();

    protected var _lib :XflLibrary;

    private static const BIN_SIZES :Vector.<int> = new <int>[8, 16, 32, 64, 128, 256, 512, 1024];
    private static const LARGEST_BIN :int = BIN_SIZES[BIN_SIZES.length - 1];
}
}

Add additional atlases as textures don't fit


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

import com.esri.builder.model.CustomWidgetType;
import com.esri.builder.model.WidgetType;
import com.esri.builder.supportClasses.FileUtil;
import com.esri.builder.supportClasses.LogUtil;

import flash.events.EventDispatcher;
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import flash.utils.ByteArray;

import modules.IBuilderModule;
import modules.supportClasses.CustomXMLModule;

import mx.core.FlexGlobals;
import mx.events.ModuleEvent;
import mx.logging.ILogger;
import mx.logging.Log;
import mx.modules.IModuleInfo;
import mx.modules.ModuleManager;

public class WidgetTypeLoader extends EventDispatcher
{
    private static const LOG:ILogger = LogUtil.createLogger(WidgetTypeLoader);

    internal static var loadedModuleInfos:Array = [];

    private var swf:File;
    private var config:File;

    //need reference when loading to avoid being garbage collected before load completes
    private var moduleInfo:IModuleInfo;

    //requires either swf or config
    public function WidgetTypeLoader(swf:File = null, config:File = null)
    {
        this.swf = swf;
        this.config = config;
    }

    public function get name():String
    {
        var fileName:String;

        if (swf && swf.exists)
        {
            fileName = FileUtil.getFileName(swf);
        }
        else if (config && config.exists)
        {
            fileName = FileUtil.getFileName(config);
        }

        return fileName;
    }

    public function load():void
    {
        if (swf && swf.exists)
        {
            loadModule();
        }
        else if (config && config.exists)
        {
            loadConfigModule();
        }
        else
        {
            dispatchError();
        }
    }

    private function loadConfigModule():void
    {
        if (Log.isInfo())
        {
            LOG.info('Loading XML module: {0}', config.url);
        }

        var moduleConfig:XML = readModuleConfig(config);
        if (moduleConfig)
        {
            var customWidgetType:CustomWidgetType = parseCustomWidgetType(moduleConfig);
            if (customWidgetType)
            {
                dispatchComplete(customWidgetType);
                return;
            }
        }

        dispatchError();
    }

    private function loadModule():void
    {
        if (Log.isInfo())
        {
            LOG.info('Loading SWF module: {0}', swf.url);
        }

        moduleInfo = ModuleManager.getModule(swf.url);

        if (moduleInfo.ready)
        {
            if (Log.isInfo())
            {
                LOG.info('Unloading module: {0}', swf.url);
            }

            moduleInfo.addEventListener(ModuleEvent.UNLOAD, moduleInfo_unloadHandler);
            moduleInfo.release();
            moduleInfo.unload();
        }
        else
        {
            if (Log.isInfo())
            {
                LOG.info('Loading module: {0}', swf.url);
            }

            var fileBytes:ByteArray = new ByteArray();
            var fileStream:FileStream = new FileStream();
            fileStream.open(swf, FileMode.READ);
            fileStream.readBytes(fileBytes);
            fileStream.close();

            //Use ModuleEvent.PROGRESS instead of ModuleEvent.READY to avoid the case where the latter is never dispatched.
            moduleInfo.addEventListener(ModuleEvent.PROGRESS, moduleInfo_progressHandler);
            moduleInfo.addEventListener(ModuleEvent.ERROR, moduleInfo_errorHandler);
            moduleInfo.load(null, null, fileBytes, FlexGlobals.topLevelApplication.moduleFactory);
        }
    }

    private function moduleInfo_progressHandler(event:ModuleEvent):void
    {
        if (event.bytesLoaded == event.bytesTotal)
        {
            var moduleInfo:IModuleInfo = event.currentTarget as IModuleInfo;
            moduleInfo.removeEventListener(ModuleEvent.PROGRESS, moduleInfo_progressHandler);
            moduleInfo.removeEventListener(ModuleEvent.ERROR, moduleInfo_errorHandler);
            FlexGlobals.topLevelApplication.callLater(processModuleInfo, [ moduleInfo ]);
        }
    }

    private function moduleInfo_unloadHandler(event:ModuleEvent):void
    {
        if (Log.isInfo())
        {
            LOG.info('Module unloaded: {0}', swf.url);
        }

        var moduleInfo:IModuleInfo = event.module;
        moduleInfo.removeEventListener(ModuleEvent.UNLOAD, moduleInfo_unloadHandler);
        var moduleInfoIndex:int = loadedModuleInfos.indexOf(moduleInfo);
        if (moduleInfoIndex > -1)
        {
            loadedModuleInfos.splice(moduleInfoIndex, 1);
        }
        this.moduleInfo = null;
        FlexGlobals.topLevelApplication.callLater(loadModule);
    }

    private function processModuleInfo(moduleInfo:IModuleInfo):void
    {
        if (Log.isInfo())
        {
            LOG.info('Module loaded: {0}', swf.url);
        }

        if (config && config.exists)
        {
            if (Log.isInfo())
            {
                LOG.info('Reading module config: {0}', config.url);
            }
            var moduleConfig:XML = readModuleConfig(config);
        }

        const builderModule:IBuilderModule = moduleInfo.factory.create() as IBuilderModule;
        if (builderModule)
        {
            if (Log.isInfo())
            {
                LOG.info('Widget type created for module: {0}', swf.url);
            }
            var widgetType:WidgetType = getWidgetType(moduleInfo, builderModule, moduleConfig);
        }

        loadedModuleInfos.push(moduleInfo);
        this.moduleInfo = null;
        dispatchComplete(widgetType);
    }

    private function dispatchComplete(widgetType:WidgetType):void
    {
        if (Log.isInfo())
        {
            LOG.info('Module load complete: {0}', name);
        }

        dispatchEvent(new WidgetTypeLoaderEvent(WidgetTypeLoaderEvent.LOAD_COMPLETE, widgetType));
    }

    private function getWidgetType(moduleInfo:IModuleInfo, builderModule:IBuilderModule, moduleConfig:XML):WidgetType
    {
        var customModulesDirectoryURL:String = WellKnownDirectories.getInstance().customModules.url;
        var isCustomModule:Boolean = (moduleInfo.url.indexOf(customModulesDirectoryURL) > -1);
        if (moduleConfig)
        {
            var configXML:XML = moduleConfig.configuration[0];
            var version:String = moduleConfig.widgetversion[0];
        }

        return isCustomModule ?
            new CustomWidgetType(builderModule, version, configXML) :
            new WidgetType(builderModule);
    }

    private function readModuleConfig(configFile:File):XML
    {
        var configXML:XML;

        var fileStream:FileStream = new FileStream();
        try
        {
            fileStream.open(configFile, FileMode.READ);
            configXML = XML(fileStream.readUTFBytes(fileStream.bytesAvailable));
        }
        catch (e:Error)
        {
            //ignore
            if (Log.isInfo())
            {
                LOG.info('Could not read module config: {0}', e.toString());
            }
        }
        finally
        {
            fileStream.close();
        }

        return configXML;
    }

    private function moduleInfo_errorHandler(event:ModuleEvent):void
    {
        var moduleInfo:IModuleInfo = event.module;
        moduleInfo.removeEventListener(ModuleEvent.ERROR, moduleInfo_errorHandler);
        moduleInfo.removeEventListener(ModuleEvent.PROGRESS, moduleInfo_progressHandler);
        this.moduleInfo = null;
        dispatchError();
    }

    private function dispatchError():void
    {
        if (Log.isInfo())
        {
            LOG.info('Module load failed: {0}', name);
        }

        dispatchEvent(new WidgetTypeLoaderEvent(WidgetTypeLoaderEvent.LOAD_ERROR));
    }

    private function parseCustomWidgetType(configXML:XML):CustomWidgetType
    {
        if (Log.isInfo())
        {
            LOG.info('Creating widget type from XML: {0}', configXML);
        }

        var customModule:CustomXMLModule = new CustomXMLModule();
        customModule.widgetName = configXML.name;
        customModule.isOpenByDefault = (configXML.openbydefault == 'true');

        var widgetLabel:String = configXML.label[0];
        var widgetDescription:String = configXML.description[0];
        var widgetHelpURL:String = configXML.helpurl[0];
        var widgetConfiguration:XML = configXML.configuration[0] ? configXML.configuration[0] : <configuration/>;
        var widgetVersion:String = configXML.widgetversion[0];

        customModule.widgetIconLocation = createWidgetIconPath(configXML.icon[0], customModule.widgetName);
        customModule.widgetLabel = widgetLabel ? widgetLabel : customModule.widgetName;
        customModule.widgetDescription = widgetDescription ? widgetDescription : "";
        customModule.widgetHelpURL = widgetHelpURL ? widgetHelpURL : "";

        return new CustomWidgetType(customModule, widgetVersion, widgetConfiguration);
    }

    private function createWidgetIconPath(iconPath:String, widgetName:String):String
    {
        var widgetIconPath:String;

        if (iconPath)
        {
            widgetIconPath = "widgets/" + widgetName + "/" + iconPath;
        }
        else
        {
            widgetIconPath = "assets/images/i_widget.png";
        }

        return widgetIconPath;
    }
}
}

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

import com.esri.builder.model.CustomWidgetType;
import com.esri.builder.model.WidgetType;
import com.esri.builder.supportClasses.FileUtil;
import com.esri.builder.supportClasses.LogUtil;

import flash.events.EventDispatcher;
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import flash.utils.ByteArray;

import modules.IBuilderModule;
import modules.supportClasses.CustomXMLModule;

import mx.core.FlexGlobals;
import mx.events.ModuleEvent;
import mx.logging.ILogger;
import mx.logging.Log;
import mx.modules.IModuleInfo;
import mx.modules.ModuleManager;

public class WidgetTypeLoader extends EventDispatcher
{
    private static const LOG:ILogger = LogUtil.createLogger(WidgetTypeLoader);

    internal static var loadedModuleInfos:Array = [];

    private var swf:File;
    private var config:File;

    //need reference when loading to avoid being garbage collected before load completes
    private var moduleInfo:IModuleInfo;

    //requires either swf or config
    public function WidgetTypeLoader(swf:File = null, config:File = null)
    {
        this.swf = swf;
        this.config = config;
    }

    public function get name():String
    {
        var fileName:String;

        if (swf && swf.exists)
        {
            fileName = FileUtil.getFileName(swf);
        }
        else if (config && config.exists)
        {
            fileName = FileUtil.getFileName(config);
        }

        return fileName;
    }

    public function load():void
    {
        if (swf && swf.exists)
        {
            loadModule();
        }
        else if (config && config.exists)
        {
            loadConfigModule();
        }
        else
        {
            dispatchError();
        }
    }

    private function loadModule():void
    {
        if (Log.isInfo())
        {
            LOG.info('Loading SWF module: {0}', swf.url);
        }

        moduleInfo = ModuleManager.getModule(swf.url);

        if (moduleInfo.ready)
        {
            if (Log.isInfo())
            {
                LOG.info('Unloading module: {0}', swf.url);
            }

            moduleInfo.addEventListener(ModuleEvent.UNLOAD, moduleInfo_unloadHandler);
            moduleInfo.release();
            moduleInfo.unload();
        }
        else
        {
            if (Log.isInfo())
            {
                LOG.info('Loading module: {0}', swf.url);
            }

            var fileBytes:ByteArray = new ByteArray();
            var fileStream:FileStream = new FileStream();
            fileStream.open(swf, FileMode.READ);
            fileStream.readBytes(fileBytes);
            fileStream.close();

            //Use ModuleEvent.PROGRESS instead of ModuleEvent.READY to avoid the case where the latter is never dispatched.
            moduleInfo.addEventListener(ModuleEvent.PROGRESS, moduleInfo_progressHandler);
            moduleInfo.addEventListener(ModuleEvent.ERROR, moduleInfo_errorHandler);
            moduleInfo.load(null, null, fileBytes, FlexGlobals.topLevelApplication.moduleFactory);
        }
    }

    private function moduleInfo_unloadHandler(event:ModuleEvent):void
    {
        if (Log.isInfo())
        {
            LOG.info('Module unloaded: {0}', swf.url);
        }

        var moduleInfo:IModuleInfo = event.module;
        moduleInfo.removeEventListener(ModuleEvent.UNLOAD, moduleInfo_unloadHandler);
        var moduleInfoIndex:int = loadedModuleInfos.indexOf(moduleInfo);
        if (moduleInfoIndex > -1)
        {
            loadedModuleInfos.splice(moduleInfoIndex, 1);
        }
        this.moduleInfo = null;
        FlexGlobals.topLevelApplication.callLater(loadModule);
    }

    private function moduleInfo_progressHandler(event:ModuleEvent):void
    {
        if (event.bytesLoaded == event.bytesTotal)
        {
            var moduleInfo:IModuleInfo = event.currentTarget as IModuleInfo;
            moduleInfo.removeEventListener(ModuleEvent.PROGRESS, moduleInfo_progressHandler);
            moduleInfo.removeEventListener(ModuleEvent.ERROR, moduleInfo_errorHandler);
            FlexGlobals.topLevelApplication.callLater(processModuleInfo, [ moduleInfo ]);
        }
    }

    private function processModuleInfo(moduleInfo:IModuleInfo):void
    {
        if (Log.isInfo())
        {
            LOG.info('Module loaded: {0}', swf.url);
        }

        if (config && config.exists)
        {
            if (Log.isInfo())
            {
                LOG.info('Reading module config: {0}', config.url);
            }
            var moduleConfig:XML = readModuleConfig(config);
        }

        const builderModule:IBuilderModule = moduleInfo.factory.create() as IBuilderModule;
        if (builderModule)
        {
            if (Log.isInfo())
            {
                LOG.info('Widget type created for module: {0}', swf.url);
            }
            var widgetType:WidgetType = getWidgetType(moduleInfo, builderModule, moduleConfig);
        }

        loadedModuleInfos.push(moduleInfo);
        this.moduleInfo = null;
        dispatchComplete(widgetType);
    }

    private function getWidgetType(moduleInfo:IModuleInfo, builderModule:IBuilderModule, moduleConfig:XML):WidgetType
    {
        var customModulesDirectoryURL:String = WellKnownDirectories.getInstance().customModules.url;
        var isCustomModule:Boolean = (moduleInfo.url.indexOf(customModulesDirectoryURL) > -1);
        if (moduleConfig)
        {
            var configXML:XML = moduleConfig.configuration[0];
            var version:String = moduleConfig.widgetversion[0];
        }

        return isCustomModule ?
            new CustomWidgetType(builderModule, version, configXML) :
            new WidgetType(builderModule);
    }

    private function dispatchComplete(widgetType:WidgetType):void
    {
        if (Log.isInfo())
        {
            LOG.info('Module load complete: {0}', name);
        }

        dispatchEvent(new WidgetTypeLoaderEvent(WidgetTypeLoaderEvent.LOAD_COMPLETE, widgetType));
    }

    private function moduleInfo_errorHandler(event:ModuleEvent):void
    {
        var moduleInfo:IModuleInfo = event.module;
        moduleInfo.removeEventListener(ModuleEvent.PROGRESS, moduleInfo_progressHandler);
        moduleInfo.removeEventListener(ModuleEvent.ERROR, moduleInfo_errorHandler);
        this.moduleInfo = null;
        dispatchError();
    }

    private function dispatchError():void
    {
        if (Log.isInfo())
        {
            LOG.info('Module load failed: {0}', name);
        }

        dispatchEvent(new WidgetTypeLoaderEvent(WidgetTypeLoaderEvent.LOAD_ERROR));
    }

    private function loadConfigModule():void
    {
        if (Log.isInfo())
        {
            LOG.info('Loading XML module: {0}', config.url);
        }

        var moduleConfig:XML = readModuleConfig(config);
        if (moduleConfig)
        {
            var customWidgetType:CustomWidgetType = parseCustomWidgetType(moduleConfig);
            if (customWidgetType)
            {
                dispatchComplete(customWidgetType);
                return;
            }
        }

        dispatchError();
    }

    private function readModuleConfig(configFile:File):XML
    {
        var configXML:XML;

        var fileStream:FileStream = new FileStream();
        try
        {
            fileStream.open(configFile, FileMode.READ);
            configXML = XML(fileStream.readUTFBytes(fileStream.bytesAvailable));
        }
        catch (e:Error)
        {
            //ignore
            if (Log.isInfo())
            {
                LOG.info('Could not read module config: {0}', e.toString());
            }
        }
        finally
        {
            fileStream.close();
        }

        return configXML;
    }

    private function parseCustomWidgetType(configXML:XML):CustomWidgetType
    {
        if (Log.isInfo())
        {
            LOG.info('Creating widget type from XML: {0}', configXML);
        }

        var customModule:CustomXMLModule = new CustomXMLModule();
        customModule.widgetName = configXML.name;
        customModule.isOpenByDefault = (configXML.openbydefault == 'true');

        var widgetLabel:String = configXML.label[0];
        var widgetDescription:String = configXML.description[0];
        var widgetHelpURL:String = configXML.helpurl[0];
        var widgetConfiguration:XML = configXML.configuration[0] ? configXML.configuration[0] : <configuration/>;
        var widgetVersion:String = configXML.widgetversion[0];

        customModule.widgetIconLocation = createWidgetIconPath(configXML.icon[0], customModule.widgetName);
        customModule.widgetLabel = widgetLabel ? widgetLabel : customModule.widgetName;
        customModule.widgetDescription = widgetDescription ? widgetDescription : "";
        customModule.widgetHelpURL = widgetHelpURL ? widgetHelpURL : "";

        return new CustomWidgetType(customModule, widgetVersion, widgetConfiguration);
    }

    private function createWidgetIconPath(iconPath:String, widgetName:String):String
    {
        var widgetIconPath:String;

        if (iconPath)
        {
            widgetIconPath = "widgets/" + widgetName + "/" + iconPath;
        }
        else
        {
            widgetIconPath = "assets/images/i_widget.png";
        }

        return widgetIconPath;
    }
}
}

Arrange methods closer to usage.

Arrange methods closer to usage.


package com.threerings.flash {

import flash.utils.getTimer;

/**
 * Tracks multiple sine waves with different periods and amplitudes, and
 * returns a
 */
public class Siner
{
    /**
     * @param args: amplitude1, period1, amplitude2, period2...
     * Periods are specified in seconds.
     *
     * If constructed with more than one amplitude, the amplitudes are
     * additive.
     *
     * The Siner will start in the reset() state.
     */
    public function Siner (... args)
    {
        if (args.length == 0 || (args.length % 2 != 0)) {
            throw new ArgumentError();
        }
        while (args.length > 0) {
            if (!(args[0] is Number) || !(args[1] is Number)) {
                throw new ArgumentError();
            }
            var amp :Number = args.shift();
            var per :Number = args.shift();

            _incs.push(TWO_PI / (per * 1000));
            _amps.push(amp);
        }
        reset();
    }

    /**
     * Reset to 0, with the amplitude about to increase.
     */
    public function reset () :void
    {
        for (var ii :int = _amps.length - 1; ii >= 0; ii--) {
            _values[ii] = 3 * Math.PI / 2;
        }
        _stamp = getTimer();
    }

    /**
     * Randomize the value.
     */
    public function randomize () :void
    {
        for (var ii :int = _amps.length - 1; ii >= 0; ii--) {
            _values[ii] = Math.random() * TWO_PI;
        }
    }

    /**
     * Access the instantaneous value, which can range from
     * [ -totalAmplitude, totalAmplitude ].
     *
     * Note: timestamps are only kept relative to the last access of the value,
     * and floating point math is used, so things could get a little "off" after
     * a while, and the frequency with which you sample the value will impact
     * the error. You cope.
     */
    public function get value () :Number
    {
        var now :Number = getTimer();
        var elapsed :Number = now - _stamp;
        _stamp = now;

        var accum :Number = 0;
        for (var ii :int = _values.length - 1; ii >= 0; ii--) {
            var val :Number = (_values[ii] + (_incs[ii] * elapsed)) % TWO_PI;
            _values[ii] = val;
            accum += _amps[ii] * Math.sin(val);
        }
        return accum;
    }

    protected var _values :Array = [];
    protected var _incs :Array = [];
    protected var _amps :Array = [];

    protected var _stamp :Number;

    protected static const TWO_PI :Number = 2 * Math.PI;
}

}

package com.threerings.flash {

import flash.utils.getTimer;

/**
 * Tracks multiple sine waves with different periods and amplitudes, and
 * returns an instantaneous additive amplitude.
 */
public class Siner
{
    /**
     * @param args: amplitude1, period1, amplitude2, period2...
     * Periods are specified in seconds.
     *
     * If constructed with more than one amplitude, the amplitudes are
     * additive.
     *
     * The Siner will start in the reset() state.
     */
    public function Siner (... args)
    {
        if (args.length == 0 || (args.length % 2 != 0)) {
            throw new ArgumentError();
        }
        while (args.length > 0) {
            if (!(args[0] is Number) || !(args[1] is Number)) {
                throw new ArgumentError();
            }
            var amp :Number = args.shift();
            var per :Number = args.shift();

            _incs.push(TWO_PI / (per * 1000));
            _amps.push(amp);
        }
        reset();
    }

    /**
     * Reset to 0, with the amplitude about to increase.
     */
    public function reset () :void
    {
        for (var ii :int = _amps.length - 1; ii >= 0; ii--) {
            _values[ii] = 3 * Math.PI / 2;
        }
        _stamp = getTimer();
    }

    /**
     * Randomize the value.
     */
    public function randomize () :void
    {
        for (var ii :int = _amps.length - 1; ii >= 0; ii--) {
            _values[ii] = Math.random() * TWO_PI;
        }
    }

    /**
     * Access the instantaneous value, which can range from
     * [ -totalAmplitude, totalAmplitude ].
     *
     * Note: timestamps are only kept relative to the last access of the value,
     * and floating point math is used, so things could get a little "off" after
     * a while, and the frequency with which you sample the value will impact
     * the error. You cope.
     */
    public function get value () :Number
    {
        var now :Number = getTimer();
        var elapsed :Number = now - _stamp;
        _stamp = now;

        var accum :Number = 0;
        for (var ii :int = _values.length - 1; ii >= 0; ii--) {
            var val :Number = (_values[ii] + (_incs[ii] * elapsed)) % TWO_PI;
            _values[ii] = val;
            accum += _amps[ii] * Math.sin(val);
        }
        return accum;
    }

    protected var _values :Array = [];
    protected var _incs :Array = [];
    protected var _amps :Array = [];

    protected var _stamp :Number;

    protected static const TWO_PI :Number = 2 * Math.PI;
}

}

Comment fixup.

Comment fixup.

git-svn-id: b675b909355d5cf946977f44a8ec5a6ceb3782e4@171 ed5b42cb-e716-0410-a449-f6a68f950b19


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

import flash.filesystem.File;

public class FileUtil
{
    private static const CRLF_LINE_ENDING:String = "\r\n";
    private static const LF_LINE_ENDING:String = "\n";

    public static function generateUniqueRelativePath(baseDirectory:File, relativeFilePath:String, relativePathBlackList:Array = null):String
    {
        var extensionIndex:int = relativeFilePath.lastIndexOf(".");
        var extension:String = "";
        if (extensionIndex > -1)
        {
            extension = relativeFilePath.substr(extensionIndex);
            relativeFilePath = relativeFilePath.substr(0, extensionIndex);
        }
        var filenameTemplate:String = relativeFilePath + "_{0}" + extension;

        var uniqueWidgetConfigPath:String =
            LabelUtil.generateUniqueLabel(filenameTemplate,
                                          relativePathBlackList,
                                          function isNonExistentFile(uniqueFilePath:String, availableNames:Array):Boolean
                                          {
                                              if (availableNames
                                                  && availableNames.indexOf(uniqueFilePath) > -1)
                                              {
                                                  return false;
                                              }

                                              return !baseDirectory.resolvePath(uniqueFilePath).exists;
                                          });
        return uniqueWidgetConfigPath;
    }

    public static function getFileName(file:File):String
    {
        return file.name.replace("." + file.extension, "");
    }

    public static function findMatchingFiles(directory:File, pattern:RegExp):Array
    {
        var moduleFiles:Array = [];

        if (directory.isDirectory)
        {
            const files:Array = directory.getDirectoryListing();

            for each (var file:File in files)
            {
                if (file.isDirectory)
                {
                    moduleFiles = moduleFiles.concat(findMatchingFiles(file, pattern));
                }
                else if (pattern.test(file.name))
                {
                    moduleFiles.push(file);
                }
            }
        }

        return moduleFiles;
    }

    public static function findMatchingFile(directory:File, pattern:RegExp):File
    {
        var matchingFile:File;

        if (directory.isDirectory)
        {
            const files:Array = directory.getDirectoryListing();

            //sort files first to reduce unnecessary directory listing calls.
            files.sortOn("isDirectory");

            for each (var file:File in files)
            {
                if (file.isDirectory)
                {
                    matchingFile = findMatchingFile(file, pattern);
                }
                else if (pattern.test(file.name))
                {
                    matchingFile = file;
                }

                if (matchingFile)
                {
                    break;
                }
            }
        }

        return matchingFile;
    }

    public static function ensureOSLineEndings(text:String):String
    {
        if (File.lineEnding == CRLF_LINE_ENDING)
        {
            return ensureCRLF(text);
        }

        if (File.lineEnding == LF_LINE_ENDING)
        {
            return ensureLF(text);
        }

        return text ? text : "";
    }

    private static function ensureCRLF(text:String):String
    {
        return text ? text.replace(/(?<!\r)\n/g, CRLF_LINE_ENDING) : "";
    }

    private static function ensureLF(text:String):String
    {
        return text ? text.replace(/\r\n/g, LF_LINE_ENDING) : "";
    }
}
}

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

import flash.filesystem.File;

public class FileUtil
{
    private static const CRLF_LINE_ENDING:String = "\r\n";
    private static const LF_LINE_ENDING:String = "\n";

    public static function ensureOSLineEndings(text:String):String
    {
        if (File.lineEnding == CRLF_LINE_ENDING)
        {
            return ensureCRLF(text);
        }

        if (File.lineEnding == LF_LINE_ENDING)
        {
            return ensureLF(text);
        }

        return text ? text : "";
    }

    private static function ensureCRLF(text:String):String
    {
        return text ? text.replace(/(?<!\r)\n/g, CRLF_LINE_ENDING) : "";
    }

    private static function ensureLF(text:String):String
    {
        return text ? text.replace(/\r\n/g, LF_LINE_ENDING) : "";
    }

    public static function generateUniqueRelativePath(baseDirectory:File, relativeFilePath:String, relativePathBlackList:Array = null):String
    {
        var extensionIndex:int = relativeFilePath.lastIndexOf(".");
        var extension:String = "";
        if (extensionIndex > -1)
        {
            extension = relativeFilePath.substr(extensionIndex);
            relativeFilePath = relativeFilePath.substr(0, extensionIndex);
        }
        var filenameTemplate:String = relativeFilePath + "_{0}" + extension;

        var uniqueWidgetConfigPath:String =
            LabelUtil.generateUniqueLabel(filenameTemplate,
                                          relativePathBlackList,
                                          function isNonExistentFile(uniqueFilePath:String, availableNames:Array):Boolean
                                          {
                                              if (availableNames
                                                  && availableNames.indexOf(uniqueFilePath) > -1)
                                              {
                                                  return false;
                                              }

                                              return !baseDirectory.resolvePath(uniqueFilePath).exists;
                                          });
        return uniqueWidgetConfigPath;
    }

    public static function getFileName(file:File):String
    {
        return file.name.replace("." + file.extension, "");
    }

    public static function findMatchingFiles(directory:File, pattern:RegExp):Array
    {
        var moduleFiles:Array = [];

        if (directory.isDirectory)
        {
            const files:Array = directory.getDirectoryListing();

            for each (var file:File in files)
            {
                if (file.isDirectory)
                {
                    moduleFiles = moduleFiles.concat(findMatchingFiles(file, pattern));
                }
                else if (pattern.test(file.name))
                {
                    moduleFiles.push(file);
                }
            }
        }

        return moduleFiles;
    }

    public static function findMatchingFile(directory:File, pattern:RegExp):File
    {
        var matchingFile:File;

        if (directory.isDirectory)
        {
            const files:Array = directory.getDirectoryListing();

            //sort files first to reduce unnecessary directory listing calls.
            files.sortOn("isDirectory");

            for each (var file:File in files)
            {
                if (file.isDirectory)
                {
                    matchingFile = findMatchingFile(file, pattern);
                }
                else if (pattern.test(file.name))
                {
                    matchingFile = file;
                }

                if (matchingFile)
                {
                    break;
                }
            }
        }

        return matchingFile;
    }
}
}

Clean up.

Clean up.


package Controller.logic
{
	import Model.AGORAModel;
	import Model.ArgumentTypeModel;
	import Model.SimpleStatementModel;
	import Model.StatementModel;

	import ValueObjects.AGORAParameters;

	import components.ArgumentPanel;
	import classes.Language;

	import mx.controls.Alert;

	public class DisjunctiveSyllogism extends ParentArg
	{
		private static var instance:DisjunctiveSyllogism;

		public function DisjunctiveSyllogism()
		{
			label = AGORAParameters.getInstance().DIS_SYLL;
		}

		public static function getInstance():DisjunctiveSyllogism{
			if(instance == null){
				instance = new DisjunctiveSyllogism;
			}
			return instance;
		}

		override public function formText(argumentTypeModel:ArgumentTypeModel):void{
			var output:String = "";
			var reasonText:String = "";
			var reasonModels:Vector.<StatementModel> = argumentTypeModel.reasonModels;
			var claimModel:StatementModel = argumentTypeModel.claimModel;
			var inferenceModel:StatementModel = argumentTypeModel.inferenceModel;
			var i:int;

			output = "Either "; //TODO: Need a translation for this
			if(reasonModels.length < inferenceModel.statements.length){
				for(i=0; i<reasonModels.length; i++){
					inferenceModel.statements[i+1].text = reasonModels[i].statement.positiveText;
					reasonText = reasonText + reasonModels[i].statement.positiveText + Language.lookup("ArgOr");
				}
				inferenceModel.statements[0].text = claimModel.statement.text;
				output = output + reasonText + claimModel.statement.text;
				inferenceModel.statement.text = output;
			}
		}

		override public function deleteLinks(argumentTypeModel:ArgumentTypeModel):void{
			var reasonModels:Vector.<StatementModel> = argumentTypeModel.reasonModels;
			var claimModel:StatementModel = argumentTypeModel.claimModel;
			var inferenceModel:StatementModel = argumentTypeModel.inferenceModel;

			//remove negativity of the reason
			reasonModels[0].negated = false;

			//remove links from reason to inference
			var simpleStatement:SimpleStatementModel;
			var stmtToBeUnlinked:SimpleStatementModel;

			simpleStatement = reasonModels[0].statement;
			stmtToBeUnlinked = inferenceModel.statements[1];
			removeDependence(simpleStatement, stmtToBeUnlinked);

			simpleStatement = claimModel.statement;
			stmtToBeUnlinked = inferenceModel.statements[0];
			removeDependence(simpleStatement, stmtToBeUnlinked);
		}
		override public function link(argumentTypeModel:ArgumentTypeModel):void{
			var reasonModels:Vector.<StatementModel> = argumentTypeModel.reasonModels;
			var claimModel:StatementModel = argumentTypeModel.claimModel;
			var inferenceModel:StatementModel = argumentTypeModel.inferenceModel;

			claimModel.statement.forwardList.push(inferenceModel.statements[0]);
			for(var i:int=0; i<reasonModels.length; i++){
				reasonModels[i].statement.forwardList.push(inferenceModel.statements[i+1]);
				reasonModels[i].negated = true;
			}
			inferenceModel.connectingString = StatementModel.DISJUNCTION;
		}
	}
}

package Controller.logic
{
	import Model.AGORAModel;
	import Model.ArgumentTypeModel;
	import Model.SimpleStatementModel;
	import Model.StatementModel;

	import ValueObjects.AGORAParameters;

	import components.ArgumentPanel;
	import classes.Language;

	import mx.controls.Alert;

	public class DisjunctiveSyllogism extends ParentArg
	{
		private static var instance:DisjunctiveSyllogism;

		public function DisjunctiveSyllogism()
		{
			label = AGORAParameters.getInstance().DIS_SYLL;
		}

		public static function getInstance():DisjunctiveSyllogism{
			if(instance == null){
				instance = new DisjunctiveSyllogism;
			}
			return instance;
		}

		override public function formText(argumentTypeModel:ArgumentTypeModel):void{
			var output:String = "";
			var reasonText:String = "";
			var reasonModels:Vector.<StatementModel> = argumentTypeModel.reasonModels;
			var claimModel:StatementModel = argumentTypeModel.claimModel;
			var inferenceModel:StatementModel = argumentTypeModel.inferenceModel;
			var i:int;

			output = Language.lookup("ArgEitherCap"); //TODO: Need a translation for this
			if(reasonModels.length < inferenceModel.statements.length){
				for(i=0; i<reasonModels.length; i++){
					inferenceModel.statements[i+1].text = reasonModels[i].statement.positiveText;
					reasonText = reasonText + reasonModels[i].statement.positiveText + Language.lookup("ArgOr");
				}
				inferenceModel.statements[0].text = claimModel.statement.text;
				output = output + reasonText + claimModel.statement.text;
				inferenceModel.statement.text = output;
			}
		}

		override public function deleteLinks(argumentTypeModel:ArgumentTypeModel):void{
			var reasonModels:Vector.<StatementModel> = argumentTypeModel.reasonModels;
			var claimModel:StatementModel = argumentTypeModel.claimModel;
			var inferenceModel:StatementModel = argumentTypeModel.inferenceModel;

			//remove negativity of the reason
			reasonModels[0].negated = false;

			//remove links from reason to inference
			var simpleStatement:SimpleStatementModel;
			var stmtToBeUnlinked:SimpleStatementModel;

			simpleStatement = reasonModels[0].statement;
			stmtToBeUnlinked = inferenceModel.statements[1];
			removeDependence(simpleStatement, stmtToBeUnlinked);

			simpleStatement = claimModel.statement;
			stmtToBeUnlinked = inferenceModel.statements[0];
			removeDependence(simpleStatement, stmtToBeUnlinked);
		}
		override public function link(argumentTypeModel:ArgumentTypeModel):void{
			var reasonModels:Vector.<StatementModel> = argumentTypeModel.reasonModels;
			var claimModel:StatementModel = argumentTypeModel.claimModel;
			var inferenceModel:StatementModel = argumentTypeModel.inferenceModel;

			claimModel.statement.forwardList.push(inferenceModel.statements[0]);
			for(var i:int=0; i<reasonModels.length; i++){
				reasonModels[i].statement.forwardList.push(inferenceModel.statements[i+1]);
				reasonModels[i].negated = true;
			}
			inferenceModel.connectingString = StatementModel.DISJUNCTION;
		}
	}
}

Add translation for Either

Add translation for Either


package dolly {
import dolly.core.dolly_internal;
import dolly.data.ClassLevelCopyable;
import dolly.data.ClassLevelCopyableCloneable;
import dolly.data.PropertyLevelCopyable;
import dolly.data.PropertyLevelCopyableCloneable;

import org.as3commons.reflect.Field;
import org.as3commons.reflect.Type;
import org.flexunit.asserts.assertEquals;
import org.flexunit.asserts.assertNotNull;
import org.flexunit.asserts.assertNull;

use namespace dolly_internal;

public class CopierTest {

	private var classLevelCopyable:ClassLevelCopyable;
	private var classLevelCopyableType:Type;

	private var classLevelCopyableCloneable:ClassLevelCopyableCloneable;
	private var classLevelCopyableCloneableType:Type;

	private var propertyLevelCopyable:PropertyLevelCopyable;
	private var propertyLevelCopyableType:Type;

	private var propertyLevelCopyableCloneable:PropertyLevelCopyableCloneable;
	private var propertyLevelCopyableCloneableType:Type;

	[Before]
	public function before():void {
		classLevelCopyable = new ClassLevelCopyable();
		classLevelCopyable.property1 = "value 1";
		classLevelCopyable.property2 = "value 2";
		classLevelCopyable.property3 = "value 3";
		classLevelCopyable.writableField = "value 4";
		classLevelCopyableType = Type.forInstance(classLevelCopyable);

		classLevelCopyableCloneable = new ClassLevelCopyableCloneable();
		classLevelCopyableCloneable.property1 = "value 1";
		classLevelCopyableCloneable.property2 = "value 2";
		classLevelCopyableCloneable.property3 = "value 3";
		classLevelCopyableCloneable.writableField = "value 4";
		classLevelCopyableCloneableType = Type.forInstance(classLevelCopyableCloneable);

		propertyLevelCopyable = new PropertyLevelCopyable();
		propertyLevelCopyable.property1 = "value 1";
		propertyLevelCopyable.property2 = "value 2";
		propertyLevelCopyable.property3 = "value 3";
		propertyLevelCopyable.writableField = "value 4";
		propertyLevelCopyableType = Type.forInstance(propertyLevelCopyable);

		propertyLevelCopyableCloneable = new PropertyLevelCopyableCloneable();
		propertyLevelCopyableCloneable.property1 = "value 1";
		propertyLevelCopyableCloneable.property2 = "value 2";
		propertyLevelCopyableCloneable.property3 = "value 3";
		propertyLevelCopyableCloneable.writableField = "value 4";
		propertyLevelCopyableCloneableType = Type.forInstance(propertyLevelCopyableCloneable);
	}

	[After]
	public function after():void {
		classLevelCopyable = null;
		classLevelCopyableType = null;

		classLevelCopyableCloneable = null;
		classLevelCopyableCloneableType = null;

		propertyLevelCopyable = null;
		propertyLevelCopyableType = null;

		propertyLevelCopyableCloneable = null;
		propertyLevelCopyableCloneableType = null;
	}

	[Test]
	public function testGetCopyableFieldsForTypeClassLevelCopyable():void {
		const copyableFields:Vector.<Field> = Copier.getCopyableFieldsForType(classLevelCopyableType);
		assertNotNull(copyableFields);
		assertEquals(4, copyableFields.length);
		assertNotNull(copyableFields[0]);
		assertNotNull(copyableFields[1]);
		assertNotNull(copyableFields[2]);
		assertNotNull(copyableFields[3]);
	}

	[Test]
	public function testGetCopyableFieldsForTypeClassLevelCopyableCloneable():void {
		const copyableFields:Vector.<Field> = Copier.getCopyableFieldsForType(classLevelCopyableCloneableType);
		assertNotNull(copyableFields);
		assertEquals(4, copyableFields.length);
		assertNotNull(copyableFields[0]);
		assertNotNull(copyableFields[1]);
		assertNotNull(copyableFields[2]);
		assertNotNull(copyableFields[3]);
	}

	[Test]
	public function testGetCopyableFieldsForTypePropertyLevelCopyable():void {
		const copyableFields:Vector.<Field> = Copier.getCopyableFieldsForType(propertyLevelCopyableType);
		assertNotNull(copyableFields);
		assertEquals(3, copyableFields.length);
		assertNotNull(copyableFields[0]);
		assertNotNull(copyableFields[1]);
		assertNotNull(copyableFields[2]);
	}

	[Test]
	public function testGetCopyableFieldsForTypePropertyLevelCopyableCloneable():void {
		const copyableFields:Vector.<Field> = Copier.getCopyableFieldsForType(propertyLevelCopyableCloneableType);
		assertNotNull(copyableFields);
		assertEquals(3, copyableFields.length);
		assertNotNull(copyableFields[0]);
		assertNotNull(copyableFields[1]);
		assertNotNull(copyableFields[2]);
	}

	[Test]
	public function testCopyClassLevelCopyable():void {
		const copy:ClassLevelCopyable = Copier.copy(classLevelCopyable);
		assertNotNull(copy);
		assertNotNull(copy.property1);
		assertEquals(copy.property1, classLevelCopyable.property1);
		assertNotNull(copy.property2);
		assertEquals(copy.property2, classLevelCopyable.property2);
		assertNotNull(copy.property3);
		assertEquals(copy.property3, classLevelCopyable.property3);
		assertNotNull(copy.writableField);
		assertEquals(copy.writableField, classLevelCopyable.writableField);
	}

	[Test]
	public function testCopyClassLevelCopyableCloneable():void {
		const copy:ClassLevelCopyableCloneable = Copier.copy(classLevelCopyableCloneable);
		assertNotNull(copy);
		assertNotNull(copy.property1);
		assertEquals(copy.property1, classLevelCopyable.property1);
		assertNotNull(copy.property2);
		assertEquals(copy.property2, classLevelCopyable.property2);
		assertNotNull(copy.property3);
		assertEquals(copy.property3, classLevelCopyable.property3);
		assertNotNull(copy.writableField);
		assertEquals(copy.writableField, classLevelCopyable.writableField);
	}

	[Test]
	public function testCopyWithPropertyLevelMetadata():void {
		const copy1:PropertyLevelCopyable = Copier.copy(propertyLevelCopyable);
		assertNotNull(copy1);
		assertNull(copy1.property1);
		assertNotNull(copy1.property2);
		assertEquals(copy1.property2, classLevelCopyable.property2);
		assertNotNull(copy1.property3);
		assertEquals(copy1.property3, classLevelCopyable.property3);
		assertNotNull(copy1.writableField);
		assertEquals(copy1.writableField, classLevelCopyable.writableField);

		const copy2:PropertyLevelCopyableCloneable = Copier.copy(propertyLevelCopyableCloneable);
		assertNotNull(copy2);
		assertNull(copy2.property1);
		assertNotNull(copy2.property2);
		assertEquals(copy2.property2, classLevelCopyable.property2);
		assertNotNull(copy2.property3);
		assertEquals(copy2.property3, classLevelCopyable.property3);
		assertNotNull(copy2.writableField);
		assertEquals(copy2.writableField, classLevelCopyable.writableField);
	}
}
}

package dolly {
import dolly.core.dolly_internal;
import dolly.data.ClassLevelCopyable;
import dolly.data.ClassLevelCopyableCloneable;
import dolly.data.PropertyLevelCopyable;
import dolly.data.PropertyLevelCopyableCloneable;

import org.as3commons.reflect.Field;
import org.as3commons.reflect.Type;
import org.flexunit.asserts.assertEquals;
import org.flexunit.asserts.assertNotNull;
import org.flexunit.asserts.assertNull;

use namespace dolly_internal;

public class CopierTest {

	private var classLevelCopyable:ClassLevelCopyable;
	private var classLevelCopyableType:Type;

	private var classLevelCopyableCloneable:ClassLevelCopyableCloneable;
	private var classLevelCopyableCloneableType:Type;

	private var propertyLevelCopyable:PropertyLevelCopyable;
	private var propertyLevelCopyableType:Type;

	private var propertyLevelCopyableCloneable:PropertyLevelCopyableCloneable;
	private var propertyLevelCopyableCloneableType:Type;

	[Before]
	public function before():void {
		classLevelCopyable = new ClassLevelCopyable();
		classLevelCopyable.property1 = "value 1";
		classLevelCopyable.property2 = "value 2";
		classLevelCopyable.property3 = "value 3";
		classLevelCopyable.writableField = "value 4";
		classLevelCopyableType = Type.forInstance(classLevelCopyable);

		classLevelCopyableCloneable = new ClassLevelCopyableCloneable();
		classLevelCopyableCloneable.property1 = "value 1";
		classLevelCopyableCloneable.property2 = "value 2";
		classLevelCopyableCloneable.property3 = "value 3";
		classLevelCopyableCloneable.writableField = "value 4";
		classLevelCopyableCloneableType = Type.forInstance(classLevelCopyableCloneable);

		propertyLevelCopyable = new PropertyLevelCopyable();
		propertyLevelCopyable.property1 = "value 1";
		propertyLevelCopyable.property2 = "value 2";
		propertyLevelCopyable.property3 = "value 3";
		propertyLevelCopyable.writableField = "value 4";
		propertyLevelCopyableType = Type.forInstance(propertyLevelCopyable);

		propertyLevelCopyableCloneable = new PropertyLevelCopyableCloneable();
		propertyLevelCopyableCloneable.property1 = "value 1";
		propertyLevelCopyableCloneable.property2 = "value 2";
		propertyLevelCopyableCloneable.property3 = "value 3";
		propertyLevelCopyableCloneable.writableField = "value 4";
		propertyLevelCopyableCloneableType = Type.forInstance(propertyLevelCopyableCloneable);
	}

	[After]
	public function after():void {
		classLevelCopyable = null;
		classLevelCopyableType = null;

		classLevelCopyableCloneable = null;
		classLevelCopyableCloneableType = null;

		propertyLevelCopyable = null;
		propertyLevelCopyableType = null;

		propertyLevelCopyableCloneable = null;
		propertyLevelCopyableCloneableType = null;
	}

	[Test]
	public function testGetCopyableFieldsForTypeClassLevelCopyable():void {
		const copyableFields:Vector.<Field> = Copier.getCopyableFieldsForType(classLevelCopyableType);
		assertNotNull(copyableFields);
		assertEquals(4, copyableFields.length);
		assertNotNull(copyableFields[0]);
		assertNotNull(copyableFields[1]);
		assertNotNull(copyableFields[2]);
		assertNotNull(copyableFields[3]);
	}

	[Test]
	public function testGetCopyableFieldsForTypeClassLevelCopyableCloneable():void {
		const copyableFields:Vector.<Field> = Copier.getCopyableFieldsForType(classLevelCopyableCloneableType);
		assertNotNull(copyableFields);
		assertEquals(4, copyableFields.length);
		assertNotNull(copyableFields[0]);
		assertNotNull(copyableFields[1]);
		assertNotNull(copyableFields[2]);
		assertNotNull(copyableFields[3]);
	}

	[Test]
	public function testGetCopyableFieldsForTypePropertyLevelCopyable():void {
		const copyableFields:Vector.<Field> = Copier.getCopyableFieldsForType(propertyLevelCopyableType);
		assertNotNull(copyableFields);
		assertEquals(3, copyableFields.length);
		assertNotNull(copyableFields[0]);
		assertNotNull(copyableFields[1]);
		assertNotNull(copyableFields[2]);
	}

	[Test]
	public function testGetCopyableFieldsForTypePropertyLevelCopyableCloneable():void {
		const copyableFields:Vector.<Field> = Copier.getCopyableFieldsForType(propertyLevelCopyableCloneableType);
		assertNotNull(copyableFields);
		assertEquals(3, copyableFields.length);
		assertNotNull(copyableFields[0]);
		assertNotNull(copyableFields[1]);
		assertNotNull(copyableFields[2]);
	}

	[Test]
	public function testCopyClassLevelCopyable():void {
		const copy:ClassLevelCopyable = Copier.copy(classLevelCopyable);
		assertNotNull(copy);
		assertNotNull(copy.property1);
		assertEquals(copy.property1, classLevelCopyable.property1);
		assertNotNull(copy.property2);
		assertEquals(copy.property2, classLevelCopyable.property2);
		assertNotNull(copy.property3);
		assertEquals(copy.property3, classLevelCopyable.property3);
		assertNotNull(copy.writableField);
		assertEquals(copy.writableField, classLevelCopyable.writableField);
	}

	[Test]
	public function testCopyClassLevelCopyableCloneable():void {
		const copy:ClassLevelCopyableCloneable = Copier.copy(classLevelCopyableCloneable);
		assertNotNull(copy);
		assertNotNull(copy.property1);
		assertEquals(copy.property1, classLevelCopyable.property1);
		assertNotNull(copy.property2);
		assertEquals(copy.property2, classLevelCopyable.property2);
		assertNotNull(copy.property3);
		assertEquals(copy.property3, classLevelCopyable.property3);
		assertNotNull(copy.writableField);
		assertEquals(copy.writableField, classLevelCopyable.writableField);
	}

	[Test]
	public function testCopyPropertyLevelCopyable():void {
		const copy:PropertyLevelCopyable = Copier.copy(propertyLevelCopyable);
		assertNotNull(copy);
		assertNull(copy.property1);
		assertNotNull(copy.property2);
		assertEquals(copy.property2, classLevelCopyable.property2);
		assertNotNull(copy.property3);
		assertEquals(copy.property3, classLevelCopyable.property3);
		assertNotNull(copy.writableField);
		assertEquals(copy.writableField, classLevelCopyable.writableField);
	}

	[Test]
	public function testCopyPropertyLevelCopyableCloneable():void {
		const copy:PropertyLevelCopyableCloneable = Copier.copy(propertyLevelCopyableCloneable);
		assertNotNull(copy);
		assertNull(copy.property1);
		assertNotNull(copy.property2);
		assertEquals(copy.property2, classLevelCopyable.property2);
		assertNotNull(copy.property3);
		assertEquals(copy.property3, classLevelCopyable.property3);
		assertNotNull(copy.writableField);
		assertEquals(copy.writableField, classLevelCopyable.writableField);
	}
}
}

Split method "testCopyWithPropertyLevelMetadata" to a few.