/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mangui.hls.model {
    import org.mangui.hls.demux.ID3Tag;
    import org.mangui.hls.flv.FLVTag;
    import org.mangui.hls.utils.AES;
    import org.mangui.hls.utils.PTS;

    import flash.utils.ByteArray;

    /** Fragment Data. **/
    public class FragmentData {
        /** valid fragment **/
        public var valid : Boolean;
        /** fragment byte array **/
        public var bytes : ByteArray;
        /* Total bytes this Fragment _will_ have */
        public var bytesTotal: int;
        /** bytes Loaded **/
        public var bytesLoaded : int;
        /** AES decryption instance **/
        public var decryptAES : AES;
        /** Start PTS of this chunk. **/
        public var pts_start : Number;
        /** computed Start PTS of this chunk. **/
        public var pts_start_computed : Number;
        /** min/max audio/video PTS/DTS of this chunk. **/
        public var pts_min_audio : Number;
        public var pts_max_audio : Number;
        public var pts_min_video : Number;
        public var pts_max_video : Number;
        public var dts_min : Number;
        /** audio/video found ? */
        public var audio_found : Boolean;
        public var video_found : Boolean;
        /** tag related stuff */
        public var metadata_tag_injected : Boolean;
        private var tags_pts_min_audio : Number;
        private var tags_pts_max_audio : Number;
        private var tags_pts_min_video : Number;
        private var tags_pts_max_video : Number;
        private var tags_audio_found : Boolean;
        private var tags_video_found : Boolean;
        public var tags : Vector.<FLVTag>;
        /* video dimension */
        public var video_width : int;
        public var video_height : int;
        /* is fragment loaded selected by autolevel algo */
        public var auto_level : Boolean;
        /* ID3 tags linked to this fragment */
        public var id3_tags : Vector.<ID3Tag>;

        /**  tag duration */
        private var audio_tag_duration : Number;
        private var video_tag_duration : Number;
        private var audio_tag_last_dts : Number;
        private var video_tag_last_dts : Number;

        /** Fragment metrics **/
        public function FragmentData() {
            this.pts_start = NaN;
            this.pts_start_computed = NaN;
            this.valid = true;
            this.video_width = 0;
            this.video_height = 0;
        };

        public function appendTags(tags : Vector.<FLVTag>) : void {
            // Audio PTS/DTS normalization + min/max computation
            for each (var tag : FLVTag in tags) {
                tag.pts = PTS.normalize(pts_start_computed, tag.pts);
                tag.dts = PTS.normalize(pts_start_computed, tag.dts);
                dts_min = Math.min(dts_min, tag.dts);
                switch( tag.type ) {
                    case FLVTag.AAC_RAW:
                    case FLVTag.AAC_HEADER:
                    case FLVTag.MP3_RAW:
                        audio_found = true;
                        tags_audio_found = true;
                        audio_tag_duration = tag.dts - audio_tag_last_dts;
                        audio_tag_last_dts = tag.dts;
                        tags_pts_min_audio = Math.min(tags_pts_min_audio, tag.pts);
                        tags_pts_max_audio = Math.max(tags_pts_max_audio, tag.pts);
                        pts_min_audio = Math.min(pts_min_audio, tag.pts);
                        pts_max_audio = Math.max(pts_max_audio, tag.pts);
                        break;
                    case FLVTag.AVC_HEADER:
                    case FLVTag.AVC_NALU:
                        video_found = true;
                        tags_video_found = true;
                        video_tag_duration = tag.dts - video_tag_last_dts;
                        video_tag_last_dts = tag.dts;
                        tags_pts_min_video = Math.min(tags_pts_min_video, tag.pts);
                        tags_pts_max_video = Math.max(tags_pts_max_video, tag.pts);
                        pts_min_video = Math.min(pts_min_video, tag.pts);
                        pts_max_video = Math.max(pts_max_video, tag.pts);
                        break;
                    case FLVTag.DISCONTINUITY:
                    case FLVTag.METADATA:
                    default:
                        break;
                }
                this.tags.push(tag);
            }
        }

        public function flushTags() : void {
            // clean-up tags
            tags = new Vector.<FLVTag>();
            tags_audio_found = tags_video_found = false;
            metadata_tag_injected = false;
            pts_min_audio = pts_min_video = dts_min = tags_pts_min_audio = tags_pts_min_video = Number.POSITIVE_INFINITY;
            pts_max_audio = pts_max_video = tags_pts_max_audio = tags_pts_max_video = Number.NEGATIVE_INFINITY;
            audio_found = video_found = tags_audio_found = tags_video_found = false;
        }

        public function shiftTags() : void {
            tags = new Vector.<FLVTag>();
            if (tags_audio_found) {
                tags_pts_min_audio = tags_pts_max_audio;
                tags_audio_found = false;
            }
            if (tags_video_found) {
                tags_pts_min_video = tags_pts_max_video;
                tags_video_found = false;
            }
        }

        public function get pts_min() : Number {
            if (audio_found) {
                return pts_min_audio;
            } else {
                return pts_min_video;
            }
        }

        public function get pts_max() : Number {
            if (audio_found) {
                return pts_max_audio;
            } else {
                return pts_max_video;
            }
        }

        public function get tag_duration() : Number {
            var duration : Number;
            if (audio_found) {
                duration = audio_tag_duration;
            } else {
                duration = video_tag_duration;
            }
            if(isNaN(duration)) {
                duration = 0;
            }
            return duration;
        }

        public function get tag_pts_min() : Number {
            if (audio_found) {
                return tags_pts_min_audio;
            } else {
                return tags_pts_min_video;
            }
        }

        public function get tag_pts_max() : Number {
            if (audio_found) {
                return tags_pts_max_audio;
            } else {
                return tags_pts_max_video;
            }
        }

        public function get tag_pts_start_offset() : Number {
            if (tags_audio_found) {
                return tags_pts_min_audio - pts_min_audio;
            } else {
                return tags_pts_min_video - pts_min_video;
            }
        }

        public function get tag_pts_end_offset() : Number {
            if (tags_audio_found) {
                return tags_pts_max_audio - pts_min_audio;
            } else {
                return tags_pts_max_video - pts_min_video;
            }
        }
    }
}

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mangui.hls.model {
    import org.mangui.hls.demux.ID3Tag;
    import org.mangui.hls.flv.FLVTag;
    import org.mangui.hls.utils.AES;
    import org.mangui.hls.utils.PTS;

    import flash.utils.ByteArray;

    /** Fragment Data. **/
    public class FragmentData {
        /** valid fragment **/
        public var valid : Boolean;
        /** fragment byte array **/
        public var bytes : ByteArray;
        /* Total bytes this Fragment _will_ have */
        public var bytesTotal: int;
        /** bytes Loaded **/
        public var bytesLoaded : int;
        /** AES decryption instance **/
        public var decryptAES : AES;
        /** Start PTS of this chunk. **/
        public var pts_start : Number;
        /** computed Start PTS of this chunk. **/
        public var pts_start_computed : Number;
        /** min/max audio/video PTS/DTS of this chunk. **/
        public var pts_min_audio : Number;
        public var pts_max_audio : Number;
        public var pts_min_video : Number;
        public var pts_max_video : Number;
        public var dts_min : Number;
        /** audio/video found ? */
        public var audio_found : Boolean;
        public var video_found : Boolean;
        /** tag related stuff */
        public var metadata_tag_injected : Boolean;
        private var tags_pts_min_audio : Number;
        private var tags_pts_max_audio : Number;
        private var tags_pts_min_video : Number;
        private var tags_pts_max_video : Number;
        private var tags_audio_found : Boolean;
        private var tags_video_found : Boolean;
        public var tags : Vector.<FLVTag>;
        /* video dimension */
        public var video_width : int;
        public var video_height : int;
        /* is fragment loaded selected by autolevel algo */
        public var auto_level : Boolean;
        /* ID3 tags linked to this fragment */
        public var id3_tags : Vector.<ID3Tag>;

        /** Whether this Fragment starts with IDR **/
        public var starts_with_idr : Boolean;

        /** PTS of earliest AVC_HEADER */
        public var pts_min_video_header : Number;

        /**  tag duration */
        private var audio_tag_duration : Number;
        private var video_tag_duration : Number;
        private var audio_tag_last_dts : Number;
        private var video_tag_last_dts : Number;

        /** Fragment metrics **/
        public function FragmentData() {
            this.pts_start = NaN;
            this.pts_start_computed = NaN;
            this.valid = true;
            this.video_width = 0;
            this.video_height = 0;
            this.starts_with_idr = false;
            this.pts_min_video_header = NaN;
        };

        public function appendTags(tags : Vector.<FLVTag>) : void {
            // Audio PTS/DTS normalization + min/max computation
            for each (var tag : FLVTag in tags) {
                tag.pts = PTS.normalize(pts_start_computed, tag.pts);
                tag.dts = PTS.normalize(pts_start_computed, tag.dts);
                dts_min = Math.min(dts_min, tag.dts);
                switch( tag.type ) {
                    case FLVTag.AAC_RAW:
                    case FLVTag.AAC_HEADER:
                    case FLVTag.MP3_RAW:
                        audio_found = true;
                        tags_audio_found = true;
                        audio_tag_duration = tag.dts - audio_tag_last_dts;
                        audio_tag_last_dts = tag.dts;
                        tags_pts_min_audio = Math.min(tags_pts_min_audio, tag.pts);
                        tags_pts_max_audio = Math.max(tags_pts_max_audio, tag.pts);
                        pts_min_audio = Math.min(pts_min_audio, tag.pts);
                        pts_max_audio = Math.max(pts_max_audio, tag.pts);
                        break;
                    case FLVTag.AVC_HEADER:
                        if (isNaN(pts_min_video_header)) {
                            pts_min_video_header = tag.pts;
                        }
                    case FLVTag.AVC_NALU:
                        video_found = true;
                        tags_video_found = true;
                        video_tag_duration = tag.dts - video_tag_last_dts;
                        video_tag_last_dts = tag.dts;
                        tags_pts_min_video = Math.min(tags_pts_min_video, tag.pts);
                        tags_pts_max_video = Math.max(tags_pts_max_video, tag.pts);
                        pts_min_video = Math.min(pts_min_video, tag.pts);
                        pts_max_video = Math.max(pts_max_video, tag.pts);
                        starts_with_idr = !isNaN(pts_min_video_header) && pts_min_video_header <= tag.pts;
                        break;
                    case FLVTag.DISCONTINUITY:
                    case FLVTag.METADATA:
                    default:
                        break;
                }
                this.tags.push(tag);
            }
        }

        public function flushTags() : void {
            // clean-up tags
            tags = new Vector.<FLVTag>();
            tags_audio_found = tags_video_found = false;
            metadata_tag_injected = false;
            pts_min_audio = pts_min_video = dts_min = tags_pts_min_audio = tags_pts_min_video = Number.POSITIVE_INFINITY;
            pts_max_audio = pts_max_video = tags_pts_max_audio = tags_pts_max_video = Number.NEGATIVE_INFINITY;
            audio_found = video_found = tags_audio_found = tags_video_found = false;
            starts_with_idr = false;
            pts_min_video_header = NaN;
        }

        public function shiftTags() : void {
            tags = new Vector.<FLVTag>();
            if (tags_audio_found) {
                tags_pts_min_audio = tags_pts_max_audio;
                tags_audio_found = false;
            }
            if (tags_video_found) {
                tags_pts_min_video = tags_pts_max_video;
                tags_video_found = false;
            }
        }

        public function get pts_min() : Number {
            if (audio_found) {
                return pts_min_audio;
            } else {
                return pts_min_video;
            }
        }

        public function get pts_max() : Number {
            if (audio_found) {
                return pts_max_audio;
            } else {
                return pts_max_video;
            }
        }

        public function get tag_duration() : Number {
            var duration : Number;
            if (audio_found) {
                duration = audio_tag_duration;
            } else {
                duration = video_tag_duration;
            }
            if(isNaN(duration)) {
                duration = 0;
            }
            return duration;
        }

        public function get tag_pts_min() : Number {
            if (audio_found) {
                return tags_pts_min_audio;
            } else {
                return tags_pts_min_video;
            }
        }

        public function get tag_pts_max() : Number {
            if (audio_found) {
                return tags_pts_max_audio;
            } else {
                return tags_pts_max_video;
            }
        }

        public function get tag_pts_start_offset() : Number {
            if (tags_audio_found) {
                return tags_pts_min_audio - pts_min_audio;
            } else {
                return tags_pts_min_video - pts_min_video;
            }
        }

        public function get tag_pts_end_offset() : Number {
            if (tags_audio_found) {
                return tags_pts_max_audio - pts_min_audio;
            } else {
                return tags_pts_max_video - pts_min_video;
            }
        }
    }
}

[FragmentData] Add `starts_with_idr` and `pts_min_video_header`


package aerys.minko.render.material.phong
{
	import aerys.minko.ns.minko_lighting;
	import aerys.minko.render.Effect;
	import aerys.minko.render.RenderTarget;
	import aerys.minko.render.Viewport;
	import aerys.minko.render.resource.texture.CubeTextureResource;
	import aerys.minko.render.resource.texture.TextureResource;
	import aerys.minko.render.shader.Shader;
	import aerys.minko.scene.data.LightDataProvider;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.type.binding.DataBindings;

	import flash.display.BitmapData;

	public class AbstractShadowMappingEffect extends Effect
	{
		use namespace minko_lighting;

		private const SHADOW_FACTORIES : Vector.<Function> = new <Function>[
			manageNoShadowing,				// 0: ShadowMappingType.NONE
			manageMatrixShadowing,			// 1: ShadowMappingType.MATRIX
			manageDualParaboloidShadowing,	// 2: ShadowMappingType.DUAL_PARABOLOID
			manageCubicShadowing			// 3: ShadowMappingType.CUBIC
		];

		private var _scene				: Scene;
		private var _renderingPass		: Shader;
		private var _watchedProperties	: Vector.<String>;

		private var _updatePasses		: Boolean;

		public function get scene() : Scene
		{
			return _scene;
		}

		public function AbstractShadowMappingEffect(scene 			: Scene,
													renderingShader : Shader)
		{
			_renderingPass		= renderingShader;
			_watchedProperties	= new Vector.<String>();
			_scene				= scene;
			_updatePasses		= true;

			scene.enterFrame.add(onSceneEnterFrame);
		}

		private function onSceneEnterFrame(scene		: Scene,
										   viewport		: Viewport,
										   destination	: BitmapData,
										   timer		: uint) : void
		{
			if (_updatePasses)
			{
				updatePasses();
				_updatePasses = false;
			}
		}

		private function propertyChangedHandler(sceneBindings	: DataBindings,
												propertyName	: String,
												oldValue		: Object,
												newValue		: Object) : void
		{
			_updatePasses = true;
		}

		private function updatePasses() : void
		{
			var passes			: Vector.<Shader>	= new <Shader>[];
			var sceneBindings	: DataBindings		= _scene.bindings;
			var shader			: Shader			= null;
			var renderTarget	: RenderTarget		= null;

			while (_watchedProperties.length != 0)
				sceneBindings.removeCallback(_watchedProperties.pop(), propertyChangedHandler);

			for (var lightId : uint = 0; ; ++lightId)
			{
				if (!lightPropertyExists(lightId, 'type'))
					break ;

				var shadowCastingPropertyName : String = LightDataProvider.getLightPropertyName(
					'shadowCastingType',
					lightId
				);

				_watchedProperties.push(shadowCastingPropertyName);
				sceneBindings.addCallback(shadowCastingPropertyName, propertyChangedHandler);

				if (sceneBindings.propertyExists(shadowCastingPropertyName))
					SHADOW_FACTORIES[sceneBindings.getProperty(shadowCastingPropertyName)](lightId, passes);
			}

			passes.push(_renderingPass);

			setPasses(passes);
		}

		private function manageNoShadowing(lightId : uint, passes : Vector.<Shader>) : void
		{
			// nothing to do here, no extra rendering is necessary
		}

		private function manageMatrixShadowing(lightId : uint, passes : Vector.<Shader>) : void
		{
			var textureResource : TextureResource	= getLightProperty(lightId, 'shadowMap');
			var renderTarget	: RenderTarget		= new RenderTarget(
				textureResource.width, textureResource.height, textureResource, 0, 0xffffffff
			);

			passes.push(new MatrixShadowMapShader(lightId, lightId + 1, renderTarget));
		}

		private function manageDualParaboloidShadowing(lightId : uint, passes : Vector.<Shader>) : void
		{
			var frontTextureResource : TextureResource	= getLightProperty(lightId, 'shadowMapDPFront');
			var backTextureResource	 : TextureResource	= getLightProperty(lightId, 'shadowMapDPBack');
			var size				 : uint				= frontTextureResource.width;
			var frontRenderTarget	 : RenderTarget		= new RenderTarget(size, size, frontTextureResource, 0, 0xffffffff);
			var backRenderTarget	 : RenderTarget		= new RenderTarget(size, size, backTextureResource, 0, 0xffffffff);

			passes.push(
				new ParaboloidShadowMapShader(lightId, true, lightId + 0.5, frontRenderTarget),
				new ParaboloidShadowMapShader(lightId, false, lightId + 1, backRenderTarget)
			);
		}

		private function manageCubicShadowing(lightId : uint, passes : Vector.<Shader>) : void
		{
			var textureResource	: CubeTextureResource	= getLightProperty(lightId, 'shadowMapCube');
			var size			: uint					= textureResource.size;
			var renderTarget0	: RenderTarget			= new RenderTarget(size, size, textureResource, 0, 0xffffffff);
			var renderTarget1	: RenderTarget			= new RenderTarget(size, size, textureResource, 1, 0xffffffff);
			var renderTarget2	: RenderTarget			= new RenderTarget(size, size, textureResource, 2, 0xffffffff);
			var renderTarget3	: RenderTarget			= new RenderTarget(size, size, textureResource, 3, 0xffffffff);
			var renderTarget4	: RenderTarget			= new RenderTarget(size, size, textureResource, 4, 0xffffffff);
			var renderTarget5	: RenderTarget			= new RenderTarget(size, size, textureResource, 5, 0xffffffff);

			passes.push(
				new CubeShadowMapShader(lightId, 0, lightId + 0.1, renderTarget0),
				new CubeShadowMapShader(lightId, 1, lightId + 0.2, renderTarget1),
				new CubeShadowMapShader(lightId, 2, lightId + 0.3, renderTarget2),
				new CubeShadowMapShader(lightId, 3, lightId + 0.4, renderTarget3),
				new CubeShadowMapShader(lightId, 4, lightId + 0.5, renderTarget4),
				new CubeShadowMapShader(lightId, 5, lightId + 0.6, renderTarget5)
			);
		}

		private function lightPropertyExists(lightId : uint, propertyName : String) : Boolean
		{
			return _scene.bindings.propertyExists(
				LightDataProvider.getLightPropertyName(propertyName, lightId)
			);
		}

		private function getLightProperty(lightId : uint, propertyName : String) : *
		{
			return _scene.bindings.getProperty(
				LightDataProvider.getLightPropertyName(propertyName, lightId)
			);
		}
	}
}

package aerys.minko.render.material.phong
{
	import aerys.minko.ns.minko_lighting;
	import aerys.minko.render.Effect;
	import aerys.minko.render.RenderTarget;
	import aerys.minko.render.Viewport;
	import aerys.minko.render.resource.texture.CubeTextureResource;
	import aerys.minko.render.resource.texture.TextureResource;
	import aerys.minko.render.shader.Shader;
	import aerys.minko.scene.data.LightDataProvider;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.type.binding.DataBindings;

	import flash.display.BitmapData;

	public class AbstractShadowMappingEffect extends Effect
	{
		use namespace minko_lighting;

		private const SHADOW_FACTORIES : Vector.<Function> = new <Function>[
			manageNoShadowing,				// 0: ShadowMappingType.NONE
			manageMatrixShadowing,			// 1: ShadowMappingType.MATRIX
			manageDualParaboloidShadowing,	// 2: ShadowMappingType.DUAL_PARABOLOID
			manageCubicShadowing			// 3: ShadowMappingType.CUBIC
		];

		private var _scene				: Scene;
		private var _renderingPass		: Shader;
		private var _watchedProperties	: Vector.<String>;

		public function get scene() : Scene
		{
			return _scene;
		}

		public function AbstractShadowMappingEffect(scene 			: Scene,
													renderingShader : Shader)
		{
			_renderingPass		= renderingShader;
			_watchedProperties	= new Vector.<String>();
			_scene				= scene;

            scene.enterFrame.add(sceneEnterFrameHandler);
		}

		private function sceneEnterFrameHandler(scene		: Scene,
                                                viewport	: Viewport,
                                                destination	: BitmapData,
                                                timer		: uint) : void
		{
            scene.enterFrame.remove(sceneEnterFrameHandler);

			updatePasses();
		}

		private function propertyChangedHandler(sceneBindings	: DataBindings,
												propertyName	: String,
												oldValue		: Object,
												newValue		: Object) : void
		{
            scene.enterFrame.add(sceneEnterFrameHandler);
		}

		private function updatePasses() : void
		{
			var passes			: Vector.<Shader>	= new <Shader>[];
			var sceneBindings	: DataBindings		= _scene.bindings;
			var shader			: Shader			= null;
			var renderTarget	: RenderTarget		= null;

			while (_watchedProperties.length != 0)
				sceneBindings.removeCallback(_watchedProperties.pop(), propertyChangedHandler);

			for (var lightId : uint = 0; ; ++lightId)
			{
				if (!lightPropertyExists(lightId, 'type'))
					break ;

				var shadowCastingPropertyName : String = LightDataProvider.getLightPropertyName(
					'shadowCastingType',
					lightId
				);

				_watchedProperties.push(shadowCastingPropertyName);
				sceneBindings.addCallback(shadowCastingPropertyName, propertyChangedHandler);

				if (sceneBindings.propertyExists(shadowCastingPropertyName))
					SHADOW_FACTORIES[sceneBindings.getProperty(shadowCastingPropertyName)](lightId, passes);
			}

			passes.push(_renderingPass);

			setPasses(passes);
		}

		private function manageNoShadowing(lightId : uint, passes : Vector.<Shader>) : void
		{
			// nothing to do here, no extra rendering is necessary
		}

		private function manageMatrixShadowing(lightId : uint, passes : Vector.<Shader>) : void
		{
			var textureResource : TextureResource	= getLightProperty(lightId, 'shadowMap');
			var renderTarget	: RenderTarget		= new RenderTarget(
				textureResource.width, textureResource.height, textureResource, 0, 0xffffffff
			);

			passes.push(new MatrixShadowMapShader(lightId, lightId + 1, renderTarget));
		}

		private function manageDualParaboloidShadowing(lightId : uint, passes : Vector.<Shader>) : void
		{
			var frontTextureResource : TextureResource	= getLightProperty(lightId, 'shadowMapDPFront');
			var backTextureResource	 : TextureResource	= getLightProperty(lightId, 'shadowMapDPBack');
			var size				 : uint				= frontTextureResource.width;
			var frontRenderTarget	 : RenderTarget		= new RenderTarget(size, size, frontTextureResource, 0, 0xffffffff);
			var backRenderTarget	 : RenderTarget		= new RenderTarget(size, size, backTextureResource, 0, 0xffffffff);

			passes.push(
				new ParaboloidShadowMapShader(lightId, true, lightId + 0.5, frontRenderTarget),
				new ParaboloidShadowMapShader(lightId, false, lightId + 1, backRenderTarget)
			);
		}

		private function manageCubicShadowing(lightId : uint, passes : Vector.<Shader>) : void
		{
			var textureResource	: CubeTextureResource	= getLightProperty(lightId, 'shadowMapCube');
			var size			: uint					= textureResource.size;
			var renderTarget0	: RenderTarget			= new RenderTarget(size, size, textureResource, 0, 0xffffffff);
			var renderTarget1	: RenderTarget			= new RenderTarget(size, size, textureResource, 1, 0xffffffff);
			var renderTarget2	: RenderTarget			= new RenderTarget(size, size, textureResource, 2, 0xffffffff);
			var renderTarget3	: RenderTarget			= new RenderTarget(size, size, textureResource, 3, 0xffffffff);
			var renderTarget4	: RenderTarget			= new RenderTarget(size, size, textureResource, 4, 0xffffffff);
			var renderTarget5	: RenderTarget			= new RenderTarget(size, size, textureResource, 5, 0xffffffff);

			passes.push(
				new CubeShadowMapShader(lightId, 0, lightId + 0.1, renderTarget0),
				new CubeShadowMapShader(lightId, 1, lightId + 0.2, renderTarget1),
				new CubeShadowMapShader(lightId, 2, lightId + 0.3, renderTarget2),
				new CubeShadowMapShader(lightId, 3, lightId + 0.4, renderTarget3),
				new CubeShadowMapShader(lightId, 4, lightId + 0.5, renderTarget4),
				new CubeShadowMapShader(lightId, 5, lightId + 0.6, renderTarget5)
			);
		}

		private function lightPropertyExists(lightId : uint, propertyName : String) : Boolean
		{
			return _scene.bindings.propertyExists(
				LightDataProvider.getLightPropertyName(propertyName, lightId)
			);
		}

		private function getLightProperty(lightId : uint, propertyName : String) : *
		{
			return _scene.bindings.getProperty(
				LightDataProvider.getLightPropertyName(propertyName, lightId)
			);
		}
	}
}

remove trace() in AbstractShadowMappingEffect


/*
 * FLINT PARTICLE SYSTEM
 * .....................
 *
 * Author: Richard Lord
 * Copyright (c) Richard Lord 2008-2010
 * http://flintparticles.org
 *
 *
 * Licence Agreement
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package org.flintparticles.common.initializers
{
	import org.flintparticles.common.emitters.Emitter;
	import org.flintparticles.common.particles.Particle;

	/**
	 * The DictionaryInit Initializer copies properties from an initializing object to a particle's dictionary.
	 */
	public class DictionaryInitializer extends InitializerBase
	{
		private var _initValues:*;

		/**
		 * The constructor creates a DictionaryInit initializer for use by
		 * an emitter. To add a DictionaryInit to all particles created by an emitter, use the
		 * emitter's addInitializer method.
		 *
		 * @param initValues The object containing the properties for copying to the particle's dictionary.
		 * May be an object or a dictionary.
		 *
		 * @see org.flintparticles.common.emitters.Emitter#addInitializer()
		 */
		public function DictionaryInitializer( initValues:* )
		{
			_initValues = initValues;
		}

		/**
		 * The object containing the properties for copying to the particle's dictionary.
		 * May be an object or a dictionary.
		 */
		public function get initValues():*
		{
			return _initValues;
		}
		public function set initValues( value:* ):void
		{
			_initValues = value;
		}

		/**
		 * @inheritDoc
		 */
		override public function initialize( emitter:Emitter, particle:Particle ):void
		{
			if ( !_initValues )
			{
				return;
			}
			for( var key:* in _initValues )
			{
				particle.dictionary[ key ] = _initValues[ key ];
			}
		}
	}
}

/*
 * FLINT PARTICLE SYSTEM
 * .....................
 *
 * Author: Richard Lord
 * Copyright (c) Richard Lord 2008-2010
 * http://flintparticles.org
 *
 *
 * Licence Agreement
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package org.flintparticles.common.initializers
{
	import org.flintparticles.common.emitters.Emitter;
	import org.flintparticles.common.particles.Particle;

	/**
	 * The Dictionary Initializer copies properties from an initializing object to a particle's dictionary.
	 */
	public class DictionaryInitializer extends InitializerBase
	{
		private var _initValues:*;

		/**
		 * The constructor creates a DictionaryInit initializer for use by
		 * an emitter. To add a DictionaryInit to all particles created by an emitter, use the
		 * emitter's addInitializer method.
		 *
		 * @param initValues The object containing the properties for copying to the particle's dictionary.
		 * May be an object or a dictionary.
		 *
		 * @see org.flintparticles.common.emitters.Emitter#addInitializer()
		 */
		public function DictionaryInitializer( initValues:* )
		{
			_initValues = initValues;
		}

		/**
		 * The object containing the properties for copying to the particle's dictionary.
		 * May be an object or a dictionary.
		 */
		public function get initValues():*
		{
			return _initValues;
		}
		public function set initValues( value:* ):void
		{
			_initValues = value;
		}

		/**
		 * @inheritDoc
		 */
		override public function initialize( emitter:Emitter, particle:Particle ):void
		{
			if ( !_initValues )
			{
				return;
			}
			for( var key:* in _initValues )
			{
				particle.dictionary[ key ] = _initValues[ key ];
			}
		}
	}
}

Fix incorrect class name in class description


package aerys.minko.scene.controller
{
	/**
	 * The SkeletonController aggregates AnimationController objects
	 * and control them in order to start/stop playing animations on
	 * multiple scene nodes at the same time and control a whole
	 * skeleton.
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public final class SkeletonController
	{
		private var _animations	: Vector.<AnimationController>	= null;

		public function SkeletonController(animations : Vector.<AnimationController>)
		{
			_animations = animations.slice();
		}

		public function get animations() : Vector.<AnimationController>
		{
			return _animations;
		}

		public function seek(time : Object) : SkeletonController
		{
			var numAnimations	: uint	= _animations.length;

			for (var animId : uint = 0; animId < numAnimations; ++animId)
				(_animations[animId] as AnimationController).seek(time);

			return this;
		}

		public function stop() : SkeletonController
		{
			var numAnimations	: uint	= _animations.length;

			for (var animId : uint = 0; animId < numAnimations; ++animId)
				(_animations[animId] as AnimationController).stop();

			return this;
		}

		public function play() : SkeletonController
		{
			var numAnimations	: uint	= _animations.length;

			for (var animId : uint = 0; animId < numAnimations; ++animId)
				(_animations[animId] as AnimationController).play();

			return this;
		}

		public function setPlaybackWindow(beginTime	: Object = null,
										  endTime	: Object = null) : SkeletonController
		{
			var numAnimations	: uint	= _animations.length;

			for (var animId : uint = 0; animId < numAnimations; ++animId)
				(_animations[animId] as AnimationController).setPlaybackWindow(beginTime, endTime);

			return this;
		}

		public function resetPlaybackWindow() : SkeletonController
		{
			var numAnimations	: uint	= _animations.length;

			for (var animId : uint = 0; animId < numAnimations; ++animId)
				(_animations[animId] as AnimationController).resetPlaybackWindow();

			return this;
		}
	}
}

package aerys.minko.scene.controller
{
import aerys.minko.scene.controller.animation.AnimationController;

/**
	 * The SkeletonController aggregates AnimationController objects
	 * and control them in order to start/stop playing animations on
	 * multiple scene nodes at the same time and control a whole
	 * skeleton.
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public final class SkeletonController
	{
		private var _animations	: Vector.<AnimationController>	= null;

		public function SkeletonController(animations : Vector.<AnimationController>)
		{
			_animations = animations.slice();
		}

		public function get animations() : Vector.<AnimationController>
		{
			return _animations;
		}

		public function seek(time : Object) : SkeletonController
		{
			var numAnimations	: uint	= _animations.length;

			for (var animId : uint = 0; animId < numAnimations; ++animId)
				(_animations[animId] as AnimationController).seek(time);

			return this;
		}

		public function stop() : SkeletonController
		{
			var numAnimations	: uint	= _animations.length;

			for (var animId : uint = 0; animId < numAnimations; ++animId)
				(_animations[animId] as AnimationController).stop();

			return this;
		}

		public function play() : SkeletonController
		{
			var numAnimations	: uint	= _animations.length;

			for (var animId : uint = 0; animId < numAnimations; ++animId)
				(_animations[animId] as AnimationController).play();

			return this;
		}

		public function setPlaybackWindow(beginTime	: Object = null,
										  endTime	: Object = null) : SkeletonController
		{
			var numAnimations	: uint	= _animations.length;

			for (var animId : uint = 0; animId < numAnimations; ++animId)
				(_animations[animId] as AnimationController).setPlaybackWindow(beginTime, endTime);

			return this;
		}

		public function resetPlaybackWindow() : SkeletonController
		{
			var numAnimations	: uint	= _animations.length;

			for (var animId : uint = 0; animId < numAnimations; ++animId)
				(_animations[animId] as AnimationController).resetPlaybackWindow();

			return this;
		}
	}
}

add MasterAnimationController

add MasterAnimationController


////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

package org.apache.flex.effects
{

import org.apache.flex.core.IDocument;
import org.apache.flex.core.IUIBase;

/**
 *  The Move effect animates a UI component's x or y position.
 *
 *  @langversion 3.0
 *  @playerversion Flash 10.2
 *  @playerversion AIR 2.6
 *  @productversion FlexJS 0.0
 */
public class Move extends Tween implements IDocument
{

    //--------------------------------------------------------------------------
    //
    //  Constructor
    //
    //--------------------------------------------------------------------------

    /**
     *  Constructor.
     *
     *  @param target Object ID or reference to an object that will
	 *  have its x and/or y property animated.
     *
     *  @langversion 3.0
     *  @playerversion Flash 9
     *  @playerversion AIR 1.1
     *  @productversion Flex 3
     */
    public function Move(target:IUIBase = null)
    {
        super();

		this.actualTarget = target;
		startValue = 0;
		endValue = 1;

		listener = this;
    }

    //--------------------------------------------------------------------------
    //
    //  Variables
    //
    //--------------------------------------------------------------------------

	/**
	 *  @private
	 *  The document.
	 */
	private var document:Object;

    /**
     *  @private
     *  The actual target.
     */
    private var actualTarget:IUIBase;

	/**
	 *  The target as the String id
     *  of a widget in an MXML Document.
	 */
	public var target:String;

	/**
	 *  The change in x.
	 */
	public var xBy:Number;

	/**
	 *  The change in y.
	 */
	public var yBy:Number;

	/**
	 *  @private
	 *  The starting x.
	 */
	private var xStart:Number;

	/**
	 *  @private
	 *  The staring y.
	 */
	private var yStart:Number;

	/**
	 *  Starting x value.  If NaN, the current x value is used
     */
    public var xFrom:Number;

	/**
	 *  Ending x value.  If NaN, the current x value is not changed
	 */
	public var xTo:Number;

	/**
	 *  Starting y value.  If NaN, the current y value is used
	 */
	public var yFrom:Number;

	/**
	 *  Ending y value.  If NaN, the current y value is not changed
	 */
	public var yTo:Number;

    //--------------------------------------------------------------------------
    //
    //  Properties
    //
    //--------------------------------------------------------------------------

    //--------------------------------------------------------------------------
    //
    //  Methods
    //
    //--------------------------------------------------------------------------

	public function setDocument(document:Object, id:String = null):void
	{
		this.document = document;
	}

	/**
	 *  @private
	 */
	override public function play():void
	{
		if (target != null)
			actualTarget = document[target];

		if (isNaN(xFrom))
			xStart = actualTarget.x;
        if (isNaN(xBy))
        {
    		if (isNaN(xTo))
    			xBy = 0;
    		else
    			xBy = xTo - xStart;
        }

		if (isNaN(yFrom))
			yStart = actualTarget.y;
        if (isNaN(yBy))
        {
    		if (isNaN(yTo))
    			yBy = 0;
    		else
    			yBy = yTo - yStart;
        }
		super.play();
	}

	public function onTweenUpdate(value:Number):void
	{
		if (xBy)
			actualTarget.x = xStart + value * xBy;
		if (yBy)
			actualTarget.y = yStart + value * yBy;
	}

	public function onTweenEnd(value:Number):void
	{
		if (xBy)
			actualTarget.x = xStart + xBy;
		if (yBy)
			actualTarget.y = yStart + yBy;
	}
}

}

////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

package org.apache.flex.effects
{

import org.apache.flex.core.IDocument;
import org.apache.flex.core.IUIBase;

/**
 *  The Move effect animates a UI component's x or y position.
 *
 *  @langversion 3.0
 *  @playerversion Flash 10.2
 *  @playerversion AIR 2.6
 *  @productversion FlexJS 0.0
 */
public class Move extends Tween implements IDocument
{

    //--------------------------------------------------------------------------
    //
    //  Constructor
    //
    //--------------------------------------------------------------------------

    /**
     *  Constructor.
     *
     *  @param target Object ID or reference to an object that will
	 *  have its x and/or y property animated.
     *
     *  @langversion 3.0
     *  @playerversion Flash 9
     *  @playerversion AIR 1.1
     *  @productversion Flex 3
     */
    public function Move(target:IUIBase = null)
    {
        super();

		this.actualTarget = target;
		startValue = 0;
		endValue = 1;

		listener = this;
    }

    //--------------------------------------------------------------------------
    //
    //  Variables
    //
    //--------------------------------------------------------------------------

	/**
	 *  @private
	 *  The document.
	 */
	private var document:Object;

    /**
     *  @private
     *  The actual target.
     */
    private var actualTarget:IUIBase;

	/**
	 *  The target as the String id
     *  of a widget in an MXML Document.
	 */
	public var target:String;

	/**
	 *  The change in x.
	 */
	public var xBy:Number;

	/**
	 *  The change in y.
	 */
	public var yBy:Number;

	/**
	 *  @private
	 *  The starting x.
	 */
	private var xStart:Number;

	/**
	 *  @private
	 *  The staring y.
	 */
	private var yStart:Number;

	/**
	 *  Starting x value.  If NaN, the current x value is used
     */
    public var xFrom:Number;

	/**
	 *  Ending x value.  If NaN, the current x value is not changed
	 */
	public var xTo:Number;

	/**
	 *  Starting y value.  If NaN, the current y value is used
	 */
	public var yFrom:Number;

	/**
	 *  Ending y value.  If NaN, the current y value is not changed
	 */
	public var yTo:Number;

    //--------------------------------------------------------------------------
    //
    //  Properties
    //
    //--------------------------------------------------------------------------

    //--------------------------------------------------------------------------
    //
    //  Methods
    //
    //--------------------------------------------------------------------------

	public function setDocument(document:Object, id:String = null):void
	{
		this.document = document;
	}

	/**
	 *  @private
	 */
	override public function play():void
	{
		if (target != null)
			actualTarget = document[target];

		if (isNaN(xFrom))
			xStart = actualTarget.x;
        else
            xStart = xFrom;

        if (isNaN(xBy))
        {
    		if (isNaN(xTo))
    			xBy = 0;
    		else
    			xBy = xTo - xStart;
        }

		if (isNaN(yFrom))
			yStart = actualTarget.y;
        else
            yStart = yFrom;
        if (isNaN(yBy))
        {
    		if (isNaN(yTo))
    			yBy = 0;
    		else
    			yBy = yTo - yStart;
        }
		super.play();
	}

	public function onTweenUpdate(value:Number):void
	{
		if (xBy)
			actualTarget.x = xStart + value * xBy;
		if (yBy)
			actualTarget.y = yStart + value * yBy;
	}

	public function onTweenEnd(value:Number):void
	{
		if (xBy)
			actualTarget.x = xStart + xBy;
		if (yBy)
			actualTarget.y = yStart + yBy;
	}
}

}

fix bug in startup

fix bug in startup


package org.concord.sparks.circuit.resistor.resistor_5band
{
    import flash.display.Graphics;
    import flash.display.Loader;
    import flash.display.MovieClip;
    import flash.display.Shape;
    import flash.events.MouseEvent;
    import flash.events.IOErrorEvent;
    import flash.geom.Point;
    import flash.net.URLRequest;

    import org.concord.sparks.util.Assert;

    public class Resistor
    {
        // Instance names in Flash movie
        public static var names = {
            resistorContainer : 'resistor_5band_mc',
            leftLeadRollOver : 'resistor_rollover',
            rightLeadRollOver : 'resistor_rollover_right',
            leftLeadEngaged : 'probe_engaged',
            rightLeadEngaged : 'probe_engaged_right'
        };

        var root;
        var container:MovieClip;

        var value:Number;

        var x = 430;
        var y = 200;
        var width = 260;
        var height = 80;

        public var lead1:ResistorLead;
        public var lead2:ResistorLead;

        public var snapRadius = 35;

        var band1Loader:Loader = new Loader();
        var band2Loader:Loader = new Loader();
        var band3Loader:Loader = new Loader();
        var band4Loader:Loader = new Loader();
        var band5Loader:Loader = new Loader();

        var colors = [];

        public function Resistor(root) {
            this.root = root;

            // Assert the root has the named objects
            for each (var name:String in names) {
                Assert.assertContains(root, name);
            }

            lead1 = new ResistorLead('resistor_lead1', new Point(591, 104),
                root[names.leftLeadRollOver], root[names.leftLeadEngaged]);
            lead2 = new ResistorLead('resistor_lead2', new Point(867, 102),
                root[names.rightLeadRollOver], root[names.rightLeadEngaged]);

            container = root[names.resistorContainer];

            container.band1.addChild(band1Loader);
            container.band2.addChild(band2Loader);
            container.band3.addChild(band3Loader);
            container.band4.addChild(band4Loader);
            container.band5.addChild(band5Loader);

            setLabel('red', 'white', 'blue', 'black', 'silver');
        }

        public function show() {
            container.visible = true;
        }

        public function hide() {
            container.visible = false;
        }

        public function isVisible():Boolean {
            return container.visible;
        }

        public function getColors() {
            return colors;
        }

        public function setLabel(color1, color2, color3, color4, color5):void {
            trace('Enter setLabel');
            this.colors = [color1, color2, color3, color4, color5];
            loadBandImage(band1Loader, 't_' + color1 + '.png');
            loadBandImage(band2Loader, 's_' + color2 + '.png');
            loadBandImage(band3Loader, 's_' + color3 + '.png');
            loadBandImage(band4Loader, 's_' + color4 + '.png');
            loadBandImage(band5Loader, 's_' + color5 + '.png');
        }

        private function loadBandImage(loader:Loader, fname:String):void {
            var s = '../../common/images/resistor/' + fname;
            //trace('path=' + s);
            try {
                var req:URLRequest = new URLRequest(s);
                loader.load(req);
                //trace('Loaded ' + s);
            }
            catch (e:IOErrorEvent) {
                trace("Failed to load " + s);
            }
        }
    }
}

package org.concord.sparks.circuit.resistor.resistor_5band
{
    import flash.display.Graphics;
    import flash.display.Loader;
    import flash.display.MovieClip;
    import flash.display.Shape;
    import flash.events.MouseEvent;
    import flash.events.IOErrorEvent;
    import flash.geom.Point;
    import flash.net.URLRequest;

    import org.concord.sparks.util.Assert;

    public class Resistor
    {
        // Instance names in Flash movie
        public static var names = {
            resistorContainer : 'resistor_5band_mc',
            leftLeadRollOver : 'resistor_rollover',
            rightLeadRollOver : 'resistor_rollover_right',
            leftLeadEngaged : 'probe_engaged',
            rightLeadEngaged : 'probe_engaged_right'
        };

        var root;
        var container:MovieClip;

        var value:Number;

        var x = 430;
        var y = 200;
        var width = 260;
        var height = 80;

        public var lead1:ResistorLead;
        public var lead2:ResistorLead;

        public var snapRadius = 35;

        var band1Loader:Loader = new Loader();
        var band2Loader:Loader = new Loader();
        var band3Loader:Loader = new Loader();
        var band4Loader:Loader = new Loader();
        var band5Loader:Loader = new Loader();

        var colors = [];

        public function Resistor(root) {
            this.root = root;

            // Assert the root has the named objects
            for each (var name:String in names) {
                Assert.assertContains(root, name);
            }

            lead1 = new ResistorLead('resistor_lead1', new Point(591, 104),
                root[names.leftLeadRollOver], root[names.leftLeadEngaged]);
            lead2 = new ResistorLead('resistor_lead2', new Point(867, 102),
                root[names.rightLeadRollOver], root[names.rightLeadEngaged]);

            container = root[names.resistorContainer];

            container.band1.addChild(band1Loader);
            container.band2.addChild(band2Loader);
            container.band3.addChild(band3Loader);
            container.band4.addChild(band4Loader);
            container.band5.addChild(band5Loader);

            setLabel('red', 'white', 'blue', 'black', 'silver');
        }

        public function show() {
            container.visible = true;
        }

        public function hide() {
            container.visible = false;
        }

        public function isVisible():Boolean {
            return container.visible;
        }

        public function getColors() {
            return colors;
        }

        public function setLabel(color1, color2, color3, color4, color5):void {
            trace('Enter setLabel');
            this.colors = [color1, color2, color3, color4, color5];
            loadBandImage(band1Loader, 't_' + color1 + '.png');
            loadBandImage(band2Loader, 's_' + color2 + '.png');
            loadBandImage(band3Loader, 's_' + color3 + '.png');
            loadBandImage(band4Loader, 's_' + color4 + '.png');
            loadBandImage(band5Loader, 's_' + color5 + '.png');
        }

        private function loadBandImage(loader:Loader, fname:String):void {
            var s = '/sparks-content/common/images/resistor/' + fname;
            //trace('path=' + s);
            try {
                var req:URLRequest = new URLRequest(s);
                loader.load(req);
                //trace('Loaded ' + s);
            }
            catch (e:IOErrorEvent) {
                trace("Failed to load " + s);
            }
        }
    }
}

use full path for resistor images

use full path for resistor images


//
// Flump - Copyright 2013 Flump Authors

package flump.xfl {

import aspire.util.Set;
import aspire.util.Sets;
import aspire.util.XmlUtil;

import flump.mold.KeyframeMold;
import flump.mold.LayerMold;
import flump.mold.MovieMold;

public class XflMovie extends XflSymbol
{
    use namespace xflns;

    /** Returns true if the given movie symbol is marked for "Export for ActionScript" */
    public static function isExported (xml :XML) :Boolean {
        return XmlUtil.hasAttr(xml, EXPORT_CLASS_NAME);
    }

    /** Returns the library name of the given movie */
    public static function getName (xml :XML) :String {
        return XmlUtil.getStringAttr(xml, NAME);
    }

    /** Return a Set of all the symbols this movie references. */
    public static function getSymbolNames (mold :MovieMold) :Set {
        var names :Set = Sets.newSetOf(String);
        for each (var layer :LayerMold in mold.layers) {
            if (!layer.flipbook) {
                for each (var kf :KeyframeMold in layer.keyframes) {
                    if (kf.ref != null) names.add(kf.ref);
                }
            }
        }
        return names;
    }

    public static function parse (lib :XflLibrary, xml :XML) :MovieMold {
        const movie :MovieMold = new MovieMold();
        const name :String = getName(xml);
        const exportName :String = XmlUtil.getStringAttr(xml, EXPORT_CLASS_NAME, null);
        movie.id = lib.createId(movie, name, exportName);
        const location :String = lib.location + ":" + movie.id;

        const layerEls :XMLList = xml.timeline.DOMTimeline[0].layers.DOMLayer;
        if (XmlUtil.getStringAttr(layerEls[0], XflLayer.NAME) == "flipbook") {
            movie.layers.push(XflLayer.parse(lib, location, layerEls[0], true));
            if (exportName == null) {
                lib.addError(location, ParseError.CRIT, "Flipbook movie '" + movie.id + "' not exported");
            }
            for each (var kf :KeyframeMold in movie.layers[0].keyframes) {
                kf.ref = movie.id + "_flipbook_" + kf.index;
            }
        } else {
            var maskName:String;
            for each (var layerEl :XML in layerEls) {
                var layerType :String = XmlUtil.getStringAttr(layerEl, XflLayer.TYPE, "");
                if ((layerType != XflLayer.TYPE_GUIDE) && (layerType != XflLayer.TYPE_FOLDER)) {
                    if (XmlUtil.hasAttr(layerEl, "parentLayerIndex")) {
                        if (maskName) {
                            movie.layers.unshift(XflLayer.parse(lib, location, layerEl, false, maskName));
                        }
                        else {
                            lib.addError(location, ParseError.WARN, "Only one masked layer is authorized on '" + movie.id + "'. The other masked layers are ignored from mask.");
                            movie.layers.unshift(XflLayer.parse(lib, location, layerEl, false));
                        }
                    } else movie.layers.unshift(XflLayer.parse(lib, location, layerEl, false));
                    maskName = layerType == XflLayer.TYPE_MASK ? movie.layers[0].name : null;
                }
            }
        }
        movie.fillLabels();

        if (movie.layers.length == 0) {
            lib.addError(location, ParseError.CRIT, "Movies must have at least one layer");
        }

        return movie;
    }
}
}

//
// Flump - Copyright 2013 Flump Authors

package flump.xfl {

import aspire.util.Set;
import aspire.util.Sets;
import aspire.util.XmlUtil;

import flump.mold.KeyframeMold;
import flump.mold.LayerMold;
import flump.mold.MovieMold;

public class XflMovie extends XflSymbol
{
    use namespace xflns;

    /** Returns true if the given movie symbol is marked for "Export for ActionScript" */
    public static function isExported (xml :XML) :Boolean {
        return XmlUtil.hasAttr(xml, EXPORT_CLASS_NAME);
    }

    /** Returns the library name of the given movie */
    public static function getName (xml :XML) :String {
        return XmlUtil.getStringAttr(xml, NAME);
    }

    /** Return a Set of all the symbols this movie references. */
    public static function getSymbolNames (mold :MovieMold) :Set {
        var names :Set = Sets.newSetOf(String);
        for each (var layer :LayerMold in mold.layers) {
            if (!layer.flipbook) {
                for each (var kf :KeyframeMold in layer.keyframes) {
                    if (kf.ref != null) names.add(kf.ref);
                }
            }
        }
        return names;
    }

    public static function parse (lib :XflLibrary, xml :XML) :MovieMold {
        const movie :MovieMold = new MovieMold();
        const name :String = getName(xml);
        const exportName :String = XmlUtil.getStringAttr(xml, EXPORT_CLASS_NAME, null);
        movie.id = lib.createId(movie, name, exportName);
        const location :String = lib.location + ":" + movie.id;

        const layerEls :XMLList = xml.timeline.DOMTimeline[0].layers.DOMLayer;
        if (XmlUtil.getStringAttr(xml, EXPORT_BASE_CLASS_NAME, null)=="Flipbook" || XmlUtil.getStringAttr(layerEls[0], XflLayer.NAME) == "flipbook") {
            movie.layers.push(XflLayer.parse(lib, location, layerEls[0], true));
            if (exportName == null) {
                lib.addError(location, ParseError.CRIT, "Flipbook movie '" + movie.id + "' not exported");
            }
            for each (var kf :KeyframeMold in movie.layers[0].keyframes) {
                kf.ref = movie.id + "_flipbook_" + kf.index;
            }
        } else {
            var maskName:String;
            for each (var layerEl :XML in layerEls) {
                var layerType :String = XmlUtil.getStringAttr(layerEl, XflLayer.TYPE, "");
                if ((layerType != XflLayer.TYPE_GUIDE) && (layerType != XflLayer.TYPE_FOLDER)) {
                    if (XmlUtil.hasAttr(layerEl, "parentLayerIndex")) {
                        if (maskName) {
                            movie.layers.unshift(XflLayer.parse(lib, location, layerEl, false, maskName));
                        }
                        else {
                            lib.addError(location, ParseError.WARN, "Only one masked layer is authorized on '" + movie.id + "'. The other masked layers are ignored from mask.");
                            movie.layers.unshift(XflLayer.parse(lib, location, layerEl, false));
                        }
                    } else movie.layers.unshift(XflLayer.parse(lib, location, layerEl, false));
                    maskName = layerType == XflLayer.TYPE_MASK ? movie.layers[0].name : null;
                }
            }
        }
        movie.fillLabels();

        if (movie.layers.length == 0) {
            lib.addError(location, ParseError.CRIT, "Movies must have at least one layer");
        }

        return movie;
    }
}
}

Fix merge Flipbook

Fix merge Flipbook


/**
 * Author: Shane Jonas
 * Child Browser Implementation for the PlayBook
 */

package blackberry.polarmobile.childbrowser
{
    // flash
    import flash.geom.Rectangle;
    import flash.display.Stage;
    import flash.events.MouseEvent;
    import flash.display.Sprite;
    import flash.events.StageOrientationEvent;
    import flash.utils.setTimeout;

    import caurina.transitions.Tweener;

    // qnx
    import qnx.media.QNXStageWebView;
    import qnx.ui.buttons.IconButton;
    import qnx.ui.skins.buttons.OutlineButtonSkinBlack;

    // webworks
    import webworks.extension.DefaultExtension;

    public class ChildBrowser extends DefaultExtension
    {
        private var childWebView:QNXStageWebView = null;
        private var closeButton:IconButton;
        private var refreshButton:IconButton;
        private var bgshape:Sprite;
        private var loading_bg_shape:Sprite;
        private var browserHeight;
        private var isVisible:Boolean = false;
        private var webViewUI:Sprite;

        //icons
        [Embed(source="assets/close.png")]
        public static var Close:Class;
        [Embed(source="assets/refresh.png")]
        public static var Refresh:Class;
        [Embed(source="assets/ajax-spinner-black-bg.gif")]
        public static var Spinner:Class;

        public function ChildBrowser()
        {
            super();
            this.isVisible = false
        }

        override public function getFeatureList():Array
        {
            return new Array ("blackberry.polarmobile.childbrowser");
        }

        private function initBG()
        {
            var self = this;
            webViewUI = new Sprite();
            bgshape = new Sprite();
            bgshape.graphics.beginFill(0x323232);
            bgshape.graphics.drawRect(0,0,webView.stage.stageWidth, webView.stage.stageHeight);
            webViewUI.addChildAt(bgshape, 0);

            //build buttons
            this.initUI();

            webViewUI.y = webView.stage.stageHeight;
            webView.stage.addChild(webViewUI);

            function loaded(){
              setTimeout(function(){
                childWebView.stage = webView.stage;
                childWebView.zOrder = 1;
                self.isVisible = true;
              }, 1000);
            }

            Tweener.addTween(webViewUI, {
              y: 0,
              time: 1,
              transition: 'easeOutExpo',
              onComplete: loaded
            });
        }

        public function clearCookies()
        {
          //if we dont have a webview, make one and put it in the background
          this.createBrowser()
          //clear the webviews cookies
          childWebView.clearCookies();
          childWebView.stage = null;
          //childWebView.dispose();
          //childWebView = null;
        }

        private function createBrowser()
        {
          if (childWebView == null)
          {
              childWebView = new QNXStageWebView("ChildBrowser");
              childWebView.stage = webView.stage;
              childWebView.viewPort = new Rectangle(0,50,webView.stage.stageWidth,browserHeight);
              childWebView.zOrder = -1;
              this.isVisible = true
              // events
              webView.stage.addEventListener(StageOrientationEvent.ORIENTATION_CHANGE, onOrientationChange);
          }
        }

        public function loadURL(url:String)
        {
            var self = this;
            browserHeight = webView.stage.stageHeight - 50;
            //if we dont have a webview, make one and put it in the background
            this.createBrowser();
            //put webview behind stage
            webView.zOrder = -1;
            //load this url
            childWebView.loadURL(url);
            this.initBG();
        }

        private function onOrientationChange(event:StageOrientationEvent)
        {
           var self = this
           this.removeUI();
           this.initBG()
           childWebView.viewPort = new Rectangle(0,50,bgshape.width,bgshape.height - 50);
        }

        public function getLocation():String
        {
            return childWebView.location;
        }

        public function forward()
        {
            childWebView.historyForward();
        }

        public function back()
        {
            childWebView.historyBack();
        }

        public function refresh()
        {
            childWebView.reload();
        }

        public function close()
        {
          childWebView.stage = null;
          childWebView.dispose();
          childWebView = null;

          Tweener.addTween(webViewUI, {
            y: webView.stage.stageHeight,
            delay: 0.5,
            time: 1,
            transition: 'easeOutExpo',
            onComplete: closeUI
          });
        }

        private function closeUI()
        {
          // the `dispose` method does not work when running inside of webworks,
          // as it closes then main `webView` instance. as a temp. work-around,
          // we hide the child
          this.removeUI();
          webView.stage.removeChild(webViewUI);
          this.isVisible = false;
          webView.zOrder = 1;
        }

        public function closeCLICK(e:MouseEvent)
        {
          this.close();
        }

        public function refreshCLICK(e:MouseEvent)
        {
          this.refresh();
        }

        private function removeUI()
        {
          removeChild(bgshape);
          removeChild(closeButton);
          removeChild(refreshButton)
        }

        //close button
        private function addClose()
        {
          closeButton = new IconButton();
          closeButton.setIcon(new Close());

          closeButton.setSize(266, 50);
          closeButton.setPosition(-5, 0);

          closeButton.setSkin(new OutlineButtonSkinBlack());
          closeButton.addEventListener(MouseEvent.CLICK, closeCLICK);
          addChild(closeButton);
        }

        //refresh button
        private function addRefresh()
        {
          refreshButton = new IconButton();
          refreshButton.setIcon(new Refresh());
          refreshButton.setSize(266, 50);
          refreshButton.setPosition(256, 0);
          refreshButton.setSkin(new OutlineButtonSkinBlack())
          refreshButton.addEventListener(MouseEvent.CLICK, refreshCLICK);
          addChild(refreshButton);
        }

        // UI Buttons
        private function initUI()
        {
          this.addClose();
          this.addRefresh();
        }

        public function getVisible():Boolean
        {
          return this.isVisible;
        }

        // our own addChild implementation
        // maps back to stage of WebWorkAppTemplate.as
        private function addChild(obj)
        {
          webViewUI.addChild(obj);
          //always set added obj's to top
          //webViewUI.setChildIndex(obj, webView.stage.numChildren -1);
        }

        private function removeChild(obj)
        {
          webViewUI.removeChild(obj);
        }

    }
}

/**
 * Author: Shane Jonas
 * Child Browser Implementation for the PlayBook
 */

package blackberry.polarmobile.childbrowser
{
    // flash
    import flash.geom.Rectangle;
    import flash.display.Stage;
    import flash.events.MouseEvent;
    import flash.display.Sprite;
    import flash.events.StageOrientationEvent;
    import flash.utils.setTimeout;

    import caurina.transitions.Tweener;

    // qnx
    import qnx.media.QNXStageWebView;
    import qnx.ui.buttons.IconButton;
    import qnx.ui.skins.buttons.OutlineButtonSkinBlack;

    // webworks
    import webworks.extension.DefaultExtension;

    public class ChildBrowser extends DefaultExtension
    {
        private var childWebView:QNXStageWebView = null;
        private var closeButton:IconButton;
        private var refreshButton:IconButton;
        private var bgshape:Sprite;
        private var loading_bg_shape:Sprite;
        private var browserHeight;
        private var isVisible:Boolean = false;
        private var webViewUI:Sprite;

        //icons
        [Embed(source="assets/close.png")]
        public static var Close:Class;
        [Embed(source="assets/refresh.png")]
        public static var Refresh:Class;
        [Embed(source="assets/ajax-spinner-black-bg.gif")]
        public static var Spinner:Class;

        public function ChildBrowser()
        {
            super();
            this.isVisible = false
        }

        override public function getFeatureList():Array
        {
            return new Array ("blackberry.polarmobile.childbrowser");
        }

        private function initBG()
        {
            if (this.isVisible)
            {
                return;
            }

            var self = this;
            webViewUI = new Sprite();
            bgshape = new Sprite();
            bgshape.graphics.beginFill(0x323232);
            bgshape.graphics.drawRect(0,0,webView.stage.stageWidth, webView.stage.stageHeight);
            webViewUI.addChildAt(bgshape, 0);

            //build buttons
            this.initUI();

            webViewUI.y = webView.stage.stageHeight;
            webView.stage.addChild(webViewUI);

            function loaded(){
              setTimeout(function(){
                childWebView.stage = webView.stage;
                childWebView.zOrder = 1;
                self.isVisible = true;
              }, 1000);
            }

            Tweener.addTween(webViewUI, {
              y: 0,
              time: 1,
              transition: 'easeOutExpo',
              onComplete: loaded
            });
        }

        public function clearCookies()
        {
          //if we dont have a webview, make one and put it in the background
          this.createBrowser()
          //clear the webviews cookies
          childWebView.clearCookies();
          childWebView.stage = null;
          //childWebView.dispose();
          //childWebView = null;
        }

        private function createBrowser()
        {
          if (childWebView == null)
          {
              childWebView = new QNXStageWebView("ChildBrowser");
              childWebView.stage = webView.stage;
              childWebView.viewPort = new Rectangle(0,50,webView.stage.stageWidth,browserHeight);
              childWebView.zOrder = -1;
              // events
              webView.stage.addEventListener(StageOrientationEvent.ORIENTATION_CHANGE, onOrientationChange);
          }
        }

        public function loadURL(url:String)
        {
            var self = this;
            browserHeight = webView.stage.stageHeight - 50;
            //if we dont have a webview, make one and put it in the background
            this.createBrowser();
            //put webview behind stage
            webView.zOrder = -1;
            //load this url
            childWebView.loadURL(url);
            this.initBG();
        }

        private function onOrientationChange(event:StageOrientationEvent)
        {
           var self = this
           this.removeUI();
           this.initBG()
           childWebView.viewPort = new Rectangle(0,50,bgshape.width,bgshape.height - 50);
        }

        public function getLocation():String
        {
            return childWebView.location;
        }

        public function forward()
        {
            childWebView.historyForward();
        }

        public function back()
        {
            childWebView.historyBack();
        }

        public function refresh()
        {
            childWebView.reload();
        }

        public function close()
        {
          childWebView.stage = null;
          childWebView.dispose();
          childWebView = null;

          Tweener.addTween(webViewUI, {
            y: webView.stage.stageHeight,
            delay: 0.5,
            time: 1,
            transition: 'easeOutExpo',
            onComplete: closeUI
          });
        }

        private function closeUI()
        {
          // the `dispose` method does not work when running inside of webworks,
          // as it closes then main `webView` instance. as a temp. work-around,
          // we hide the child
          this.removeUI();
          webView.stage.removeChild(webViewUI);
          webView.zOrder = 1;
        }

        public function closeCLICK(e:MouseEvent)
        {
          this.close();
        }

        public function refreshCLICK(e:MouseEvent)
        {
          this.refresh();
        }

        private function removeUI()
        {
          removeChild(bgshape);
          removeChild(closeButton);
          removeChild(refreshButton)
          this.isVisible = false;
        }

        //close button
        private function addClose()
        {
          closeButton = new IconButton();
          closeButton.setIcon(new Close());

          closeButton.setSize(266, 50);
          closeButton.setPosition(-5, 0);

          closeButton.setSkin(new OutlineButtonSkinBlack());
          closeButton.addEventListener(MouseEvent.CLICK, closeCLICK);
          addChild(closeButton);
        }

        //refresh button
        private function addRefresh()
        {
          refreshButton = new IconButton();
          refreshButton.setIcon(new Refresh());
          refreshButton.setSize(266, 50);
          refreshButton.setPosition(256, 0);
          refreshButton.setSkin(new OutlineButtonSkinBlack())
          refreshButton.addEventListener(MouseEvent.CLICK, refreshCLICK);
          addChild(refreshButton);
        }

        // UI Buttons
        private function initUI()
        {
          this.addClose();
          this.addRefresh();
        }

        public function getVisible():Boolean
        {
          return this.isVisible;
        }

        // our own addChild implementation
        // maps back to stage of WebWorkAppTemplate.as
        private function addChild(obj)
        {
          webViewUI.addChild(obj);
          //always set added obj's to top
          //webViewUI.setChildIndex(obj, webView.stage.numChildren -1);
        }

        private function removeChild(obj)
        {
          webViewUI.removeChild(obj);
        }

    }
}

fix issue with multiple sets of controls being created if loadURL() called multiple times


package org.servebox.cafe.core.modularity
{
	import flash.utils.getQualifiedClassName;

	import org.servebox.cafe.core.Container;
	import org.servebox.cafe.core.application.ApplicationInitializer;
	import org.servebox.cafe.core.layout.ILayoutArea;
	import org.servebox.cafe.core.layout.ILayoutAreaManager;
	import org.servebox.cafe.core.observer.AbstractObserver;
	import org.servebox.cafe.core.signal.ISignalObserver;
	import org.servebox.cafe.core.signal.SignalAggregator;
	import org.servebox.cafe.core.spring.IApplicationContext;
	import org.servebox.cafe.core.spring.IApplicationContextListener;
	import org.servebox.cafe.core.util.ApplicationUnitUtils;
	import org.servebox.cafe.core.view.IView;

	public class LocalApplicationUnitImpl extends AbstractObserver implements IApplicationUnit, IApplicationContextListener, ISignalObserver
	{
		private var _id : String;
		private var _loadAtStartup  :Boolean = false;
		private var _configLocations : Array;
		private var _context : IApplicationContext;

		[Autowired]
		public var signalAggregator : SignalAggregator;

		public function LocalApplicationUnitImpl()
		{
			super();
		}

		public function get id():String
		{
			return _id;
		}

		public function set id(value:String):void
		{
			_id = value;
		}

		public function get loadAtStartup():Boolean
		{
			return _loadAtStartup;
		}

		public function set loadAtStartup(value:Boolean):void
		{
			_loadAtStartup = value;
		}

		public function get configLocations():Array
		{
			if( _configLocations == null )
			{
				_configLocations = [ApplicationUnitUtils.getDefaultContextLocation( this )];
			}
			return _configLocations;
		}

		public function set configLocations(value:Array):void
		{
			_configLocations = value;
		}

		protected function getContext() : IApplicationContext
		{
			return _context;
		}

		protected function initializeContext( parentContext : IApplicationContext ) : void
		{
			_context = ApplicationInitializer.getContextInstance( configLocations, parentContext );
		}

		public function prepare(parentContext:IApplicationContext):void
		{
			initializeContext( parentContext );
			// Should we do that ? I guess so
			getContext().setListener( this );
			getContext().load();
		}

		public function applicationContextReady() : void
		{
			start();
		}

		public function getLayoutAreaManager() : ILayoutAreaManager
		{
			return Container.getInstance().getLayoutAreaManager();
		}

		public function cleanLayout( layoutName : String ) : void
		{
			var layoutArea : ILayoutArea = getLayoutAreaManager().getArea(layoutName);
			for each ( var view : IView in layoutArea.getViews() )
			{
				layoutArea.remove(view);
			}
		}

		public function getView( id : String ) : IView
		{
			return getContext().getObject(getQualifiedClassName(this) + id );
		}

		public function start():void
		{
		}
	}
}

package org.servebox.cafe.core.modularity
{
	import flash.utils.getQualifiedClassName;

	import org.servebox.cafe.core.Container;
	import org.servebox.cafe.core.application.ApplicationInitializer;
	import org.servebox.cafe.core.layout.ILayoutArea;
	import org.servebox.cafe.core.layout.ILayoutAreaManager;
	import org.servebox.cafe.core.observer.AbstractObserver;
	import org.servebox.cafe.core.signal.ISignalObserver;
	import org.servebox.cafe.core.signal.SignalAggregator;
	import org.servebox.cafe.core.spring.IApplicationContext;
	import org.servebox.cafe.core.spring.IApplicationContextListener;
	import org.servebox.cafe.core.util.ApplicationUnitUtils;
	import org.servebox.cafe.core.view.IView;

	public class LocalApplicationUnitImpl extends AbstractObserver implements IApplicationUnit, IApplicationContextListener, ISignalObserver
	{
		private var _id : String;
		private var _loadAtStartup  :Boolean = false;
		private var _configLocations : Array;
		private var _context : IApplicationContext;

		[Autowired]
		public var signalAggregator : SignalAggregator;

		public function LocalApplicationUnitImpl()
		{
			super();
		}

		public function get id():String
		{
			return _id;
		}

		public function set id(value:String):void
		{
			_id = value;
		}

		public function get loadAtStartup():Boolean
		{
			return _loadAtStartup;
		}

		public function set loadAtStartup(value:Boolean):void
		{
			_loadAtStartup = value;
		}

		public function get configLocations():Array
		{
			if( _configLocations == null )
			{
				_configLocations = [ApplicationUnitUtils.getDefaultContextLocation( this )];
			}
			return _configLocations;
		}

		public function set configLocations(value:Array):void
		{
			_configLocations = value;
		}

		protected function getContext() : IApplicationContext
		{
			return _context;
		}

		protected function initializeContext( parentContext : IApplicationContext ) : void
		{
			_context = ApplicationInitializer.getContextInstance( configLocations, parentContext );
		}

		public function prepare(parentContext:IApplicationContext):void
		{
			initializeContext( parentContext );
			// Should we do that ? I guess so
			getContext().setListener( this );
			getContext().load();
		}

		public function applicationContextReady() : void
		{
			start();
		}

		public function getLayoutAreaManager() : ILayoutAreaManager
		{
			return Container.getInstance().getLayoutAreaManager();
		}

		public function cleanLayout( layoutName : String ) : void
		{
			var layoutArea : ILayoutArea = getLayoutAreaManager().getArea(layoutName);
			for each ( var view : IView in layoutArea.getViews() )
			{
				layoutArea.remove(view);
			}
		}

		public function getView( id : String ) : IView
		{
			return getContext().getObject( id );
		}

		public function start():void
		{
		}
	}
}

Remove applicationunit name from view id in applicationunit context.


// Localization example.
// This sample demonstrates:
//     - Loading a collection of strings from JSON-files
//     - Creating text elements that automatically translates itself by changing the language
//     - The manually reaction to change language

#include "Scripts/Utilities/Sample.as"

void Start()
{
    // Execute the common startup for samples
    SampleStart();

    // Enable OS cursor
    input.mouseVisible = true;

    // Load strings from JSON files and subscribe to the change language event
    InitLocalizationSystem();

    // Init the 3D space
    CreateScene();

    // Init the user interface
    CreateGUI();
}

void InitLocalizationSystem()
{
    // JSON files must be in UTF8 encoding without BOM
    // The first founded language will be set as current
    localization.LoadJSONFile("StringsEnRu.json");
    // You can load multiple files
    localization.LoadJSONFile("StringsDe.json");
    // Hook up to the change language
    SubscribeToEvent("ChangeLanguage", "HandleChangeLanguage");
}

void CreateGUI()
{
    ui.root.defaultStyle = cache.GetResource("XMLFile", "UI/DefaultStyle.xml");

    Window@ window = Window();
    ui.root.AddChild(window);
    window.SetMinSize(384, 192);
    window.SetLayout(LM_VERTICAL, 6, IntRect(6, 6, 6, 6));
    window.SetAlignment(HA_CENTER, VA_CENTER);
    window.SetStyleAuto();

    Text@ windowTitle = Text();
    windowTitle.name = "WindowTitle";
    windowTitle.SetStyleAuto();
    window.AddChild(windowTitle);

    // In this place the current language is "en" because it was found first when loading the JSON files
    String langName = localization.language;
    // Languages are numbered in the loading order
    int langIndex = localization.languageIndex; // == 0 at the beginning
    // Get string with identifier "title" in the current language
    String localizedString = localization.Get("title");
    // Localization.Get returns String::EMPTY if the id is empty.
    // Localization.Get returns the id if translation is not found and will be added a warning into the log.

    windowTitle.text = localizedString + " (" + String(langIndex) + " " + langName + ")";

    Button@ b = Button();
    window.AddChild(b);
    b.SetStyle("Button");
    b.minHeight = 24;

    Text@ t = b.CreateChild("Text", "ButtonTextChangeLang");
    // The showing text value will automatically change when language is changed
    t.autoLocalizable = true;
    // The text value used as a string identifier in this mode.
    // Remember that a letter case of the id and of the lang name is important.
    t.text = "Press this button";

    t.SetAlignment(HA_CENTER, VA_CENTER);
    t.SetStyle("Text");
    SubscribeToEvent(b, "Released", "HandleChangeLangButtonPressed");

    b = Button();
    window.AddChild(b);
    b.SetStyle("Button");
    b.minHeight = 24;
    t = b.CreateChild("Text", "ButtonTextQuit");
    t.SetAlignment(HA_CENTER, VA_CENTER);
    t.SetStyle("Text");

    // Manually set text in the current language
    t.text = localization.Get("quit");

    SubscribeToEvent(b, "Released", "HandleQuitButtonPressed");
}

void CreateScene()
{
    scene_ = Scene();
    scene_.CreateComponent("Octree");

    Zone@ zone = scene_.CreateComponent("Zone");
    zone.boundingBox = BoundingBox(-1000.0f, 1000.0f);
    zone.ambientColor = Color(0.5f, 0.5f, 0.5f);
    zone.fogColor = Color(0.4f, 0.5f, 0.8f);
    zone.fogStart = 1.0f;
    zone.fogEnd = 100.0f;

    Node@ planeNode = scene_.CreateChild("Plane");
    planeNode.scale = Vector3(300.0f, 1.0f, 300.0f);
    StaticModel@ planeObject = planeNode.CreateComponent("StaticModel");
    planeObject.model = cache.GetResource("Model", "Models/Plane.mdl");
    planeObject.material = cache.GetResource("Material", "Materials/StoneTiled.xml");

    Node@ lightNode = scene_.CreateChild("DirectionalLight");
    lightNode.direction = Vector3(0.6f, -1.0f, 0.8f);
    Light@ light = lightNode.CreateComponent("Light");
    light.lightType = LIGHT_DIRECTIONAL;
    light.color = Color(0.8f, 0.8f, 0.8f);

    cameraNode = scene_.CreateChild("Camera");
    cameraNode.CreateComponent("Camera");
    cameraNode.position = Vector3(0.0f, 10.0f, -30.0f);

    Node@ text3DNode = scene_.CreateChild("Text3D");
    text3DNode.position = Vector3(0.0f, 0.1f, 30.0f);
    text3DNode.SetScale(15);
    Text3D@ text3D = text3DNode.CreateComponent("Text3D");

    // Manually set text in the current language.
    text3D.text = localization.Get("lang");

    text3D.SetFont(cache.GetResource("Font", "Fonts/Anonymous Pro.ttf"), 30);
    text3D.color = Color::BLACK;
    text3D.SetAlignment(HA_CENTER, VA_BOTTOM);

    Viewport@ viewport = Viewport(scene_, cameraNode.GetComponent("Camera"));
    renderer.viewports[0] = viewport;

    SubscribeToEvent("Update", "HandleUpdate");
}

void HandleUpdate(StringHash eventType, VariantMap& eventData)
{
    float timeStep = eventData["TimeStep"].GetFloat();
    const float MOUSE_SENSITIVITY = 0.1f;
    IntVector2 mouseMove = input.mouseMove;
    yaw += MOUSE_SENSITIVITY * mouseMove.x;
    pitch += MOUSE_SENSITIVITY * mouseMove.y;
    pitch = Clamp(pitch, -90.0f, 90.0f);
    cameraNode.rotation = Quaternion(pitch, yaw, 0.0f);
}

void HandleChangeLangButtonPressed(StringHash eventType, VariantMap& eventData)
{
    // Languages are numbered in the loading order
    int lang = localization.languageIndex;
    lang++;
    if (lang >= localization.numLanguages)
        lang = 0;
    localization.SetLanguage(lang);
}

void HandleQuitButtonPressed(StringHash eventType, VariantMap& eventData)
{
    engine.Exit();
}

// You can manually change texts, sprites and other aspects of the game when language is changed
void HandleChangeLanguage(StringHash eventType, VariantMap& eventData)
{
    Text@ windowTitle = ui.root.GetChild("WindowTitle", true);
    windowTitle.text = localization.Get("title") + " (" +
                           String(localization.languageIndex) + " " +
                           localization.language + ")";

    Text@ buttonText = ui.root.GetChild("ButtonTextQuit", true);
    buttonText.text = localization.Get("quit");

    Text3D@ text3D = scene_.GetChild("Text3D").GetComponent("Text3D");
    text3D.text = localization.Get("lang");

    // A text on the button "Press this button" changes automatically
}

String patchInstructions = "";

// Localization example.
// This sample demonstrates:
//     - Loading a collection of strings from JSON-files
//     - Creating text elements that automatically translates itself by changing the language
//     - The manually reaction to change language

#include "Scripts/Utilities/Sample.as"

void Start()
{
    // Execute the common startup for samples
    SampleStart();

    // Enable OS cursor
    input.mouseVisible = true;

    // Load strings from JSON files and subscribe to the change language event
    InitLocalizationSystem();

    // Init the 3D space
    CreateScene();

    // Init the user interface
    CreateGUI();
}

void InitLocalizationSystem()
{
    // JSON files must be in UTF8 encoding without BOM
    // The first founded language will be set as current
    localization.LoadJSONFile("StringsEnRu.json");
    // You can load multiple files
    localization.LoadJSONFile("StringsDe.json");
    // Hook up to the change language
    SubscribeToEvent("ChangeLanguage", "HandleChangeLanguage");
}

void CreateGUI()
{
    ui.root.defaultStyle = cache.GetResource("XMLFile", "UI/DefaultStyle.xml");

    Window@ window = Window();
    ui.root.AddChild(window);
    window.SetMinSize(384, 192);
    window.SetLayout(LM_VERTICAL, 6, IntRect(6, 6, 6, 6));
    window.SetAlignment(HA_CENTER, VA_CENTER);
    window.SetStyleAuto();

    Text@ windowTitle = Text();
    windowTitle.name = "WindowTitle";
    windowTitle.SetStyleAuto();
    window.AddChild(windowTitle);

    // In this place the current language is "en" because it was found first when loading the JSON files
    String langName = localization.language;
    // Languages are numbered in the loading order
    int langIndex = localization.languageIndex; // == 0 at the beginning
    // Get string with identifier "title" in the current language
    String localizedString = localization.Get("title");
    // Localization.Get returns String::EMPTY if the id is empty.
    // Localization.Get returns the id if translation is not found and will be added a warning into the log.

    windowTitle.text = localizedString + " (" + String(langIndex) + " " + langName + ")";

    Button@ b = Button();
    window.AddChild(b);
    b.SetStyle("Button");
    b.minHeight = 24;

    Text@ t = b.CreateChild("Text", "ButtonTextChangeLang");
    // The showing text value will automatically change when language is changed
    t.autoLocalizable = true;
    // The text value used as a string identifier in this mode.
    // Remember that a letter case of the id and of the lang name is important.
    t.text = "Press this button";

    t.SetAlignment(HA_CENTER, VA_CENTER);
    t.SetStyle("Text");
    SubscribeToEvent(b, "Released", "HandleChangeLangButtonPressed");

    b = Button();
    window.AddChild(b);
    b.SetStyle("Button");
    b.minHeight = 24;
    t = b.CreateChild("Text", "ButtonTextQuit");
    t.SetAlignment(HA_CENTER, VA_CENTER);
    t.SetStyle("Text");

    // Manually set text in the current language
    t.text = localization.Get("quit");

    SubscribeToEvent(b, "Released", "HandleQuitButtonPressed");
}

void CreateScene()
{
    scene_ = Scene();
    scene_.CreateComponent("Octree");

    Zone@ zone = scene_.CreateComponent("Zone");
    zone.boundingBox = BoundingBox(-1000.0f, 1000.0f);
    zone.ambientColor = Color(0.5f, 0.5f, 0.5f);
    zone.fogColor = Color(0.4f, 0.5f, 0.8f);
    zone.fogStart = 1.0f;
    zone.fogEnd = 100.0f;

    Node@ planeNode = scene_.CreateChild("Plane");
    planeNode.scale = Vector3(300.0f, 1.0f, 300.0f);
    StaticModel@ planeObject = planeNode.CreateComponent("StaticModel");
    planeObject.model = cache.GetResource("Model", "Models/Plane.mdl");
    planeObject.material = cache.GetResource("Material", "Materials/StoneTiled.xml");

    Node@ lightNode = scene_.CreateChild("DirectionalLight");
    lightNode.direction = Vector3(0.6f, -1.0f, 0.8f);
    Light@ light = lightNode.CreateComponent("Light");
    light.lightType = LIGHT_DIRECTIONAL;
    light.color = Color(0.8f, 0.8f, 0.8f);

    cameraNode = scene_.CreateChild("Camera");
    cameraNode.CreateComponent("Camera");
    cameraNode.position = Vector3(0.0f, 10.0f, -30.0f);

    Node@ text3DNode = scene_.CreateChild("Text3D");
    text3DNode.position = Vector3(0.0f, 0.1f, 30.0f);
    text3DNode.SetScale(15);
    Text3D@ text3D = text3DNode.CreateComponent("Text3D");

    // Manually set text in the current language.
    text3D.text = localization.Get("lang");

    text3D.SetFont(cache.GetResource("Font", "Fonts/Anonymous Pro.ttf"), 30);
    text3D.color = BLACK;
    text3D.SetAlignment(HA_CENTER, VA_BOTTOM);

    Viewport@ viewport = Viewport(scene_, cameraNode.GetComponent("Camera"));
    renderer.viewports[0] = viewport;

    SubscribeToEvent("Update", "HandleUpdate");
}

void HandleUpdate(StringHash eventType, VariantMap& eventData)
{
    float timeStep = eventData["TimeStep"].GetFloat();
    const float MOUSE_SENSITIVITY = 0.1f;
    IntVector2 mouseMove = input.mouseMove;
    yaw += MOUSE_SENSITIVITY * mouseMove.x;
    pitch += MOUSE_SENSITIVITY * mouseMove.y;
    pitch = Clamp(pitch, -90.0f, 90.0f);
    cameraNode.rotation = Quaternion(pitch, yaw, 0.0f);
}

void HandleChangeLangButtonPressed(StringHash eventType, VariantMap& eventData)
{
    // Languages are numbered in the loading order
    int lang = localization.languageIndex;
    lang++;
    if (lang >= localization.numLanguages)
        lang = 0;
    localization.SetLanguage(lang);
}

void HandleQuitButtonPressed(StringHash eventType, VariantMap& eventData)
{
    engine.Exit();
}

// You can manually change texts, sprites and other aspects of the game when language is changed
void HandleChangeLanguage(StringHash eventType, VariantMap& eventData)
{
    Text@ windowTitle = ui.root.GetChild("WindowTitle", true);
    windowTitle.text = localization.Get("title") + " (" +
                           String(localization.languageIndex) + " " +
                           localization.language + ")";

    Text@ buttonText = ui.root.GetChild("ButtonTextQuit", true);
    buttonText.text = localization.Get("quit");

    Text3D@ text3D = scene_.GetChild("Text3D").GetComponent("Text3D");
    text3D.text = localization.Get("lang");

    // A text on the button "Press this button" changes automatically
}

String patchInstructions = "";

Fix Color::BLACK to just BLACK in Localization AngelScript sample. Thanks JSandusky.