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

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

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

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

			registerCallback(returnInstance, type, false);
		}

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

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

			registerCallback(resolveType, type, asSingleton);
		}

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

			validateCallback(callback);

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

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

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

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

			return resolveByClass(type);
		}

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

			var description:XML = getTypeDescription(type);

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

			var parameters:Array = resolveConstructorParameters(description.factory.constructor);
			var instance:Object = createObject(type, parameters);
			injectProperties(instance, description.factory);

			return instance;
		}

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

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

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

		/**
		 * Gets the class description for the type
		 * @param	type The class to be described
		 * @return An XML of the properties and methods for the class
		 */
		private function getTypeDescription(type:Class):XML
		{
			if (_descriptions[type] !== undefined)
				return _descriptions[type];

			return _descriptions[type] = describeType(type);
		}

		/**
		 * Resolves the non-optional parameters for a constructor
		 * @param	constructor The constructor node from a class description xml
		 * @return An array of objects to use as constructor arguments
		 */
		private function resolveConstructorParameters(constructor:XMLList):Array
		{
			var parameters:Array = [];

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

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

			return parameters;
		}

		/**
		 * Resolves the properties on the instance object that are marked 'Inject'
		 * @param	instance The object to be inspected
		 * @param	factory The factory node from a class description xml
		 */
		private function injectProperties(instance:Object, factory:XMLList):void
		{
			for each (var accessor:XML in factory.accessor)
			{
				if (shouldInjectAccessor(accessor))
				{
					var propertyType:Class = Class(getDefinitionByName(accessor.@type.toString()));
					instance[accessor.@name.toString()] = resolve(propertyType);
				}
			}
		}

		/**
		 * Determines whether the accessor should be injected
		 * @param	accessor An accessor node from a class description xml
		 * @return true is the Inject metadata is present, otherwise false
		 */
		private function shouldInjectAccessor(accessor:XML):Boolean
		{
			if (accessor.@access == "readwrite" ||
				accessor.@access == "write")
			{
				for each (var metadata:XML in accessor.metadata)
				{
					if (metadata.@name.toString() == "Inject")
						return true;
				}
			}

			return false;
		}
	}
}

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

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

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

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

			registerCallback(returnInstance, type, false);
		}

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

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

			registerCallback(resolveType, type, asSingleton);
		}

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

			validateCallback(callback);

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

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

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

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

			return resolveByClass(type);
		}

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

			var typeDescription:Object = getTypeDescription(type);

			if (!typeDescription)
				throw new IllegalOperationError("Interface must be registered before it can be resolved.");

			var parameters:Array = resolveConstructorParameters(typeDescription);
			var instance:Object = createObject(type, parameters);
			injectProperties(instance, typeDescription);

			return instance;
		}

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

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

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

		/**
		 * Gets the class description for the type
		 * @param	type The class to be described
		 * @return An object of constructor types and injectable properties
		 */
		private function getTypeDescription(type:Class):Object
		{
			if (_descriptions[type] !== undefined)
				return _descriptions[type];

			return _descriptions[type] = buildTypeDescription(type);
		}

		/**
		 * Builds an optimized description of the type.
		 * @param	type The type to be described.
		 * @return An optimized description of the constructor and injectable properties
		 */
		private function buildTypeDescription(type:Class):Object
		{
			var typeDescription:Object = { constructorTypes:[], injectableProperties:[] };
			var description:XML = describeType(type);

			if (description.factory.extendsClass.length() === 0)
				return null;

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

				var parameterType:Class = Class(getDefinitionByName(parameter.@type.toString()));
				typeDescription.constructorTypes.push(parameterType);
			}

			for each (var accessor:XML in description.factory.accessor)
			{
				if (shouldInjectAccessor(accessor))
				{
					var propertyType:Class = Class(getDefinitionByName(accessor.@type.toString()));
					typeDescription.injectableProperties.push( { name:accessor.@name.toString(), type:propertyType } );
				}
			}

			return typeDescription;
		}

		/**
		 * Determines whether the accessor should be injected
		 * @param	accessor An accessor node from a class description xml
		 * @return true is the Inject metadata is present, otherwise false
		 */
		private function shouldInjectAccessor(accessor:XML):Boolean
		{
			if (accessor.@access == "readwrite" ||
				accessor.@access == "write")
			{
				for each (var metadata:XML in accessor.metadata)
				{
					if (metadata.@name.toString() == "Inject")
						return true;
				}
			}

			return false;
		}

		/**
		 * Resolves the non-optional parameters for a constructor
		 * @param	typeDescription The optimized description of the type
		 * @return An array of objects to use as constructor arguments
		 */
		private function resolveConstructorParameters(typeDescription:Object):Array
		{
			var parameters:Array = [];

			for each (var parameterType:Class in typeDescription.constructorTypes)
				parameters.push(resolve(parameterType));

			return parameters;
		}

		/**
		 * Resolves the properties on the instance object that are marked 'Inject'
		 * @param	instance The object to be inspected
		 * @param	typeDescription The optimized description of the type
		 */
		private function injectProperties(instance:Object, typeDescription:Object):void
		{
			for each (var injectableProperty:Object in typeDescription.injectableProperties)
			{
				instance[injectableProperty.name] = resolve(injectableProperty.type);
			}
		}
	}
}

Store an optimized version of type description.


package aerys.minko.scene.node.mesh.modifier
{
	import aerys.minko.ns.minko_stream;
	import aerys.minko.scene.node.mesh.IMesh;
	import aerys.minko.scene.visitor.ISceneVisitor;
	import aerys.minko.type.bounding.BoundingBox;
	import aerys.minko.type.bounding.BoundingSphere;
	import aerys.minko.type.math.Vector4;
	import aerys.minko.type.stream.VertexStream;
	import aerys.minko.type.vertex.format.VertexComponent;

	public class BVHMesh extends AbstractMeshModifier
	{
		use namespace minko_stream;

		private var _version		: uint				= 0;

		private var _boundingBox	: BoundingBox		= null;
		private var _boundingSphere	: BoundingSphere	= null;

		override public function get version() : uint	{ return _version; }

		public function BVHMesh(target : IMesh)
		{
			super(target);
		}

		/*public function visited(query : ISceneVisitor) : void
		{
			if (target.version != _version || !_boundingBox)
			{
				var min				: Vector4			= new Vector4(Number.POSITIVE_INFINITY,
															 		  Number.POSITIVE_INFINITY,
																	  Number.POSITIVE_INFINITY);

				var max				: Vector4			= new Vector4(Number.NEGATIVE_INFINITY,
																	  Number.NEGATIVE_INFINITY,
																	  Number.NEGATIVE_INFINITY);

				var xyzStream		: VertexStream	= vertexStreamList.getVertexStreamByComponent(VertexComponent.XYZ);
				var xyzOffset		: int				= xyzStream.format.getOffsetForComponent(VertexComponent.XYZ);

				var dwords			: Vector.<Number>	= xyzStream._data;
				var dwordsPerVertex	: int				= xyzStream.format.dwordsPerVertex;
				var dwordsCount		: int				= dwords.length;

				for (var i : int = xyzOffset; i < dwordsCount; i += dwordsPerVertex)
				{
					var x : Number = dwords[i];
					var y : Number = dwords[int(i + 1)];
					var z : Number = dwords[int(i + 2)];

					min.x = x < min.x ? x : min.x;
					min.y = y < min.y ? y : min.y;
					min.z = z < min.z ? z : min.z;

					max.x = x > max.x ? x : max.x;
					max.y = y > max.y ? y : max.y;
					max.z = z > max.z ? z : max.z;
				}

				_boundingSphere = BoundingSphere.fromMinMax(min, max);
				_boundingBox = new BoundingBox(min, max);

				_version = target.version;
			}
		}*/

	}
}

package aerys.minko.scene.node.mesh.modifier
{
	import aerys.minko.ns.minko_stream;
	import aerys.minko.scene.node.mesh.IMesh;
	import aerys.minko.scene.visitor.ISceneVisitor;
	import aerys.minko.type.bounding.BoundingBox;
	import aerys.minko.type.bounding.BoundingSphere;
	import aerys.minko.type.math.Vector4;
	import aerys.minko.type.stream.VertexStream;
	import aerys.minko.type.vertex.format.VertexComponent;

	public class BVHMesh extends AbstractMeshModifier
	{
		use namespace minko_stream;

		private var _version		: uint				= 0;

		private var _boundingBox	: BoundingBox		= null;
		private var _boundingSphere	: BoundingSphere	= null;

		override public function get version() : uint	{ return _version; }

		public function BVHMesh(target : IMesh)
		{
			super(target);

			computeBoundingVolumes();
		}

		public function computeBoundingVolumes() : void
		{
			var min				: Vector4			= new Vector4(Number.POSITIVE_INFINITY,
														 		  Number.POSITIVE_INFINITY,
																  Number.POSITIVE_INFINITY);

			var max				: Vector4			= new Vector4(Number.NEGATIVE_INFINITY,
																  Number.NEGATIVE_INFINITY,
																  Number.NEGATIVE_INFINITY);

			var xyzStream		: VertexStream		= vertexStreamList.getVertexStreamByComponent(VertexComponent.XYZ);
			var xyzOffset		: int				= xyzStream.format.getOffsetForComponent(VertexComponent.XYZ);

			var dwords			: Vector.<Number>	= xyzStream._data;
			var dwordsPerVertex	: int				= xyzStream.format.dwordsPerVertex;
			var dwordsCount		: int				= dwords.length;

			for (var i : int = xyzOffset; i < dwordsCount; i += dwordsPerVertex)
			{
				var x : Number = dwords[i];
				var y : Number = dwords[int(i + 1)];
				var z : Number = dwords[int(i + 2)];

				min.x = x < min.x ? x : min.x;
				min.y = y < min.y ? y : min.y;
				min.z = z < min.z ? z : min.z;

				max.x = x > max.x ? x : max.x;
				max.y = y > max.y ? y : max.y;
				max.z = z > max.z ? z : max.z;
			}

			_boundingSphere = BoundingSphere.fromMinMax(min, max);
			_boundingBox = new BoundingBox(min, max);
		}
	}
}

Enable dead code from BVHMesh

Enable dead code from BVHMesh


package
{
	import flash.display.Sprite;

	import org.osmf.containers.MediaContainer;
	import org.osmf.elements.VideoElement;
	import org.osmf.media.DefaultMediaFactory;
	import org.osmf.media.MediaElement;
	import org.osmf.media.MediaPlayer;
	import org.osmf.media.URLResource;

	[SWF( width="640", height="360" )]
	public class RTMP extends Sprite
	{
		public function RTMP()
		{
			// Store the URL
			var videoPath:String = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short";

			// Create a resource
			var resource:URLResource = new URLResource( videoPath );

			// Create a mediafactory instance
			var mediaFactory:DefaultMediaFactory = new DefaultMediaFactory();

			// Create a MediaElement
			//var element:VideoElement = new VideoElement( resource );
			var element:MediaElement = mediaFactory.createMediaElement( resource );

			// Create a media player
			var mediaPlayer:MediaPlayer = new MediaPlayer( element );

			// Create a media container & add the MediaElement
			var mediaContainer:MediaContainer = new MediaContainer();
			mediaContainer.addMediaElement( element );

			// Add the container to the display list
			addChild( mediaContainer );

		}
	}
}

package {
  import flash.display.Sprite;
  import flash.external.ExternalInterface;

  import org.osmf.containers.MediaContainer;
  import org.osmf.elements.VideoElement;
  import org.osmf.media.DefaultMediaFactory;
  import org.osmf.media.MediaElement;
  import org.osmf.media.MediaPlayer;
  import org.osmf.media.URLResource;

  [SWF(width="640", height="360")]
  public class RTMP extends Sprite {
    private var playbackId:String;
    private var mediaFactory:DefaultMediaFactory;
    private var mediaContainer:MediaContainer;

    public function RTMP() {
      playbackId = this.root.loaderInfo.parameters.playbackId;
      mediaFactory = new DefaultMediaFactory();
      mediaContainer = new MediaContainer();

      setupCallbacks();
      _triggerEvent('flashready');
      ExternalInterface.call('console.log', 'clappr rtmp 0.0-alpha');
    }

    private function setupCallbacks():void {
      ExternalInterface.addCallback("playerPlay", play);
    }

    private function play(url:String):void {
      ExternalInterface.call('console.log', 'playing ' + url);
      var resource:URLResource = new URLResource(url);
      var element:MediaElement = mediaFactory.createMediaElement(resource);
      var mediaPlayer:MediaPlayer = new MediaPlayer(element);
      mediaContainer.addMediaElement(element);
      addChild(mediaContainer);
    }

    private function _triggerEvent(name: String):void {
      ExternalInterface.call('Clappr.Mediator.trigger("' + playbackId + ':' + name +'")');
    }
  }
}

fix identation, add first callback

RTMP.as: fix identation, add first callback


package org.shypl.common.util {
	import org.shypl.common.lang.IllegalStateException;

	public class Path {
		private var _value:String;

		public function Path(value:String = null) {
			if (value === "") {
				value = null;
			}
			else if (value !== null) {
				while (StringUtils.endsWith(value, "/")) {
					value = value.substr(0, -1);
				}
			}
			_value = value;
		}

		public function get parent():Path {
			if (_value === null) {
				throw new IllegalStateException();
			}

			var i:int = _value.lastIndexOf("/");
			if (i === -1) {
				throw new IllegalStateException();
			}

			return factoryPath(_value.substring(0, i));
		}

		public function get empty():Boolean {
			return _value === null;
		}

		protected function get value():String {
			return _value;
		}

		public function resolve(path:String):Path {
			var i:int;
			var p:Path = this;
			while ((i = path.indexOf("../")) >= 0) {
				p = p.parent;
				path = path.substr(3);
			}
			return factoryPath(p.empty ? path : (p.toString() + "/" + path));
		}

		public function resolveSibling(path:String):Path {
			return parent.resolve(path);
		}

		public function toString():String {
			return _value;
		}

		protected function factoryPath(value:String):Path {
			return new Path(value);
		}
	}
}

package org.shypl.common.util {
	import org.shypl.common.lang.IllegalStateException;

	public class Path {
		private var _value:String;

		public function Path(value:String = null) {
			if (value === "") {
				value = null;
			}
			else if (value !== null) {
				while (StringUtils.endsWith(value, "/")) {
					value = value.substr(0, -1);
				}
			}
			_value = value;
		}

		public function get parent():Path {
			if (_value === null) {
				throw new IllegalStateException();
			}

			var i:int = _value.lastIndexOf("/");
			if (i === -1) {
				throw new IllegalStateException();
			}

			return factoryPath(_value.substring(0, i));
		}

		public function get empty():Boolean {
			return _value === null;
		}

		public function get value():String {
			return _value;
		}

		public function resolve(path:String):Path {
			var i:int;
			var p:Path = this;
			while ((i = path.indexOf("../")) >= 0) {
				p = p.parent;
				path = path.substr(3);
			}
			return factoryPath(p.empty ? path : (p.toString() + "/" + path));
		}

		public function resolveSibling(path:String):Path {
			return parent.resolve(path);
		}

		public function toString():String {
			return _value;
		}

		protected function factoryPath(value:String):Path {
			return new Path(value);
		}
	}
}

Refactor Path

Refactor Path


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

package com.threerings.media.tile {

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.DisplayObject;

public class Tile
{
    /** The key associated with this tile. */
    public var key :Tile_Key;

    /**
     * Configures this tile with its tile image.
     */
    public function setImage (image :DisplayObject) :void
    {
        _image = image;

        // Notify them all and clear our list.
        for each (var func :Function in _notifyOnLoad) {
            func(this);
        }
    }

    public function getImage () :DisplayObject
    {
        if (_image is Bitmap) {
            // TODO - handle this more consistently...
            return new Bitmap(Bitmap(_image).bitmapData);
        } else {
            return _image;
        }
    }

    /**
     * Returns the width of this tile.
     */
    public function getWidth () :int
    {
        return _image.width;
    }

    /**
     * Returns the height of this tile.
     */
    public function getHeight () :int
    {
        return _image.height;
    }

    /**
     * Returns true if the specified coordinates within this tile contains
     * a non-transparent pixel.
     */
    public function hitTest (x :int, y :int) :Boolean
    {
        return _image.hitTestPoint(x, y, true);
    }

    public function toString () :String
    {
        return "[" + toStringBuf(new String()) + "]";
    }

    /**
     * This should be overridden by derived classes (which should be sure
     * to call super.toString()) to append the derived class
     * specific tile information to the string buffer.
     */
    protected function toStringBuf (buf :String) :String
    {
        if (_image == null) {
            return buf.concat("null-image");
        } else {
            return buf.concat(_image.width, "x", _image.height);
        }
    }

    public function notifyOnLoad (func :Function) :void
    {
        _notifyOnLoad.push(func);
    }

    /**
     * Returns the x offset into the tile image of the origin (which will be aligned with the
     * bottom center of the origin tile) or Integer.MIN_VALUE if the origin is not
     * explicitly specified and should be computed from the image size and tile footprint.
     */
    public function getOriginX () :int
    {
        throw new Error("abstract");
    }

    /**
     * Returns the y offset into the tile image of the origin (which will be aligned with the
     * bottom center of the origin tile) or Integer.MIN_VALUE if the origin is not
     * explicitly specified and should be computed from the image size and tile footprint.
     */
    public function getOriginY () :int
    {
        throw new Error("abstract")
    }

    /**
     * Returns the object footprint width in tile units.
     */
    public function getBaseWidth () :int
    {
        throw new Error("abstract");
    }

    /**
     * Returns the object footprint height in tile units.
     */
    public function getBaseHeight () :int
    {
        throw new Error("abstract");
    }

    /** Our tileset image. */
    protected var _image :DisplayObject;

    /** Everyone who cares when we're loaded. */
    protected var _notifyOnLoad :Array = [];
}
}

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

package com.threerings.media.tile {

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.DisplayObject;

public class Tile
{
    /** The key associated with this tile. */
    public var key :Tile_Key;

    /**
     * Configures this tile with its tile image.
     */
    public function setImage (image :DisplayObject) :void
    {
        _image = image;

        // Notify them all and clear our list.
        for each (var func :Function in _notifyOnLoad) {
            func(this);
        }
    }

    public function getImage () :DisplayObject
    {
        if (_image is Bitmap) {
            // TODO - handle this more consistently...
            return new Bitmap(Bitmap(_image).bitmapData);
        } else {
            return _image;
        }
    }

    /**
     * Returns the width of this tile.
     */
    public function getWidth () :int
    {
        return _image.width;
    }

    /**
     * Returns the height of this tile.
     */
    public function getHeight () :int
    {
        return _image.height;
    }

    /**
     * Returns true if the specified coordinates within this tile contains
     * a non-transparent pixel.
     */
    public function hitTest (x :int, y :int) :Boolean
    {
        return _image.hitTestPoint(x, y, true);
    }

    public function toString () :String
    {
        return "[" + toStringBuf(new String()) + "]";
    }

    /**
     * This should be overridden by derived classes (which should be sure
     * to call super.toString()) to append the derived class
     * specific tile information to the string buffer.
     */
    protected function toStringBuf (buf :String) :String
    {
        if (_image == null) {
            return buf.concat("null-image");
        } else {
            return buf.concat(_image.width, "x", _image.height);
        }
    }

    public function notifyOnLoad (func :Function) :void
    {
        if (_image != null) {
            func(this);
        } else {
            _notifyOnLoad.push(func);
        }
    }

    /**
     * Returns the x offset into the tile image of the origin (which will be aligned with the
     * bottom center of the origin tile) or Integer.MIN_VALUE if the origin is not
     * explicitly specified and should be computed from the image size and tile footprint.
     */
    public function getOriginX () :int
    {
        throw new Error("abstract");
    }

    /**
     * Returns the y offset into the tile image of the origin (which will be aligned with the
     * bottom center of the origin tile) or Integer.MIN_VALUE if the origin is not
     * explicitly specified and should be computed from the image size and tile footprint.
     */
    public function getOriginY () :int
    {
        throw new Error("abstract")
    }

    /**
     * Returns the object footprint width in tile units.
     */
    public function getBaseWidth () :int
    {
        throw new Error("abstract");
    }

    /**
     * Returns the object footprint height in tile units.
     */
    public function getBaseHeight () :int
    {
        throw new Error("abstract");
    }

    /** Our tileset image. */
    protected var _image :DisplayObject;

    /** Everyone who cares when we're loaded. */
    protected var _notifyOnLoad :Array = [];
}
}

Make tiles work like tilesets - if you ask to be notified and it's already loaded, notify immediately.

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


/*
 * Copyright 2008 Adobe Systems Inc., 2008 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Contributor(s):
 *   Zwetan Kjukov <zwetan@gmail.com>.
 *   Marc Alcaraz <ekameleon@gmail.com>.
 */

package com.google.analytics.campaign
{
    import com.google.analytics.utils.Variables;

    /**
     * Campaign tracker object.
     * Contains all the data associated with a campaign.
     *
     * AdWords:
     * The following variables
     * name, source, medium, term, content
     * are automatically generated for AdWords hits when autotagging
     * is turned on through the AdWords interface.
     *
     *
     * note:
     * we can not use a CampaignInfo because here the serialization
     * to URL have to be injected into __utmz and is then a special case.
     *
     * links:
     *
     * Understanding campaign variables: The five dimensions of campaign tracking
     * http://www.google.com/support/googleanalytics/bin/answer.py?answer=55579&hl=en
     *
     * How does campaign tracking work?
     * http://www.google.com/support/googleanalytics/bin/answer.py?hl=en&answer=55540
     *
     * What is A/B Testing and how can it help me?
     * http://www.google.com/support/googleanalytics/bin/answer.py?answer=55589
     *
     * What information do the filter fields represent?
     * http://www.google.com/support/googleanalytics/bin/answer.py?hl=en&answer=55588
     */
    public class CampaignTracker
    {

        /**
         * @private
         */
        private function _addIfNotEmpty( arr:Array, field:String, value:String ):void
        {
            if( value != "" )
            {
                value = value.split( "+" ).join( "%20" );
                value = value.split( " " ).join( "%20" );
                arr.push( field + value );
            }
        }

        /**
         * The campaign code or id can be used to refer to a campaign lookup table,
         * or chart of referring codes used to define variables in place of multiple request query tags.
         * variable: utmcid
         */
        public var id:String;

        /**
         * The resource that provided the click.
         * Every referral to a web site has an origin, or source.
         * Examples of sources are the Google search engine,
         * the AOL search engine, the name of a newsletter,
         * or the name of a referring web site.
         * Other example: "AdWords".
         *
         * variable: utmcsr
         */
        public var source:String; //required

        /**
        * google ad click id
        *
        * variable: utmgclid
        */
        public var clickId:String;

        /**
        * Usually refers to name given to the marketing campaign or is used to differentiate campaign source.
        * The campaign name differentiates product promotions such as "Spring Ski Sale"
        * or slogan campaigns such as "Get Fit For Summer".
        *
        * alternative:
        * Used for keyword analysis to identify a specific product promotion or strategic campaign.
        *
        * variable: utmccn
        */
        public var name:String; //required

        /**
        * Method of Delivery.
        * The medium helps to qualify the source;
        * together, the source and medium provide specific information
        * about the origin of a referral.
        * For example, in the case of a Google search engine source,
        * the medium might be "cost-per-click", indicating a sponsored link for which the advertiser paid,
        * or "organic", indicating a link in the unpaid search engine results.
        * In the case of a newsletter source, examples of medium include "email" and "print".
        * Other examples: "Organic", "CPC", or "PPC".
        *
        * variable: utmcmd
        */
        public var medium:String; //required

        /**
         * The term or keyword is the word or phrase that a user types into a search engine.
         * Used for paid search.
         * variable: utmctr
         */
        public var term:String;

        /**
         * The content dimension describes the version of an advertisement on which a visitor clicked.
         *
It is used in content-targeted advertising and Content (A/B) Testing to determine which version of an advertisement is most effective at attracting profitable leads.

         *
Alternative: Used for A/B testing and content-targeted ads to differentiate ads or links that point to the same URL.

         *
variable: utmcct

         */
        public var content:String;

        /**
         * Creates a new CampaingTracker instance.
         */
        public function CampaignTracker( id:String = "", source:String = "", clickId:String = "",
                                         name:String = "", medium:String = "", term:String = "", content:String = "" )
        {
            this.id      = id;
            this.source  = source;
            this.clickId = clickId;
            this.name    = name;
            this.medium  = medium;
            this.term    = term;
            this.content = content;
        }

        /**
         * Returns a flag indicating whether this tracker object is valid.
         * A tracker object is considered to be valid if and only if one of id, source or clickId is present.
         */
        public function isValid():Boolean
        {
            if( (id != "") ||
                (source != "") ||
                (clickId != "") )
                {
                    return true;
                }

            return false;
        }

        /**
         * Builds the tracker object from a tracker string.
         *
         * @private
         * @param {String} trackerString Tracker string to parse tracker object from.
         */
        public function fromTrackerString( tracker:String ):void
        {
            /* note:
               we are basically deserializing the utmz.campaignTracking property
            */
            var data:String = tracker.split( CampaignManager.trackingDelimiter ).join( "&" );
            var vars:Variables = new Variables( data );

            if( vars.hasOwnProperty( "utmcid" ) )
            {
                this.id = vars["utmcid"];
            }

            if( vars.hasOwnProperty( "utmcsr" ) )
            {
                this.source = vars["utmcsr"];
            }

            if( vars.hasOwnProperty( "utmccn" ) )
            {
                this.name = vars["utmccn"];
            }

            if( vars.hasOwnProperty( "utmcmd" ) )
            {
                this.medium = vars["utmcmd"];
            }

            if( vars.hasOwnProperty( "utmctr" ) )
            {
                this.term = vars["utmctr"];
            }

            if( vars.hasOwnProperty( "utmcct" ) )
            {
                this.content = vars["utmcct"];
            }

            if( vars.hasOwnProperty( "utmgclid" ) )
            {
                this.clickId = vars["utmgclid"];
            }

        }

        /**
         * Format for tracker have the following fields (seperated by "|"):
         *

         *
utmcid - lookup table id

         *
utmcsr - campaign source

         *
utmgclid - google ad click id

         *
utmccn - campaign name

         *
utmcmd - campaign medium

         *
utmctr - keywords

         *
utmcct - ad content description

         *
         *
         *

         * should be in this order : utmcid=one|utmcsr=two|utmgclid=three|utmccn=four|utmcmd=five|utmctr=six|utmcct=seven
         *
         */
        public function toTrackerString():String
        {
            var data:Array = [];

                /* for each value, append key=value if and only if
                   the value is not empty.
                */
                _addIfNotEmpty( data, "utmcid=",   id );
                _addIfNotEmpty( data, "utmcsr=",   source );
                _addIfNotEmpty( data, "utmgclid=", clickId );
                _addIfNotEmpty( data, "utmccn=",   name );
                _addIfNotEmpty( data, "utmcmd=",   medium );
                _addIfNotEmpty( data, "utmctr=",   term );
                _addIfNotEmpty( data, "utmcct=",   content );

            return data.join( CampaignManager.trackingDelimiter );
        }

    }
}

/*
 * Copyright 2008 Adobe Systems Inc., 2008 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Contributor(s):
 *   Zwetan Kjukov <zwetan@gmail.com>.
 *   Marc Alcaraz <ekameleon@gmail.com>.
 */

package com.google.analytics.campaign
{
    import com.google.analytics.utils.Variables;

    /* Campaign tracker object.
       Contains all the data associated with a campaign.

       AdWords:
       The following variables
       name, source, medium, term, content
       are automatically generated for AdWords hits when autotagging
       is turned on through the AdWords interface.

       note:
       we can not use a CampaignInfo because here the serialization
       to URL have to be injected into __utmz and is then a special case.

       links:

       Understanding campaign variables: The five dimensions of campaign tracking
       http://www.google.com/support/googleanalytics/bin/answer.py?answer=55579&hl=en

       How does campaign tracking work?
       http://www.google.com/support/googleanalytics/bin/answer.py?hl=en&answer=55540

       What is A/B Testing and how can it help me?
       http://www.google.com/support/googleanalytics/bin/answer.py?answer=55589

       What information do the filter fields represent?
       http://www.google.com/support/googleanalytics/bin/answer.py?hl=en&answer=55588
     */
    public class CampaignTracker
    {

        /**
         * @private
         */
        private function _addIfNotEmpty( arr:Array, field:String, value:String ):void
        {
            if( value != "" )
            {
                value = value.split( "+" ).join( "%20" );
                value = value.split( " " ).join( "%20" );
                arr.push( field + value );
            }
        }

        /**
         * The campaign code or id can be used to refer to a campaign lookup table,
         * or chart of referring codes used to define variables in place of multiple request query tags.
         * variable: utmcid
         */
        public var id:String;

        /**
         * The resource that provided the click.
         * Every referral to a web site has an origin, or source.
         * Examples of sources are the Google search engine,
         * the AOL search engine, the name of a newsletter,
         * or the name of a referring web site.
         * Other example: "AdWords".
         *
         * variable: utmcsr
         */
        public var source:String; //required

        /**
        * google ad click id
        *
        * variable: utmgclid
        */
        public var clickId:String;

        /**
        * Usually refers to name given to the marketing campaign or is used to differentiate campaign source.
        * The campaign name differentiates product promotions such as "Spring Ski Sale"
        * or slogan campaigns such as "Get Fit For Summer".
        *
        * alternative:
        * Used for keyword analysis to identify a specific product promotion or strategic campaign.
        *
        * variable: utmccn
        */
        public var name:String; //required

        /**
        * Method of Delivery.
        * The medium helps to qualify the source;
        * together, the source and medium provide specific information
        * about the origin of a referral.
        * For example, in the case of a Google search engine source,
        * the medium might be "cost-per-click", indicating a sponsored link for which the advertiser paid,
        * or "organic", indicating a link in the unpaid search engine results.
        * In the case of a newsletter source, examples of medium include "email" and "print".
        * Other examples: "Organic", "CPC", or "PPC".
        *
        * variable: utmcmd
        */
        public var medium:String; //required

        /**
         * The term or keyword is the word or phrase that a user types into a search engine.
         * Used for paid search.
         * variable: utmctr
         */
        public var term:String;

        /**
         * The content dimension describes the version of an advertisement on which a visitor clicked.
         *
It is used in content-targeted advertising and Content (A/B) Testing to determine which version of an advertisement is most effective at attracting profitable leads.

         *
Alternative: Used for A/B testing and content-targeted ads to differentiate ads or links that point to the same URL.

         *
variable: utmcct

         */
        public var content:String;

        /**
         * Creates a new CampaingTracker instance.
         */
        public function CampaignTracker( id:String = "", source:String = "", clickId:String = "",
                                         name:String = "", medium:String = "", term:String = "", content:String = "" )
        {
            this.id      = id;
            this.source  = source;
            this.clickId = clickId;
            this.name    = name;
            this.medium  = medium;
            this.term    = term;
            this.content = content;
        }

        /**
         * Returns a flag indicating whether this tracker object is valid.
         * A tracker object is considered to be valid if and only if one of id, source or clickId is present.
         */
        public function isValid():Boolean
        {
            if( (id != "") ||
                (source != "") ||
                (clickId != "") )
                {
                    return true;
                }

            return false;
        }

        /**
         * Builds the tracker object from a tracker string.
         *
         * @private
         * @param {String} trackerString Tracker string to parse tracker object from.
         */
        public function fromTrackerString( tracker:String ):void
        {
            /* note:
               we are basically deserializing the utmz.campaignTracking property
            */
            var data:String = tracker.split( CampaignManager.trackingDelimiter ).join( "&" );
            var vars:Variables = new Variables( data );

            if( vars.hasOwnProperty( "utmcid" ) )
            {
                this.id = vars["utmcid"];
            }

            if( vars.hasOwnProperty( "utmcsr" ) )
            {
                this.source = vars["utmcsr"];
            }

            if( vars.hasOwnProperty( "utmccn" ) )
            {
                this.name = vars["utmccn"];
            }

            if( vars.hasOwnProperty( "utmcmd" ) )
            {
                this.medium = vars["utmcmd"];
            }

            if( vars.hasOwnProperty( "utmctr" ) )
            {
                this.term = vars["utmctr"];
            }

            if( vars.hasOwnProperty( "utmcct" ) )
            {
                this.content = vars["utmcct"];
            }

            if( vars.hasOwnProperty( "utmgclid" ) )
            {
                this.clickId = vars["utmgclid"];
            }

        }

        /**
         * Format for tracker have the following fields (seperated by "|"):
         *

         *
utmcid - lookup table id

         *
utmcsr - campaign source

         *
utmgclid - google ad click id

         *
utmccn - campaign name

         *
utmcmd - campaign medium

         *
utmctr - keywords

         *
utmcct - ad content description

         *
         *
         *

         * should be in this order : utmcid=one|utmcsr=two|utmgclid=three|utmccn=four|utmcmd=five|utmctr=six|utmcct=seven
         *
         */
        public function toTrackerString():String
        {
            var data:Array = [];

                /* for each value, append key=value if and only if
                   the value is not empty.
                */
                _addIfNotEmpty( data, "utmcid=",   id );
                _addIfNotEmpty( data, "utmcsr=",   source );
                _addIfNotEmpty( data, "utmgclid=", clickId );
                _addIfNotEmpty( data, "utmccn=",   name );
                _addIfNotEmpty( data, "utmcmd=",   medium );
                _addIfNotEmpty( data, "utmctr=",   term );
                _addIfNotEmpty( data, "utmcct=",   content );

            return data.join( CampaignManager.trackingDelimiter );
        }

    }
}

update comment for asdoc

update comment for asdoc


package dolly {

import dolly.core.dolly_internal;
import dolly.core.errors.CloningError;
import dolly.core.metadata.MetadataName;

import org.as3commons.reflect.Accessor;
import org.as3commons.reflect.AccessorAccess;
import org.as3commons.reflect.Field;
import org.as3commons.reflect.Type;

use namespace dolly_internal;

public class Cloner {

	private static function isTypeCloneable(type:Type):Boolean {
		return type.hasMetadata(MetadataName.CLONEABLE);
	}

	dolly_internal static function findAllWritableFieldsForType(type:Type):Vector.<Field> {
		if (!isTypeCloneable(type)) {
			throw new CloningError(
					CloningError.CLASS_IS_NOT_CLONEABLE_MESSAGE,
					CloningError.CLASS_IS_NOT_CLONEABLE_CODE
			);
		}

		const result:Vector.<Field> = new Vector.<Field>();

		for each(var field:Field in type.properties) {
			if (!(field is Accessor) || (field as Accessor).access == AccessorAccess.READ_WRITE) {
				result.push(field);
			}
		}

		return result;
	}

	public static function clone(source:*):* {
		const type:Type = Type.forInstance(source);

		if (!isTypeCloneable(type)) {
			throw new CloningError(
					CloningError.CLASS_IS_NOT_CLONEABLE_MESSAGE,
					CloningError.CLASS_IS_NOT_CLONEABLE_CODE
			);
		}

		const clonedInstance:* = new (type.clazz)();

		// Find all public writable fields in a hierarchy of a source object
		// and assign their values to a clone object.
		const fieldsToClone:Vector.<Field> = findAllWritableFieldsForType(type);
		var name:String;
		for each(var field:Field in fieldsToClone) {
			name = field.name;
			clonedInstance[name] = source[name];
		}

		return clonedInstance;
	}
}
}

package dolly {

import dolly.core.dolly_internal;
import dolly.core.errors.CloningError;
import dolly.core.metadata.MetadataName;

import org.as3commons.reflect.Accessor;
import org.as3commons.reflect.AccessorAccess;
import org.as3commons.reflect.Field;
import org.as3commons.reflect.Type;

use namespace dolly_internal;

public class Cloner {

	private static function isTypeCloneable(type:Type):Boolean {
		return type.hasMetadata(MetadataName.CLONEABLE);
	}

	dolly_internal static function findAllWritableFieldsForType(type:Type):Vector.<Field> {
		if (!isTypeCloneable(type)) {
			throw new CloningError(
					CloningError.CLASS_IS_NOT_CLONEABLE_MESSAGE,
					CloningError.CLASS_IS_NOT_CLONEABLE_CODE
			);
		}

		const result:Vector.<Field> = new Vector.<Field>();

		for each(var field:Field in type.properties) {
			if (!(field is Accessor) || (field as Accessor).access == AccessorAccess.READ_WRITE) {
				result.push(field);
			}
		}

		return result;
	}

	public static function clone(source:*):* {
		const type:Type = Type.forInstance(source);

		// Find all public writable fields in a hierarchy of a source object
		// and assign their values to a clone object.
		const fieldsToClone:Vector.<Field> = findAllWritableFieldsForType(type);
		const clonedInstance:* = new (type.clazz)();

		var name:String;
		for each(var field:Field in fieldsToClone) {
			name = field.name;
			clonedInstance[name] = source[name];
		}

		return clonedInstance;
	}
}
}

Check for class marking as cloneable only once in method Cloner.findAllWritableFieldsForType().


/*
# Copyright (c) 2008-2010 rPath, Inc.
#
# This program is distributed under the terms of the MIT License as found
# in a file called LICENSE. If it is not present, the license
# is always available at http://www.opensource.org/licenses/mit-license.php.
#
# This program is distributed in the hope that it will be useful, but
# without any warranty; without even the implied warranty of merchantability
# or fitness for a particular purpose. See the MIT License for full details.
#
*/

package com.rpath.xobj
{
import mx.utils.URLUtil;

/** URL provides more "intelligent" String instances that
 * wrap up some of the functionality of the URLUtil helper
 * as well as make URL's more typesafe in general usage
 */

public class URL
{

    public function URL(v:*="", useHTTPS:Boolean=false)
    {
        super();

        this.useHTTPS = useHTTPS;
        if (v is URL)
        {
            this.value = (v as URL).value;
        }
        else
        {
            this.value = v;
        }
    }

    public var useHTTPS:Boolean;

    public function get value():String
    {
        return _value;
    }

    private var _value:String;

    public function set value(value:String):void
    {
        _value = value;
        if (_value && useHTTPS && !isHTTPS)
        {
            // make the URL HTTPS
            if (_value.indexOf("http://") == 0)
            {
                _value = _value.replace("http://", "https://");
            }
        }
    }
    public function get isHTTPS():Boolean
    {
        return URLUtil.isHttpsURL(value);
    }

    public function get isHTTP():Boolean
    {
        return URLUtil.isHttpURL(value);
    }

    public function hasQuery():Boolean
    {
        return value.indexOf("?") != -1;
    }

    public function toString():String
    {
        return value;
    }

}
}

/*
# Copyright (c) 2008-2010 rPath, Inc.
#
# This program is distributed under the terms of the MIT License as found
# in a file called LICENSE. If it is not present, the license
# is always available at http://www.opensource.org/licenses/mit-license.php.
#
# This program is distributed in the hope that it will be useful, but
# without any warranty; without even the implied warranty of merchantability
# or fitness for a particular purpose. See the MIT License for full details.
#
*/

package com.rpath.xobj
{
import mx.utils.URLUtil;

/** URL provides more "intelligent" String instances that
 * wrap up some of the functionality of the URLUtil helper
 * as well as make URL's more typesafe in general usage
 */

public class URL
{

    public function URL(v:*="", useHTTPS:Boolean=false)
    {
        super();

        this.useHTTPS = useHTTPS;
        if (v is URL)
        {
            this.value = (v as URL).value;
        }
        else
        {
            this.value = v;
        }
    }

    public var useHTTPS:Boolean;

    public function get value():String
    {
        return _value;
    }

    private var _value:String;

    public function set value(value:String):void
    {
        _value = value;
        if (_value && useHTTPS && !isHTTPS)
        {
            // make the URL HTTPS
            if (_value.indexOf("http://") == 0)
            {
                _value = _value.replace("http://", "https://");
            }
        }
    }
    public function get isHTTPS():Boolean
    {
        return URLUtil.isHttpsURL(value);
    }

    public function get isHTTP():Boolean
    {
        return URLUtil.isHttpURL(value);
    }

    public function hasQuery():Boolean
    {
        return value.indexOf("?") != -1;
    }

    public function toString():String
    {
        return value;
    }

    public function set url(s:String):void
    {
        value = s;
    }

    public function get url():String
    {
        return value;
    }
}
}

Allow URL.url for lazy modelling

Allow URL.url for lazy modelling


package {
  var last = new Date();

  function clockUnder(max, name) {
    var elapsed = new Date() - last;
    // Keep this disabled when committing this file.
    var elapsedSuffix = false ? " (" + elapsed + ")" : "";
    var nameSuffix = name ? ": " + name : "";
    if (elapsed > max) {
      trace("FAIL: > " + max + " ms" + elapsedSuffix + nameSuffix);
    } else {
      trace("PASS: < " + max + " ms" + elapsedSuffix + nameSuffix);
    }
    last = new Date();
  }

  var K = 1024;

  var JS_FAST = 200;
  var AS_FAST = JS_FAST * 5;
  var VERY_SLOW = 5000;

  (function () {
    var s = 0;
    var COUNT = 1 * K * K;
    for (var i = 0; i < COUNT; i++) {
      s = s + i;
      s = s + i;
      s = s + i;
      s = s + i;
      s = s + i;
      s = s + i;
      s = s + i;
      s = s + i;
      s = s + i;
      s = s + i;
      s = s + i;
      s = s + i;
      s = s + i;
    }
    trace(s);
  })();

  clockUnder(AS_FAST, "Adding Numbers");

  (function () {
    var s = "";
    var COUNT = 1 * K * K;
    for (var i = 0; i < COUNT; i++) {
      s = s + i;
    }
    trace(s.length);
  })();

  clockUnder(AS_FAST, "Adding Strings + Numbers");

  (function () {
    var s = 0;
    var COUNT = 1 * K;
    for (var i = 0; i < COUNT; i++) {
      var a = [];
      for (var j = 0; j < K; j++) {
        a.AS3::push(i);
      }
      s += a.length;
    }
    trace(s);
  })();

  clockUnder(AS_FAST, "Arrays AS3 Namespace Push");

  (function () {
    var s = 0;
    var COUNT = 1 * K;
    for (var i = 0; i < COUNT; i++) {
      var a = [];
      for (var j = 0; j < K; j++) {
        a.push(i);
      }
      s += a.length;
    }
    trace(s);
  })();

  clockUnder(AS_FAST, "Arrays AS3 Prototype Push");

  class C {
    function foo() {
      return 2;
    }
  }

  (function () {
    var s = 0;
    var COUNT = 1 * K * K;
    var c = new C();
    for (var i = 0; i < COUNT; i++) {
      s += c.foo();
    }
    trace(s);
  })();

  clockUnder(AS_FAST, "Class Method Call");

  (function () {
    var s = 0;
    var COUNT = 1 * K * K;
    var v : Vector.<C> = new Vector.<C>();
    v.push(new C());
    for (var i = 0; i < COUNT; i++) {
      s += v[0].foo();
    }
    trace(s);
  })();

  clockUnder(AS_FAST, "Class Method Call - Vector");

  (function () {
    var s = 0;
    var COUNT = 1 * K * K;
    var v : Vector.<C> = new Vector.<C>();
    var o = new C();
    for (var i = 0; i < COUNT; i++) {
      v[0] = o;
    }
  })();

  clockUnder(AS_FAST, "Set Vector");

  class A {
    static const staticConstant = 123;
    const instanceConstant = 234;

    static var staticVar = 345;
    var instanceVar = 456;

    static function staticFunction() {
      var s = 0;
      for (var i = 0; i < 10000000; i++) {
        s += staticConstant;
        s += staticVar;
      }
      clockUnder(5000, "Access Static Constant / Var");
      return s;
    }

    function instanceFunction() {
      var s = 0;
      for (var i = 0; i < 10000000; i++) {
        s += instanceConstant;
        s += instanceVar;
      }
      clockUnder(5000, "Access Instance Constant / Var");
      return s;
    }
  }

  class B extends A {
    static function staticFunctionB() {
      var s = 0;
      for (var i = 0; i < 10000000; i++) {
        s += staticConstant;
        s += staticVar;
      }
      clockUnder(5000, "Access Static Constant / Var");
      return s;
    }
    function instanceFunctionB() {
      var s = 0;
      for (var i = 0; i < 10000000; i++) {
        s += instanceConstant;
        s += instanceVar;
      }
      clockUnder(5000, "Access Instance Constant / Var");
      return s;
    }
  }

  A.staticFunction();
  (new A()).instanceFunction();

  B.staticFunctionB();
  (new B()).instanceFunctionB();

  (function () {
    var s = 0;
    for (var i = 0; i < 5000000; i++) {
      s += -Number.MAX_VALUE;
      s += Number.MAX_VALUE;
      s += Math.abs(i);
    }
    clockUnder(5000, "Math.abs()");
    return s;
  })();

  class D {
    var foobar = 0;
    var y = 0;
    function D(x, y) {
      this.foobar = x;
      this.y = y;
    }
  }

  (function () {
    var s = 0;
    for (var i = 0; i < 1000000; i++) {
      s += (new D(2, 3)).foobar;
      s += (new D(2, 3)).y;
    }
    clockUnder(500, "Object allocation with property access");
    return s;
  })();

}

package {
  var last = new Date();

  function clockUnder(max, name) {
    var elapsed = new Date() - last;
    // Keep this disabled when committing this file.
    var elapsedSuffix = true ? " (" + elapsed + ")" : "";
    var nameSuffix = name ? ": " + name : "";
    if (elapsed > max) {
      trace("FAIL: > " + max + " ms" + elapsedSuffix + nameSuffix);
    } else {
      trace("PASS: < " + max + " ms" + elapsedSuffix + nameSuffix);
    }
    last = new Date();
  }

  var K = 1024;

  var JS_FAST = 200;
  var AS_FAST = JS_FAST * 5;
  var VERY_SLOW = 5000;

  (function () {
    var s = 0;
    var COUNT = 1 * K * K;
    for (var i = 0; i < COUNT; i++) {
      s = s + i;
      s = s + i;
      s = s + i;
      s = s + i;
      s = s + i;
      s = s + i;
      s = s + i;
      s = s + i;
      s = s + i;
      s = s + i;
      s = s + i;
      s = s + i;
      s = s + i;
    }
    trace(s);
  })();

  clockUnder(AS_FAST, "Adding Numbers");

  (function () {
    var s = "";
    var COUNT = 1 * K * K;
    for (var i = 0; i < COUNT; i++) {
      s = s + i;
    }
    trace(s.length);
  })();

  clockUnder(AS_FAST, "Adding Strings + Numbers");

  (function () {
    var s = 0;
    var COUNT = 1 * K;
    for (var i = 0; i < COUNT; i++) {
      var a = [];
      for (var j = 0; j < K; j++) {
        a.AS3::push(i);
      }
      s += a.length;
    }
    trace(s);
  })();

  clockUnder(AS_FAST, "Arrays AS3 Namespace Push");

  (function () {
    var s = 0;
    var COUNT = 1 * K;
    for (var i = 0; i < COUNT; i++) {
      var a = [];
      for (var j = 0; j < K; j++) {
        a.push(i);
      }
      s += a.length;
    }
    trace(s);
  })();

  clockUnder(AS_FAST, "Arrays AS3 Prototype Push");

  class C {
    function foo() {
      return 2;
    }
  }

  (function () {
    var s = 0;
    var COUNT = 1 * K * K;
    var c = new C();
    for (var i = 0; i < COUNT; i++) {
      s += c.foo();
    }
    trace(s);
  })();

  clockUnder(AS_FAST, "Class Method Call");

  (function () {
    var s = 0;
    var COUNT = 1 * K * K;
    var v : Vector.<C> = new Vector.<C>();
    v.push(new C());
    for (var i = 0; i < COUNT; i++) {
      s += v[0].foo();
    }
    trace(s);
  })();

  clockUnder(AS_FAST, "Class Method Call - Vector");

  (function () {
    var s = 0;
    var COUNT = 1 * K * K;
    var v : Vector.<C> = new Vector.<C>();
    var o = new C();
    for (var i = 0; i < COUNT; i++) {
      v[0] = o;
    }
  })();

  clockUnder(AS_FAST, "Set Vector");

  class A {
    static const staticConstant = 123;
    const instanceConstant = 234;

    static var staticVar = 345;
    var instanceVar = 456;

    static function staticFunction() {
      var s = 0;
      for (var i = 0; i < 10000000; i++) {
        s += staticConstant;
        s += staticVar;
      }
      clockUnder(5000, "Access Static Constant / Var");
      return s;
    }

    function instanceFunction() {
      var s = 0;
      for (var i = 0; i < 10000000; i++) {
        s += instanceConstant;
        s += instanceVar;
      }
      clockUnder(5000, "Access Instance Constant / Var");
      return s;
    }
  }

  class B extends A {
    static function staticFunctionB() {
      var s = 0;
      for (var i = 0; i < 10000000; i++) {
        s += staticConstant;
        s += staticVar;
      }
      clockUnder(5000, "Access Static Constant / Var");
      return s;
    }
    function instanceFunctionB() {
      var s = 0;
      for (var i = 0; i < 10000000; i++) {
        s += instanceConstant;
        s += instanceVar;
      }
      clockUnder(5000, "Access Instance Constant / Var");
      return s;
    }
  }

  A.staticFunction();
  (new A()).instanceFunction();

  B.staticFunctionB();
  (new B()).instanceFunctionB();

  (function () {
    var s = 0;
    for (var i = 0; i < 4000000; i++) {
      s += -Number.MAX_VALUE;
      s += Number.MAX_VALUE;
      s += Math.abs(i);
    }
    clockUnder(5000, "Math.abs()");
    return s;
  })();

  class D {
    var foobar = 0;
    var y = 0;
    function D(x, y) {
      this.foobar = x;
      this.y = y;
    }
  }

  (function () {
    var s = 0;
    for (var i = 0; i < 1000000; i++) {
      s += (new D(2, 3)).foobar;
      s += (new D(2, 3)).y;
    }
    clockUnder(500, "Object allocation with property access");
    return s;
  })();

}

Tweak perf timings

Tweak perf timings


/*
 * Copyright 2017 FreshPlanet
 * 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.freshplanet.ane.AirCapabilities {

import com.freshplanet.ane.AirCapabilities.events.AirCapabilitiesLowMemoryEvent;
import com.freshplanet.ane.AirCapabilities.events.AirCapabilitiesOpenURLEvent;
	import flash.display.BitmapData;
	import flash.events.EventDispatcher;
	import flash.events.StatusEvent;
	import flash.external.ExtensionContext;
	import flash.system.Capabilities;

	public class AirCapabilities extends EventDispatcher {

		// --------------------------------------------------------------------------------------//
		//																						 //
		// 									   PUBLIC API										 //
		// 																						 //
		// --------------------------------------------------------------------------------------//

		/**
		 * Is the ANE supported on the current platform
		 */
        static public function get isSupported():Boolean {
            return (Capabilities.manufacturer.indexOf("iOS") > -1 && Capabilities.os.indexOf("x86_64") < 0 && Capabilities.os.indexOf("i386") < 0) || Capabilities.manufacturer.indexOf("Android") > -1;
        }

		/**
		 * If true, logs will be displayed at the ActionScript and native level.
		 */
		public function setLogging(value:Boolean):void {

			_doLogging = value;
			if (isSupported)
				_extContext.call("setLogging", value);
		}

		public function get nativeLogger():ILogger {
            return _logger;
        }

        /**
         * AirCapabilities instance
         */
        static public function get instance():AirCapabilities {
			return _instance != null ? _instance : new AirCapabilities()
		}

        /**
         * Is SMS available
         * @return
         */
		public function hasSmsEnabled():Boolean {

			if (isSupported)
				return _extContext.call("hasSMS");

			return false;
		}

        /**
         * Is Twitter available
         * @return
         */
		public function hasTwitterEnabled():Boolean {

			if (isSupported)
				return _extContext.call("hasTwitter");

			return false;
		}

        /**
         * Sends an SMS message
         * @param message to send
         * @param recipient phonenumber
         */
		public function sendMsgWithSms(message:String, recipient:String = null):void {

			if (isSupported)
				_extContext.call("sendWithSms", message, recipient);
		}

        /**
         * Sends a Twitter message
         * @param message
         */
		public function sendMsgWithTwitter(message:String):void {

			if (isSupported)
				_extContext.call("sendWithTwitter", message);
		}

        /**
         * Redirect user to Rating page
         * @param appId
         * @param appName
         */
		public function redirecToRating(appId:String, appName:String):void {

			if (isSupported)
				_extContext.call("redirectToRating", appId, appName);
		}

        /**
         * Model of the device
         * @return
         */
		public function getDeviceModel():String {

			if (isSupported)
				return _extContext.call("getDeviceModel") as String;

            return "";
		}

        /**
         * Name of the machine
         * @return
         */
		public function getMachineName():String {

			if (isSupported)
				return _extContext.call("getMachineName") as String;

            return "";
		}

        /**
         * Opens the referral link URL
         * @param url
         */
		public function processReferralLink(url:String):void {

			if (isSupported)
				_extContext.call("processReferralLink", url);
		}

        /**
         * Opens Facebook page
         * @param pageId id of the facebook page
         */
		public function redirectToPageId(pageId:String):void {

			if (isSupported)
				_extContext.call("redirectToPageId", pageId);
		}

        /**
         * Opens Twitter account
         * @param twitterAccount
         */
		public function redirectToTwitterAccount(twitterAccount:String):void {

			if (isSupported)
				_extContext.call("redirectToTwitterAccount", twitterAccount);
		}

        /**
         * Is posting pictures on Twitter enabled
         * @return
         */
		public function canPostPictureOnTwitter():Boolean {

			if (isSupported)
				return _extContext.call("canPostPictureOnTwitter");

			return false;
		}

        /**
         * Post new picture on Twitter
         * @param message
         * @param bitmapData
         */
		public function postPictureOnTwitter(message:String, bitmapData:BitmapData):void {

			if (isSupported)
				_extContext.call("postPictureOnTwitter", message, bitmapData);
		}

        /**
         * Is Instagram enabled
         * @return
         */
		public function hasInstagramEnabled():Boolean {

			if (isSupported)
				return _extContext.call("hasInstagramEnabled");

			return false;
		}

        /**
         * Post new picture on Instagram
         * @param message
         * @param bitmapData
         * @param x
         * @param y
         * @param width
         * @param height
         */
		public function postPictureOnInstagram(message:String, bitmapData:BitmapData,
                                               x:int, y:int, width:int, height:int):void {

			if (isSupported)
				_extContext.call("postPictureOnInstagram", message, bitmapData, x, y, width, height);
		}

		/**
		 * Open an application (if installed on the Device) or send the player to the appstore.  iOS Only
		 * @param schemes 		List of schemes (String) that the application accepts.  Examples : @"sms://", @"twit://".  You can find schemes in http://handleopenurl.com/
		 * @param appStoreURL 	(optional) Link to the AppStore page for the Application for the player to download. URL can be generated via Apple's linkmaker (itunes.apple.com/linkmaker?)
		 */
		public function openExternalApplication(schemes:Array, appStoreURL:String = null):void {

			if (isSupported && Capabilities.manufacturer.indexOf("Android") == -1)
				_extContext.call("openExternalApplication", schemes, appStoreURL);
		}

        /**
         * Is opening URLs available
         * @param url
         * @return
         */
		public function canOpenURL(url:String):Boolean {
			return isSupported ? _extContext.call("canOpenURL", url) as Boolean : false;
		}

        /**
         * Open URL
         * @param url
         */
		public function openURL(url:String):void {

			if (canOpenURL(url))
				_extContext.call("openURL", url);
		}

		/**
		 * Opens modal app store. Available on iOS only
		 * @param appStoreId	id of the app to open a modal view to (do not include the "id" at the beginning of the number)
		 */
		public function openModalAppStoreIOS(appStoreId:String):void {

			if (Capabilities.manufacturer.indexOf("iOS") > -1)
				_extContext.call("openModalAppStore", appStoreId);
		}

        /**
         * Version of the operating system
         * @return
         */
        public function getOSVersion():String {

            if (isSupported)
                return _extContext.call("getOSVersion") as String;

            return "";
        }

        /**
         * @return  current amount of RAM being used in bytes
         */
        public function getCurrentMem():Number {

			if (!isSupported)
				return -1;

            var ret:Object = _extContext.call("getCurrentMem");
            if (ret is Error)
                throw ret;
            else
                return ret ? ret as Number : 0;
        }

        /**
         * @return  amount of RAM used by the VM
         */
        public function getCurrentVirtualMem():Number {

            if (Capabilities.manufacturer.indexOf("iOS") == -1)
                return -1;

            var ret:Object = _extContext.call("getCurrentVirtualMem");
            if (ret is Error)
                throw ret;
            else
                return ret ? ret as Number : 0;
        }

		/**
		 * @return  is requesting review available. Available on iOS only
		 */
		public function canRequestReview():Boolean {

			if (!isSupported)
				return false;

			if (Capabilities.manufacturer.indexOf("iOS") == -1)
				return false;

			return _extContext.call("canRequestReview");
		}

		/**
		 * Request AppStore review. Available on iOS only
		 */
		public function requestReview():void {

			if (!canRequestReview())
				return;

			_extContext.call("requestReview");
		}

		// --------------------------------------------------------------------------------------//
		//																						 //
		// 									 	PRIVATE API										 //
		// 																						 //
		// --------------------------------------------------------------------------------------//

		static private const EXTENSION_ID:String = "com.freshplanet.ane.AirCapabilities";

		static private var _instance:AirCapabilities = null;

		private var _extContext:ExtensionContext = null;
		private var _doLogging:Boolean = false;
		private var _logger:ILogger;

		/**
		 * "private" singleton constructor
		 */
		public function AirCapabilities() {

			super();

			if (_instance)
				throw new Error("singleton class, use .instance");

			_extContext = ExtensionContext.createExtensionContext(EXTENSION_ID, null);
			_extContext.addEventListener(StatusEvent.STATUS, _handleStatusEvent);

			if (isSupported)
				_logger = new NativeLogger(_extContext);
			else
				_logger = new DefaultLogger();

			_instance = this;
		}

        private function _handleStatusEvent(event:StatusEvent):void {

            if (event.code == "log")
	            _doLogging && trace("[AirCapabilities] " + event.level);
            else if (event.code == "OPEN_URL")
                this.dispatchEvent(new AirCapabilitiesOpenURLEvent(AirCapabilitiesOpenURLEvent.OPEN_URL_SUCCESS, event.level));
            else if (event.code == AirCapabilitiesLowMemoryEvent.LOW_MEMORY_WARNING) {
	            var memory:Number = Number(event.level);
	            this.dispatchEvent(new AirCapabilitiesLowMemoryEvent(event.code, memory));
            }
            else
                this.dispatchEvent(event);
        }
	}
}

/*
 * Copyright 2017 FreshPlanet
 * 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.freshplanet.ane.AirCapabilities {

import com.freshplanet.ane.AirCapabilities.events.AirCapabilitiesLowMemoryEvent;
import com.freshplanet.ane.AirCapabilities.events.AirCapabilitiesOpenURLEvent;
	import flash.display.BitmapData;
	import flash.events.EventDispatcher;
	import flash.events.StatusEvent;
	import flash.external.ExtensionContext;
	import flash.system.Capabilities;

	public class AirCapabilities extends EventDispatcher {

		// --------------------------------------------------------------------------------------//
		//																						 //
		// 									   PUBLIC API										 //
		// 																						 //
		// --------------------------------------------------------------------------------------//

		/**
		 * Is the ANE supported on the current platform
		 */
        static public function get isSupported():Boolean {
            return (Capabilities.manufacturer.indexOf("iOS") > -1 && Capabilities.os.indexOf("x86_64") < 0 && Capabilities.os.indexOf("i386") < 0) || Capabilities.manufacturer.indexOf("Android") > -1;
        }

		/**
		 * If true, logs will be displayed at the ActionScript and native level.
		 */
		public function setLogging(value:Boolean):void {

			_doLogging = value;
			if (isSupported)
				_extContext.call("setLogging", value);
		}

		public function get nativeLogger():ILogger {
            return _logger;
        }

        /**
         * AirCapabilities instance
         */
        static public function get instance():AirCapabilities {
			return _instance != null ? _instance : new AirCapabilities()
		}

        /**
         * Is SMS available
         * @return
         */
		public function hasSmsEnabled():Boolean {

			if (isSupported)
				return _extContext.call("hasSMS");

			return false;
		}

        /**
         * Is Twitter available
         * @return
         */
		public function hasTwitterEnabled():Boolean {

			if (isSupported)
				return _extContext.call("hasTwitter");

			return false;
		}

        /**
         * Sends an SMS message
         * @param message to send
         * @param recipient phonenumber
         */
		public function sendMsgWithSms(message:String, recipient:String = null):void {

			if (isSupported)
				_extContext.call("sendWithSms", message, recipient);
		}

        /**
         * Sends a Twitter message
         * @param message
         */
		public function sendMsgWithTwitter(message:String):void {

			if (isSupported)
				_extContext.call("sendWithTwitter", message);
		}

        /**
         * Redirect user to Rating page
         * @param appId
         * @param appName
         */
		public function redirecToRating(appId:String, appName:String):void {

			if (isSupported)
				_extContext.call("redirectToRating", appId, appName);
		}

        /**
         * Model of the device
         * @return
         */
		public function getDeviceModel():String {

			if (isSupported)
				return _extContext.call("getDeviceModel") as String;

            return "";
		}

        /**
         * Name of the machine
         * @return
         */
		public function getMachineName():String {

			if (isSupported)
				return _extContext.call("getMachineName") as String;

            return "";
		}

        /**
         * Opens the referral link URL
         * @param url
         */
		public function processReferralLink(url:String):void {

			if (isSupported)
				_extContext.call("processReferralLink", url);
		}

        /**
         * Opens Facebook page
         * @param pageId id of the facebook page
         */
		public function redirectToPageId(pageId:String):void {

			if (isSupported)
				_extContext.call("redirectToPageId", pageId);
		}

        /**
         * Opens Twitter account
         * @param twitterAccount
         */
		public function redirectToTwitterAccount(twitterAccount:String):void {

			if (isSupported)
				_extContext.call("redirectToTwitterAccount", twitterAccount);
		}

        /**
         * Is posting pictures on Twitter enabled
         * @return
         */
		public function canPostPictureOnTwitter():Boolean {

			if (isSupported)
				return _extContext.call("canPostPictureOnTwitter");

			return false;
		}

        /**
         * Post new picture on Twitter
         * @param message
         * @param bitmapData
         */
		public function postPictureOnTwitter(message:String, bitmapData:BitmapData):void {

			if (isSupported)
				_extContext.call("postPictureOnTwitter", message, bitmapData);
		}

        /**
         * Is Instagram enabled
         * @return
         */
		public function hasInstagramEnabled():Boolean {

			if (isSupported)
				return _extContext.call("hasInstagramEnabled");

			return false;
		}

        /**
         * Post new picture on Instagram
         * @param message
         * @param bitmapData
         * @param x
         * @param y
         * @param width
         * @param height
         */
		public function postPictureOnInstagram(message:String, bitmapData:BitmapData,
                                               x:int, y:int, width:int, height:int):void {

			if (isSupported)
				_extContext.call("postPictureOnInstagram", message, bitmapData, x, y, width, height);
		}

		/**
		 * Open an application (if installed on the Device) or send the player to the appstore.  iOS Only
		 * @param schemes 		List of schemes (String) that the application accepts.  Examples : @"sms://", @"twit://".  You can find schemes in http://handleopenurl.com/
		 * @param appStoreURL 	(optional) Link to the AppStore page for the Application for the player to download. URL can be generated via Apple's linkmaker (itunes.apple.com/linkmaker?)
		 */
		public function openExternalApplication(schemes:Array, appStoreURL:String = null):void {

			if (isSupported && Capabilities.manufacturer.indexOf("Android") == -1)
				_extContext.call("openExternalApplication", schemes, appStoreURL);
		}

        /**
         * Is opening URLs available
         * @param url
         * @return
         */
		public function canOpenURL(url:String):Boolean {
			return isSupported ? _extContext.call("canOpenURL", url) as Boolean : false;
		}

        /**
         * Open URL
         * @param url
         */
		public function openURL(url:String):void {

			if (canOpenURL(url))
				_extContext.call("openURL", url);
		}

		/**
		 * Opens modal app store. Available on iOS only
		 * @param appStoreId	id of the app to open a modal view to (do not include the "id" at the beginning of the number)
		 */
		public function openModalAppStoreIOS(appStoreId:String):void {

			if (Capabilities.manufacturer.indexOf("iOS") > -1)
				_extContext.call("openModalAppStore", appStoreId);
		}

        /**
         * Version of the operating system
         * @return
         */
        public function getOSVersion():String {

            if (isSupported)
                return _extContext.call("getOSVersion") as String;

            return "";
        }

        /**
         * @return  current amount of RAM being used in bytes
         */
        public function getCurrentMem():Number {

			if (!isSupported)
				return -1;

            var ret:Object = _extContext.call("getCurrentMem");
            if (ret is Error)
                throw ret;
            else
                return ret ? ret as Number : 0;
        }

        /**
         * @return  amount of RAM used by the VM
         */
        public function getCurrentVirtualMem():Number {

			if(!isSupported)
				return -1;

            if (Capabilities.manufacturer.indexOf("iOS") == -1)
                return -1;

            var ret:Object = _extContext.call("getCurrentVirtualMem");
            if (ret is Error)
                throw ret;
            else
                return ret ? ret as Number : 0;
        }

		/**
		 * @return  is requesting review available. Available on iOS only
		 */
		public function canRequestReview():Boolean {

			if (!isSupported)
				return false;

			if (Capabilities.manufacturer.indexOf("iOS") == -1)
				return false;

			return _extContext.call("canRequestReview");
		}

		/**
		 * Request AppStore review. Available on iOS only
		 */
		public function requestReview():void {

			if (!canRequestReview())
				return;

			_extContext.call("requestReview");
		}

		// --------------------------------------------------------------------------------------//
		//																						 //
		// 									 	PRIVATE API										 //
		// 																						 //
		// --------------------------------------------------------------------------------------//

		static private const EXTENSION_ID:String = "com.freshplanet.ane.AirCapabilities";

		static private var _instance:AirCapabilities = null;

		private var _extContext:ExtensionContext = null;
		private var _doLogging:Boolean = false;
		private var _logger:ILogger;

		/**
		 * "private" singleton constructor
		 */
		public function AirCapabilities() {

			super();

			if (_instance)
				throw new Error("singleton class, use .instance");

			_extContext = ExtensionContext.createExtensionContext(EXTENSION_ID, null);
			_extContext.addEventListener(StatusEvent.STATUS, _handleStatusEvent);

			if (isSupported)
				_logger = new NativeLogger(_extContext);
			else
				_logger = new DefaultLogger();

			_instance = this;
		}

        private function _handleStatusEvent(event:StatusEvent):void {

            if (event.code == "log")
	            _doLogging && trace("[AirCapabilities] " + event.level);
            else if (event.code == "OPEN_URL")
                this.dispatchEvent(new AirCapabilitiesOpenURLEvent(AirCapabilitiesOpenURLEvent.OPEN_URL_SUCCESS, event.level));
            else if (event.code == AirCapabilitiesLowMemoryEvent.LOW_MEMORY_WARNING) {
	            var memory:Number = Number(event.level);
	            this.dispatchEvent(new AirCapabilitiesLowMemoryEvent(event.code, memory));
            }
            else
                this.dispatchEvent(event);
        }
	}
}

fix for simulator

fix for simulator