package htmlelements
{
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.TimerEvent;
	import flash.media.ID3Info;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.media.SoundLoaderContext;
	import flash.media.SoundTransform;
	import flash.net.URLRequest;
	import flash.utils.Timer;

	/**
	* ...
	* @author DefaultUser (Tools -> Custom Arguments...)
	*/
	public class AudioElement implements IMediaElement
	{

		private var _sound:Sound;
		private var _soundTransform:SoundTransform;
		private var _soundChannel:SoundChannel;
		private var _soundLoaderContext:SoundLoaderContext;

		private var _volume:Number = 1;
		private var _preMuteVolume:Number = 0;
		private var _isMuted:Boolean = false;
		private var _isPaused:Boolean = true;
		private var _isEnded:Boolean = false;
		private var _isLoaded:Boolean = false;
		private var _currentTime:Number = 0;
		private var _duration:Number = 0;
		private var _bytesLoaded:Number = 0;
		private var _bytesTotal:Number = 0;
		private var _bufferedTime:Number = 0;

		private var _currentUrl:String = "";
		private var _autoplay:Boolean = true;
		private var _preload:String = "";

		private var _element:FlashMediaElement;
		private var _timer:Timer;
		private var _firedCanPlay:Boolean = false;

		public function setSize(width:Number, height:Number):void {
			// do nothing!
		}

		public function duration():Number {
			return _duration;
		}

		public function currentTime():Number {
			return _currentTime;
		}

		public function currentProgress():Number {
				return Math.round(_bytesLoaded/_bytesTotal*100);
		}

		public function AudioElement(element:FlashMediaElement, autoplay:Boolean, preload:String, timerRate:Number, startVolume:Number)
		{
			_element = element;
			_autoplay = autoplay;
			_volume = startVolume;
			_preload = preload;

			_timer = new Timer(timerRate);
			_timer.addEventListener(TimerEvent.TIMER, timerEventHandler);

			_soundTransform = new SoundTransform(_volume);
			_soundLoaderContext = new SoundLoaderContext();
		}

		// events
		function progressHandler(e:ProgressEvent):void {

			_bytesLoaded = e.bytesLoaded;
			_bytesTotal = e.bytesTotal;

			sendEvent(HtmlMediaEvent.PROGRESS);
		}

		function id3Handler(e:Event):void {
			sendEvent(HtmlMediaEvent.LOADEDMETADATA);

			try {
				var id3:ID3Info = _sound.id3;
				var obj = {
					type:'id3',
					album:id3.album,
					artist:id3.artist,
					comment:id3.comment,
					genre:id3.genre,
					songName:id3.songName,
					track:id3.track,
					year:id3.year
				}
			} catch (err:Error) {}

		}

		function timerEventHandler(e:TimerEvent) {
			_currentTime = _soundChannel.position/1000;

			// calculate duration
			var duration = Math.round(_sound.length * _sound.bytesTotal/_sound.bytesLoaded/100) / 10;

			// check to see if the estimated duration changed
			if (_duration != duration && !isNaN(duration)) {

				_duration = duration;
				sendEvent(HtmlMediaEvent.LOADEDMETADATA);
			}

			// send timeupdate
			sendEvent(HtmlMediaEvent.TIMEUPDATE);

			// sometimes the ended event doesn't fire, here's a fake one
			if (_duration > 0 && _currentTime >= _duration-0.2) {
				handleEnded();
			}
		}

		function soundCompleteHandler(e:Event) {
			handleEnded();
		}

		function handleEnded():void {
			_timer.stop();
			_currentTime = 0;
			_isEnded = true;

			sendEvent(HtmlMediaEvent.ENDED);
		}

		//events

		// METHODS
		public function setSrc(url:String):void {
			_currentUrl = url;
			_isLoaded = false;
		}

		public function load():void {

			if (_currentUrl == "")
				return;

			_sound = new Sound();
			//sound.addEventListener(IOErrorEvent.IO_ERROR,errorHandler);
			_sound.addEventListener(ProgressEvent.PROGRESS,progressHandler);
			_sound.addEventListener(Event.ID3,id3Handler);
			_sound.load(new URLRequest(_currentUrl));
			_currentTime = 0;

			sendEvent(HtmlMediaEvent.LOADSTART);

			_isLoaded = true;

			sendEvent(HtmlMediaEvent.LOADEDDATA);
			sendEvent(HtmlMediaEvent.CANPLAY);
			_firedCanPlay = true;

			if (_playAfterLoading) {
				_playAfterLoading = false;
				play();
			}
		}

		private var _playAfterLoading:Boolean= false;

		public function play():void {

			if (!_isLoaded) {
				_playAfterLoading = true;
				load();
				return;
			}

			_timer.stop();

			_soundChannel = _sound.play(_currentTime*1000, 0, _soundTransform);
			_soundChannel.removeEventListener(Event.SOUND_COMPLETE, soundCompleteHandler);
			_soundChannel.addEventListener(Event.SOUND_COMPLETE, soundCompleteHandler);

			_timer.start();

			didStartPlaying();
		}

		public function pause():void {

			_timer.stop();
			if (_soundChannel != null) {
				_currentTime = _soundChannel.position/1000;
				_soundChannel.stop();
			}

			_isPaused = true;
			sendEvent(HtmlMediaEvent.PAUSE);
		}

		public function stop():void {
			if (_timer != null) {
				_timer.stop();
			}
			if (_soundChannel != null) {
				_soundChannel.stop();
				_sound.close();
			}
			unload();
			sendEvent(HtmlMediaEvent.STOP);
		}

		public function setCurrentTime(pos:Number):void {
			sendEvent(HtmlMediaEvent.SEEKING);
			_timer.stop();
			_currentTime = pos;
			_soundChannel.stop();
			_sound.length
			_soundChannel = _sound.play(_currentTime * 1000, 0, _soundTransform);
			sendEvent(HtmlMediaEvent.SEEKED);

			_timer.start();

			didStartPlaying();
		}

		private function didStartPlaying():void {
			_isPaused = false;
			sendEvent(HtmlMediaEvent.PLAY);
			sendEvent(HtmlMediaEvent.PLAYING);
			if (!_firedCanPlay) {
				sendEvent(HtmlMediaEvent.LOADEDDATA);
				sendEvent(HtmlMediaEvent.CANPLAY);
				_firedCanPlay = true;
			}
		}

		public function setVolume(volume:Number):void {

			_volume = volume;
			_soundTransform.volume = volume;

			if (_soundChannel != null) {
				_soundChannel.soundTransform = _soundTransform;
			}

			_isMuted = (_volume == 0);

			sendEvent(HtmlMediaEvent.VOLUMECHANGE);
		}

		public function getVolume():Number {
			if(_isMuted) {
				return 0;
			} else {
				return _volume;
			}
		}

		public function setMuted(muted:Boolean):void {

			// ignore if already set
			if ( (muted && _isMuted) || (!muted && !_isMuted))
				return;

			if (muted) {
				_preMuteVolume = _soundTransform.volume;
				setVolume(0);
			} else {
				setVolume(_preMuteVolume);
			}

			_isMuted = muted;
		}

		public function unload():void {
			_sound = null;
			_isLoaded = false;
		}

		private function sendEvent(eventName:String) {

			// calculate this to mimic HTML5
			_bufferedTime = _bytesLoaded / _bytesTotal * _duration;

			// build JSON
			var values:String = "duration:" + _duration +
							",currentTime:" + _currentTime +
							",muted:" + _isMuted +
							",paused:" + _isPaused +
							",ended:" + _isEnded +
							",volume:" + _volume +
							",src:\"" + _currentUrl + "\"" +
							",bytesTotal:" + _bytesTotal +
							",bufferedBytes:" + _bytesLoaded +
							",bufferedTime:" + _bufferedTime +
							"";

			_element.sendEvent(eventName, values);
		}

	}

}

package htmlelements
{
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.TimerEvent;
	import flash.media.ID3Info;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.media.SoundLoaderContext;
	import flash.media.SoundTransform;
	import flash.net.URLRequest;
	import flash.utils.Timer;

	/**
	* ...
	* @author DefaultUser (Tools -> Custom Arguments...)
	*/
	public class AudioElement implements IMediaElement
	{

		private var _sound:Sound;
		private var _soundTransform:SoundTransform;
		private var _soundChannel:SoundChannel;
		private var _soundLoaderContext:SoundLoaderContext;

		private var _volume:Number = 1;
		private var _preMuteVolume:Number = 0;
		private var _isMuted:Boolean = false;
		private var _isPaused:Boolean = true;
		private var _isEnded:Boolean = false;
		private var _isLoaded:Boolean = false;
		private var _currentTime:Number = 0;
		private var _duration:Number = 0;
		private var _bytesLoaded:Number = 0;
		private var _bytesTotal:Number = 0;
		private var _bufferedTime:Number = 0;
		private var _bufferingChanged:Boolean = false;

		private var _currentUrl:String = "";
		private var _autoplay:Boolean = true;
		private var _preload:String = "";

		private var _element:FlashMediaElement;
		private var _timer:Timer;
		private var _firedCanPlay:Boolean = false;

		public function setSize(width:Number, height:Number):void {
			// do nothing!
		}

		public function duration():Number {
			return _duration;
		}

		public function currentTime():Number {
			return _currentTime;
		}

		public function currentProgress():Number {
				return Math.round(_bytesLoaded/_bytesTotal*100);
		}

		public function AudioElement(element:FlashMediaElement, autoplay:Boolean, preload:String, timerRate:Number, startVolume:Number)
		{
			_element = element;
			_autoplay = autoplay;
			_volume = startVolume;
			_preload = preload;

			_timer = new Timer(timerRate);
			_timer.addEventListener(TimerEvent.TIMER, timerEventHandler);

			_soundTransform = new SoundTransform(_volume);
			_soundLoaderContext = new SoundLoaderContext();
		}

		// events
		function progressHandler(e:ProgressEvent):void {

			_bytesLoaded = e.bytesLoaded;
			_bytesTotal = e.bytesTotal;

			// this happens too much to send every time
			//sendEvent(HtmlMediaEvent.PROGRESS);

			// so now we just trigger a flag and send with the timer
			_bufferingChanged = true;
		}

		function id3Handler(e:Event):void {
			sendEvent(HtmlMediaEvent.LOADEDMETADATA);

			try {
				var id3:ID3Info = _sound.id3;
				var obj = {
					type:'id3',
					album:id3.album,
					artist:id3.artist,
					comment:id3.comment,
					genre:id3.genre,
					songName:id3.songName,
					track:id3.track,
					year:id3.year
				}
			} catch (err:Error) {}

		}

		function timerEventHandler(e:TimerEvent) {
			_currentTime = _soundChannel.position/1000;

			// calculate duration
			var duration = Math.round(_sound.length * _sound.bytesTotal/_sound.bytesLoaded/100) / 10;

			// check to see if the estimated duration changed
			if (_duration != duration && !isNaN(duration)) {

				_duration = duration;
				sendEvent(HtmlMediaEvent.LOADEDMETADATA);
			}

			// check for progress
			if (_bufferingChanged) {

				sendEvent(HtmlMediaEvent.PROGRESS);

				_bufferingChanged = false;
			}

			// send timeupdate
			sendEvent(HtmlMediaEvent.TIMEUPDATE);

			// sometimes the ended event doesn't fire, here's a fake one
			if (_duration > 0 && _currentTime >= _duration-0.2) {
				handleEnded();
			}
		}

		function soundCompleteHandler(e:Event) {
			handleEnded();
		}

		function handleEnded():void {
			_timer.stop();
			_currentTime = 0;
			_isEnded = true;

			sendEvent(HtmlMediaEvent.ENDED);
		}

		//events

		// METHODS
		public function setSrc(url:String):void {
			_currentUrl = url;
			_isLoaded = false;
		}

		public function load():void {

			if (_currentUrl == "")
				return;

			_sound = new Sound();
			//sound.addEventListener(IOErrorEvent.IO_ERROR,errorHandler);
			_sound.addEventListener(ProgressEvent.PROGRESS,progressHandler);
			_sound.addEventListener(Event.ID3,id3Handler);
			_sound.load(new URLRequest(_currentUrl));
			_currentTime = 0;

			sendEvent(HtmlMediaEvent.LOADSTART);

			_isLoaded = true;

			sendEvent(HtmlMediaEvent.LOADEDDATA);
			sendEvent(HtmlMediaEvent.CANPLAY);
			_firedCanPlay = true;

			if (_playAfterLoading) {
				_playAfterLoading = false;
				play();
			}
		}

		private var _playAfterLoading:Boolean= false;

		public function play():void {

			if (!_isLoaded) {
				_playAfterLoading = true;
				load();
				return;
			}

			_timer.stop();

			_soundChannel = _sound.play(_currentTime*1000, 0, _soundTransform);
			_soundChannel.removeEventListener(Event.SOUND_COMPLETE, soundCompleteHandler);
			_soundChannel.addEventListener(Event.SOUND_COMPLETE, soundCompleteHandler);

			_timer.start();

			didStartPlaying();
		}

		public function pause():void {

			_timer.stop();
			if (_soundChannel != null) {
				_currentTime = _soundChannel.position/1000;
				_soundChannel.stop();
			}

			_isPaused = true;
			sendEvent(HtmlMediaEvent.PAUSE);
		}

		public function stop():void {
			if (_timer != null) {
				_timer.stop();
			}
			if (_soundChannel != null) {
				_soundChannel.stop();
				_sound.close();
			}
			unload();
			sendEvent(HtmlMediaEvent.STOP);
		}

		public function setCurrentTime(pos:Number):void {
			sendEvent(HtmlMediaEvent.SEEKING);
			_timer.stop();
			_currentTime = pos;
			_soundChannel.stop();
			_sound.length
			_soundChannel = _sound.play(_currentTime * 1000, 0, _soundTransform);
			sendEvent(HtmlMediaEvent.SEEKED);

			_timer.start();

			didStartPlaying();
		}

		private function didStartPlaying():void {
			_isPaused = false;
			sendEvent(HtmlMediaEvent.PLAY);
			sendEvent(HtmlMediaEvent.PLAYING);
			if (!_firedCanPlay) {
				sendEvent(HtmlMediaEvent.LOADEDDATA);
				sendEvent(HtmlMediaEvent.CANPLAY);
				_firedCanPlay = true;
			}
		}

		public function setVolume(volume:Number):void {

			_volume = volume;
			_soundTransform.volume = volume;

			if (_soundChannel != null) {
				_soundChannel.soundTransform = _soundTransform;
			}

			_isMuted = (_volume == 0);

			sendEvent(HtmlMediaEvent.VOLUMECHANGE);
		}

		public function getVolume():Number {
			if(_isMuted) {
				return 0;
			} else {
				return _volume;
			}
		}

		public function setMuted(muted:Boolean):void {

			// ignore if already set
			if ( (muted && _isMuted) || (!muted && !_isMuted))
				return;

			if (muted) {
				_preMuteVolume = _soundTransform.volume;
				setVolume(0);
			} else {
				setVolume(_preMuteVolume);
			}

			_isMuted = muted;
		}

		public function unload():void {
			_sound = null;
			_isLoaded = false;
		}

		private function sendEvent(eventName:String) {

			// calculate this to mimic HTML5
			_bufferedTime = _bytesLoaded / _bytesTotal * _duration;

			// build JSON
			var values:String = "duration:" + _duration +
							",currentTime:" + _currentTime +
							",muted:" + _isMuted +
							",paused:" + _isPaused +
							",ended:" + _isEnded +
							",volume:" + _volume +
							",src:\"" + _currentUrl + "\"" +
							",bytesTotal:" + _bytesTotal +
							",bufferedBytes:" + _bytesLoaded +
							",bufferedTime:" + _bufferedTime +
							"";

			_element.sendEvent(eventName, values);
		}

	}

}

fix for too many buffering events by tying it to the timer event


package aerys.minko.scene.node
{
	import aerys.minko.render.Effect;
	import aerys.minko.render.geometry.Geometry;
	import aerys.minko.render.material.Material;
	import aerys.minko.render.material.basic.BasicMaterial;
	import aerys.minko.render.material.basic.BasicShader;
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.controller.mesh.MeshVisibilityController;
	import aerys.minko.type.Signal;
	import aerys.minko.type.binding.DataBindings;
	import aerys.minko.type.binding.DataProvider;
	import aerys.minko.type.bounding.FrustumCulling;
	import aerys.minko.type.enum.DataProviderUsage;
	import aerys.minko.type.math.Ray;

	/**
	 * Mesh objects are a visible instance of a Geometry rendered using a specific
	 * Effect with specific rendering properties.
	 *
	 *

	 * Those rendering properties are stored in a DataBindings object so they can
	 * be directly used by the shaders in the rendering API.
	 *

	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public class Mesh extends AbstractSceneNode
	{
		public static const DEFAULT_MATERIAL	: Material	= new Material(
			new Effect(new BasicShader())
		);

		private var _geometry			: Geometry					= null;
		private var _properties			: DataProvider				= null;
		private var _material			: Material					= null;
		private var _bindings			: DataBindings				= null;

		private var _visibility			: MeshVisibilityController	= new MeshVisibilityController();

		private var _frame				: uint						= 0;

		private var _cloned				: Signal 					= new Signal('Mesh.clones');
		private var _materialChanged	: Signal					= new Signal('Mesh.materialChanged');
		private var _frameChanged		: Signal					= new Signal('Mesh.frameChanged');
		private var _geometryChanged	: Signal					= new Signal('Mesh.geometryChanged');

		/**
		 * A DataProvider object already bound to the Mesh bindings.
		 *
		 *

		 * // set the "diffuseColor" property to 0x0000ffff
		 * mesh.properties.diffuseColor = 0x0000ffff;
		 *
		 * // animate the "diffuseColor" property
		 * mesh.addController(
		 *   new AnimationController(
		 * 	  new <ITimeline>[new ColorTimeline(
		 * 	    "dataProvider.diffuseColor",
		 * 	    5000,
		 * 	    new <uint>[0xffffffff, 0xffffff00, 0xffffffff]
		 *    )]
		 *   )
		 * );
		 *

		 *
		 * @return
		 *
		 */
		public function get properties() : DataProvider
		{
			return _properties;
		}

		public function set properties(value : DataProvider) : void
		{
			if (_properties != value)
			{
				if (_properties)
					_bindings.removeProvider(_properties);

				_properties = value;

				if (value)
					_bindings.addProvider(value);
			}
		}

		public function get material() : Material
		{
			return _material;
		}
		public function set material(value : Material) : void
		{
			if (_material != value)
			{
				if (_material)
					_bindings.removeProvider(_material);

				_material = value;

				if (value)
					_bindings.addProvider(value);
			}
		}

		/**
		 * The rendering properties provided to the shaders to customize
		 * how the mesh will appear on screen.
		 *
		 * @return
		 *
		 */
		public function get bindings() : DataBindings
		{
			return _bindings;
		}

		/**
		 * The Geometry of the mesh.
		 * @return
		 *
		 */
		public function get geometry() : Geometry
		{
			return _geometry;
		}

		public function set geometry(value : Geometry) : void
		{
			if (_geometry != value)
			{
				var oldGeometry	: Geometry = _geometry;

				_geometry = value;
				_geometryChanged.execute(this, oldGeometry, value);
			}
		}

		/**
		 * Whether the mesh is visible or not.
		 *
		 * @return
		 *
		 */
		public function get visible() : Boolean
		{
			return _visibility.visible;
		}
		public function set visible(value : Boolean) : void
		{
			_visibility.visible = value;
		}

		public function get frustumCulling() : uint
		{
			return _visibility.frustumCulling;
		}
		public function set frustumCulling(value : uint) : void
		{
			_visibility.frustumCulling = value;
		}

		public function get cloned() : Signal
		{
			return _cloned;
		}

		public function get materialChanged() : Signal
		{
			return _materialChanged;
		}

		public function get frameChanged() : Signal
		{
			return _frameChanged;
		}

		public function get geometryChanged() : Signal
		{
			return _geometryChanged;
		}

		public function get frame() : uint
		{
			return _frame;
		}
		public function set frame(value : uint) : void
		{
			if (_frame != value)
			{
				var oldFrame : uint = _frame;

				_frame = value;
				_frameChanged.execute(this, oldFrame, value);
			}
		}

		public function Mesh(geometry	: Geometry	= null,
							 material	: Material	= null,
							 ...controllers)
		{
			super();

			initialize(geometry, material, controllers);
		}

		private function initialize(geometry	: Geometry,
									material	: Material,
									controllers	: Array) : void
		{
			_bindings = new DataBindings(this);
			this.properties = new DataProvider(properties, 'meshProperties', DataProviderUsage.EXCLUSIVE);

			_geometry = geometry;
			this.material = material || DEFAULT_MATERIAL;

//			_visibility.frustumCulling = FrustumCulling.ENABLED;
			addController(_visibility);

			while (controllers && !(controllers[0] is AbstractController))
				controllers = controllers[0];

			if (controllers)
				for each (var ctrl : AbstractController in controllers)
					addController(ctrl);
		}

		public function cast(ray : Ray, maxDistance : Number = Number.POSITIVE_INFINITY) : Number
		{
			return _geometry.boundingBox.testRay(
				ray,
				worldToLocal,
				maxDistance
			);
		}

		override public function clone(cloneControllers : Boolean = false) : ISceneNode
		{
			var clone : Mesh = new Mesh();

			clone.copyFrom(this, true, cloneControllers);

			return clone;
		}

		override protected function addedToSceneHandler(child : ISceneNode, scene : Scene) : void
		{
			super.addedToSceneHandler(child, scene);

			if (child === this)
				_bindings.addProvider(transformData);
		}

		override protected function removedFromSceneHandler(child : ISceneNode, scene : Scene) : void
		{
			super.removedFromSceneHandler(child, scene);

			if (child === this)
				_bindings.removeProvider(transformData);
		}

		protected function copyFrom(source 				: Mesh,
									withBindings 		: Boolean,
									cloneControllers 	: Boolean) : void
		{
			var numControllers : uint = source.numControllers;

			name 		= source.name;

			geometry 	= source._geometry;
			properties	= DataProvider(source._properties.clone());

			_bindings.copySharedProvidersFrom(source._bindings);

			copyControllersFrom(
				source, this, cloneControllers, new <AbstractController>[source._visibility]
			);

			_visibility = source._visibility.clone() as MeshVisibilityController;
			addController(_visibility);

			transform.copyFrom(source.transform);
			material = source._material;

			source.cloned.execute(this, source);
		}
	}
}

package aerys.minko.scene.node
{
	import aerys.minko.render.Effect;
	import aerys.minko.render.geometry.Geometry;
	import aerys.minko.render.material.Material;
	import aerys.minko.render.material.basic.BasicMaterial;
	import aerys.minko.render.material.basic.BasicShader;
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.controller.mesh.MeshVisibilityController;
	import aerys.minko.type.Signal;
	import aerys.minko.type.binding.DataBindings;
	import aerys.minko.type.binding.DataProvider;
	import aerys.minko.type.bounding.FrustumCulling;
	import aerys.minko.type.enum.DataProviderUsage;
	import aerys.minko.type.math.Ray;

	/**
	 * Mesh objects are a visible instance of a Geometry rendered using a specific
	 * Effect with specific rendering properties.
	 *
	 *

	 * Those rendering properties are stored in a DataBindings object so they can
	 * be directly used by the shaders in the rendering API.
	 *

	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public class Mesh extends AbstractSceneNode
	{
		public static const DEFAULT_MATERIAL	: Material	= new Material(
			new Effect(new BasicShader())
		);

		private var _geometry			: Geometry					= null;
		private var _properties			: DataProvider				= null;
		private var _material			: Material					= null;
		private var _bindings			: DataBindings				= null;

		private var _visibility			: MeshVisibilityController	= new MeshVisibilityController();

		private var _frame				: uint						= 0;

		private var _cloned				: Signal 					= new Signal('Mesh.clones');
		private var _materialChanged	: Signal					= new Signal('Mesh.materialChanged');
		private var _frameChanged		: Signal					= new Signal('Mesh.frameChanged');
		private var _geometryChanged	: Signal					= new Signal('Mesh.geometryChanged');

		/**
		 * A DataProvider object already bound to the Mesh bindings.
		 *
		 *

		 * // set the "diffuseColor" property to 0x0000ffff
		 * mesh.properties.diffuseColor = 0x0000ffff;
		 *
		 * // animate the "diffuseColor" property
		 * mesh.addController(
		 *   new AnimationController(
		 * 	  new <ITimeline>[new ColorTimeline(
		 * 	    "dataProvider.diffuseColor",
		 * 	    5000,
		 * 	    new <uint>[0xffffffff, 0xffffff00, 0xffffffff]
		 *    )]
		 *   )
		 * );
		 *

		 *
		 * @return
		 *
		 */
		public function get properties() : DataProvider
		{
			return _properties;
		}

		public function set properties(value : DataProvider) : void
		{
			if (_properties != value)
			{
				if (_properties)
					_bindings.removeProvider(_properties);

				_properties = value;

				if (value)
					_bindings.addProvider(value);
			}
		}

		public function get material() : Material
		{
			return _material;
		}
		public function set material(value : Material) : void
		{
			if (_material != value)
			{
				if (_material)
					_bindings.removeProvider(_material);

				_material = value;

				if (value)
					_bindings.addProvider(value);
			}
		}

		/**
		 * The rendering properties provided to the shaders to customize
		 * how the mesh will appear on screen.
		 *
		 * @return
		 *
		 */
		public function get bindings() : DataBindings
		{
			return _bindings;
		}

		/**
		 * The Geometry of the mesh.
		 * @return
		 *
		 */
		public function get geometry() : Geometry
		{
			return _geometry;
		}

		public function set geometry(value : Geometry) : void
		{
			if (_geometry != value)
			{
				var oldGeometry	: Geometry = _geometry;

				_geometry = value;
				_geometryChanged.execute(this, oldGeometry, value);
			}
		}

		/**
		 * Whether the mesh is visible or not.
		 *
		 * @return
		 *
		 */
		public function get visible() : Boolean
		{
			return _visibility.visible;
		}
		public function set visible(value : Boolean) : void
		{
			_visibility.visible = value;
		}

		public function get frustumCulling() : uint
		{
			return _visibility.frustumCulling;
		}
		public function set frustumCulling(value : uint) : void
		{
			_visibility.frustumCulling = value;
		}

		public function get cloned() : Signal
		{
			return _cloned;
		}

		public function get materialChanged() : Signal
		{
			return _materialChanged;
		}

		public function get frameChanged() : Signal
		{
			return _frameChanged;
		}

		public function get geometryChanged() : Signal
		{
			return _geometryChanged;
		}

		public function get frame() : uint
		{
			return _frame;
		}
		public function set frame(value : uint) : void
		{
			if (_frame != value)
			{
				var oldFrame : uint = _frame;

				_frame = value;
				_frameChanged.execute(this, oldFrame, value);
			}
		}

		public function Mesh(geometry	: Geometry	= null,
							 material	: Material	= null,
							 ...controllers)
		{
			super();

			initialize(geometry, material, controllers);
		}

		private function initialize(geometry	: Geometry,
									material	: Material,
									controllers	: Array) : void
		{
			_bindings = new DataBindings(this);
			this.properties = new DataProvider(properties, 'meshProperties', DataProviderUsage.EXCLUSIVE);

			_geometry = geometry;
			this.material = material || DEFAULT_MATERIAL;

//			_visibility.frustumCulling = FrustumCulling.ENABLED;
			addController(_visibility);

			while (controllers && !(controllers[0] is AbstractController))
				controllers = controllers[0];

			if (controllers)
				for each (var ctrl : AbstractController in controllers)
					addController(ctrl);
		}

		public function cast(ray : Ray, maxDistance : Number = Number.POSITIVE_INFINITY) : Number
		{
			return _geometry.boundingBox.testRay(
				ray,
				worldToLocal,
				maxDistance
			);
		}

		override public function clone(cloneControllers : Boolean = false) : ISceneNode
		{
			var clone : Mesh = new Mesh();

			clone.copyFrom(this, true, cloneControllers);

			return clone;
		}

		override protected function addedToSceneHandler(child : ISceneNode, scene : Scene) : void
		{
			super.addedToSceneHandler(child, scene);

			if (child === this)
				_bindings.addProvider(transformData);
		}

		override protected function removedFromSceneHandler(child : ISceneNode, scene : Scene) : void
		{
			super.removedFromSceneHandler(child, scene);

			if (child === this)
				_bindings.removeProvider(transformData);
		}

		protected function copyFrom(source 				: Mesh,
									withBindings 		: Boolean,
									cloneControllers 	: Boolean) : void
		{
			var numControllers : uint = source.numControllers;

			name 		= source.name;

			geometry 	= source._geometry;
			properties	= DataProvider(source._properties.clone());

			_bindings.copySharedProvidersFrom(source._bindings);

			copyControllersFrom(
				source, this, cloneControllers, new <AbstractController>[source._visibility]
			);

			_visibility = source._visibility.clone() as MeshVisibilityController;
			addController(_visibility);

			transform.copyFrom(source.transform);
			material = source._material;

			source.cloned.execute(source, this);
		}
	}
}

Switch arguments in callbacks of the cloned signal


/**
 * Created by newkrok on 08/04/16.
 */
package ageofai.home.view
{
	import ageofai.building.base.BaseBuildingView;
<<<<<<< Updated upstream
	import ageofai.home.view.event.HomeViewEvent;
	import ageofai.villager.event.VillagerEvent;
	import ageofai.villager.view.VillagerView;
=======
	import ageofai.map.constant.CMap;
>>>>>>> Stashed changes

	public class HomeView extends BaseBuildingView
	{
		public function HomeView()
		{
			this.createUI( HomeUI );
			this.createLifeBar();
			this.createProgressBar();

			this._graphicUI.x = CMap.TILE_SIZE;
			this._graphicUI.y = CMap.TILE_SIZE;
		}

		public function showProgressValue( value:Number):void
		{
			this._buildProgressBar.show();
			this._buildProgressBar.drawProcessBar( value );
		}

		public function createVillagerView():void
		{
            var homeViewEvent:HomeViewEvent = new HomeViewEvent( HomeViewEvent.VILLAGER_VIEW_CREATED );
            homeViewEvent.villagerView = new VillagerView( );
            this.dispatchEvent( homeViewEvent );
		}
	}
}

/**
 * Created by newkrok on 08/04/16.
 */
package ageofai.home.view
{
	import ageofai.building.base.BaseBuildingView;
	import ageofai.home.view.event.HomeViewEvent;
	import ageofai.villager.view.VillagerView;

	import ageofai.map.constant.CMap;

	public class HomeView extends BaseBuildingView
	{
		public function HomeView()
		{
			this.createUI( HomeUI );
			this.createLifeBar();
			this.createProgressBar();

			this._graphicUI.x = CMap.TILE_SIZE;
			this._graphicUI.y = CMap.TILE_SIZE;
		}

		public function showProgressValue( value:Number ):void
		{
			this._buildProgressBar.show();
			this._buildProgressBar.drawProcessBar( value );
		}

		public function createVillagerView():void
		{
			var homeViewEvent:HomeViewEvent = new HomeViewEvent( HomeViewEvent.VILLAGER_VIEW_CREATED );
			homeViewEvent.villagerView = new VillagerView();
			this.dispatchEvent( homeViewEvent );
		}
	}
}

Fix merge problem

Fix merge problem

Fix merge problem


/**
  * LzTimeKernel.as
  *
  * @copyright Copyright 2001-2009 Laszlo Systems, Inc.  All Rights Reserved.
  *            Use is subject to license terms.
  *
  * @topic Kernel
  * @subtopic swf9
  */

// Receives and sends timing events
final class LzTimeKernelClass {
    #passthrough (toplevel:true) {
    import flash.utils.getTimer;
    import flash.events.TimerEvent;
    }#

    private const MAX_POOL :int = 10;
    private var timerPool :Array = [];
    private var timers :Object = {};

    /**
      * Creates a new timer and returns an unique identifier which can be used to remove the timer.
      */
    private function createTimer (delay:Number, repeatCount:int, closure:Function, args:Array) :uint {
        var timer:LzKernelTimer = this.timerPool.pop() || new LzKernelTimer();
        this.timers[timer.timerID] = timer;
        timer.delay = delay;
        timer.repeatCount = repeatCount;
        timer.closure = closure;
        timer.arguments = args;
        timer.addEventListener(TimerEvent.TIMER, this.timerHandler);
        timer.addEventListener(TimerEvent.TIMER_COMPLETE, this.timerCompleteHandler);
        timer.start();
        return timer.timerID;
    }

    /**
      * Stops and removes the timer with the given id.
      */
    private function removeTimer (id:uint) :void {
        var timer:LzKernelTimer = this.timers[id];
        if (timer) {
            timer.closure = null;
            timer.arguments = null;
            timer.removeEventListener(TimerEvent.TIMER, this.timerHandler);
            timer.removeEventListener(TimerEvent.TIMER_COMPLETE, this.timerCompleteHandler);
            timer.reset();
            delete this.timers[id];
            if (this.timerPool.length < this.MAX_POOL) {
                this.timerPool.push(timer);
            }
        }
    }

    private function timerHandler (event:TimerEvent) :void {
        var timer:LzKernelTimer = LzKernelTimer(event.target);
        if (timer.closure) {
            timer.closure.apply(null, timer.arguments);
        }
    }

    private function timerCompleteHandler (event:TimerEvent) :void {
        var timer:LzKernelTimer = LzKernelTimer(event.target);
        this.removeTimer(timer.timerID);
    }

    public const getTimer :Function = flash.utils.getTimer;

    // const setTimeout :Function = flash.utils.setTimeout;
    public function setTimeout (closure:Function, delay:Number, ...args) :uint {
        return this.createTimer(delay, 1, closure, args);
    }

    // const setInterval :Function = flash.utils.setInterval;
    public function setInterval (closure:Function, delay:Number, ...args) :uint {
        return this.createTimer(delay, 0, closure, args);
    }

    // const clearTimeout :Function = flash.utils.clearTimeout;
    public function clearTimeout (id:uint) :void {
        this.removeTimer(id);
    }

    // const clearInterval :Function = flash.utils.clearInterval;
    public function clearInterval (id:uint) :void {
        this.removeTimer(id);
    }

    function LzTimeKernelClass() {
    }
}
var LzTimeKernel = new LzTimeKernelClass();

/**
  * This is a helper class for LzTimeKernel. In addition to the flash.utils.Timer
  * class, each timer has got an unique id and holds a reference to a function
  * and an arguments array.
  * @see LzTimeKernelClass#createTimer
  * @see LzTimeKernelClass#removeTimer
  */
final class LzKernelTimer extends Timer {
  #passthrough (toplevel:true) {
    import flash.utils.Timer;
  }#

  #passthrough {
    private static var idCounter :uint = 0;

    public function LzKernelTimer () {
        super(0);
        this._timerID = LzKernelTimer.idCounter++;
    }

    private var _timerID :uint;
    public function get timerID () :uint {
        return this._timerID;
    }

    private var _closure :Function;
    public function get closure () :Function {
        return this._closure;
    }
    public function set closure (c:Function) :void {
        this._closure = c;
    }

    private var _arguments :Array;
    public function get arguments () :Array {
        return this._arguments;
    }
    public function set arguments (a:Array) :void {
        this._arguments = a;
    }
  }#
}

/**
  * LzTimeKernel.as
  *
  * @copyright Copyright 2001-2009 Laszlo Systems, Inc.  All Rights Reserved.
  *            Use is subject to license terms.
  *
  * @topic Kernel
  * @subtopic swf9
  */

// Receives and sends timing events
final class LzTimeKernelClass {
    #passthrough (toplevel:true) {
    import flash.utils.getTimer;
    import flash.events.TimerEvent;
    }#

    private var timers :Object = {};

    /**
      * Creates a new timer and returns an unique identifier which can be used to remove the timer.
      */
    private function createTimer (delay:Number, repeatCount:int, closure:Function, args:Array) :uint {
        var timer:LzKernelTimer = LzKernelTimer.create();
        this.timers[timer.timerID] = timer;
        timer.delay = delay;
        timer.repeatCount = repeatCount;
        timer.closure = closure;
        timer.arguments = args;
        timer.addEventListener(TimerEvent.TIMER, this.timerHandler);
        timer.addEventListener(TimerEvent.TIMER_COMPLETE, this.timerCompleteHandler);
        timer.start();
        return timer.timerID;
    }

    /**
      * Stops and removes the timer with the given id.
      */
    private function removeTimer (id:uint) :void {
        var timer:LzKernelTimer = this.timers[id];
        if (timer) {
            timer.closure = null;
            timer.arguments = null;
            timer.removeEventListener(TimerEvent.TIMER, this.timerHandler);
            timer.removeEventListener(TimerEvent.TIMER_COMPLETE, this.timerCompleteHandler);
            timer.reset();
            delete this.timers[id];
            LzKernelTimer.remove(timer);
        }
    }

    private function timerHandler (event:TimerEvent) :void {
        var timer:LzKernelTimer = LzKernelTimer(event.target);
        if (timer.closure) {
            timer.closure.apply(null, timer.arguments);
        }
    }

    private function timerCompleteHandler (event:TimerEvent) :void {
        var timer:LzKernelTimer = LzKernelTimer(event.target);
        this.removeTimer(timer.timerID);
    }

    public const getTimer :Function = flash.utils.getTimer;

    // const setTimeout :Function = flash.utils.setTimeout;
    public function setTimeout (closure:Function, delay:Number, ...args) :uint {
        return this.createTimer(delay, 1, closure, args);
    }

    // const setInterval :Function = flash.utils.setInterval;
    public function setInterval (closure:Function, delay:Number, ...args) :uint {
        return this.createTimer(delay, 0, closure, args);
    }

    // const clearTimeout :Function = flash.utils.clearTimeout;
    public function clearTimeout (id:uint) :void {
        this.removeTimer(id);
    }

    // const clearInterval :Function = flash.utils.clearInterval;
    public function clearInterval (id:uint) :void {
        this.removeTimer(id);
    }

    function LzTimeKernelClass() {
    }
}
var LzTimeKernel = new LzTimeKernelClass();

/**
  * This is a helper class for LzTimeKernel. In addition to the flash.utils.Timer
  * class, each timer has got an unique id and holds a reference to a function
  * and an arguments array.
  * @see LzTimeKernelClass#createTimer
  * @see LzTimeKernelClass#removeTimer
  */
final class LzKernelTimer extends Timer {
  #passthrough (toplevel:true) {
    import flash.utils.Timer;
  }#

  #passthrough {
    private static var idCounter :uint = 0;
    private static const MAX_POOL :int = 10;
    private static var timerPool :Array = [];

    /**
     * Use this method instead of the constructor to create an instance
     */
    public static function create () :LzKernelTimer {
        var timer:LzKernelTimer = timerPool.pop() || new LzKernelTimer();
        timer._timerID = idCounter++;
        return timer;
    }

    /**
     * Allow timers to be pooled and reused later
     */
    public static function remove (timer:LzKernelTimer) :void {
        if (timerPool.length < MAX_POOL) {
            timerPool.push(timer);
        }
    }

    public function LzKernelTimer () {
        super(0);
    }

    private var _timerID :uint;
    public function get timerID () :uint {
        return this._timerID;
    }

    private var _closure :Function;
    public function get closure () :Function {
        return this._closure;
    }
    public function set closure (c:Function) :void {
        this._closure = c;
    }

    private var _arguments :Array;
    public function get arguments () :Array {
        return this._arguments;
    }
    public function set arguments (a:Array) :void {
        this._arguments = a;
    }
  }#
}

Change 20091010-bargull-uVg by bargull@dell--p4--2-53 on 2009-10-10 17:05:16
    in /home/Admin/src/svn/openlaszlo/trunk
    for http://svn.openlaszlo.org/openlaszlo/trunk

Summary: ensure pooled timers don't reuse UID

New Features:

Bugs Fixed: LPP-8545 (SWF9: Pooled Timer must not reuse UID)

Technical Reviewer: ptw
QA Reviewer: (pending)
Doc Reviewer: (pending)

Documentation:

Release Notes:

Details:
Moved timer pool from LzTimeKernelClass to LzKernelTimer. Timers should now be created to the static function "create()" and later returned to the timer pool through "remove()". "create()" takes care that timers won't reuse an UID.

Tests:
test case from bug report works in swf9+

git-svn-id: d62bde4b5aa582fdf07c8d403e53e0399a7ed285@15012 fa20e4f9-1d0a-0410-b5f3-dc9c16b8b17c


package goplayer
{
  public class ConfigurationParser
  {
    public static const DEFAULT_SKIN_URL : String = "goplayer-skin.swf"
    public static const DEFAULT_STREAMIO_API_URL : String
      = "http://staging.streamio.com/api"
    public static const DEFAULT_STREAMIO_TRACKER_ID : String = "global"

    public static const VALID_PARAMETERS : Array
      = ["skin", "src", "bitrate",
         "enablertmp", "autoplay", "loop",
         "skin:showchrome", "skin:showtitle",
         "streamio:api", "streamio:tracker"]

    private const result : Configuration = new Configuration

    private var parameters : Object
    private var originalParameterNames : Object

    public function ConfigurationParser
      (parameters : Object, originalParameterNames : Object)
    {
      this.parameters = parameters
      this.originalParameterNames = originalParameterNames
    }

    public function execute() : void
    {
      result.skinURL = getString("skin", DEFAULT_SKIN_URL)
      result.movieID = getStreamioVideoID()
      result.bitratePolicy = getBitratePolicy("bitrate", BitratePolicy.BEST)
      result.enableRTMP = getBoolean("enablertmp", true)
      result.enableAutoplay = getBoolean("autoplay", false)
      result.enableLooping = getBoolean("loop", false)
      result.enableChrome = getBoolean("skin:showchrome", true)
      result.enableTitle = getBoolean("skin:showtitle", true)
      result.apiURL = getString
        ("streamio:api", DEFAULT_STREAMIO_API_URL)
      result.trackerID = getString
        ("streamio:tracker", DEFAULT_STREAMIO_TRACKER_ID)
    }

    private function getStreamioVideoID() : String
    {
      if ("src" in parameters)
        return $getStreamioVideoID()
      else
        {
          debug("Error: Missing “src” parameter.")

          return null
        }
    }

    private function $getStreamioVideoID() : String
    {
      const src : String = parameters["src"]
      const match : Array = src.match(/^streamio:video:(.*)$/)

      if (match != null)
        return match[1]
      else
        {
          debug("Error: Unrecognized “src” value: “" + src + "”; " +
                "must be “streamio:video:foo”.")

          return null
        }
    }

    public static function parse(parameters : Object) : Configuration
    {
      const normalizedParameters : Object = {}
      const originalParameterNames : Object = {}

      for (var name : String in parameters)
        if (VALID_PARAMETERS.indexOf(normalize(name)) == -1)
          reportUnknownParameter(name)
        else
          normalizedParameters[normalize(name)] = parameters[name],
            originalParameterNames[normalize(name)] = name

      const parser : ConfigurationParser = new ConfigurationParser
        (normalizedParameters, originalParameterNames)

      parser.execute()

      return parser.result
    }

    private static function normalize(name : String) : String
    { return name.toLowerCase().replace(/[^a-z:]/g, "") }

    private static function reportUnknownParameter(name : String) : void
    { debug("Error: Unknown parameter: " + name) }

    // -----------------------------------------------------

    private function getString(name : String, fallback : String) : String
    { return name in parameters ? parameters[name] : fallback }

    private function getBoolean
      (name : String, fallback : Boolean) : Boolean
    {
      if (name in parameters)
        return $getBoolean(name, parameters[name], fallback)
      else
        return fallback
    }

    private function $getBoolean
      (name : String, value : String, fallback : Boolean) : Boolean
    {
      try
        { return $$getBoolean(value) }
      catch (error : Error)
        {
          reportInvalidParameter(name, value, ["true", "false"])

          return fallback
        }

      throw new Error
    }

    private function $$getBoolean(value : String) : Boolean
    {
      if (value == "true")
        return true
      else if (value == "false")
        return false
      else
        throw new Error
    }

    // -----------------------------------------------------

    private function getBitratePolicy
      (name : String, fallback : BitratePolicy) : BitratePolicy
    {
      if (name in parameters)
        return $getBitratePolicy(name, parameters[name], fallback)
      else
        return fallback
    }

    private function $getBitratePolicy
      (name : String, value : String,
       fallback : BitratePolicy) : BitratePolicy
    {
      try
        { return $$getBitratePolicy(value) }
      catch (error : Error)
        {
          reportInvalidParameter(name, value, BITRATE_POLICY_VALUES)

          return fallback
        }

      throw new Error
    }

    private const BITRATE_POLICY_VALUES : Array =
      ["<number>kbps", "min", "max", "best"]

    private function $$getBitratePolicy(value : String) : BitratePolicy
    {
      if (value == "max")
        return BitratePolicy.MAX
      else if (value == "min")
        return BitratePolicy.MIN
      else if (value == "best")
        return BitratePolicy.BEST
      else if (Bitrate.parse(value))
        return BitratePolicy.specific(Bitrate.parse(value))
      else
        throw new Error
    }

    // -----------------------------------------------------

    private function reportInvalidParameter
      (name : String, value : String, validValues : Array) : void
    {
      debug("Error: Invalid parameter: " +
            "“" + originalParameterNames[name] + "=" + value + "”; " +
            getInvalidParameterHint(validValues) + ".")
    }

    private function getInvalidParameterHint(values : Array) : String
    { return $getInvalidParameterHint(getQuotedValues(values)) }

    private function $getInvalidParameterHint(values : Array) : String
    {
      return "please use " +
        "either " + values.slice(0, -1).join(", ") + " " +
        "or " + values[values.length - 1]
    }

    private function getQuotedValues(values : Array) : Array
    {
      var result : Array = []

      for each (var value : String in values)
        result.push("“" + value + "”")

      return result
    }
  }
}

package goplayer
{
  public class ConfigurationParser
  {
    public static const DEFAULT_SKIN_URL : String = "goplayer-skin.swf"
    public static const DEFAULT_STREAMIO_API_URL : String
      = "http://streamio.com/api"
    public static const DEFAULT_STREAMIO_TRACKER_ID : String = "global"

    public static const VALID_PARAMETERS : Array
      = ["skin", "src", "bitrate",
         "enablertmp", "autoplay", "loop",
         "skin:showchrome", "skin:showtitle",
         "streamio:api", "streamio:tracker"]

    private const result : Configuration = new Configuration

    private var parameters : Object
    private var originalParameterNames : Object

    public function ConfigurationParser
      (parameters : Object, originalParameterNames : Object)
    {
      this.parameters = parameters
      this.originalParameterNames = originalParameterNames
    }

    public function execute() : void
    {
      result.skinURL = getString("skin", DEFAULT_SKIN_URL)
      result.movieID = getStreamioVideoID()
      result.bitratePolicy = getBitratePolicy("bitrate", BitratePolicy.BEST)
      result.enableRTMP = getBoolean("enablertmp", true)
      result.enableAutoplay = getBoolean("autoplay", false)
      result.enableLooping = getBoolean("loop", false)
      result.enableChrome = getBoolean("skin:showchrome", true)
      result.enableTitle = getBoolean("skin:showtitle", true)
      result.apiURL = getString
        ("streamio:api", DEFAULT_STREAMIO_API_URL)
      result.trackerID = getString
        ("streamio:tracker", DEFAULT_STREAMIO_TRACKER_ID)
    }

    private function getStreamioVideoID() : String
    {
      if ("src" in parameters)
        return $getStreamioVideoID()
      else
        {
          debug("Error: Missing “src” parameter.")

          return null
        }
    }

    private function $getStreamioVideoID() : String
    {
      const src : String = parameters["src"]
      const match : Array = src.match(/^streamio:video:(.*)$/)

      if (match != null)
        return match[1]
      else
        {
          debug("Error: Unrecognized “src” value: “" + src + "”; " +
                "must be “streamio:video:foo”.")

          return null
        }
    }

    public static function parse(parameters : Object) : Configuration
    {
      const normalizedParameters : Object = {}
      const originalParameterNames : Object = {}

      for (var name : String in parameters)
        if (VALID_PARAMETERS.indexOf(normalize(name)) == -1)
          reportUnknownParameter(name)
        else
          normalizedParameters[normalize(name)] = parameters[name],
            originalParameterNames[normalize(name)] = name

      const parser : ConfigurationParser = new ConfigurationParser
        (normalizedParameters, originalParameterNames)

      parser.execute()

      return parser.result
    }

    private static function normalize(name : String) : String
    { return name.toLowerCase().replace(/[^a-z:]/g, "") }

    private static function reportUnknownParameter(name : String) : void
    { debug("Error: Unknown parameter: " + name) }

    // -----------------------------------------------------

    private function getString(name : String, fallback : String) : String
    { return name in parameters ? parameters[name] : fallback }

    private function getBoolean
      (name : String, fallback : Boolean) : Boolean
    {
      if (name in parameters)
        return $getBoolean(name, parameters[name], fallback)
      else
        return fallback
    }

    private function $getBoolean
      (name : String, value : String, fallback : Boolean) : Boolean
    {
      try
        { return $$getBoolean(value) }
      catch (error : Error)
        {
          reportInvalidParameter(name, value, ["true", "false"])

          return fallback
        }

      throw new Error
    }

    private function $$getBoolean(value : String) : Boolean
    {
      if (value == "true")
        return true
      else if (value == "false")
        return false
      else
        throw new Error
    }

    // -----------------------------------------------------

    private function getBitratePolicy
      (name : String, fallback : BitratePolicy) : BitratePolicy
    {
      if (name in parameters)
        return $getBitratePolicy(name, parameters[name], fallback)
      else
        return fallback
    }

    private function $getBitratePolicy
      (name : String, value : String,
       fallback : BitratePolicy) : BitratePolicy
    {
      try
        { return $$getBitratePolicy(value) }
      catch (error : Error)
        {
          reportInvalidParameter(name, value, BITRATE_POLICY_VALUES)

          return fallback
        }

      throw new Error
    }

    private const BITRATE_POLICY_VALUES : Array =
      ["<number>kbps", "min", "max", "best"]

    private function $$getBitratePolicy(value : String) : BitratePolicy
    {
      if (value == "max")
        return BitratePolicy.MAX
      else if (value == "min")
        return BitratePolicy.MIN
      else if (value == "best")
        return BitratePolicy.BEST
      else if (Bitrate.parse(value))
        return BitratePolicy.specific(Bitrate.parse(value))
      else
        throw new Error
    }

    // -----------------------------------------------------

    private function reportInvalidParameter
      (name : String, value : String, validValues : Array) : void
    {
      debug("Error: Invalid parameter: " +
            "“" + originalParameterNames[name] + "=" + value + "”; " +
            getInvalidParameterHint(validValues) + ".")
    }

    private function getInvalidParameterHint(values : Array) : String
    { return $getInvalidParameterHint(getQuotedValues(values)) }

    private function $getInvalidParameterHint(values : Array) : String
    {
      return "please use " +
        "either " + values.slice(0, -1).join(", ") + " " +
        "or " + values[values.length - 1]
    }

    private function getQuotedValues(values : Array) : Array
    {
      var result : Array = []

      for each (var value : String in values)
        result.push("“" + value + "”")

      return result
    }
  }
}

Change default API URL to <http://streamio.com/api>.


package aerys.minko.scene.controller.light
{
	import aerys.minko.scene.data.LightDataProvider;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.scene.node.light.AbstractLight;
	import aerys.minko.scene.node.light.SpotLight;
	import aerys.minko.type.math.Matrix4x4;
	import aerys.minko.type.math.Vector4;

	/**
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public final class SpotLightController extends LightController
	{
		private static const SCREEN_TO_UV	: Matrix4x4	= new Matrix4x4(
			.5,		.0,		.0,		.0,
			.0, 	-.5,	.0,		.0,
			.0,		.0,		1.,		.0,
			.5, 	.5,		.0, 	1.
		);

		private var _worldPosition	: Vector4;
		private var _worldDirection	: Vector4;
		private var _projection		: Matrix4x4;
		private var _worldToScreen	: Matrix4x4;
		private var _worldToUV		: Matrix4x4;

		public function SpotLightController()
		{
			super(SpotLight);

			initialize();
		}

		private function initialize() : void
		{
			_worldDirection = new Vector4();
			_worldPosition	= new Vector4();
			_projection		= new Matrix4x4();
			_worldToScreen	= new Matrix4x4();
			_worldToUV		= new Matrix4x4();
		}

		override protected function lightAddedHandler(ctrl	: LightController,
													  light	: AbstractLight) : void
		{
			super.lightAddedHandler(ctrl, light);

			lightData.setLightProperty('worldDirection', _worldDirection);
			lightData.setLightProperty('worldPosition', _worldPosition);
			lightData.setLightProperty('projection', _projection);
			lightData.setLightProperty('worldToScreen', _worldToScreen);
			lightData.setLightProperty('worldToUV', _worldToUV);
		}

		override protected function lightAddedToSceneHandler(light : AbstractLight,
															 scene : Scene) : void
		{
			super.lightAddedToSceneHandler(light, scene);

			updateProjectionMatrix();
			lightLocalToWorldChangedHandler(light.localToWorld);
			light.localToWorld.changed.add(lightLocalToWorldChangedHandler);
		}

		override protected function lightRemovedFromSceneHandler(light : AbstractLight,
																 scene : Scene) : void
		{
			super.lightRemovedFromSceneHandler(light, scene);

			light.localToWorld.changed.remove(lightLocalToWorldChangedHandler);
		}

		private function lightLocalToWorldChangedHandler(localToWorld : Matrix4x4) : void
		{
			_worldPosition	= localToWorld.getTranslation(_worldPosition);

			_worldDirection.lock();
			_worldDirection	= localToWorld.deltaTransformVector(Vector4.Z_AXIS, _worldDirection);
			_worldDirection.normalize();
			_worldDirection.unlock();

			_worldToScreen.lock()
				.copyFrom(light.worldToLocal)
				.append(_projection)
				.unlock();

			_worldToUV.lock()
				.copyFrom(_worldToScreen)
				.append(SCREEN_TO_UV)
				.unlock();
		}

		override protected function lightDataChangedHandler(lightData		: LightDataProvider,
															propertyName	: String) : void
		{
			super.lightDataChangedHandler(lightData, propertyName);

			propertyName = LightDataProvider.getPropertyName(propertyName);

			if (propertyName == 'shadowZNear' || propertyName == 'shadowZFar'
			    || propertyName == 'outerRadius')
				updateProjectionMatrix();
		}

		private function updateProjectionMatrix() : void
		{
			var zNear		: Number 	= lightData.getLightProperty('shadowZNear');
			var zFar		: Number 	= lightData.getLightProperty('shadowZFar');
			var outerRadius	: Number	= lightData.getLightProperty('outerRadius');
			var fd			: Number 	= 1. / Math.tan(outerRadius * .5);
			var m33			: Number 	= 1. / (zFar - zNear);
			var m43			: Number 	= -zNear / (zFar - zNear);

			_projection.initialize(
				fd, 	0.,		0.,		0.,
				0.,		fd, 	0.,		0.,
				0.,		0.,		m33, 	1.,
				0.,		0.,		m43,	0.
			);

			_worldToScreen.lock()
                .copyFrom(light.worldToLocal)
                .append(_projection)
                .unlock();

			_worldToUV.lock()
                .copyFrom(_worldToScreen)
                .append(SCREEN_TO_UV)
                .unlock();
		}
	}
}

fix coding style

fix coding style


/*
#
# Copyright (c) 2008 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 waranty; 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.collections.ArrayCollection;
    import mx.utils.DescribeTypeCache;
    import mx.utils.ObjectProxy;

    import flash.utils.getQualifiedClassName;
    import flash.utils.getDefinitionByName;
    import flash.xml.XMLNode;

    import mx.utils.object_proxy;
    use namespace object_proxy;

    public class XObjUtils
    {

        public static const DEFAULT_NAMESPACE_PREFIX:String = "_default_";

        /**
         * @private
         */
        private static var CLASS_INFO_CACHE:Object = {};

        /**
         * Returns the local name of an XMLNode.
         *
         * @return The local name of an XMLNode.
         */
        public static function getLocalName(xmlNode:XMLNode):String
        {
            return getNCName(xmlNode.nodeName);
        }

        public static function getNCName(name:String):String
        {
            var myPrefixIndex:int = name.indexOf(":");
            if (myPrefixIndex != -1)
            {
                name = name.substring(myPrefixIndex+1);
            }
            return name;
        }

        public static function encodeElementTag(qname:XObjQName, node:XMLNode):String
        {
            var elementTag:String = XObjUtils.getNCName(qname.localName);

            var prefix:String = node.getPrefixForNamespace(qname.uri);

            if (prefix)
                elementTag =  prefix + ":" + elementTag;

            return elementTag;
        }

        /**
         * Return a Class instance based on a string class name
         * @private
          */
        public static function getClassByName(className:String):Class
        {
            var classReference:Class = null;

            try
            {
                 classReference = getDefinitionByName(className) as Class;
            }
            catch (e:ReferenceError)
            {
                trace("Request for unknown class "+className);
            }

            return classReference;
         }

        private static var typePropertyCache:Object = {};

        public static function isTypeArray(type:Class):Boolean
        {
            if (type == null)
                return false;

            var foo:* = new type();
            return (foo is Array);
        }

        public static function isTypeArrayCollection(type:Class):Boolean
        {
            if (type == null)
                return false;

            var foo:* = new type();
            return (foo is ArrayCollection);
        }

        public static function typeInfoForProperty(object:*, className:String, propName:String):Object
        {
            var isArray:Boolean = false;
            var result:Object = {typeName: null, isArray: false, isArrayCollection: false};

            if (propName == "label")
                trace("stop");

            if (className == "Object" || className == "mx.utils::ObjectProxy")
                return result;

            var propertyCacheKey:String = className + "." + propName;
            var arrayElementType:String;

            result = typePropertyCache[propertyCacheKey];

            if (result == null)
            {
                result = {typeName: null, isArray: false, isArrayCollection: false};

                // go look it up (expensive)
                // very important to use the instance object here, not the classname
                // using the classname results in the typeInfo cache
                // returning class not instance info later on! Bad cache!
                var typeDesc:* = DescribeTypeCache.describeType(object);
                var typeInfo:XML = typeDesc.typeDescription;

                result.typeName = typeInfo..accessor.(@name == propName).@type.toString().replace( /::/, "." );
                if (result.typeName == null || result.typeName == "")
                {
                    result.typeName = typeInfo..variable.(@name == propName).@type.toString().replace( /::/, "." );
                    arrayElementType = typeInfo..variable.(@name == propName).metadata.(@name == 'ArrayElementType').arg.@value.toString().replace( /::/, "." );
                }
                else
                    arrayElementType = typeInfo..accessor.(@name == propName).metadata.(@name == 'ArrayElementType').arg.@value.toString().replace( /::/, "." );

                if (result.typeName == "Array")
                {
                    result.isArray = true;
                    result.typeName = null; // assume generic object unless told otherwise
                }
                else if (result.typeName == "mx.collections.ArrayCollection")
                {
                    result.isArrayCollection = true;
                    result.typeName = null; // assume generic object unless told otherwise
                }

                if (arrayElementType != "")
                {
                    // use type specified
                    result.typeName = arrayElementType;
                }

                if (result.typeName == "Object"
                    || result.typeName == "mx.utils::ObjectProxy"
                    || result.typeName == "Undefined"
                    || result.typeName == "*"
                    || result.typeName == "")
                {
                    result.typeName = null;
                }

                // cache the result for next time
                typePropertyCache[propertyCacheKey] = result;
            }

            return result;
        }

        /**
         * Use our own version of getClassInfo to support various metadata
         * tags we use.  See ObjectUtil.getClassInfo for more info about
         * the baisc functionality of this method.
         */
        public static function getClassInfo(obj:Object,
                                            excludes:Array = null,
                                            options:Object = null):Object
        {
            var n:int;
            var i:int;

            if (obj is ObjectProxy)
                obj = ObjectProxy(obj).object_proxy::object;

            if (options == null)
                options = { includeReadOnly: true, uris: null, includeTransient: true };

            var result:Object;
            var propertyNames:Array = [];
            var cacheKey:String;

            var className:String;
            var classAlias:String;
            var properties:XMLList;
            var prop:XML;
            var dynamic:Boolean = false;
            var metadataInfo:Object;

            if (typeof(obj) == "xml")
            {
                className = "XML";
                properties = obj.text();
                if (properties.length())
                    propertyNames.push("*");
                properties = obj.attributes();
            }
            else
            {
                var classInfo:XML = DescribeTypeCache.describeType(obj).typeDescription;
                className = classInfo.@name.toString();
                classAlias = classInfo.@alias.toString();
                dynamic = (classInfo.@isDynamic.toString() == "true");

                if (options.includeReadOnly)
                    properties = classInfo..accessor.(@access != "writeonly") + classInfo..variable;
                else
                    properties = classInfo..accessor.(@access == "readwrite") + classInfo..variable;

                var numericIndex:Boolean = false;
            }

            // If type is not dynamic, check our cache for class info...
            if (!dynamic)
            {
                cacheKey = getCacheKey(obj, excludes, options);
                result = CLASS_INFO_CACHE[cacheKey];
                if (result != null)
                    return result;
            }

            result = {};
            result["name"] = className;
            result["alias"] = classAlias;
            result["properties"] = propertyNames;
            result["dynamic"] = dynamic;
            result["metadata"] = metadataInfo = recordMetadata(properties);

            var excludeObject:Object = {};
            if (excludes)
            {
                n = excludes.length;
                for (i = 0; i < n; i++)
                {
                    excludeObject[excludes[i]] = 1;
                }
            }

            //TODO this seems slightly fragile, why not use the 'is' operator?
            var isArray:Boolean = (className == "Array");
            var isDict:Boolean  = (className == "flash.utils::Dictionary");

            if (isDict)
            {
                // dictionaries can have multiple keys of the same type,
                // (they can index by reference rather than QName, String, or number),
                // which cannot be looked up by QName, so use references to the actual key
                for (var key:* in obj)
                {
                    propertyNames.push(key);
                }
            }
            else if (dynamic)
            {
                for (var p:String in obj)
                {
                    if (excludeObject[p] != 1)
                    {
                        if (isArray)
                        {
                             var pi:Number = parseInt(p);
                             if (isNaN(pi))
                                propertyNames.push(new QName("", p));
                             else
                                propertyNames.push(pi);
                        }
                        else
                        {
                            propertyNames.push(new QName("", p));
                        }
                    }
                }
                numericIndex = isArray && !isNaN(Number(p));
            }

            if (isArray || isDict || className == "Object")
            {
                // Do nothing since we've already got the dynamic members
            }
            else if (className == "XML")
            {
                n = properties.length();
                for (i = 0; i < n; i++)
                {
                    p = properties[i].name();
                    if (excludeObject[p] != 1)
                        propertyNames.push(new QName("", "@" + p));
                }
            }
            else
            {
                n = properties.length();
                var uris:Array = options.uris;
                var uri:String;
                var qName:QName;
                for (i = 0; i < n; i++)
                {
                    prop = properties[i];
                    p = prop.@name.toString();
                    uri = prop.@uri.toString();

                    if (excludeObject[p] == 1)
                        continue;

                    if (!options.includeTransient && internalHasMetadata(metadataInfo, p, "Transient"))
                        continue;

                    if (internalHasMetadata(metadataInfo, p, "xobjTransient"))
                        continue;

                    if (uris != null)
                    {
                        if (uris.length == 1 && uris[0] == "*")
                        {
                            qName = new QName(uri, p);
                            try
                            {
                                obj[qName]; // access the property to ensure it is supported
                                propertyNames.push();
                            }
                            catch(e:Error)
                            {
                                // don't keep property name
                            }
                        }
                        else
                        {
                            for (var j:int = 0; j < uris.length; j++)
                            {
                                uri = uris[j];
                                if (prop.@uri.toString() == uri)
                                {
                                    qName = new QName(uri, p);
                                    try
                                    {
                                        obj[qName];
                                        propertyNames.push(qName);
                                    }
                                    catch(e:Error)
                                    {
                                        // don't keep property name
                                    }
                                }
                            }
                        }
                    }
                    else if (uri.length == 0)
                    {
                        qName = new QName(uri, p);
                        try
                        {
                            obj[qName];
                            propertyNames.push(qName);
                        }
                        catch(e:Error)
                        {
                            // don't keep property name
                        }
                    }
                }
            }

            propertyNames.sort(Array.CASEINSENSITIVE |
                               (numericIndex ? Array.NUMERIC : 0));

            // dictionary keys can be indexed by an object reference
            // there's a possibility that two keys will have the same toString()
            // so we don't want to remove dupes
            if (!isDict)
            {
                // for Arrays, etc., on the other hand...
                // remove any duplicates, i.e. any items that can't be distingushed by toString()
                for (i = 0; i < propertyNames.length - 1; i++)
                {
                    // the list is sorted so any duplicates should be adjacent
                    // two properties are only equal if both the uri and local name are identical
                    if (propertyNames[i].toString() == propertyNames[i + 1].toString())
                    {
                        propertyNames.splice(i, 1);
                        i--; // back up
                    }
                }
            }

            // For normal, non-dynamic classes we cache the class info
            if (!dynamic)
            {
                cacheKey = getCacheKey(obj, excludes, options);
                CLASS_INFO_CACHE[cacheKey] = result;
            }

            return result;
        }

        /**
         *  @private
         */
        private static function internalHasMetadata(metadataInfo:Object, propName:String, metadataName:String):Boolean
        {
            if (metadataInfo != null)
            {
                var metadata:Object = metadataInfo[propName];
                if (metadata != null)
                {
                    if (metadata[metadataName] != null)
                        return true;
                }
            }
            return false;
        }

        /**
         *  @private
         */
        private static function recordMetadata(properties:XMLList):Object
        {
            var result:Object = null;

            try
            {
                for each (var prop:XML in properties)
                {
                    var propName:String = prop.attribute("name").toString();
                    var metadataList:XMLList = prop.metadata;

                    if (metadataList.length() > 0)
                    {
                        if (result == null)
                            result = {};

                        var metadata:Object = {};
                        result[propName] = metadata;

                        for each (var md:XML in metadataList)
                        {
                            var mdName:String = md.attribute("name").toString();

                            var argsList:XMLList = md.arg;
                            var value:Object = {};

                            for each (var arg:XML in argsList)
                            {
                                var argKey:String = arg.attribute("key").toString();
                                if (argKey != null)
                                {
                                    var argValue:String = arg.attribute("value").toString();
                                    value[argKey] = argValue;
                                }
                            }

                            var existing:Object = metadata[mdName];
                            if (existing != null)
                            {
                                var existingArray:Array;
                                if (existing is Array)
                                    existingArray = existing as Array;
                                else
                                    existingArray = [];
                                existingArray.push(value);
                                existing = existingArray;
                            }
                            else
                            {
                                existing = value;
                            }
                            metadata[mdName] = existing;
                        }
                    }
                }
            }
            catch(e:Error)
            {
            }

            return result;
        }

        /**
         *  @private
         */
        private static function getCacheKey(o:Object, excludes:Array = null, options:Object = null):String
        {
            var key:String = getQualifiedClassName(o);

            if (excludes != null)
            {
                for (var i:uint = 0; i < excludes.length; i++)
                {
                    var excl:String = excludes[i] as String;
                    if (excl != null)
                        key += excl;
                }
            }

            if (options != null)
            {
                for (var flag:String in options)
                {
                    key += flag;
                    var value:String = options[flag] as String;
                    if (value != null)
                        key += value;
                }
            }
            return key;
        }
    }
}

/*
#
# Copyright (c) 2008 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 waranty; 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.collections.ArrayCollection;
    import mx.utils.DescribeTypeCache;
    import mx.utils.ObjectProxy;

    import flash.utils.getQualifiedClassName;
    import flash.utils.getDefinitionByName;
    import flash.xml.XMLNode;

    import mx.utils.object_proxy;
    use namespace object_proxy;

    public class XObjUtils
    {

        public static const DEFAULT_NAMESPACE_PREFIX:String = "_default_";

        /**
         * @private
         */
        private static var CLASS_INFO_CACHE:Object = {};

        /**
         * Returns the local name of an XMLNode.
         *
         * @return The local name of an XMLNode.
         */
        public static function getLocalName(xmlNode:XMLNode):String
        {
            return getNCName(xmlNode.nodeName);
        }

        public static function getNCName(name:String):String
        {
            var myPrefixIndex:int = name.indexOf(":");
            if (myPrefixIndex != -1)
            {
                name = name.substring(myPrefixIndex+1);
            }
            return name;
        }

        public static function encodeElementTag(qname:XObjQName, node:XMLNode):String
        {
            var elementTag:String = XObjUtils.getNCName(qname.localName);

            var prefix:String = node.getPrefixForNamespace(qname.uri);

            if (prefix)
                elementTag =  prefix + ":" + elementTag;

            return elementTag;
        }

        /**
         * Return a Class instance based on a string class name
         * @private
          */
        public static function getClassByName(className:String):Class
        {
            var classReference:Class = null;

            try
            {
                 classReference = getDefinitionByName(className) as Class;
            }
            catch (e:ReferenceError)
            {
                trace("Request for unknown class "+className);
            }

            return classReference;
         }

        private static var typePropertyCache:Object = {};

        public static function isTypeArray(type:Class):Boolean
        {
            if (type == null)
                return false;

            var foo:* = new type();
            return (foo is Array);
        }

        public static function isTypeArrayCollection(type:Class):Boolean
        {
            if (type == null)
                return false;

            var foo:* = new type();
            return (foo is ArrayCollection);
        }

        public static function typeInfoForProperty(object:*, className:String, propName:String):Object
        {
            var isArray:Boolean = false;
            var result:Object = {typeName: null, isArray: false, isArrayCollection: false};

            if (className == "Object" || className == "mx.utils::ObjectProxy")
                return result;

            var propertyCacheKey:String = className + "." + propName;
            var arrayElementType:String;

            result = typePropertyCache[propertyCacheKey];

            if (result == null)
            {
                result = {typeName: null, isArray: false, isArrayCollection: false};

                // go look it up (expensive)
                // very important to use the instance object here, not the classname
                // using the classname results in the typeInfo cache
                // returning class not instance info later on! Bad cache!
                var typeDesc:* = DescribeTypeCache.describeType(object);
                var typeInfo:XML = typeDesc.typeDescription;

                result.typeName = typeInfo..accessor.(@name == propName).@type.toString().replace( /::/, "." );
                if (result.typeName == null || result.typeName == "")
                {
                    result.typeName = typeInfo..variable.(@name == propName).@type.toString().replace( /::/, "." );
                    arrayElementType = typeInfo..variable.(@name == propName).metadata.(@name == 'ArrayElementType').arg.@value.toString().replace( /::/, "." );
                }
                else
                    arrayElementType = typeInfo..accessor.(@name == propName).metadata.(@name == 'ArrayElementType').arg.@value.toString().replace( /::/, "." );

                if (result.typeName == "Array")
                {
                    result.isArray = true;
                    result.typeName = null; // assume generic object unless told otherwise
                }
                else if (result.typeName == "mx.collections.ArrayCollection")
                {
                    result.isArrayCollection = true;
                    result.typeName = null; // assume generic object unless told otherwise
                }

                if (arrayElementType != "")
                {
                    // use type specified
                    result.typeName = arrayElementType;
                }

                if (result.typeName == "Object"
                    || result.typeName == "mx.utils::ObjectProxy"
                    || result.typeName == "Undefined"
                    || result.typeName == "*"
                    || result.typeName == "")
                {
                    result.typeName = null;
                }

                // cache the result for next time
                typePropertyCache[propertyCacheKey] = result;
            }

            return result;
        }

        /**
         * Use our own version of getClassInfo to support various metadata
         * tags we use.  See ObjectUtil.getClassInfo for more info about
         * the baisc functionality of this method.
         */
        public static function getClassInfo(obj:Object,
                                            excludes:Array = null,
                                            options:Object = null):Object
        {
            var n:int;
            var i:int;

            if (obj is ObjectProxy)
                obj = ObjectProxy(obj).object_proxy::object;

            if (options == null)
                options = { includeReadOnly: true, uris: null, includeTransient: true };

            var result:Object;
            var propertyNames:Array = [];
            var cacheKey:String;

            var className:String;
            var classAlias:String;
            var properties:XMLList;
            var prop:XML;
            var dynamic:Boolean = false;
            var metadataInfo:Object;

            if (typeof(obj) == "xml")
            {
                className = "XML";
                properties = obj.text();
                if (properties.length())
                    propertyNames.push("*");
                properties = obj.attributes();
            }
            else
            {
                var classInfo:XML = DescribeTypeCache.describeType(obj).typeDescription;
                className = classInfo.@name.toString();
                classAlias = classInfo.@alias.toString();
                dynamic = (classInfo.@isDynamic.toString() == "true");

                if (options.includeReadOnly)
                    properties = classInfo..accessor.(@access != "writeonly") + classInfo..variable;
                else
                    properties = classInfo..accessor.(@access == "readwrite") + classInfo..variable;

                var numericIndex:Boolean = false;
            }

            // If type is not dynamic, check our cache for class info...
            if (!dynamic)
            {
                cacheKey = getCacheKey(obj, excludes, options);
                result = CLASS_INFO_CACHE[cacheKey];
                if (result != null)
                    return result;
            }

            result = {};
            result["name"] = className;
            result["alias"] = classAlias;
            result["properties"] = propertyNames;
            result["dynamic"] = dynamic;
            result["metadata"] = metadataInfo = recordMetadata(properties);

            var excludeObject:Object = {};
            if (excludes)
            {
                n = excludes.length;
                for (i = 0; i < n; i++)
                {
                    excludeObject[excludes[i]] = 1;
                }
            }

            //TODO this seems slightly fragile, why not use the 'is' operator?
            var isArray:Boolean = (className == "Array");
            var isDict:Boolean  = (className == "flash.utils::Dictionary");

            if (isDict)
            {
                // dictionaries can have multiple keys of the same type,
                // (they can index by reference rather than QName, String, or number),
                // which cannot be looked up by QName, so use references to the actual key
                for (var key:* in obj)
                {
                    propertyNames.push(key);
                }
            }
            else if (dynamic)
            {
                for (var p:String in obj)
                {
                    if (excludeObject[p] != 1)
                    {
                        if (isArray)
                        {
                             var pi:Number = parseInt(p);
                             if (isNaN(pi))
                                propertyNames.push(new QName("", p));
                             else
                                propertyNames.push(pi);
                        }
                        else
                        {
                            propertyNames.push(new QName("", p));
                        }
                    }
                }
                numericIndex = isArray && !isNaN(Number(p));
            }

            if (isArray || isDict || className == "Object")
            {
                // Do nothing since we've already got the dynamic members
            }
            else if (className == "XML")
            {
                n = properties.length();
                for (i = 0; i < n; i++)
                {
                    p = properties[i].name();
                    if (excludeObject[p] != 1)
                        propertyNames.push(new QName("", "@" + p));
                }
            }
            else
            {
                n = properties.length();
                var uris:Array = options.uris;
                var uri:String;
                var qName:QName;
                for (i = 0; i < n; i++)
                {
                    prop = properties[i];
                    p = prop.@name.toString();
                    uri = prop.@uri.toString();

                    if (excludeObject[p] == 1)
                        continue;

                    if (!options.includeTransient && internalHasMetadata(metadataInfo, p, "Transient"))
                        continue;

                    if (internalHasMetadata(metadataInfo, p, "xobjTransient"))
                        continue;

                    if (uris != null)
                    {
                        if (uris.length == 1 && uris[0] == "*")
                        {
                            qName = new QName(uri, p);
                            try
                            {
                                obj[qName]; // access the property to ensure it is supported
                                propertyNames.push();
                            }
                            catch(e:Error)
                            {
                                // don't keep property name
                            }
                        }
                        else
                        {
                            for (var j:int = 0; j < uris.length; j++)
                            {
                                uri = uris[j];
                                if (prop.@uri.toString() == uri)
                                {
                                    qName = new QName(uri, p);
                                    try
                                    {
                                        obj[qName];
                                        propertyNames.push(qName);
                                    }
                                    catch(e:Error)
                                    {
                                        // don't keep property name
                                    }
                                }
                            }
                        }
                    }
                    else if (uri.length == 0)
                    {
                        qName = new QName(uri, p);
                        try
                        {
                            obj[qName];
                            propertyNames.push(qName);
                        }
                        catch(e:Error)
                        {
                            // don't keep property name
                        }
                    }
                }
            }

            propertyNames.sort(Array.CASEINSENSITIVE |
                               (numericIndex ? Array.NUMERIC : 0));

            // dictionary keys can be indexed by an object reference
            // there's a possibility that two keys will have the same toString()
            // so we don't want to remove dupes
            if (!isDict)
            {
                // for Arrays, etc., on the other hand...
                // remove any duplicates, i.e. any items that can't be distingushed by toString()
                for (i = 0; i < propertyNames.length - 1; i++)
                {
                    // the list is sorted so any duplicates should be adjacent
                    // two properties are only equal if both the uri and local name are identical
                    if (propertyNames[i].toString() == propertyNames[i + 1].toString())
                    {
                        propertyNames.splice(i, 1);
                        i--; // back up
                    }
                }
            }

            // For normal, non-dynamic classes we cache the class info
            if (!dynamic)
            {
                cacheKey = getCacheKey(obj, excludes, options);
                CLASS_INFO_CACHE[cacheKey] = result;
            }

            return result;
        }

        /**
         *  @private
         */
        private static function internalHasMetadata(metadataInfo:Object, propName:String, metadataName:String):Boolean
        {
            if (metadataInfo != null)
            {
                var metadata:Object = metadataInfo[propName];
                if (metadata != null)
                {
                    if (metadata[metadataName] != null)
                        return true;
                }
            }
            return false;
        }

        /**
         *  @private
         */
        private static function recordMetadata(properties:XMLList):Object
        {
            var result:Object = null;

            try
            {
                for each (var prop:XML in properties)
                {
                    var propName:String = prop.attribute("name").toString();
                    var metadataList:XMLList = prop.metadata;

                    if (metadataList.length() > 0)
                    {
                        if (result == null)
                            result = {};

                        var metadata:Object = {};
                        result[propName] = metadata;

                        for each (var md:XML in metadataList)
                        {
                            var mdName:String = md.attribute("name").toString();

                            var argsList:XMLList = md.arg;
                            var value:Object = {};

                            for each (var arg:XML in argsList)
                            {
                                var argKey:String = arg.attribute("key").toString();
                                if (argKey != null)
                                {
                                    var argValue:String = arg.attribute("value").toString();
                                    value[argKey] = argValue;
                                }
                            }

                            var existing:Object = metadata[mdName];
                            if (existing != null)
                            {
                                var existingArray:Array;
                                if (existing is Array)
                                    existingArray = existing as Array;
                                else
                                    existingArray = [];
                                existingArray.push(value);
                                existing = existingArray;
                            }
                            else
                            {
                                existing = value;
                            }
                            metadata[mdName] = existing;
                        }
                    }
                }
            }
            catch(e:Error)
            {
            }

            return result;
        }

        /**
         *  @private
         */
        private static function getCacheKey(o:Object, excludes:Array = null, options:Object = null):String
        {
            var key:String = getQualifiedClassName(o);

            if (excludes != null)
            {
                for (var i:uint = 0; i < excludes.length; i++)
                {
                    var excl:String = excludes[i] as String;
                    if (excl != null)
                        key += excl;
                }
            }

            if (options != null)
            {
                for (var flag:String in options)
                {
                    key += flag;
                    var value:String = options[flag] as String;
                    if (value != null)
                        key += value;
                }
            }
            return key;
        }
    }
}

Remove debug trace

Remove debug trace