package aerys.minko.render
{
	import aerys.minko.Minko;
	import aerys.minko.ns.minko;
	import aerys.minko.render.effect.IEffect;
	import aerys.minko.render.effect.basic.BasicEffect;
	import aerys.minko.render.renderer.DefaultRenderer;
	import aerys.minko.render.renderer.IRenderer;
	import aerys.minko.scene.node.IScene;
	import aerys.minko.scene.visitor.ISceneVisitor;
	import aerys.minko.scene.visitor.data.CameraData;
	import aerys.minko.scene.visitor.data.LocalData;
	import aerys.minko.scene.visitor.data.RenderingData;
	import aerys.minko.scene.visitor.data.ViewportData;
	import aerys.minko.scene.visitor.rendering.RenderingVisitor;
	import aerys.minko.scene.visitor.rendering.WorldDataVisitor;
	import aerys.minko.type.Factory;
	import aerys.minko.type.IVersionnable;

	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.display.Stage3D;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.display3D.Context3DRenderMode;
	import flash.events.Event;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.system.Capabilities;
	import flash.system.System;
	import flash.utils.Dictionary;
	import flash.utils.getTimer;

	/**
	 * The viewport is the the display area used to render a 3D scene.
	 * It can be used to render any IScene3D object.
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public class Viewport extends Sprite implements IVersionnable
	{
		use namespace minko;

		private static const ZERO2		: Point						= new Point();

		private var _version			: uint						= 0;

		private var _width				: Number					= 0.;
		private var _height				: Number					= 0.;
		private var _autoResize			: Boolean					= false;
		private var _antiAliasing		: int						= 0;

		private var _visitors			: Vector.<ISceneVisitor>	= null;

		private var _time				: int						= 0;
		private var _sceneSize			: uint						= 0;
		private var _drawTime			: int						= 0;

		private var _stage3d			: Stage3D					= null;
		private var _rendererClass		: Class						= null;
		private var _renderer			: IRenderer					= null;
		private var _defaultEffect		: IEffect					= new BasicEffect();
		private var _backgroundColor	: int						= 0;

		private var _viewportData		: ViewportData				= null;

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

		override public function set x(value : Number) : void
		{
			super.x = value;
			updateRectangle();
		}

		override public function set y(value : Number) : void
		{
			super.y = value;
			updateRectangle();
		}

		/**
		 * Indicates the width of the viewport.
		 * @return The width of the viewport.
		 *
		 */
		override public function get width()	: Number
		{
			return _width;
		}

		override public function set width(value : Number) : void
		{
			if (value != _width)
			{
				_width = value;
				++_version;

				resetStage3D();
			}
		}

		public function get sceneSize() : uint
		{
			return _sceneSize;
		}

		/**
		 * Indicates the height of the viewport.
		 * @return The height of the viewport.
		 *
		 */
		override public function get height() : Number
		{
			return _height;
		}

		override public function set height(value : Number) : void
		{
			if (value != _height)
			{
				_height = value;
				++_version;

				resetStage3D();
			}
		}

		/**
		 * The anti-aliasing value used to render the scene.
		 *
		 * @return
		 *
		 */
		public function get antiAliasing() : int
		{
			return _antiAliasing;
		}

		public function set antiAliasing(value : int) : void
		{
			if (value != _antiAliasing)
			{
				_antiAliasing = value;
				++_version;

				resetStage3D();
			}
		}

		public function get defaultEffect() : IEffect
		{
			return _defaultEffect;
		}

		public function set defaultEffect(value : IEffect) : void
		{
			_defaultEffect = value;
		}

		/**
		 * The amount of triangle rendered durung the last call to the
		 * "render" method. Sometimes, the number of triangles is higher
		 * than the total amount of triangles in the scene because some
		 * triangles are renderer multiple times (multipass).
		 *
		 * @return
		 *
		 */
		public function get numTriangles() : uint
		{
			return _renderer ? _renderer.numTriangles : 0;
		}

		/**
		 * The time spent during the last call to the "render" method.
		 *
		 * This time includes:
		 *

		 *
updating the scene graph

		 *
rendering the scene graph

		 *
performing draw calls to the internal 3D APIs

		 *

		 *
		 * @return
		 *
		 */
		public function get renderingTime() : uint
		{
			return _time;
		}

		public function get drawingTime() : int
		{
			return _drawTime;
		}

		public function get renderMode() : String
		{
			return _stage3d && _stage3d.context3D ? _stage3d.context3D.driverInfo : null;
		}

		public function get backgroundColor() : int
		{
			return _backgroundColor;
		}

		public function set backgroundColor(value : int) : void
		{
			_backgroundColor = value;
		}

		public function get visitors() : Vector.<ISceneVisitor>
		{
			return _visitors;
		}

		/**
		 * Creates a new Viewport object.
		 *
		 * @param width The width of the viewport.
		 * @param height The height of the viewport.
		 */
		public function Viewport(width			: uint		= 0,
								 height			: uint		= 0,
								 antiAliasing	: int		= 0,
								 rendererType	: Class 	= null)
		{
			this.width = width;
			this.height = height;

			_autoResize		= _width == 0 || _height == 0;
			_antiAliasing	= antiAliasing;
			_rendererClass	= rendererType || DefaultRenderer;
			_viewportData	= new ViewportData(this);

			addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
			addEventListener(Event.REMOVED_FROM_STAGE, removedFromStage);
			addEventListener(Event.ADDED, addedHandler);
		}

		private function addedToStageHandler(event : Event) : void
		{
			var stageId	: int 		= 0;

			_stage3d = stage.stage3Ds[stageId];

			while (_stage3d.willTrigger(Event.CONTEXT3D_CREATE))
				_stage3d = stage.stage3Ds[int(++stageId)];

			_stage3d.addEventListener(Event.CONTEXT3D_CREATE, resetStage3D);
			_stage3d.requestContext3D(Context3DRenderMode.AUTO);

			if (_autoResize)
			{
				stage.align = StageAlign.TOP_LEFT;
				stage.scaleMode = StageScaleMode.NO_SCALE;
				stage.addEventListener(Event.RESIZE, stageResizeHandler);

				width = stage.stageWidth;
				height = stage.stageHeight;
			}

			showLogo();
		}

		private function removedFromStage(event : Event) : void
		{
			_stage3d.removeEventListener(Event.CONTEXT3D_CREATE, resetStage3D);
			_stage3d.context3D.dispose();
			_stage3d = null;
		}

		private function addedHandler(event : Event) : void
		{
			updateRectangle();
		}

		private function stageResizeHandler(event : Event) : void
		{
			var stage : Stage = event.target as Stage;

			if (stage.stageWidth)
				width = stage.stageWidth;
			if (stage.stageHeight)
				height = stage.stageHeight;

			resetStage3D();
			showLogo();
		}

		private function resetStage3D(event : Event = null) : void
		{
			if (_stage3d && _stage3d.context3D)
			{
				updateRectangle();

				_stage3d.context3D.configureBackBuffer(
					Math.min(2048, _width),
					Math.min(2048, _height),
					_antiAliasing,
					true
				);

				_renderer = new _rendererClass(this, _stage3d.context3D);

				_visitors = Vector.<ISceneVisitor>([
					new WorldDataVisitor(),
					new RenderingVisitor()
				]);

				dispatchEvent(new Event(Event.INIT));
			}
		}

		private function updateRectangle() : void
		{
			if (_stage3d)
			{
				var origin : Point = localToGlobal(ZERO2);

				_stage3d.viewPort = new Rectangle(origin.x, origin.y, _width, _height);
			}
		}

		/**
		 * Render the specified scene.
		 * @param scene
		 */
		public function render(scene : IScene) : void
		{
			if (_visitors && _visitors.length != 0)
			{
				var time : Number = getTimer();

				// create the data sources the visitors are going to write and read from during render.
				var localData		: LocalData		= new LocalData();
				var worldData		: Dictionary	= new Dictionary();
				var renderingData	: RenderingData	= new RenderingData();

				// push viewport related data into the data sources
				worldData[ViewportData] = _viewportData;
				renderingData.effect = defaultEffect;

				// execute all visitors
				for each (var visitor : ISceneVisitor in _visitors)
					visitor.processSceneGraph(scene, localData, worldData, renderingData, _renderer);

				_sceneSize	= visitors[0].numNodes;
				_time		= getTimer() - time;
				_drawTime	= _renderer.drawingTime;
			}
			else
			{
				_time = 0;
				_drawTime = 0;
			}

			Factory.sweep();
			showLogo();
		}

		public function showLogo() : void
		{
			var logo : Sprite = Minko.logo;

			addChild(logo);

			logo.x = 5;
			logo.y = _height - logo.height - 5;
		}
	}
}

package aerys.minko.render
{
	import aerys.minko.Minko;
	import aerys.minko.ns.minko;
	import aerys.minko.render.effect.IEffect;
	import aerys.minko.render.effect.basic.BasicEffect;
	import aerys.minko.render.renderer.DefaultRenderer;
	import aerys.minko.render.renderer.IRenderer;
	import aerys.minko.scene.node.IScene;
	import aerys.minko.scene.visitor.ISceneVisitor;
	import aerys.minko.scene.visitor.data.CameraData;
	import aerys.minko.scene.visitor.data.LocalData;
	import aerys.minko.scene.visitor.data.RenderingData;
	import aerys.minko.scene.visitor.data.ViewportData;
	import aerys.minko.scene.visitor.rendering.RenderingVisitor;
	import aerys.minko.scene.visitor.rendering.WorldDataVisitor;
	import aerys.minko.type.Factory;
	import aerys.minko.type.IVersionnable;

	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.display.Stage3D;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.display3D.Context3DRenderMode;
	import flash.events.Event;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.system.Capabilities;
	import flash.system.System;
	import flash.utils.Dictionary;
	import flash.utils.getTimer;

	/**
	 * The viewport is the the display area used to render a 3D scene.
	 * It can be used to render any IScene3D object.
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public class Viewport extends Sprite implements IVersionnable
	{
		use namespace minko;

		private static const ZERO2		: Point						= new Point();

		private var _version			: uint						= 0;

		private var _width				: Number					= 0.;
		private var _height				: Number					= 0.;
		private var _autoResize			: Boolean					= false;
		private var _antiAliasing		: int						= 0;

		private var _visitors			: Vector.<ISceneVisitor>	= null;

		private var _time				: int						= 0;
		private var _sceneSize			: uint						= 0;
		private var _drawTime			: int						= 0;

		private var _stage3d			: Stage3D					= null;
		private var _rendererClass		: Class						= null;
		private var _renderer			: IRenderer					= null;
		private var _defaultEffect		: IEffect					= new BasicEffect();
		private var _backgroundColor	: int						= 0;

		private var _viewportData		: ViewportData				= null;

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

		override public function set x(value : Number) : void
		{
			super.x = value;
			updateRectangle();
		}

		override public function set y(value : Number) : void
		{
			super.y = value;
			updateRectangle();
		}

		/**
		 * Indicates the width of the viewport.
		 * @return The width of the viewport.
		 *
		 */
		override public function get width()	: Number
		{
			return _width;
		}

		override public function set width(value : Number) : void
		{
			if (value != _width)
			{
				_width = value;
				++_version;

				resetStage3D();
			}
		}

		public function get sceneSize() : uint
		{
			return _sceneSize;
		}

		/**
		 * Indicates the height of the viewport.
		 * @return The height of the viewport.
		 *
		 */
		override public function get height() : Number
		{
			return _height;
		}

		override public function set height(value : Number) : void
		{
			if (value != _height)
			{
				_height = value;
				++_version;

				resetStage3D();
			}
		}

		/**
		 * The anti-aliasing value used to render the scene.
		 *
		 * @return
		 *
		 */
		public function get antiAliasing() : int
		{
			return _antiAliasing;
		}

		public function set antiAliasing(value : int) : void
		{
			if (value != _antiAliasing)
			{
				_antiAliasing = value;
				++_version;

				resetStage3D();
			}
		}

		public function get defaultEffect() : IEffect
		{
			return _defaultEffect;
		}

		public function set defaultEffect(value : IEffect) : void
		{
			_defaultEffect = value;
		}

		/**
		 * The amount of triangle rendered durung the last call to the
		 * "render" method. Sometimes, the number of triangles is higher
		 * than the total amount of triangles in the scene because some
		 * triangles are renderer multiple times (multipass).
		 *
		 * @return
		 *
		 */
		public function get numTriangles() : uint
		{
			return _renderer ? _renderer.numTriangles : 0;
		}

		/**
		 * The time spent during the last call to the "render" method.
		 *
		 * This time includes:
		 *

		 *
updating the scene graph

		 *
rendering the scene graph

		 *
performing draw calls to the internal 3D APIs

		 *

		 *
		 * @return
		 *
		 */
		public function get renderingTime() : uint
		{
			return _time;
		}

		public function get drawingTime() : int
		{
			return _drawTime;
		}

		public function get renderMode() : String
		{
			return _stage3d && _stage3d.context3D ? _stage3d.context3D.driverInfo : null;
		}

		public function get backgroundColor() : int
		{
			return _backgroundColor;
		}

		public function set backgroundColor(value : int) : void
		{
			_backgroundColor = value;
		}

		public function get visitors() : Vector.<ISceneVisitor>
		{
			return _visitors;
		}

		/**
		 * Creates a new Viewport object.
		 *
		 * @param width The width of the viewport.
		 * @param height The height of the viewport.
		 */
		public function Viewport(width			: uint		= 0,
								 height			: uint		= 0,
								 antiAliasing	: int		= 0,
								 rendererType	: Class 	= null)
		{
			this.width = width;
			this.height = height;

			_autoResize		= _width == 0 || _height == 0;
			_antiAliasing	= antiAliasing;
			_rendererClass	= rendererType || DefaultRenderer;
			_viewportData	= new ViewportData(this);

			addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
			addEventListener(Event.REMOVED_FROM_STAGE, removedFromStage);
			addEventListener(Event.ADDED, addedHandler);
		}

		private function addedToStageHandler(event : Event) : void
		{
			var stageId	: int 		= 0;

			_stage3d = stage.stage3Ds[stageId];

			while (_stage3d.willTrigger(Event.CONTEXT3D_CREATE))
				_stage3d = stage.stage3Ds[int(++stageId)];

			_stage3d.addEventListener(Event.CONTEXT3D_CREATE, resetStage3D);
			_stage3d.requestContext3D(Context3DRenderMode.AUTO);

			if (_autoResize)
			{
				stage.align = StageAlign.TOP_LEFT;
				stage.scaleMode = StageScaleMode.NO_SCALE;
				stage.addEventListener(Event.RESIZE, stageResizeHandler);

				width = stage.stageWidth;
				height = stage.stageHeight;
			}

			showLogo();
		}

		private function removedFromStage(event : Event) : void
		{
			_stage3d.removeEventListener(Event.CONTEXT3D_CREATE, resetStage3D);
			_stage3d.context3D.dispose();
			_stage3d = null;
		}

		private function addedHandler(event : Event) : void
		{
			updateRectangle();
		}

		private function stageResizeHandler(event : Event) : void
		{
			var stage : Stage = event.target as Stage;

			if (stage.stageWidth)
				width = stage.stageWidth;
			if (stage.stageHeight)
				height = stage.stageHeight;

			resetStage3D();
			showLogo();
		}

		private function resetStage3D(event : Event = null) : void
		{
			if (_stage3d && _stage3d.context3D)
			{
				updateRectangle();

				_stage3d.context3D.configureBackBuffer(
					Math.min(2048, _width),
					Math.min(2048, _height),
					_antiAliasing,
					true
				);

				_renderer = new _rendererClass(this, _stage3d.context3D);

				_visitors = Vector.<ISceneVisitor>([
					new WorldDataVisitor(),
					new RenderingVisitor()
				]);

				dispatchEvent(new Event(Event.INIT));
			}
		}

		private function updateRectangle() : void
		{
			if (_stage3d)
			{
				var origin : Point = localToGlobal(ZERO2);

				_stage3d.viewPort = new Rectangle(origin.x, origin.y, _width, _height);
			}
		}

		/**
		 * Render the specified scene.
		 * @param scene
		 */
		public function render(scene : IScene) : void
		{
			showLogo();

			if (_visitors && _visitors.length != 0)
			{
				var time : Number = getTimer();

				// create the data sources the visitors are going to write and read from during render.
				var localData		: LocalData		= new LocalData();
				var worldData		: Dictionary	= new Dictionary();
				var renderingData	: RenderingData	= new RenderingData();

				// push viewport related data into the data sources
				worldData[ViewportData] = _viewportData;
				renderingData.effect = defaultEffect;

				// execute all visitors
				for each (var visitor : ISceneVisitor in _visitors)
					visitor.processSceneGraph(scene, localData, worldData, renderingData, _renderer);

				_sceneSize	= visitors[0].numNodes;
				_time		= getTimer() - time;
				_drawTime	= _renderer.drawingTime;
			}
			else
			{
				_time = 0;
				_drawTime = 0;
			}

			Factory.sweep();
		}

		public function showLogo() : void
		{
			var logo : Sprite = Minko.logo;

			addChild(logo);

			logo.x = 5;
			logo.y = _height - logo.height - 5;
		}
	}
}

call showLogo() at the very begining of Viewport.render


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

import com.esri.ags.symbols.PictureMarkerSymbol;
import com.esri.ags.symbols.SimpleFillSymbol;
import com.esri.ags.symbols.SimpleLineSymbol;
import com.esri.ags.symbols.SimpleMarkerSymbol;
import com.esri.ags.symbols.Symbol;

public class SymbolParser
{
    public function parseSymbol(symbolXML:XML):Symbol
    {
        var symbol:Symbol;

        if (symbolXML)
        {
            if (symbolXML.simplemarkersymbol[0])
            {
                symbol = parseSimpleMarkerSymbol(symbolXML.simplemarkersymbol[0]);
            }
            else if (symbolXML.picturemarkersymbol[0])
            {
                symbol = parsePictureMarkerSymbol(symbolXML.picturemarkersymbol[0]);
            }
            else if (symbolXML.simplelinesymbol[0])
            {
                symbol = parseSimpleLineSymbol(symbolXML.simplelinesymbol[0]);
            }
            else if (symbolXML.simplefillsymbol[0])
            {
                symbol = parseSimpleFillSymbol(symbolXML.simplefillsymbol[0]);
            }
        }

        return symbol;
    }

    public function parseSimpleMarkerSymbol(smsXML:XML):SimpleMarkerSymbol
    {
        const simpleMarkerSymbol:SimpleMarkerSymbol = createDefaultPointSymbol();

        const parsedColor:Number = parseInt(smsXML.@color[0]);
        const parsedAlpha:Number = parseFloat(smsXML.@alpha[0]);
        const parsedSize:Number = parseFloat(smsXML.@size[0]);

        if (smsXML.@style[0])
        {
            simpleMarkerSymbol.style = smsXML.@style;
        }
        if (!isNaN(parsedAlpha))
        {
            simpleMarkerSymbol.alpha = parsedAlpha;
        }
        if (!isNaN(parsedColor))
        {
            simpleMarkerSymbol.color = parsedColor;
        }
        if (!isNaN(parsedSize))
        {
            simpleMarkerSymbol.size = parsedSize;
        }

        if (!simpleMarkerSymbol.outline)
        {
            simpleMarkerSymbol.outline = createDefaultOutlineSymbol();
        }

        const outlineSymbol:SimpleLineSymbol = simpleMarkerSymbol.outline;

        const parsedOutlineColor:uint = parseInt(smsXML.outline.@color[0]);
        const parsedOutlineWidth:Number = parseFloat(smsXML.outline.@width[0]);

        if (smsXML.outline.@style[0])
        {
            outlineSymbol.style = smsXML.outline.@style
        }
        if (!isNaN(parsedOutlineColor))
        {
            outlineSymbol.color = parsedOutlineColor;
        }
        if (!isNaN(parsedOutlineWidth))
        {
            outlineSymbol.width = parsedOutlineWidth;
        }

        return simpleMarkerSymbol;
    }

    private var _defaultPointSymbol:SimpleMarkerSymbol;

    public function get defaultPointSymbol():SimpleMarkerSymbol
    {
        return _defaultPointSymbol ||= new SimpleMarkerSymbol();
    }

    public function set defaultPointSymbol(value:SimpleMarkerSymbol):void
    {
        _defaultPointSymbol = value;
    }

    protected function createDefaultPointSymbol():SimpleMarkerSymbol
    {
        return defaultPointSymbol.clone() as SimpleMarkerSymbol;
    }

    private var _defaultOutlineSymbol:SimpleLineSymbol;

    public function get defaultOutlineSymbol():SimpleLineSymbol
    {
        return _defaultOutlineSymbol ||= new SimpleLineSymbol();
    }

    public function set defaultOutlineSymbol(value:SimpleLineSymbol):void
    {
        _defaultOutlineSymbol = value;
    }

    protected function createDefaultOutlineSymbol():SimpleLineSymbol
    {
        return defaultOutlineSymbol.clone() as SimpleLineSymbol;
    }

    public function parsePictureMarkerSymbol(pmsXML:XML):PictureMarkerSymbol
    {
        const url:String = pmsXML.@url;

        const parsedHeight:Number = parseFloat(pmsXML.@height[0]);
        const parsedWidth:Number = parseFloat(pmsXML.@width[0]);
        const parsedXOffset:Number = parseFloat(pmsXML.@xoffset[0]);
        const parsedYOffset:Number = parseFloat(pmsXML.@yoffset[0]);
        const parsedAngle:Number = parseFloat(pmsXML.@angle[0]);

        const height:Number = !isNaN(parsedHeight) ? parsedHeight : 0;
        const width:Number = !isNaN(parsedWidth) ? parsedWidth : 0;
        const xOffset:Number = !isNaN(parsedXOffset) ? parsedXOffset : 0;
        const yOffset:Number = !isNaN(parsedYOffset) ? parsedYOffset : 0;
        const angle:Number = !isNaN(parsedAngle) ? parsedAngle : 0;

        return new PictureMarkerSymbol(url, width, height, xOffset, yOffset, angle);
    }

    public function parseSimpleLineSymbol(slsXML:XML):SimpleLineSymbol
    {
        const simpleLineSymbol:SimpleLineSymbol = createDefaultPolylineSymbol();

        const parsedAlpha:Number = parseFloat(slsXML.@alpha[0]);
        const parsedOutlineColor:uint = parseInt(slsXML.@color[0]);
        const parsedOutlineWidth:Number = parseFloat(slsXML.@width[0]);

        if (slsXML.@style[0])
        {
            simpleLineSymbol.style = slsXML.@style;
        }
        if (!isNaN(parsedAlpha))
        {
            simpleLineSymbol.alpha = parsedAlpha;
        }
        if (!isNaN(parsedOutlineColor))
        {
            simpleLineSymbol.color = parsedOutlineColor;
        }
        if (!isNaN(parsedOutlineWidth))
        {
            simpleLineSymbol.width = parsedOutlineWidth;
        }

        return simpleLineSymbol;
    }

    private var _defaultPolylineSymbol:SimpleLineSymbol;

    public function get defaultPolylineSymbol():SimpleLineSymbol
    {
        return _defaultPolylineSymbol ||= new SimpleLineSymbol();
    }

    public function set defaultPolylineSymbol(value:SimpleLineSymbol):void
    {
        _defaultPolylineSymbol = value;
    }

    protected function createDefaultPolylineSymbol():SimpleLineSymbol
    {
        return defaultPolylineSymbol.clone() as SimpleLineSymbol;
    }

    public function parseSimpleFillSymbol(sfsXML:XML):SimpleFillSymbol
    {
        const simpleFillSymbol:SimpleFillSymbol = createDefaultPolygonSymbol();

        const parsedColor:Number = parseInt(sfsXML.@color[0]);
        const parsedAlpha:Number = parseFloat(sfsXML.@alpha[0]);

        if (sfsXML.@style[0])
        {
            simpleFillSymbol.style = sfsXML.@style;
        }
        if (!isNaN(parsedAlpha))
        {
            simpleFillSymbol.alpha = parsedAlpha;
        }
        if (!isNaN(parsedColor))
        {
            simpleFillSymbol.color = parsedColor;
        }

        if (!simpleFillSymbol.outline)
        {
            simpleFillSymbol.outline = createDefaultOutlineSymbol();
        }

        const outlineSymbol:SimpleLineSymbol = simpleFillSymbol.outline;

        const parsedOutlineColor:uint = parseInt(sfsXML.outline.@color[0]);
        const parsedOutlineWidth:Number = parseFloat(sfsXML.outline.@width[0]);

        if (sfsXML.outline.@style[0])
        {
            outlineSymbol.style = sfsXML.outline.@style;
        }
        if (!isNaN(parsedOutlineColor))
        {
            outlineSymbol.color = parsedOutlineColor;
        }
        if (!isNaN(parsedOutlineWidth))
        {
            outlineSymbol.width = parsedOutlineWidth;
        }

        return simpleFillSymbol;
    }

    private var _defaultPolygonSymbol:SimpleFillSymbol;

    public function get defaultPolygonSymbol():SimpleFillSymbol
    {
        return _defaultPolygonSymbol ||= new SimpleFillSymbol();
    }

    public function set defaultPolygonSymbol(value:SimpleFillSymbol):void
    {
        _defaultPolygonSymbol = value;
    }

    protected function createDefaultPolygonSymbol():SimpleFillSymbol
    {
        return defaultPolygonSymbol.clone() as SimpleFillSymbol;
    }
}
}

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

import com.esri.ags.symbols.PictureMarkerSymbol;
import com.esri.ags.symbols.SimpleFillSymbol;
import com.esri.ags.symbols.SimpleLineSymbol;
import com.esri.ags.symbols.SimpleMarkerSymbol;
import com.esri.ags.symbols.Symbol;

import flash.utils.ByteArray;

import mx.utils.Base64Decoder;

public class SymbolParser
{
    public function parseSymbol(symbolXML:XML):Symbol
    {
        var symbol:Symbol;

        if (symbolXML)
        {
            if (symbolXML.simplemarkersymbol[0])
            {
                symbol = parseSimpleMarkerSymbol(symbolXML.simplemarkersymbol[0]);
            }
            else if (symbolXML.picturemarkersymbol[0])
            {
                symbol = parsePictureMarkerSymbol(symbolXML.picturemarkersymbol[0]);
            }
            else if (symbolXML.simplelinesymbol[0])
            {
                symbol = parseSimpleLineSymbol(symbolXML.simplelinesymbol[0]);
            }
            else if (symbolXML.simplefillsymbol[0])
            {
                symbol = parseSimpleFillSymbol(symbolXML.simplefillsymbol[0]);
            }
        }

        return symbol;
    }

    public function parseSimpleMarkerSymbol(smsXML:XML):SimpleMarkerSymbol
    {
        const simpleMarkerSymbol:SimpleMarkerSymbol = createDefaultPointSymbol();

        const parsedColor:Number = parseInt(smsXML.@color[0]);
        const parsedAlpha:Number = parseFloat(smsXML.@alpha[0]);
        const parsedSize:Number = parseFloat(smsXML.@size[0]);

        if (smsXML.@style[0])
        {
            simpleMarkerSymbol.style = smsXML.@style;
        }
        if (!isNaN(parsedAlpha))
        {
            simpleMarkerSymbol.alpha = parsedAlpha;
        }
        if (!isNaN(parsedColor))
        {
            simpleMarkerSymbol.color = parsedColor;
        }
        if (!isNaN(parsedSize))
        {
            simpleMarkerSymbol.size = parsedSize;
        }

        if (!simpleMarkerSymbol.outline)
        {
            simpleMarkerSymbol.outline = createDefaultOutlineSymbol();
        }

        const outlineSymbol:SimpleLineSymbol = simpleMarkerSymbol.outline;

        const parsedOutlineColor:uint = parseInt(smsXML.outline.@color[0]);
        const parsedOutlineWidth:Number = parseFloat(smsXML.outline.@width[0]);

        if (smsXML.outline.@style[0])
        {
            outlineSymbol.style = smsXML.outline.@style
        }
        if (!isNaN(parsedOutlineColor))
        {
            outlineSymbol.color = parsedOutlineColor;
        }
        if (!isNaN(parsedOutlineWidth))
        {
            outlineSymbol.width = parsedOutlineWidth;
        }

        return simpleMarkerSymbol;
    }

    private var _defaultPointSymbol:SimpleMarkerSymbol;

    public function get defaultPointSymbol():SimpleMarkerSymbol
    {
        return _defaultPointSymbol ||= new SimpleMarkerSymbol();
    }

    public function set defaultPointSymbol(value:SimpleMarkerSymbol):void
    {
        _defaultPointSymbol = value;
    }

    protected function createDefaultPointSymbol():SimpleMarkerSymbol
    {
        return defaultPointSymbol.clone() as SimpleMarkerSymbol;
    }

    private var _defaultOutlineSymbol:SimpleLineSymbol;

    public function get defaultOutlineSymbol():SimpleLineSymbol
    {
        return _defaultOutlineSymbol ||= new SimpleLineSymbol();
    }

    public function set defaultOutlineSymbol(value:SimpleLineSymbol):void
    {
        _defaultOutlineSymbol = value;
    }

    protected function createDefaultOutlineSymbol():SimpleLineSymbol
    {
        return defaultOutlineSymbol.clone() as SimpleLineSymbol;
    }

    public function parsePictureMarkerSymbol(pmsXML:XML):PictureMarkerSymbol
    {
        const url:String = pmsXML.@url[0];
        const source:String = pmsXML.@source[0];

        var sourceData:ByteArray;
        if (source)
        {
            var decoder:Base64Decoder = new Base64Decoder();
            decoder.decode(source);
            sourceData = decoder.toByteArray();
        }

        const pictureSource:Object = sourceData ? sourceData : url;

        const parsedHeight:Number = parseFloat(pmsXML.@height[0]);
        const parsedWidth:Number = parseFloat(pmsXML.@width[0]);
        const parsedXOffset:Number = parseFloat(pmsXML.@xoffset[0]);
        const parsedYOffset:Number = parseFloat(pmsXML.@yoffset[0]);
        const parsedAngle:Number = parseFloat(pmsXML.@angle[0]);

        const height:Number = !isNaN(parsedHeight) ? parsedHeight : 0;
        const width:Number = !isNaN(parsedWidth) ? parsedWidth : 0;
        const xOffset:Number = !isNaN(parsedXOffset) ? parsedXOffset : 0;
        const yOffset:Number = !isNaN(parsedYOffset) ? parsedYOffset : 0;
        const angle:Number = !isNaN(parsedAngle) ? parsedAngle : 0;

        return new PictureMarkerSymbol(pictureSource, width, height, xOffset, yOffset, angle);
    }

    public function parseSimpleLineSymbol(slsXML:XML):SimpleLineSymbol
    {
        const simpleLineSymbol:SimpleLineSymbol = createDefaultPolylineSymbol();

        const parsedAlpha:Number = parseFloat(slsXML.@alpha[0]);
        const parsedOutlineColor:uint = parseInt(slsXML.@color[0]);
        const parsedOutlineWidth:Number = parseFloat(slsXML.@width[0]);

        if (slsXML.@style[0])
        {
            simpleLineSymbol.style = slsXML.@style;
        }
        if (!isNaN(parsedAlpha))
        {
            simpleLineSymbol.alpha = parsedAlpha;
        }
        if (!isNaN(parsedOutlineColor))
        {
            simpleLineSymbol.color = parsedOutlineColor;
        }
        if (!isNaN(parsedOutlineWidth))
        {
            simpleLineSymbol.width = parsedOutlineWidth;
        }

        return simpleLineSymbol;
    }

    private var _defaultPolylineSymbol:SimpleLineSymbol;

    public function get defaultPolylineSymbol():SimpleLineSymbol
    {
        return _defaultPolylineSymbol ||= new SimpleLineSymbol();
    }

    public function set defaultPolylineSymbol(value:SimpleLineSymbol):void
    {
        _defaultPolylineSymbol = value;
    }

    protected function createDefaultPolylineSymbol():SimpleLineSymbol
    {
        return defaultPolylineSymbol.clone() as SimpleLineSymbol;
    }

    public function parseSimpleFillSymbol(sfsXML:XML):SimpleFillSymbol
    {
        const simpleFillSymbol:SimpleFillSymbol = createDefaultPolygonSymbol();

        const parsedColor:Number = parseInt(sfsXML.@color[0]);
        const parsedAlpha:Number = parseFloat(sfsXML.@alpha[0]);

        if (sfsXML.@style[0])
        {
            simpleFillSymbol.style = sfsXML.@style;
        }
        if (!isNaN(parsedAlpha))
        {
            simpleFillSymbol.alpha = parsedAlpha;
        }
        if (!isNaN(parsedColor))
        {
            simpleFillSymbol.color = parsedColor;
        }

        if (!simpleFillSymbol.outline)
        {
            simpleFillSymbol.outline = createDefaultOutlineSymbol();
        }

        const outlineSymbol:SimpleLineSymbol = simpleFillSymbol.outline;

        const parsedOutlineColor:uint = parseInt(sfsXML.outline.@color[0]);
        const parsedOutlineWidth:Number = parseFloat(sfsXML.outline.@width[0]);

        if (sfsXML.outline.@style[0])
        {
            outlineSymbol.style = sfsXML.outline.@style;
        }
        if (!isNaN(parsedOutlineColor))
        {
            outlineSymbol.color = parsedOutlineColor;
        }
        if (!isNaN(parsedOutlineWidth))
        {
            outlineSymbol.width = parsedOutlineWidth;
        }

        return simpleFillSymbol;
    }

    private var _defaultPolygonSymbol:SimpleFillSymbol;

    public function get defaultPolygonSymbol():SimpleFillSymbol
    {
        return _defaultPolygonSymbol ||= new SimpleFillSymbol();
    }

    public function set defaultPolygonSymbol(value:SimpleFillSymbol):void
    {
        _defaultPolygonSymbol = value;
    }

    protected function createDefaultPolygonSymbol():SimpleFillSymbol
    {
        return defaultPolygonSymbol.clone() as SimpleFillSymbol;
    }
}
}

Add Base64 source property to <picturemarkersymbol/>.


package
{
  import flash.display.BlendMode;

  import org.flixel.*;
  import org.flixel.FlxPoint;

  public class PlayState extends FlxState
  {
    // Tileset that works with AUTO mode (best for thin walls)
    [Embed(source = 'auto_tiles.png')]private static var auto_tiles:Class;
    // Tileset that works with ALT mode (best for thicker walls)
    [Embed(source = 'alt_tiles.png')]private static var alt_tiles:Class;
    // Tileset that works with OFF mode (do what you want mode)
    [Embed(source = 'empty_tiles.png')]private static var empty_tiles:Class;

    [Embed(source="player.png")] private static var ImgPlayer:Class;

    [Embed(source="background.jpg")] private static var ImgBg:Class;

    // Some static constants for the size of the tilemap tiles
    private const TILE_WIDTH:uint = 24;
    private const TILE_HEIGHT:uint = 24;
    private const PLAYER_WIDTH:uint = 72;
    private const PLAYER_HEIGHT:uint = 72;

    // The dynamically generated FlxTilemap we're using.
    private var collisionMap:FlxTilemap;
    // Ledge controls, in tiles.
    private var minLedgeSize:uint = 3;
    private var maxLedgeSize:uint = 6;
    private var minLedgeSpacing:FlxPoint = new FlxPoint(4, 2);
    private var maxLedgeSpacing:FlxPoint = new FlxPoint(8, 4);

    // Instance of custom player class.
    private var player:Player;
    private var fallChecking:Boolean;

    private var bg:FlxSprite;

    // Flixel Methods
    // --------------
    override public function create():void
    {
      // Globals.
      FlxG.framerate = 50;
      FlxG.flashFramerate = 50;
      fallChecking = true;

      // Start our setup chain.
      setupPlatform();

      // For now, we add things in order to get correct layering.
      // TODO - offload to draw method?
      add(bg);
      add(collisionMap);
      add(player);
    }
    override public function update():void
    {
      // Start our update chain.
      updatePlatform();

      super.update();
    }
    override public function draw():void
    {
      super.draw();
    }

    // Setup Routines
    // --------------
    // Since the observer pattern is too slow, we'll just name our functions to be like hooks.
    // The platform is the first thing that gets set up.
    private function setupPlatform():void
    {
      // Load our scenery.
      bg = new FlxSprite(0, 0);
      bg.loadGraphic(ImgBg);

      // Generate our map string.
      var mapData:String = '';
      var rows:int = Math.round(Math.round(bg.height / TILE_HEIGHT)) ;
      var cols:int = Math.round(Math.round(bg.width / TILE_WIDTH));
      // Smarts of our algo.
      var cStart:uint, cEnd:uint, facing:uint, rSize:int, rSpacing:int, sizeRange:uint, spacingRange:uint;
      // Grunts of our algo.
      var r:int, c:int, col:Array;
      sizeRange = (maxLedgeSize - minLedgeSize);
      spacingRange = (maxLedgeSpacing.y - minLedgeSpacing.y);
      facing = FlxObject.RIGHT;
      for (r = 0; r < rows; r++) {
        col = [];
        if (r >= rows - minLedgeSpacing.y) {
          cStart = 0;
          cEnd = 0;
        }
        if (r == rows-1) {
          cStart = 0;
          cEnd = cols;
          rSpacing = 0;
        } else {
          if (rSpacing == 0) {
            rSpacing = minLedgeSpacing.y + int(Math.random() * spacingRange);
            rSize = minLedgeSize + uint(Math.random() * sizeRange);
            if (facing == FlxObject.LEFT) {
              cStart = 0;
              cEnd = rSize;
              facing = FlxObject.RIGHT;
            } else if (facing == FlxObject.RIGHT) {
              cStart = cols - rSize;
              cEnd = cols;
              facing = FlxObject.LEFT;
            }
          } else {
            rSpacing--;
          }
        }
        for (c = 0; c < cStart; c++) {
          col.push('0');
        }
        for (c = cStart; c < cEnd; c++) {
          col.push((rSpacing == 0) ? '1' : '0');
        }
        for (c = cEnd; c < cols; c++) {
          col.push('0');
        }
        mapData += col.join(',')+"\n";
      }

      // Creates a new tilemap with no arguments.
      collisionMap = new FlxTilemap();
      // Initializes the map using the generated string, the tile images, and the tile size.
      collisionMap.loadMap(mapData, auto_tiles, TILE_WIDTH, TILE_HEIGHT, FlxTilemap.AUTO);

      setupPlatformAfter();
    }
    // Hooks.
    private function setupPlatformAfter():void
    {
      // Draw player at the bottom.
      var start:FlxPoint = new FlxPoint();
      var floorHeight:Number = PLAYER_HEIGHT;
      start.x = (FlxG.width - PLAYER_HEIGHT) / 2;
      start.y = collisionMap.height - (PLAYER_HEIGHT + floorHeight);
      setupPlayer(start);

      // Move until we don't overlap.
      while (collisionMap.overlaps(player)) {
        if (player.x <= 0) {
          player.x = FlxG.width;
        }
        player.x -= TILE_WIDTH;
      }

      setupPlatformAndPlayerAfter();
    }
    private function setupPlatformAndPlayerAfter():void
    {
      setupCamera();
    }
    // Hooked routines.
    private function setupPlayer(start:FlxPoint):void
    {
      // Find start position for player.

      player = new Player(start.x, start.y);
      player.loadGraphic(ImgPlayer, true, true, 72);

      // Bounding box tweaks.
      player.height = 36;
      player.offset.y = 36;

      // Basic player physics.
      player.drag.x = 900; // anti-friction
      player.acceleration.y = 500; // gravity
      player.maxVelocity.x = 300;
      player.maxVelocity.y = 700;

      // Player jump physics.
      player.jumpVelocity.y = -420;

      // Animations.
      player.addAnimation('idle', [7]);
      player.addAnimation('run', [0,1,2,3,4,5,6,7,8,9,10,11], 12);
      player.addAnimation('jump', [3]);
    }
    private function setupCamera():void
    {
      FlxG.camera.follow(player);
      collisionMap.follow();
    }

    // Update Routines
    // ---------------
    private function updatePlatform():void
    {
      updatePlatformAfter();
    }
    // Hooks.
    private function updatePlatformAfter():void
    {
      // Tilemaps can be collided just like any other FlxObject, and flixel
      // automatically collides each individual tile with the object.
      FlxG.collide(player, collisionMap);

      wrapToStage(player);
      updatePlayer();

      updatePlatformAndPlayerAfter();
    }
    private function updatePlatformAndPlayerAfter():void
    {
      updateCamera(player.justFell());
    }
    // Hooked routines.
    private function updatePlayer():void
    {
      player.moveWithInput();

      if (player.velocity.y != 0)
      {
        player.play('jump');
      }
      else if (player.velocity.x == 0)
      {
        player.play('idle');
      }
      else
      {
        player.play('run');
      }
    }
    private function updateCamera(playerJustFell:Boolean):void
    {
      if (fallChecking && playerJustFell) {
        FlxG.camera.shake(
          0.01,
          0.1, null, true,
          FlxCamera.SHAKE_VERTICAL_ONLY
        );
      }
    }

    // Helpers
    // -------
    private function wrapToStage(obj:FlxObject):void
    {
      obj.x = Math.min(Math.max(obj.x, 0), (collisionMap.width - obj.width));
    }
  }
}

package
{
  import flash.display.BlendMode;

  import org.flixel.*;
  import org.flixel.FlxPoint;

  public class PlayState extends FlxState
  {
    // Tileset that works with AUTO mode (best for thin walls)
    [Embed(source = 'auto_tiles.png')]private static var auto_tiles:Class;
    // Tileset that works with ALT mode (best for thicker walls)
    [Embed(source = 'alt_tiles.png')]private static var alt_tiles:Class;
    // Tileset that works with OFF mode (do what you want mode)
    [Embed(source = 'empty_tiles.png')]private static var empty_tiles:Class;

    [Embed(source="player.png")] private static var ImgPlayer:Class;

    [Embed(source="background.jpg")] private static var ImgBg:Class;

    // Some static constants for the size of the tilemap tiles
    private const TILE_WIDTH:uint = 24;
    private const TILE_HEIGHT:uint = 24;
    private const PLAYER_WIDTH:uint = 72;
    private const PLAYER_HEIGHT:uint = 72;

    // The dynamically generated FlxTilemap we're using.
    private var collisionMap:FlxTilemap;
    // Ledge controls, in tiles.
    private var minLedgeSize:uint = 3;
    private var maxLedgeSize:uint = 6;
    private var minLedgeSpacing:FlxPoint = new FlxPoint(4, 2);
    private var maxLedgeSpacing:FlxPoint = new FlxPoint(8, 4);

    // Instance of custom player class.
    private var player:Player;
    private var fallChecking:Boolean;

    private var bg:FlxSprite;

    // Flixel Methods
    // --------------
    override public function create():void
    {
      // Globals.
      FlxG.framerate = 50;
      FlxG.flashFramerate = 50;
      fallChecking = true;

      // Start our setup chain.
      setupPlatform();

      // For now, we add things in order to get correct layering.
      // TODO - offload to draw method?
      add(bg);
      add(collisionMap);
      add(player);
    }
    override public function update():void
    {
      // Start our update chain.
      updatePlatform();

      super.update();
    }
    override public function draw():void
    {
      super.draw();
    }

    // Setup Routines
    // --------------
    // Since the observer pattern is too slow, we'll just name our functions to be like hooks.
    // The platform is the first thing that gets set up.
    private function setupPlatform():void
    {
      // Load our scenery.
      bg = new FlxSprite(0, 0);
      bg.loadGraphic(ImgBg);

      // Generate our map string.
      var mapData:String = '';
      var rows:int = Math.round(Math.round(bg.height / TILE_HEIGHT)) ;
      var cols:int = Math.round(Math.round(bg.width / TILE_WIDTH));
      // Smarts of our algo.
      var cStart:uint, cEnd:uint, facing:uint, rSize:int, rSpacing:int, sizeRange:uint, spacingRange:uint;
      // Grunts of our algo.
      var r:int, c:int, col:Array;
      sizeRange = (maxLedgeSize - minLedgeSize);
      spacingRange = (maxLedgeSpacing.y - minLedgeSpacing.y);
      facing = FlxObject.RIGHT;
      for (r = 0; r < rows; r++) {
        col = [];
        if (r >= rows - minLedgeSpacing.y) {
          cStart = 0;
          cEnd = 0;
        }
        if (r == rows-1) {
          cStart = 0;
          cEnd = cols;
          rSpacing = 0;
        } else {
          if (rSpacing == 0) {
            rSpacing = minLedgeSpacing.y + int(Math.random() * spacingRange);
            rSize = minLedgeSize + uint(Math.random() * sizeRange);
            if (facing == FlxObject.LEFT) {
              cStart = 0;
              cEnd = rSize;
              facing = FlxObject.RIGHT;
            } else if (facing == FlxObject.RIGHT) {
              cStart = cols - rSize;
              cEnd = cols;
              facing = FlxObject.LEFT;
            }
          } else {
            rSpacing--;
          }
        }
        for (c = 0; c < cStart; c++) {
          col.push('0');
        }
        for (c = cStart; c < cEnd; c++) {
          col.push((rSpacing == 0) ? '1' : '0');
        }
        for (c = cEnd; c < cols; c++) {
          col.push('0');
        }
        mapData += col.join(',')+"\n";
      }

      // Creates a new tilemap with no arguments.
      collisionMap = new FlxTilemap();
      // Initializes the map using the generated string, the tile images, and the tile size.
      collisionMap.loadMap(mapData, auto_tiles, TILE_WIDTH, TILE_HEIGHT, FlxTilemap.AUTO);

      setupPlatformAfter();
    }
    // Hooks.
    private function setupPlatformAfter():void
    {
      // Draw player at the bottom.
      var start:FlxPoint = new FlxPoint();
      var floorHeight:Number = PLAYER_HEIGHT;
      start.x = (FlxG.width - PLAYER_HEIGHT) / 2;
      start.y = collisionMap.height - (PLAYER_HEIGHT + floorHeight);
      setupPlayer(start);

      // Move until we don't overlap.
      while (collisionMap.overlaps(player)) {
        if (player.x <= 0) {
          player.x = FlxG.width;
        }
        player.x -= TILE_WIDTH;
      }

      setupPlatformAndPlayerAfter();
    }
    private function setupPlatformAndPlayerAfter():void
    {
      setupCamera();
    }
    // Hooked routines.
    private function setupPlayer(start:FlxPoint):void
    {
      // Find start position for player.

      player = new Player(start.x, start.y);
      player.loadGraphic(ImgPlayer, true, true, 72);

      // Bounding box tweaks.
      player.height = 36;
      player.offset.y = 36;

      // Basic player physics.
      player.drag.x = 900; // anti-friction
      player.acceleration.y = 500; // gravity
      player.maxVelocity.x = 300;
      player.maxVelocity.y = 700;

      // Player jump physics.
      player.jumpVelocity.y = -420;

      // Animations.
      player.addAnimation('idle', [12,13,14], 12);
      player.addAnimation('run', [0,1,2,3,4,5,6,7,8,9,10,11], 12);
      player.addAnimation('jump', [3]);
    }
    private function setupCamera():void
    {
      FlxG.camera.follow(player);
      collisionMap.follow();
    }

    // Update Routines
    // ---------------
    private function updatePlatform():void
    {
      updatePlatformAfter();
    }
    // Hooks.
    private function updatePlatformAfter():void
    {
      // Tilemaps can be collided just like any other FlxObject, and flixel
      // automatically collides each individual tile with the object.
      FlxG.collide(player, collisionMap);

      wrapToStage(player);
      updatePlayer();

      updatePlatformAndPlayerAfter();
    }
    private function updatePlatformAndPlayerAfter():void
    {
      updateCamera(player.justFell());
    }
    // Hooked routines.
    private function updatePlayer():void
    {
      player.moveWithInput();

      if (player.velocity.y != 0)
      {
        player.play('jump');
      }
      else if (player.velocity.x == 0)
      {
        player.play('idle');
      }
      else
      {
        player.play('run');
      }
    }
    private function updateCamera(playerJustFell:Boolean):void
    {
      if (fallChecking && playerJustFell) {
        FlxG.camera.shake(
          0.01,
          0.1, null, true,
          FlxCamera.SHAKE_VERTICAL_ONLY
        );
      }
    }

    // Helpers
    // -------
    private function wrapToStage(obj:FlxObject):void
    {
      obj.x = Math.min(Math.max(obj.x, 0), (collisionMap.width - obj.width));
    }
  }
}

Add basic idle animation.

Add basic idle animation.


;===============================================================================
;
;       Empty template for new programs (replace with Title)
;
;       Year Author <Email>
;       Year Author <Email>
;
;       Description
;
;============== Constants ======================================================

; Interrupt table (fe00h - feffh)
; Ends at feffh, but there are no devices connected to interrupts above fe0fh.
INT0_BTN        EQU     fe00h
INT1_BTN        EQU     fe01h
INT2_BTN        EQU     fe02h
; ...
INT14_BTN       EQU     fe02h
INT15_TIMER     EQU     fe0fh

; I/O addresses (ff00h - ffffh)
; Starts at ff00h, but there are no devices connected below fff0h.
DISP7SEG_0      EQU     fff0h   ; write
DISP7SEG_1      EQU     fff1h   ; write
DISP7SEG_2      EQU     fff2h   ; write
DISP7SEG_3      EQU     fff3h   ; write
LCD_CONTROL     EQU     fff4h   ; write
LCD_WRITE       EQU     fff5h   ; write
TIMER_VALUE     EQU     fff6h   ; read/write
TIMER_CONTROL   EQU     fff7h   ; read/write
LEDS            EQU     fff8h   ; write
SWITCHES        EQU     fff9h   ; read
INT_MASK        EQU     fffah   ; read/write
TERM_CURSOR     EQU     fffch   ; write
TERM_STATE      EQU     fffdh   ; read
TERM_WRITE      EQU     fffeh   ; write
TERM_READ       EQU     ffffh   ; read

; Default values
STR_END         EQU     0000h   ; string terminator
SP_ADDRESS      EQU     fdffh   ; starts at the last available address (fdffh)
INT_MASK_VALUE  EQU     ffffh   ; ffffh = enable all

;============== Data Region (starting at address 8000h) =======================

                ORIG    8000h

A_VARIABLE      WORD    1010011010b
A_STRING        STR     'A String', ' more words', '!', STR_END
A_BUFFER        TAB     1337

;============== Code Region (starting at address 0000h) ========================

                ORIG    0000h
                JMP     Main                    ; jump to main

;-------------- Routines -------------------------------------------------------

                ; a routine routine for INT0_BTN

Int0Routine:    NOP
                RTI

                ; a routine routine for INT1_BTN

Int1Routine:    NOP
                RTI

                ; a routine routine for INT2_BTN

Int2Routine:    NOP
                RTI

                ; a routine that does nothing

ARoutine:       NOP
                RET

                ; another routine that does nothing

AnotherRoutine: NOP
                RET

;-------------- Main Program ---------------------------------------------------

Main:           MOV     R1, SP_ADDRESS
                MOV     SP, R1                  ; set stack pointer

                MOV     R1, Int0Routine         ; set routine for INT0
                MOV     M[INT0_BTN], R1
                MOV     R1, Int1Routine         ; set routine for INT1
                MOV     M[INT1_BTN], R1
                MOV     R1, Int2Routine         ; set routine for INT2
                MOV     M[INT2_BTN], R1

                MOV     R1, ffffh
                MOV     M[INT_MASK], R1         ; set interrupt mask
                ENI                             ; enable interrupts

                CALL    ARoutine
                CALL    AnotherRoutine
                NOP
                NOP
                NOP

TheEnd:         BR      TheEnd

;===============================================================================

;===============================================================================
;
;       Empty template for new programs (replace with Title)
;
;       Year Author <Email>
;       Year Author <Email>
;
;       Description
;
;===============================================================================

; Interrupt Vector Table addresses (fe00h to feffh)
INT0_BTN        EQU     fe00h
INT1_BTN        EQU     fe01h
INT2_BTN        EQU     fe02h
; ...
INT14_BTN       EQU     fe0eh
INT15_TIMER     EQU     fe0fh

; I/O addresses (ff00h to ffffh)
DISP7SEG_0      EQU     fff0h
DISP7SEG_1      EQU     fff1h
DISP7SEG_2      EQU     fff2h
DISP7SEG_3      EQU     fff3h
LCD_CONTROL     EQU     fff4h
LCD_WRITE       EQU     fff5h
TIMER_VALUE     EQU     fff6h
TIMER_CONTROL   EQU     fff7h
LEDS            EQU     fff8h
SWITCHES        EQU     fff9h
INT_MASK        EQU     fffah
TERM_CURSOR     EQU     fffch
TERM_STATE      EQU     fffdh
TERM_WRITE      EQU     fffeh
TERM_READ       EQU     ffffh

; Other constants
STR_END         EQU     0000h
SP_ADDRESS      EQU     fdffh
INT_MASK_VALUE  EQU     ffffh

;============== Data Region (starting at address 8000h) ========================

                ORIG    8000h

                ; allocate variables and data here (WORD, STR and TAB)

A_VARIABLE      WORD    1010011010b
A_STRING        STR     'A String', ' more words', '!', STR_END
A_BUFFER        TAB     1337

;============== Code Region (starting at address 0000h) ========================

                ORIG    0000h
                JMP     Main                    ; jump to main

;-------------- Routines -------------------------------------------------------

                ; put routines here

Int0Routine:    NOP     ; a routine routine for INT0
                INC     M[A_VARIABLE]
                RTI

ARoutine:       NOP     ; a routine that does nothing
                MOV     R2, M[A_VARIABLE]
                RET

;-------------- Main Program ---------------------------------------------------

Main:           MOV     R1, SP_ADDRESS
                MOV     SP, R1                  ; set stack pointer

                MOV     R1, Int0Routine
                MOV     M[INT0_BTN], R1         ; set routine for INT0

                MOV     R1, INT_MASK_VALUE
                MOV     M[INT_MASK], R1         ; set interrupt mask
                ENI                             ; enable interrupts

                ; start code here

                CALL    ARoutine

TheEnd:         BR      TheEnd

;===============================================================================

Clean 'template.as' demo

Clean 'template.as' demo


//
// $Id$

package {

import flash.display.Sprite;

import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.KeyboardEvent;
import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;

import flash.geom.Rectangle;

import flash.net.Socket;

import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;

import flash.ui.Keyboard;

[SWF(frameRate="60", width=800, height=600, backgroundColor="#000000")]
public class ClientApp extends Sprite {

    /**
     * Creates a new client app.
     */
    public function ClientApp ()
    {
        // initialize when we've got our dimensions
        loaderInfo.addEventListener(Event.INIT, init);
    }

    /**
     * Initializes the app.
     */
    protected function init (event :Event) :void
    {
        // create and add the text field display
        _field = new TextField();
        addChild(_field);
        _field.autoSize = TextFieldAutoSize.CENTER;
        _field.textColor = 0x00FF00;
        _field.text = " ";
        _field.selectable = false;
        _field.multiline = true;
        var format :TextFormat = new TextFormat();
        format.font = "_typewriter";
        _field.setTextFormat(format);

        // get the size of a character and use it to determine the char width/height
        var bounds :Rectangle = _field.getCharBoundaries(0);
        _width = loaderInfo.width / bounds.width;
        _height = loaderInfo.height / bounds.height;
        var line :String = "", text :String = "";
        for (var ii :int = 0; ii < _width; ii++) {
            line += " ";
        }
        line += '\n';
        for (var jj :int = 0; jj < _height; jj++) {
            text += line;
        }
        _field.text = text;
        _field.setTextFormat(format);
        _field.x = (loaderInfo.width - _field.width) / 2;
        _field.y = (loaderInfo.height - _field.height) / 2;

        // listen for key events
        addEventListener(KeyboardEvent.KEY_DOWN, sendKeyMessage);
        addEventListener(KeyboardEvent.KEY_UP, sendKeyMessage);

        // create the socket
        _socket = new Socket();
        _socket.addEventListener(Event.CONNECT, function (event :Event) :void {
            // write the magic number, version, screen dimensions
            _socket.writeUnsignedInt(0x57544750);
            _socket.writeUnsignedInt(0x00000001);
            _socket.writeShort(_width);
            _socket.writeShort(_height);
        });
        _socket.addEventListener(IOErrorEvent.IO_ERROR, function (event :IOErrorEvent) :void {
            // TODO: display error

            var str :String = "Connect error";
            drawString(str, (_width - str.length) / 2, _height/2);
        });
        _socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR,
                function (event :SecurityErrorEvent) :void {
            // we get this when we can't connect; ignore it
        });
        _socket.addEventListener(ProgressEvent.SOCKET_DATA, readMessages);

        // attempt to connect to the server
        var params :Object = loaderInfo.parameters;
        _socket.connect(String(params["server_host"]), int(params["server_port"]));
    }

    /**
     * Handles key events.
     */
    protected function sendKeyMessage (event :KeyboardEvent) :void
    {
        if (!_socket.connected) {
            return;
        }
        _socket.writeShort(6);
        _socket.writeShort(event.type == KeyboardEvent.KEY_DOWN ? 0 : 1);
        _socket.writeUnsignedInt(getQtKeyCode(event));
    }

    /**
     * Handles incoming socket data.
     */
    protected function readMessages (event :ProgressEvent) :void
    {
    }

    /**
     * Draws a string at the specified x and y positions.
     */
    protected function drawString (str :String, x :int, y :int) :void
    {
        var begin :int = y*(_width + 1) + x;
        _field.replaceText(begin, begin + str.length, str);
    }

    /**
     * Converts an ActionScript key code to a Qt one.
     */
    protected function getQtKeyCode (event :KeyboardEvent) :uint
    {
        switch (event.keyCode) {
            case Keyboard.ESCAPE: return 0x01000000;
            case Keyboard.F1: return 0x01000030;
            case Keyboard.F2: return 0x01000031;
            case Keyboard.F3: return 0x01000032;
            case Keyboard.F4: return 0x01000033;
            case Keyboard.F5: return 0x01000034;
            case Keyboard.F6: return 0x01000035;
            case Keyboard.F7: return 0x01000036;
            case Keyboard.F8: return 0x01000037;
            case Keyboard.F9: return 0x01000038;
            case Keyboard.F10: return 0x01000039;
            case Keyboard.F11: return 0x0100003a;
            case Keyboard.F12: return 0x0100003b;
            case Keyboard.F13: return 0x0100003c;
            case Keyboard.F14: return 0x0100003d;
            case Keyboard.F15: return 0x0100003e;
            case Keyboard.PAUSE: return 0x01000008;

            case Keyboard.BACKQUOTE: return 0x60;
            case Keyboard.NUMBER_0: return 0x30;
            case Keyboard.NUMBER_1: return 0x31;
            case Keyboard.NUMBER_2: return 0x32;
            case Keyboard.NUMBER_3: return 0x33;
            case Keyboard.NUMBER_4: return 0x34;
            case Keyboard.NUMBER_5: return 0x35;
            case Keyboard.NUMBER_6: return 0x36;
            case Keyboard.NUMBER_7: return 0x37;
            case Keyboard.NUMBER_8: return 0x38;
            case Keyboard.NUMBER_9: return 0x39;
            case Keyboard.MINUS: return 0x2d;
            case Keyboard.EQUAL: return 0x3d;
            case Keyboard.BACKSPACE: return 0x01000003;
            case Keyboard.INSERT: return 0x01000006;
            case Keyboard.HOME: return 0x01000010;
            case Keyboard.PAGE_UP: return 0x01000016;
            case Keyboard.NUMPAD_DIVIDE: return 0x2f;
            case Keyboard.NUMPAD_MULTIPLY: return 0x2a;
            case Keyboard.NUMPAD_SUBTRACT: return 0x2d;

            case Keyboard.TAB: return 0x01000001;
            case Keyboard.Q: return 0x51;
            case Keyboard.W: return 0x57;
            case Keyboard.E: return 0x45;
            case Keyboard.R: return 0x52;
            case Keyboard.T: return 0x54;
            case Keyboard.Y: return 0x59;
            case Keyboard.U: return 0x55;
            case Keyboard.I: return 0x49;
            case Keyboard.O: return 0x4f;
            case Keyboard.P: return 0x50;
            case Keyboard.LEFTBRACKET: return 0x5b;
            case Keyboard.RIGHTBRACKET: return 0x5d;
            case Keyboard.BACKSLASH: return 0x5c;
            case Keyboard.DELETE: return 0x01000007;
            case Keyboard.END: return 0x01000011;
            case Keyboard.PAGE_DOWN: return 0x01000017;
            case Keyboard.NUMPAD_7: return 0x37;
            case Keyboard.NUMPAD_8: return 0x38;
            case Keyboard.NUMPAD_9: return 0x39;
            case Keyboard.NUMPAD_ADD: return 0x2b;

            case Keyboard.CAPS_LOCK: return 0x01000024;
            case Keyboard.A: return 0x41;
            case Keyboard.S: return 0x53;
            case Keyboard.D: return 0x44;
            case Keyboard.F: return 0x46;
            case Keyboard.G: return 0x47;
            case Keyboard.H: return 0x48;
            case Keyboard.J: return 0x4a;
            case Keyboard.K: return 0x4b;
            case Keyboard.L: return 0x4c;
            case Keyboard.SEMICOLON: return 0x3b;
            case Keyboard.QUOTE: return 0x27;
            case Keyboard.ENTER: return 0x01000004;
            case Keyboard.NUMPAD_4: return 0x34;
            case Keyboard.NUMPAD_5: return 0x35;
            case Keyboard.NUMPAD_6: return 0x36;

            case Keyboard.SHIFT: return 0x01000020;
            case Keyboard.Z: return 0x5a;
            case Keyboard.X: return 0x58;
            case Keyboard.C: return 0x43;
            case Keyboard.V: return 0x56;
            case Keyboard.B: return 0x42;
            case Keyboard.N: return 0x4e;
            case Keyboard.M: return 0x4d;
            case Keyboard.COMMA: return 0x2c;
            case Keyboard.PERIOD: return 0x2e;
            case Keyboard.SLASH: return 0x2f;
            case Keyboard.UP: return 0x01000013;
            case Keyboard.NUMPAD_1: return 0x31;
            case Keyboard.NUMPAD_2: return 0x32;
            case Keyboard.NUMPAD_3: return 0x33;
            case Keyboard.NUMPAD_ENTER: return 0x01000005;

            case Keyboard.CONTROL: return 0x01000021;
            case Keyboard.COMMAND: return 0x01000021;
            case Keyboard.ALTERNATE: return 0x01000023;
            case Keyboard.SPACE: return 0x20;
            case Keyboard.MENU: return 0x01000055;
            case Keyboard.LEFT: return 0x01000012;
            case Keyboard.DOWN: return 0x01000015;
            case Keyboard.RIGHT: return 0x01000014;

            case Keyboard.HELP: return 0x01000058;

            default: return 0x01ffffff; // Key_unknown
        }
    }

    /** Our gigantic text field. */
    protected var _field :TextField;

    /** The width and height of the display in characters. */
    protected var _width :int, _height :int;

    /** The socket via which we communicate with the server. */
    protected var _socket :Socket;
}
}

//
// $Id$

package {

import flash.display.Sprite;

import flash.events.ContextMenuEvent;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.KeyboardEvent;
import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;

import flash.geom.Rectangle;

import flash.net.SharedObject;
import flash.net.Socket;

import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;

import flash.ui.ContextMenu;
import flash.ui.ContextMenuItem;
import flash.ui.Keyboard;

/**
 * The Witgap client application.
 */
[SWF(frameRate="60", width=800, height=600, backgroundColor="#000000")]
public class ClientApp extends Sprite {

    /**
     * Creates a new client app.
     */
    public function ClientApp ()
    {
        // initialize when we've got our dimensions
        loaderInfo.addEventListener(Event.INIT, init);
    }

    /**
     * Initializes the app.
     */
    protected function init (event :Event) :void
    {
        // create and add the text field display
        _field = new TextField();
        addChild(_field);
        _field.autoSize = TextFieldAutoSize.CENTER;
        _field.textColor = 0x00FF00;
        _field.text = " ";
        _field.selectable = false;
        _field.multiline = true;
        var format :TextFormat = new TextFormat();
        format.font = "_typewriter";
        _field.setTextFormat(format);

        // get the size of a character and use it to determine the char width/height
        var bounds :Rectangle = _field.getCharBoundaries(0);
        _width = loaderInfo.width / bounds.width;
        _height = loaderInfo.height / bounds.height;
        var line :String = "", text :String = "";
        for (var ii :int = 0; ii < _width; ii++) {
            line += " ";
        }
        line += '\n';
        for (var jj :int = 0; jj < _height; jj++) {
            text += line;
        }
        _field.text = text;
        _field.setTextFormat(format);
        _field.x = (loaderInfo.width - _field.width) / 2;
        _field.y = (loaderInfo.height - _field.height) / 2;

        // get the preferences
        _prefs = SharedObject.getLocal("prefs");

        // add the context menu to change colors
        contextMenu = new ContextMenu();
        contextMenu.hideBuiltInItems();
        contextMenu.customItems = [ ];
        var captions :Array = [ "White", "Green", "Amber" ];
        var colors :Array = [ 0xFFFFFF, 0x00FF00, 0xFFFF00 ];
        var setColor :Function = function (caption :String) :void {
            _prefs.setProperty("color", caption);
            for (var kk :int = 0; kk < captions.length; kk++) {
                if (captions[kk] == caption) {
                    _field.textColor = colors[kk];
                    contextMenu.customItems[kk].enabled = false;
                } else {
                    contextMenu.customItems[kk].enabled = true;
                }
            }
        };
        var updateColor :Function = function (event :ContextMenuEvent) :void {
            setColor(ContextMenuItem(event.target).caption);
        };
        for (var kk :int = 0; kk < captions.length; kk++) {
            var item :ContextMenuItem = new ContextMenuItem(captions[kk]);
            contextMenu.customItems.push(item);
            item.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, updateColor);
        }
        setColor(_prefs.data["color"] == undefined ? "Green" : _prefs.data["color"]);

        // listen for key events
        addEventListener(KeyboardEvent.KEY_DOWN, sendKeyMessage);
        addEventListener(KeyboardEvent.KEY_UP, sendKeyMessage);

        // create the socket
        _socket = new Socket();
        _socket.addEventListener(Event.CONNECT, function (event :Event) :void {
            // write the magic number, version, screen dimensions
            _socket.writeUnsignedInt(0x57544750);
            _socket.writeUnsignedInt(0x00000001);
            _socket.writeShort(_width);
            _socket.writeShort(_height);
        });
        _socket.addEventListener(IOErrorEvent.IO_ERROR, function (event :IOErrorEvent) :void {
            // TODO: display error

            var str :String = "Connect error";
            drawString(str, (_width - str.length) / 2, _height/2);
        });
        _socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR,
                function (event :SecurityErrorEvent) :void {
            // we get this when we can't connect; ignore it
        });
        _socket.addEventListener(ProgressEvent.SOCKET_DATA, readMessages);

        // attempt to connect to the server
        var params :Object = loaderInfo.parameters;
        _socket.connect(String(params["server_host"]), int(params["server_port"]));
    }

    /**
     * Handles key events.
     */
    protected function sendKeyMessage (event :KeyboardEvent) :void
    {
        if (!_socket.connected) {
            return;
        }
        _socket.writeShort(6);
        _socket.writeShort(event.type == KeyboardEvent.KEY_DOWN ? 0 : 1);
        _socket.writeUnsignedInt(getQtKeyCode(event));
    }

    /**
     * Handles incoming socket data.
     */
    protected function readMessages (event :ProgressEvent) :void
    {
    }

    /**
     * Draws a string at the specified x and y positions.
     */
    protected function drawString (str :String, x :int, y :int) :void
    {
        var begin :int = y*(_width + 1) + x;
        _field.replaceText(begin, begin + str.length, str);
    }

    /**
     * Converts an ActionScript key code to a Qt one.
     */
    protected function getQtKeyCode (event :KeyboardEvent) :uint
    {
        switch (event.keyCode) {
            case Keyboard.ESCAPE: return 0x01000000;
            case Keyboard.F1: return 0x01000030;
            case Keyboard.F2: return 0x01000031;
            case Keyboard.F3: return 0x01000032;
            case Keyboard.F4: return 0x01000033;
            case Keyboard.F5: return 0x01000034;
            case Keyboard.F6: return 0x01000035;
            case Keyboard.F7: return 0x01000036;
            case Keyboard.F8: return 0x01000037;
            case Keyboard.F9: return 0x01000038;
            case Keyboard.F10: return 0x01000039;
            case Keyboard.F11: return 0x0100003a;
            case Keyboard.F12: return 0x0100003b;
            case Keyboard.F13: return 0x0100003c;
            case Keyboard.F14: return 0x0100003d;
            case Keyboard.F15: return 0x0100003e;
            case Keyboard.PAUSE: return 0x01000008;

            case Keyboard.BACKQUOTE: return 0x60;
            case Keyboard.NUMBER_0: return 0x30;
            case Keyboard.NUMBER_1: return 0x31;
            case Keyboard.NUMBER_2: return 0x32;
            case Keyboard.NUMBER_3: return 0x33;
            case Keyboard.NUMBER_4: return 0x34;
            case Keyboard.NUMBER_5: return 0x35;
            case Keyboard.NUMBER_6: return 0x36;
            case Keyboard.NUMBER_7: return 0x37;
            case Keyboard.NUMBER_8: return 0x38;
            case Keyboard.NUMBER_9: return 0x39;
            case Keyboard.MINUS: return 0x2d;
            case Keyboard.EQUAL: return 0x3d;
            case Keyboard.BACKSPACE: return 0x01000003;
            case Keyboard.INSERT: return 0x01000006;
            case Keyboard.HOME: return 0x01000010;
            case Keyboard.PAGE_UP: return 0x01000016;
            case Keyboard.NUMPAD_DIVIDE: return 0x2f;
            case Keyboard.NUMPAD_MULTIPLY: return 0x2a;
            case Keyboard.NUMPAD_SUBTRACT: return 0x2d;

            case Keyboard.TAB: return 0x01000001;
            case Keyboard.Q: return 0x51;
            case Keyboard.W: return 0x57;
            case Keyboard.E: return 0x45;
            case Keyboard.R: return 0x52;
            case Keyboard.T: return 0x54;
            case Keyboard.Y: return 0x59;
            case Keyboard.U: return 0x55;
            case Keyboard.I: return 0x49;
            case Keyboard.O: return 0x4f;
            case Keyboard.P: return 0x50;
            case Keyboard.LEFTBRACKET: return 0x5b;
            case Keyboard.RIGHTBRACKET: return 0x5d;
            case Keyboard.BACKSLASH: return 0x5c;
            case Keyboard.DELETE: return 0x01000007;
            case Keyboard.END: return 0x01000011;
            case Keyboard.PAGE_DOWN: return 0x01000017;
            case Keyboard.NUMPAD_7: return 0x37;
            case Keyboard.NUMPAD_8: return 0x38;
            case Keyboard.NUMPAD_9: return 0x39;
            case Keyboard.NUMPAD_ADD: return 0x2b;

            case Keyboard.CAPS_LOCK: return 0x01000024;
            case Keyboard.A: return 0x41;
            case Keyboard.S: return 0x53;
            case Keyboard.D: return 0x44;
            case Keyboard.F: return 0x46;
            case Keyboard.G: return 0x47;
            case Keyboard.H: return 0x48;
            case Keyboard.J: return 0x4a;
            case Keyboard.K: return 0x4b;
            case Keyboard.L: return 0x4c;
            case Keyboard.SEMICOLON: return 0x3b;
            case Keyboard.QUOTE: return 0x27;
            case Keyboard.ENTER: return 0x01000004;
            case Keyboard.NUMPAD_4: return 0x34;
            case Keyboard.NUMPAD_5: return 0x35;
            case Keyboard.NUMPAD_6: return 0x36;

            case Keyboard.SHIFT: return 0x01000020;
            case Keyboard.Z: return 0x5a;
            case Keyboard.X: return 0x58;
            case Keyboard.C: return 0x43;
            case Keyboard.V: return 0x56;
            case Keyboard.B: return 0x42;
            case Keyboard.N: return 0x4e;
            case Keyboard.M: return 0x4d;
            case Keyboard.COMMA: return 0x2c;
            case Keyboard.PERIOD: return 0x2e;
            case Keyboard.SLASH: return 0x2f;
            case Keyboard.UP: return 0x01000013;
            case Keyboard.NUMPAD_1: return 0x31;
            case Keyboard.NUMPAD_2: return 0x32;
            case Keyboard.NUMPAD_3: return 0x33;
            case Keyboard.NUMPAD_ENTER: return 0x01000005;

            case Keyboard.CONTROL: return 0x01000021;
            case Keyboard.COMMAND: return 0x01000021;
            case Keyboard.ALTERNATE: return 0x01000023;
            case Keyboard.SPACE: return 0x20;
            case Keyboard.MENU: return 0x01000055;
            case Keyboard.LEFT: return 0x01000012;
            case Keyboard.DOWN: return 0x01000015;
            case Keyboard.RIGHT: return 0x01000014;

            case Keyboard.HELP: return 0x01000058;

            default: return 0x01ffffff; // Key_unknown
        }
    }

    /** Persistent preferences. */
    protected var _prefs :SharedObject;

    /** Our gigantic text field. */
    protected var _field :TextField;

    /** The width and height of the display in characters. */
    protected var _width :int, _height :int;

    /** The socket via which we communicate with the server. */
    protected var _socket :Socket;
}
}

Allow customizing the text color, persist to preferences.

git-svn-id: 41360ad359616a519dfba9f2f48af1afe653c9f7@10 be230a1c-449f-4488-b524-6273046f66f0


package org.hola
{
   import flash.utils.ByteArray;

   public class Base64 extends Object
   {

      private static const _decodeChars:Vector.<int> = InitDecodeChar();

      public function Base64()
      {
         super();
      }

      public static function decode(param1:String) : ByteArray
      {
         var _loc2_:* = 0;
         var _loc3_:* = 0;
         var _loc4_:* = 0;
         var _loc5_:* = 0;
         var _loc6_:* = 0;
         var _loc7_:int = param1.length;
         var _loc8_:ByteArray = new ByteArray();
         _loc8_.writeUTFBytes(param1);
         var _loc9_:* = 0;
         while(_loc6_ < _loc7_)
         {
            _loc2_ = _decodeChars[int(_loc8_[_loc6_++])];
            if(_loc2_ == -1)
            {
               break;
            }
            _loc3_ = _decodeChars[int(_loc8_[_loc6_++])];
            if(_loc3_ == -1)
            {
               break;
            }
            _loc8_[int(_loc9_++)] = _loc2_ << 2 | (_loc3_ & 48) >> 4;
            _loc4_ = _loc8_[int(_loc6_++)];
            if(_loc4_ == 61)
            {
               _loc8_.length = _loc9_;
               return _loc8_;
            }
            _loc4_ = _decodeChars[int(_loc4_)];
            if(_loc4_ == -1)
            {
               break;
            }
            _loc8_[int(_loc9_++)] = (_loc3_ & 15) << 4 | (_loc4_ & 60) >> 2;
            _loc5_ = _loc8_[int(_loc6_++)];
            if(_loc5_ == 61)
            {
               _loc8_.length = _loc9_;
               return _loc8_;
            }
            _loc5_ = _decodeChars[int(_loc5_)];
            if(_loc5_ == -1)
            {
               break;
            }
            _loc8_[int(_loc9_++)] = (_loc4_ & 3) << 6 | _loc5_;
         }
         _loc8_.length = _loc9_;
         return _loc8_;
      }

      public static function InitDecodeChar() : Vector.<int>
      {
         var _loc1_:Vector.<int> = new <int>[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1];
         return _loc1_;
      }
   }
}

package org.hola
{
    import flash.utils.ByteArray;

    public class Base64 extends Object
    {
        private static const _decodeChars:Vector.<int> = InitDecodeChar();

        public static function decode(str : String) : ByteArray {
            var c1 : int;
            var c2 : int;
            var c3 : int;
            var c4 : int;
            var i : int = 0;
            var len : int = str.length;
            var arr : ByteArray = new ByteArray();
            arr.length = len/4*3;
            var pos : int = 0;
            while (i<len)
            {
                c1 = _decodeChars[int(str.charCodeAt(i++))];
                if (c1 == -1)
                    break;
                c2 = _decodeChars[int(str.charCodeAt(i++))];
                if (c2 == -1)
                    break;
                arr[int(pos++)] = (c1 << 2) | ((c2 & 0x30) >> 4);
                c3 = int(str.charCodeAt(i++));
                if (c3 == 61)
                    break;
                c3 = _decodeChars[int(c3)];
                if (c3 == -1)
                    break;
                arr[int(pos++)] = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2);
                c4 = int(str.charCodeAt(i++));
                if (c4 == 61)
                    break;
                c4 = _decodeChars[int(c4)];
                if (c4 == -1)
                    break;
                arr[int(pos++)] = ((c3 & 0x03) << 6) | c4;
            }
            arr.length = pos;
            return arr;
        }

        public static function InitDecodeChar() : Vector.<int>
        {
            var decodeChars : Vector.<int> = new <int>[
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
                52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
                -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
                15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
                -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
                41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1];
            return decodeChars;
        }
    }
}

improve performance and readability of Base64.as


package org.jivesoftware.xiff.core
{
	public class AbstractJID
	{
		//TODO: this doesn't actually validate properly in some cases; need separate nodePrep, etc...
		protected static var jidNodeValidator:RegExp = /^([\x29\x23-\x25\x28-\x2E\x30-\x39\x3B\x3D\x3F\x41-\x7E\xA0 \u1680\u202F\u205F\u3000\u2000-\u2009\u200A-\u200B\u06DD \u070F\u180E\u200C-\u200D\u2028-\u2029\u0080-\u009F \u2060-\u2063\u206A-\u206F\uFFF9-\uFFFC\uE000-\uF8FF\uFDD0-\uFDEF \uFFFE-\uFFFF\uD800-\uDFFF\uFFF9-\uFFFD\u2FF0-\u2FFB]{1,1023})/;
		protected var _node:String = "";
		protected var _domain:String = "";
		protected var _resource:String = "";

		public function AbstractJID(inJID:String, validate:Boolean=false):void {
			if(validate)
			{
    			if(!jidNodeValidator.test(inJID) || inJID.indexOf(" ") > -1)
    			{
        			trace("Invalid JID: %s", inJID);
        			throw "Invalid JID";
    			}
   			}
   			var separatorIndex:int = inJID.lastIndexOf("@");
   			var slashIndex:int = inJID.lastIndexOf("/");
   			if(slashIndex >= 0)
   				_resource = inJID.substring(slashIndex + 1);
   			if(separatorIndex >= 0)
   				_domain = inJID.substring(separatorIndex + 1, slashIndex >= 0 ? slashIndex : inJID.length);
   			if(separatorIndex >= 1)
   				_node = inJID.substring(0, separatorIndex);
		}

		//if we use the literal regexp notation, flex gets confused and thinks the quote starts a string
		private static var quoteregex:RegExp = new RegExp('"', "g");
		private static var quoteregex2:RegExp = new RegExp("'", "g");

		protected function get escapedNode():String
		{
			var n:String = node;
			n = n.replace(/\\/g, "\\5c");
			n = n.replace(/@/g, "\\40");
    		n = n.replace(/ /g, "\\20");
    		n = n.replace(/&/g, "\\26");
     		n = n.replace(/>/g, "\\3e");
     		n = n.replace(/</g, "\\3c");
     		n = n.replace(/:/g, "\\3a");
     		n = n.replace(/\//g, "\\2f");
   			n = n.replace(quoteregex, "\\22");
   			n = n.replace(quoteregex2, "\\27");
   			trace(n);
   			return n;
		}

		protected function get unescapedNode():String
		{
			var n:String = node;
			n = n.replace(/\40/g, "@");
    		n = n.replace(/\20/g, " ");
    		n = n.replace(/\26/g, "&");
     		n = n.replace(/\3e/g, ">");
     		n = n.replace(/\3c/g, "<");
     		n = n.replace(/\3a/g, ":");
     		n = n.replace(/\2f/g, "/");
   			n = n.replace(quoteregex, '"');
   			n = n.replace(quoteregex2, "'");
   			n = n.replace(/\5c/g, "\\");
   			return n;
		}

    	public function toString():String
    	{
    		var j:String = "";
    		if(node)
    			j += node + "@";
    		j += domain;
    		if(resource)
    			j += "/" + resource;

			return j;
    	}

    	public function get bareJID():String
    	{
    		var str:String = toString();
    		var slashIndex:int = str.lastIndexOf("/");
    		if(slashIndex > 0)
    			str = str.substring(0, slashIndex);
        	return str;
    	}

    	public function get resource():String
    	{
        	if(_resource.length > 0)
        		return _resource;
        	return null;
    	}

    	public function get node():String
    	{
        	if(_node.length > 0)
        		return _node;
            return null;
    	}

    	public function get domain():String
    	{
        	return _domain;
    	}
	}
}

package org.jivesoftware.xiff.core
{
	public class AbstractJID
	{
		//TODO: this doesn't actually validate properly in some cases; need separate nodePrep, etc...
		protected static var jidNodeValidator:RegExp = /^([\x29\x23-\x25\x28-\x2E\x30-\x39\x3B\x3D\x3F\x41-\x7E\xA0 \u1680\u202F\u205F\u3000\u2000-\u2009\u200A-\u200B\u06DD \u070F\u180E\u200C-\u200D\u2028-\u2029\u0080-\u009F \u2060-\u2063\u206A-\u206F\uFFF9-\uFFFC\uE000-\uF8FF\uFDD0-\uFDEF \uFFFE-\uFFFF\uD800-\uDFFF\uFFF9-\uFFFD\u2FF0-\u2FFB]{1,1023})/;
		protected var _node:String = "";
		protected var _domain:String = "";
		protected var _resource:String = "";

		public function AbstractJID(inJID:String, validate:Boolean=false):void {
			if(validate)
			{
    			if(!jidNodeValidator.test(inJID) || inJID.indexOf(" ") > -1)
    			{
        			trace("Invalid JID: %s", inJID);
        			throw "Invalid JID";
    			}
   			}
   			var separatorIndex:int = inJID.lastIndexOf("@");
   			var slashIndex:int = inJID.lastIndexOf("/");
   			if(slashIndex >= 0)
   				_resource = inJID.substring(slashIndex + 1);
   			_domain = inJID.substring(separatorIndex + 1, slashIndex >= 0 ? slashIndex : inJID.length);
   			if(separatorIndex >= 1)
   				_node = inJID.substring(0, separatorIndex);
		}

		//if we use the literal regexp notation, flex gets confused and thinks the quote starts a string
		private static var quoteregex:RegExp = new RegExp('"', "g");
		private static var quoteregex2:RegExp = new RegExp("'", "g");

		protected function get escapedNode():String
		{
			var n:String = node;
			n = n.replace(/\\/g, "\\5c");
			n = n.replace(/@/g, "\\40");
    		n = n.replace(/ /g, "\\20");
    		n = n.replace(/&/g, "\\26");
     		n = n.replace(/>/g, "\\3e");
     		n = n.replace(/</g, "\\3c");
     		n = n.replace(/:/g, "\\3a");
     		n = n.replace(/\//g, "\\2f");
   			n = n.replace(quoteregex, "\\22");
   			n = n.replace(quoteregex2, "\\27");
   			trace(n);
   			return n;
		}

		protected function get unescapedNode():String
		{
			var n:String = node;
			n = n.replace(/\40/g, "@");
    		n = n.replace(/\20/g, " ");
    		n = n.replace(/\26/g, "&");
     		n = n.replace(/\3e/g, ">");
     		n = n.replace(/\3c/g, "<");
     		n = n.replace(/\3a/g, ":");
     		n = n.replace(/\2f/g, "/");
   			n = n.replace(quoteregex, '"');
   			n = n.replace(quoteregex2, "'");
   			n = n.replace(/\5c/g, "\\");
   			return n;
		}

    	public function toString():String
    	{
    		var j:String = "";
    		if(node)
    			j += node + "@";
    		j += domain;
    		if(resource)
    			j += "/" + resource;

			return j;
    	}

    	public function get bareJID():String
    	{
    		var str:String = toString();
    		var slashIndex:int = str.lastIndexOf("/");
    		if(slashIndex > 0)
    			str = str.substring(0, slashIndex);
        	return str;
    	}

    	public function get resource():String
    	{
        	if(_resource.length > 0)
        		return _resource;
        	return null;
    	}

    	public function get node():String
    	{
        	if(_node.length > 0)
        		return _node;
            return null;
    	}

    	public function get domain():String
    	{
        	return _domain;
    	}
	}
}

Fix another NPE. r=Armando

Fix another NPE. r=Armando


import mx.transitions.easing.*;
import com.mosesSupposes.fuse.*;

class com segonquart menuColouridiomes extends MoviieClip

	{
		public var cat, es, en ,fr:MovieClip;
		public var arrayLang_arr:Array = new Array ("cat", "es", "en", "fr");

		function menuColourIdiomes ():Void

		{

		this.onRollOver = this.mOver;
		this.onRollOut = this.mOut;
		this.onRelease =this.mOver;

		}

		private function mOver():Void

		{

                arrayLang_arr[i].colorTo("#95C60D", 0.3, "easeOutCirc");

		}

		private function mOut():Void

		{

                arrayLang_arr[i].colorTo("#010101", 0.3, "easeInCirc");

		}

	}

import mx.transitions.easing.*;
import com.mosesSupposes.fuse.*;

class menuColouridiomes extends MoviieClip

	{
		public var cat, es, en ,fr:MovieClip;
		public var arrayLang_arr:Array = new Array ("cat", "es", "en", "fr");

		function menuColourIdiomes ():Void

		{

		this.onRollOver = this.mOver;
		this.onRollOut = this.mOut;
		this.onRelease =this.mOver;

		}

		private function mOver():Void

		{

                arrayLang_arr[i].colorTo("#95C60D", 0.3, "easeOutCirc");

		}

		private function mOut():Void

		{

                arrayLang_arr[i].colorTo("#010101", 0.3, "easeInCirc");

		}

	}

Update menuColourIdiomes.as

Update menuColourIdiomes.as