////////////////////////////////////////////////////////////////////////////////
//
//  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.core
{
    import flash.display.DisplayObject;

    import mx.states.AddItems;
    import mx.states.SetProperty;
    import mx.states.State;

    import org.apache.flex.core.IParent;
    import org.apache.flex.core.IStatesObject;
    import org.apache.flex.events.Event;
    import org.apache.flex.events.EventDispatcher;
    import org.apache.flex.events.IEventDispatcher;
    import org.apache.flex.events.ValueChangeEvent;
    import org.apache.flex.utils.MXMLDataInterpreter;

    /**
     *  The SimpleStatesImpl class implements a minimal set of
     *  view state functionality that is sufficient for most applications.
     *  It only supports AddItems and SetProperty changes at this time.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
     */
	public class SimpleStatesImpl extends EventDispatcher implements IStatesImpl, IBead
	{
        /**
         *  Constructor.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function SimpleStatesImpl()
		{
			super();
		}

        private var _strand:IStrand;

        /**
         *  @copy org.apache.flex.core.IBead#strand
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public function set strand(value:IStrand):void
        {
            _strand = value;
            IEventDispatcher(_strand).addEventListener("currentStateChange", stateChangeHandler);
            IEventDispatcher(_strand).addEventListener("initComplete", initialStateHandler);
        }

        private function initialStateHandler(event:org.apache.flex.events.Event):void
        {
            stateChangeHandler(new ValueChangeEvent("currentStateChange", false, false, null,
                IStatesObject(_strand).currentState));
        }

        private function stateChangeHandler(event:ValueChangeEvent):void
        {
            var doc:IStatesObject = _strand as IStatesObject;
            var arr:Array = doc.states;
            for each (var s:State in arr)
            {
                if (s.name == event.oldValue)
                {
                    revert(s);
                    break;
                }
            }
            for each (s in arr)
            {
                if (s.name == event.newValue)
                {
                    apply(s);
                    break;
                }
            }
            doc.dispatchEvent(new Event("stateChangeComplete"));
        }

        private function revert(s:State):void
        {
            var arr:Array = s.overrides;
            for each (var o:Object in arr)
            {
                if (o is AddItems)
                {
                    var ai:AddItems = AddItems(o);
                    for each (var item:DisplayObject in ai.items)
                    {
                        var parent:IParent = ai.document as IParent;
                        if (ai.destination != null)
                            parent = parent[ai.destination] as IParent;
                        parent.removeElement(item);
                    }
                    if (parent is IContainer)
                        IContainer(parent).childrenAdded();
                }
                else if (o is SetProperty)
                {
                    var sp:SetProperty = SetProperty(o);
                    sp.document[sp.target][sp.name] = sp.previousValue;
                }
            }
        }

        private function apply(s:State):void
        {
            var arr:Array = s.overrides;
            for each (var o:Object in arr)
            {
                if (o is AddItems)
                {
                    var ai:AddItems = AddItems(o);
                    if (ai.items == null)
                    {
                        ai.items = MXMLDataInterpreter.generateMXMLArray(ai.document,
                                                    null, ai.itemsDescriptor);
                    }
                    for each (var item:DisplayObject in ai.items)
                    {
                        var parent:IParent = ai.document as IParent;
                        if (ai.destination != null)
                            parent = parent[ai.destination] as IParent;
                        if (ai.relativeTo != null)
                        {
                            var index:int = parent.numElements;
                            if (ai.relativeTo != null)
                            {
                                var child:Object = ai.document[ai.relativeTo];
                                index = parent.getElementIndex(child);
                                if (ai.position == "after")
                                    index++;
                            }
                            parent.addElementAt(item, index);
                        }
                        else
                        {
                            parent.addElement(item);
                        }
                    }
                    if (parent is IContainer)
                        IContainer(parent).childrenAdded();
                }
                else if (o is SetProperty)
                {
                    var sp:SetProperty = SetProperty(o);
                    sp.previousValue = sp.document[sp.target][sp.name];
                    sp.document[sp.target][sp.name] = sp.value;
                }
            }
        }
	}
}

////////////////////////////////////////////////////////////////////////////////
//
//  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.core
{
    import flash.display.DisplayObject;

    import mx.states.AddItems;
    import mx.states.SetProperty;
    import mx.states.State;

    import org.apache.flex.core.IParent;
    import org.apache.flex.core.IStatesObject;
    import org.apache.flex.events.Event;
    import org.apache.flex.events.EventDispatcher;
    import org.apache.flex.events.IEventDispatcher;
    import org.apache.flex.events.ValueChangeEvent;
    import org.apache.flex.utils.MXMLDataInterpreter;

    /**
     *  The SimpleStatesImpl class implements a minimal set of
     *  view state functionality that is sufficient for most applications.
     *  It only supports AddItems and SetProperty changes at this time.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
     */
	public class SimpleStatesImpl extends EventDispatcher implements IStatesImpl, IBead
	{
        /**
         *  Constructor.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function SimpleStatesImpl()
		{
			super();
		}

        private var _strand:IStrand;

        /**
         *  @copy org.apache.flex.core.IBead#strand
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public function set strand(value:IStrand):void
        {
            _strand = value;
            IEventDispatcher(_strand).addEventListener("currentStateChange", stateChangeHandler);
            IEventDispatcher(_strand).addEventListener("initComplete", initialStateHandler);
        }

        private function initialStateHandler(event:org.apache.flex.events.Event):void
        {
            stateChangeHandler(new ValueChangeEvent("currentStateChange", false, false, null,
                IStatesObject(_strand).currentState));
        }

        private function stateChangeHandler(event:ValueChangeEvent):void
        {
            var doc:IStatesObject = _strand as IStatesObject;
            var arr:Array = doc.states;
            for each (var s:State in arr)
            {
                if (s.name == event.oldValue)
                {
                    revert(s);
                    break;
                }
            }
            for each (s in arr)
            {
                if (s.name == event.newValue)
                {
                    apply(s);
                    break;
                }
            }
            doc.dispatchEvent(new Event("stateChangeComplete"));
        }

        private function revert(s:State):void
        {
            var arr:Array = s.overrides;
            for each (var o:Object in arr)
            {
                if (o is AddItems)
                {
                    var ai:AddItems = AddItems(o);
                    for each (var item:DisplayObject in ai.items)
                    {
                        var parent:IParent = ai.document as IParent;
                        if (ai.destination != null)
                            parent = parent[ai.destination] as IParent;
                        parent.removeElement(item);
                    }
                    if (parent is IContainer)
                        IContainer(parent).childrenAdded();
                }
                else if (o is SetProperty)
                {
                    var sp:SetProperty = SetProperty(o);
                    if (sp.target != null)
                        sp.document[sp.target][sp.name] = sp.previousValue;
                    else
                        sp.document[sp.name] = sp.previousValue;
                }
            }
        }

        private function apply(s:State):void
        {
            var arr:Array = s.overrides;
            for each (var o:Object in arr)
            {
                if (o is AddItems)
                {
                    var ai:AddItems = AddItems(o);
                    if (ai.items == null)
                    {
                        ai.items = MXMLDataInterpreter.generateMXMLArray(ai.document,
                                                    null, ai.itemsDescriptor);
                    }
                    for each (var item:DisplayObject in ai.items)
                    {
                        var parent:IParent = ai.document as IParent;
                        if (ai.destination != null)
                            parent = parent[ai.destination] as IParent;
                        if (ai.relativeTo != null)
                        {
                            var index:int = parent.numElements;
                            if (ai.relativeTo != null)
                            {
                                var child:Object = ai.document[ai.relativeTo];
                                index = parent.getElementIndex(child);
                                if (ai.position == "after")
                                    index++;
                            }
                            parent.addElementAt(item, index);
                        }
                        else
                        {
                            parent.addElement(item);
                        }
                    }
                    if (parent is IContainer)
                        IContainer(parent).childrenAdded();
                }
                else if (o is SetProperty)
                {
                    var sp:SetProperty = SetProperty(o);
                    if (sp.target != null)
                    {
                        sp.previousValue = sp.document[sp.target][sp.name];
                        sp.document[sp.target][sp.name] = sp.value;
                    }
                    else
                    {
                        sp.previousValue = sp.document[sp.name];
                        sp.document[sp.name] = sp.value;
                    }
                }
            }
        }
	}
}

handle state vars on the top tag

handle state vars on the top tag


/**
 * Created by vizoli on 4/8/16.
 */
package ageofai.map.model
{
	import ageofai.home.vo.HomeVO;
	import ageofai.map.astar.AStar;
	import ageofai.map.constant.CMap;
	import ageofai.map.constant.CMapNodeType;
	import ageofai.map.event.MapCreatedEvent;
	import ageofai.map.geom.IntPoint;
	import ageofai.map.vo.MapDataVO;
	import ageofai.unit.base.BaseUnitView;
	import ageofai.villager.view.VillagerView;

	import common.mvc.model.base.BaseModel;

	public class MapModel extends BaseModel implements IMapModel
	{

		private var _astarMap:GeneralAStarMap;
		private var _map:Vector.<Vector.<MapNode>>;
		private var _units:Vector.<Vector.<BaseUnitView>>;
		private var _homes:Vector.<HomeVO>;
		private var _fruits:Vector.<IntPoint>;
		private var _trees:Vector.<IntPoint>;

		public function get map():Vector.<Vector.<MapNode>>
		{
			return this._map;
		}

		public function get homes():Vector.<HomeVO>
		{
			return this._homes;
		}

		public function get fruits():Vector.<IntPoint>
		{
			return this._fruits;
		}

		public function get trees():Vector.<IntPoint>
		{
			return this._trees;
		}

		public function createMap( rowCount:int, columnCount:int ):void
		{
			this._map = new Vector.<Vector.<MapNode>>( rowCount, true );
			for( var i:int = 0; i < rowCount; i++ )
			{
				this._map[ i ] = new Vector.<MapNode>( columnCount, true );
				for( var j:int = 0; j < columnCount; j++ )
				{
					this._map[ i ][ j ] = this.getMapNode();
				}
			}

			// Get homes
			this._homes = this.getHomes( columnCount, rowCount );

			for each ( var home:HomeVO in this._homes )
			{
				for( i = home.pos.y; i < home.pos.y + 1; i++ )
				{
					for( j = home.pos.x; j < home.pos.x + 1; j++ )
					{
						this._map[ i ][ j ].objectType = CMapNodeType.OBJECT_HOME;
					}
				}
			}

			// Fruits
			 this._fruits = this.getFruits(columnCount, rowCount);

			 for each (var fruit:IntPoint in this._fruits)
			 {
			 this._map[fruit.y][fruit.x].objectType = CMapNodeType.OBJECT_FRUIT;
			 }

			 // Trees
			 this._trees = this.getTrees(columnCount, rowCount);

			 for each (var tree:IntPoint in this._trees)
			 {
			 this._map[ tree.y ][ tree.x ].objectType = CMapNodeType.OBJECT_TREE;
			 }

			this.eventDispatcher.dispatchEvent( new MapCreatedEvent( MapCreatedEvent.MAP_CREATED, this.getMapData() ) );
		}

		private function getHomes( columnCount:int, rowCount:int ):Vector.<HomeVO>
		{
			var homes:Vector.<HomeVO> = new Vector.<HomeVO>( CMap.HOME_COUNT, true );
			var minDistanceX:int = columnCount / CMap.HOME_COUNT;
			var minDistanceY:int = rowCount / CMap.HOME_COUNT;
			var offsetX:int, offsetY:int;
			do
			{
				offsetX = offsetY = 1;
				for( var i:int = 0; i < CMap.HOME_COUNT - 1; i++ )
				{
					var home:HomeVO = new HomeVO();
					home.pos = getRandomPoint( offsetX, offsetX += minDistanceX, offsetY, offsetY += minDistanceY );
					homes[ i ] = home;
				}
				home = new HomeVO();
				home.pos = getRandomPoint( offsetX, columnCount - 1, offsetY, rowCount - 1 );
				homes[ i ] = home;

				var isHomeInWalkableArea:Boolean = true;
				for( i = 0; i < CMap.HOME_COUNT; i++ )
				{
					if( this.isUnWalkablePointNextToIt( homes[ i ].pos ) )
					{
						isHomeInWalkableArea = false;
						break;
					}
				}

				if( !isHomeInWalkableArea )
				{
					continue;
				}

				// Make sure they are valid
				_astarMap = new GeneralAStarMap( _map );
				for( i = 0; i < CMap.HOME_COUNT; i++ )
				{
					if( this.isUnWalkablePointNextToIt( homes[ i ].pos ) )
					{
						break;
					}

					for( var j:int = 0; j < CMap.HOME_COUNT; j++ )
					{
                        if( i == j )
                        {
                            continue;
                        }
						var aStar:AStar = new AStar( _astarMap, homes[ i ].pos, homes[ j ].pos );
						var solution:Vector.<IntPoint> = aStar.solve();

                        if( solution )
                        {
                            break;
                        }
					}
                    if( !solution )
                    {
                        break;
                    }
				}
			}while( !solution );

			return homes;
		}

		private function isUnWalkablePointNextToIt( pos:IntPoint ):Boolean
		{
			var offsets:Array = [
				[ -1, -1 ], [ 0, -1 ], [ 1, -1 ], [ 2, -1 ],
				[ -1, 0 ], [ 0, 0 ],[ 1, 0 ],[ 2, 0 ],
				[ -1, 1 ], [ 0, 1 ],[ 1, 1 ],[ 2, 1 ],
				[ -1, 2 ], [ 0, 2 ], [ 1, 2 ], [ 2, 2 ],
			];

			for( var i:int = 0; i < offsets.length; i++ )
			{
				var colIndex:int = pos.y + offsets[ i ][ 0 ];
				var rowIndex:int = pos.x + offsets[ i ][ 1 ];

				if( colIndex >= 0 && rowIndex >= 0 && colIndex < this._map.length && rowIndex < this._map[ 0 ].length && this.isUnWalkablePoint( new IntPoint( colIndex, rowIndex ) ) )
				{
					return true;
				}
			}

			return false;
		}

		private function isUnWalkablePoint( pos:IntPoint ):Boolean
		{
			return !this._map[ pos.x ][ pos.y ].walkable;
		}

		private function getFruits( columnCount:int, rowCount:int ):Vector.<IntPoint>
		{
			var fruits:Vector.<IntPoint> = new Vector.<IntPoint>();
			for( var i:int = 0; i < CMap.HOME_COUNT; i++ )
			{
				var nearFruitsNo:int = Math.round( Math.random() * 4 ) + 2;

				for( var j:int = 0; j < nearFruitsNo; j++ )
				{
					do{
						var fruitX:int = Math.round( Math.random() * 8 ) + (this._homes[ i ].pos.x - 3);
						var fruitY:int = Math.round( Math.random() * 8 ) + (this._homes[ i ].pos.y - 3);
					}while( fruitX < 0 || fruitX >= columnCount || fruitY < 0 || fruitY >= rowCount
					|| (fruitX >= this._homes[ i ].pos.x && fruitX <= this._homes[ i ].pos.x + 2 && fruitY >= this._homes[ i ].pos.y && fruitY <= this._homes[ i ].pos.y + 2)
					|| !this._map[ fruitY ][ fruitX ].walkable
					|| this.isHomeInTheNear( fruitY, fruitX ) )

					fruits[ fruits.length ] = new IntPoint( fruitX, fruitY );
				}
			}

			var farFruitsNo:int = Math.round( Math.random() * 2 ) + 8;
			for( i = 0; i < farFruitsNo; i++ )
			{
				do{
					var fruitPos:IntPoint = getRandomPoint( 0, columnCount, 0, rowCount );
				}while( !this._map[ fruitPos.y ][ fruitPos.x ].walkable || distanceLessThan( 8, fruitPos ) )

				fruits[ fruits.length ] = fruitPos;
			}

			return fruits;
		}

		private function getTrees( columnCount:int, rowCount:int ):Vector.<IntPoint>
		{
			var trees:Vector.<IntPoint> = new Vector.<IntPoint>();
			for( var i:int = 0; i < CMap.HOME_COUNT; i++ )
			{
				var nearTreesNo:int = Math.round( Math.random() * 3 ) + 2;

				for( var j:int = 0; j < nearTreesNo; j++ )
				{
					do{
						var treeX:int = Math.round( Math.random() * 8 ) + (this._homes[ i ].pos.x - 3);
						var treeY:int = Math.round( Math.random() * 8 ) + (this._homes[ i ].pos.y - 3);
					}while( treeX < 0 || treeX >= columnCount || treeY < 0 || treeY >= rowCount
					|| (treeX >= this._homes[ i ].pos.x && treeX <= this._homes[ i ].pos.x + 2 && treeY >= this._homes[ i ].pos.y && treeY <= this._homes[ i ].pos.y + 2)
					|| !this._map[ treeY ][ treeX ].walkable
					|| this.isHomeInTheNear( treeY, treeX ) )

					trees[ trees.length ] = new IntPoint( treeX, treeY );
				}
			}

			var farTreesNo:int = Math.round( Math.random() * 2 ) + 14;
			for( i = 0; i < farTreesNo; i++ )
			{
				do{
					var treePos:IntPoint = getRandomPoint( 0, columnCount, 0, rowCount );
				}while( !this._map[ treePos.y ][ treePos.x ].walkable || distanceLessThan( 8, treePos ) )

				trees[ trees.length ] = treePos;
			}

			return trees;
		}

		private function isHomeInTheNear( col:uint, row:uint ):Boolean
		{
			var offsets:Array = [
				[ -1, -1 ], [ 0, -1 ], [ 1, -1 ],
				[ -1, 0 ], [ 0, 0 ], [ 1, 0 ],
				[ -1, 1 ], [ 0, 1 ], [ 1, 1 ]
			];

			for( var i:int = 0; i < offsets.length; i++ )
			{
				var colIndex:int = col + offsets[ i ][ 0 ];
				var rowIndex:int = row + offsets[ i ][ 1 ];

				if( this._map.length < rowIndex && rowIndex > 0
						&& this.map[ 0 ].length <= colIndex && colIndex > 0
						&& this._map[ colIndex ][ rowIndex ].objectType == CMapNodeType.OBJECT_HOME )
				{
					return true;
				}
			}

			return false;
		}

		/* INTERFACE ageofai.map.model.IMapModel */

		public function getMapData():MapDataVO
		{
			var mapData:MapDataVO = new MapDataVO();
			mapData.fruits = this._fruits;
			mapData.homes = this._homes;
			mapData.map = this._map;
			mapData.trees = this._trees;

			return mapData;
		}

		public function addUnit( villager:VillagerView ):void
		{
			if( !this._units )
			{
				this._units = new <Vector.<BaseUnitView>>[];
			}

			this._units.push( villager );

			this.eventDispatcher.dispatchEvent( new MapCreatedEvent( MapCreatedEvent.MAP_CREATED, this.getMapData() ) );
		}

		public function getPath( startPos:IntPoint, endPos:IntPoint ):Vector.<IntPoint>
		{
			var aStar:AStar = new AStar( this._astarMap, startPos, endPos );
			return aStar.solve();
		}

		private function getMapNode():MapNode
		{
			var rnd:Number = Math.random() * 100;
			var type:int;

			if( rnd <= 50 )
			{
				type = CMapNodeType.GRASS;
			}
			else if( rnd <= 95 )
			{
				type = CMapNodeType.DARK_GRASS;
			}
			else
			{
				type = CMapNodeType.WATER;
			}

			return new MapNode( type );
		}

		private function getRandomPoint( offsetX:int, limitX:int, offsetY:int, limitY:int ):IntPoint
		{
			var x:int = Math.random() * (limitX - offsetX) + offsetX;
			var y:int = Math.random() * (limitY - offsetY) + offsetY;

			return new IntPoint( x, y );
		}

		private function distanceLessThan( units:int, pos:IntPoint ):Boolean
		{
			for( var i:int = 0, count:int = this._homes.length; i < count; i++ )
			{
				if( Math.abs( pos.x - this._homes[ i ].pos.x ) + Math.abs( pos.y - this._homes[ i ].pos.y ) < units )
				{
					return true;
				}
			}
			return false;
		}
	}
}

/**
 * Created by vizoli on 4/8/16.
 */
package ageofai.map.model
{
	import ageofai.home.vo.HomeVO;
	import ageofai.map.astar.AStar;
	import ageofai.map.constant.CMap;
	import ageofai.map.constant.CMapNodeType;
	import ageofai.map.event.MapCreatedEvent;
	import ageofai.map.geom.IntPoint;
	import ageofai.map.vo.MapDataVO;
	import ageofai.unit.base.BaseUnitView;
	import ageofai.villager.view.VillagerView;

	import common.mvc.model.base.BaseModel;

	public class MapModel extends BaseModel implements IMapModel
	{

		private var _astarMap:GeneralAStarMap;
		private var _map:Vector.<Vector.<MapNode>>;
		private var _units:Vector.<Vector.<BaseUnitView>>;
		private var _homes:Vector.<HomeVO>;
		private var _fruits:Vector.<IntPoint>;
		private var _trees:Vector.<IntPoint>;

		public function get map():Vector.<Vector.<MapNode>>
		{
			return this._map;
		}

		public function get homes():Vector.<HomeVO>
		{
			return this._homes;
		}

		public function get fruits():Vector.<IntPoint>
		{
			return this._fruits;
		}

		public function get trees():Vector.<IntPoint>
		{
			return this._trees;
		}

		public function createMap( rowCount:int, columnCount:int ):void
		{
			this._map = new Vector.<Vector.<MapNode>>( rowCount, true );
			for( var i:int = 0; i < rowCount; i++ )
			{
				this._map[ i ] = new Vector.<MapNode>( columnCount, true );
				for( var j:int = 0; j < columnCount; j++ )
				{
					this._map[ i ][ j ] = this.getMapNode();
				}
			}

			// Get homes
			this._homes = this.getHomes( columnCount, rowCount );

			for each ( var home:HomeVO in this._homes )
			{
				for( i = home.pos.y; i < home.pos.y + 1; i++ )
				{
					for( j = home.pos.x; j < home.pos.x + 1; j++ )
					{
						this._map[ i ][ j ].objectType = CMapNodeType.OBJECT_HOME;
					}
				}
			}

			// Fruits
			 this._fruits = this.getFruits(columnCount, rowCount);

			 for each (var fruit:IntPoint in this._fruits)
			 {
			 this._map[fruit.y][fruit.x].objectType = CMapNodeType.OBJECT_FRUIT;
			 }

			 // Trees
			 this._trees = this.getTrees(columnCount, rowCount);

			 for each (var tree:IntPoint in this._trees)
			 {
			 this._map[ tree.y ][ tree.x ].objectType = CMapNodeType.OBJECT_TREE;
			 }

			this.eventDispatcher.dispatchEvent( new MapCreatedEvent( MapCreatedEvent.MAP_CREATED, this.getMapData() ) );
		}

		private function getHomes( columnCount:int, rowCount:int ):Vector.<HomeVO>
		{
			var homes:Vector.<HomeVO> = new Vector.<HomeVO>( CMap.HOME_COUNT, true );
			var minDistanceX:int = columnCount / CMap.HOME_COUNT;
			var minDistanceY:int = rowCount / CMap.HOME_COUNT;
			var offsetX:int, offsetY:int;
			do
			{
				offsetX = offsetY = 1;
				for( var i:int = 0; i < CMap.HOME_COUNT - 1; i++ )
				{
					var home:HomeVO = new HomeVO();
					home.pos = getRandomPoint( offsetX, offsetX += minDistanceX, offsetY, offsetY += minDistanceY );
					homes[ i ] = home;
				}
				home = new HomeVO();
				home.pos = getRandomPoint( offsetX, columnCount - 2, offsetY, rowCount - 2 );
				homes[ i ] = home;

				var isHomeInWalkableArea:Boolean = true;
				for( i = 0; i < CMap.HOME_COUNT; i++ )
				{
					if( this.isUnWalkablePointNextToIt( homes[ i ].pos ) )
					{
						isHomeInWalkableArea = false;
						break;
					}
				}

				if( !isHomeInWalkableArea )
				{
					continue;
				}

				// Make sure they are valid
				_astarMap = new GeneralAStarMap( _map );
				for( i = 0; i < CMap.HOME_COUNT; i++ )
				{
					if( this.isUnWalkablePointNextToIt( homes[ i ].pos ) )
					{
						break;
					}

					for( var j:int = 0; j < CMap.HOME_COUNT; j++ )
					{
                        if( i == j )
                        {
                            continue;
                        }
						var aStar:AStar = new AStar( _astarMap, homes[ i ].pos, homes[ j ].pos );
						var solution:Vector.<IntPoint> = aStar.solve();

                        if( solution )
                        {
                            break;
                        }
					}
                    if( !solution )
                    {
                        break;
                    }
				}
			}while( !solution );

			return homes;
		}

		private function isUnWalkablePointNextToIt( pos:IntPoint ):Boolean
		{
			var offsets:Array = [
				[ -1, -1 ], [ 0, -1 ], [ 1, -1 ], [ 2, -1 ],
				[ -1, 0 ], [ 0, 0 ],[ 1, 0 ],[ 2, 0 ],
				[ -1, 1 ], [ 0, 1 ],[ 1, 1 ],[ 2, 1 ],
				[ -1, 2 ], [ 0, 2 ], [ 1, 2 ], [ 2, 2 ],
			];

			for( var i:int = 0; i < offsets.length; i++ )
			{
				var colIndex:int = pos.y + offsets[ i ][ 0 ];
				var rowIndex:int = pos.x + offsets[ i ][ 1 ];

				if( colIndex >= 0 && rowIndex >= 0 && colIndex < this._map.length && rowIndex < this._map[ 0 ].length && this.isUnWalkablePoint( new IntPoint( colIndex, rowIndex ) ) )
				{
					return true;
				}
			}

			return false;
		}

		private function isUnWalkablePoint( pos:IntPoint ):Boolean
		{
			return !this._map[ pos.x ][ pos.y ].walkable;
		}

		private function getFruits( columnCount:int, rowCount:int ):Vector.<IntPoint>
		{
			var fruits:Vector.<IntPoint> = new Vector.<IntPoint>();
			for( var i:int = 0; i < CMap.HOME_COUNT; i++ )
			{
				var nearFruitsNo:int = Math.round( Math.random() * 4 ) + 2;

				for( var j:int = 0; j < nearFruitsNo; j++ )
				{
					do{
						var fruitX:int = Math.round( Math.random() * 8 ) + (this._homes[ i ].pos.x - 3);
						var fruitY:int = Math.round( Math.random() * 8 ) + (this._homes[ i ].pos.y - 3);
					}while( fruitX < 0 || fruitX >= columnCount || fruitY < 0 || fruitY >= rowCount
					|| (fruitX >= this._homes[ i ].pos.x && fruitX <= this._homes[ i ].pos.x + 2 && fruitY >= this._homes[ i ].pos.y && fruitY <= this._homes[ i ].pos.y + 2)
					|| !this._map[ fruitY ][ fruitX ].walkable
					|| this.isHomeInTheNear( fruitY, fruitX ) )

					fruits[ fruits.length ] = new IntPoint( fruitX, fruitY );
				}
			}

			var farFruitsNo:int = Math.round( Math.random() * 2 ) + 8;
			for( i = 0; i < farFruitsNo; i++ )
			{
				do{
					var fruitPos:IntPoint = getRandomPoint( 0, columnCount, 0, rowCount );
				}while( !this._map[ fruitPos.y ][ fruitPos.x ].walkable || distanceLessThan( 8, fruitPos ) )

				fruits[ fruits.length ] = fruitPos;
			}

			return fruits;
		}

		private function getTrees( columnCount:int, rowCount:int ):Vector.<IntPoint>
		{
			var trees:Vector.<IntPoint> = new Vector.<IntPoint>();
			for( var i:int = 0; i < CMap.HOME_COUNT; i++ )
			{
				var nearTreesNo:int = Math.round( Math.random() * 3 ) + 2;

				for( var j:int = 0; j < nearTreesNo; j++ )
				{
					do{
						var treeX:int = Math.round( Math.random() * 8 ) + (this._homes[ i ].pos.x - 3);
						var treeY:int = Math.round( Math.random() * 8 ) + (this._homes[ i ].pos.y - 3);
					}while( treeX < 0 || treeX >= columnCount || treeY < 0 || treeY >= rowCount
					|| (treeX >= this._homes[ i ].pos.x && treeX <= this._homes[ i ].pos.x + 2 && treeY >= this._homes[ i ].pos.y && treeY <= this._homes[ i ].pos.y + 2)
					|| !this._map[ treeY ][ treeX ].walkable
					|| this.isHomeInTheNear( treeY, treeX ) )

					trees[ trees.length ] = new IntPoint( treeX, treeY );
				}
			}

			var farTreesNo:int = Math.round( Math.random() * 2 ) + 14;
			for( i = 0; i < farTreesNo; i++ )
			{
				do{
					var treePos:IntPoint = getRandomPoint( 0, columnCount, 0, rowCount );
				}while( !this._map[ treePos.y ][ treePos.x ].walkable || distanceLessThan( 8, treePos ) )

				trees[ trees.length ] = treePos;
			}

			return trees;
		}

		private function isHomeInTheNear( col:uint, row:uint ):Boolean
		{
			var offsets:Array = [
				[ -1, -1 ], [ 0, -1 ], [ 1, -1 ],
				[ -1, 0 ], [ 0, 0 ], [ 1, 0 ],
				[ -1, 1 ], [ 0, 1 ], [ 1, 1 ]
			];

			for( var i:int = 0; i < offsets.length; i++ )
			{
				var colIndex:int = col + offsets[ i ][ 0 ];
				var rowIndex:int = row + offsets[ i ][ 1 ];

				if( this._map.length < rowIndex && rowIndex > 0
						&& this.map[ 0 ].length <= colIndex && colIndex > 0
						&& this._map[ colIndex ][ rowIndex ].objectType == CMapNodeType.OBJECT_HOME )
				{
					return true;
				}
			}

			return false;
		}

		/* INTERFACE ageofai.map.model.IMapModel */

		public function getMapData():MapDataVO
		{
			var mapData:MapDataVO = new MapDataVO();
			mapData.fruits = this._fruits;
			mapData.homes = this._homes;
			mapData.map = this._map;
			mapData.trees = this._trees;

			return mapData;
		}

		public function addUnit( villager:VillagerView ):void
		{
			if( !this._units )
			{
				this._units = new <Vector.<BaseUnitView>>[];
			}

			this._units.push( villager );

			this.eventDispatcher.dispatchEvent( new MapCreatedEvent( MapCreatedEvent.MAP_CREATED, this.getMapData() ) );
		}

		public function getPath( startPos:IntPoint, endPos:IntPoint ):Vector.<IntPoint>
		{
			var aStar:AStar = new AStar( this._astarMap, startPos, endPos );
			return aStar.solve();
		}

		private function getMapNode():MapNode
		{
			var rnd:Number = Math.random() * 100;
			var type:int;

			if( rnd <= 50 )
			{
				type = CMapNodeType.GRASS;
			}
			else if( rnd <= 95 )
			{
				type = CMapNodeType.DARK_GRASS;
			}
			else
			{
				type = CMapNodeType.WATER;
			}

			return new MapNode( type );
		}

		private function getRandomPoint( offsetX:int, limitX:int, offsetY:int, limitY:int ):IntPoint
		{
			var x:int = Math.random() * (limitX - offsetX) + offsetX;
			var y:int = Math.random() * (limitY - offsetY) + offsetY;

			return new IntPoint( x, y );
		}

		private function distanceLessThan( units:int, pos:IntPoint ):Boolean
		{
			for( var i:int = 0, count:int = this._homes.length; i < count; i++ )
			{
				if( Math.abs( pos.x - this._homes[ i ].pos.x ) + Math.abs( pos.y - this._homes[ i ].pos.y ) < units )
				{
					return true;
				}
			}
			return false;
		}
	}
}

fix homes

fix homes


/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the at.matthew.httpstreaming package.
 *
 * The Initial Developer of the Original Code is
 * Matthew Kaufman.
 * Portions created by the Initial Developer are Copyright (C) 2011
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * ***** END LICENSE BLOCK ***** */

package org.denivip.osmf.net.httpstreaming.hls
{
	import flash.utils.ByteArray;

	import org.osmf.logging.Log;
	import org.osmf.logging.Logger;
	import org.osmf.net.httpstreaming.flv.FLVTagVideo;

	internal class HTTPStreamingMP2PESVideo extends HTTPStreamingMP2PESBase
	{
		private var _nalData:ByteArray;

		private var _vTag:FLVTagVideo;
		private var _vTagData:ByteArray;
		private var _scState:int;

		private var spsNAL:HTTPStreamingH264NALU = null;
		private var ppsNAL:HTTPStreamingH264NALU = null;

		public function HTTPStreamingMP2PESVideo()
		{
			_scState = 0;
			_nalData = new ByteArray();
			_vTag = null;
			_vTagData = null;
		}

		override public function processES(pusi:Boolean, packet:ByteArray, flush:Boolean = false): ByteArray
		{
			if(pusi)
			{
				// start of a new PES packet
				var startCode:uint =  packet.readUnsignedInt();
				if(startCode != 0x1e0 && startCode != 0x1ea && startCode != 0x1bd)
				{
					throw new Error("PES start code not found or not AAC/AVC");
				}
				// Ignore packet length and marker bits.
				packet.position += 3;
				// Need PTS and DTS
				var flags:uint = (packet.readUnsignedByte() & 0xc0) >> 6;
				CONFIG::LOGGING
				{
					if(flags != 0x03) {
						logger.warn("video PES packet without DTS");
					}
				}

				if(flags != 0x03 && flags != 0x02 && flags != 0x00)
				{
					throw new Error("video PES packet without PTS cannot be decoded");
				}
				// Check PES header length
				var length:uint = packet.readUnsignedByte();
				var pts:Number =
					uint((packet.readUnsignedByte() & 0x0e) << 29) +
					uint((packet.readUnsignedShort() & 0xfffe) << 14) +
					uint((packet.readUnsignedShort() & 0xfffe) >> 1);

				length -= 5;

				var timestamp:Number;
				if(flags == 0x03)
				{
					var dts:Number =
						((packet.readUnsignedByte() & 0x0e) << 29) +
						((packet.readUnsignedShort() & 0xfffe) << 14) +
						((packet.readUnsignedShort() & 0xfffe) >> 1);

					timestamp = Math.round(dts/90);
					_compositionTime =  Math.round(pts/90) - timestamp;
					length -= 5;
				}
				else
				{
					timestamp = Math.round(pts/90);
					_compositionTime = 0;
				}

				if(!_timestampReseted) {
					_offset += timestamp - _prevTimestamp;
				}

				if (_isDiscontunity || (!_streamOffsetSet)) {// && _prevTimestamp == 0)) { -- in most cases _prevTimestamp (like any timestamps in stream) can't be 0.
					/*if(timestamp > 0) {
						_offset += timestamp;
					}*/
					_timestamp = _initialTimestamp;
					_streamOffsetSet = true;
				}else{
					_timestamp = _initialTimestamp + _offset;
				}

				_prevTimestamp = timestamp;
				_timestampReseted = false;
				_isDiscontunity = false;

				// Skip other header data.
				packet.position += length;
			}

			if(!flush)
				var dStart:uint = packet.position;	// assume that the copy will be from start-of-data

			var nals:Vector.<HTTPStreamingH264NALU> = new Vector.<HTTPStreamingH264NALU>;
			var nal:HTTPStreamingH264NALU;

			if(flush)
			{
				nal = new HTTPStreamingH264NALU(_nalData); // full length to end, don't need to trim last 3 bytes
				if(nal.NALtype != 0)
				{
					nals.push(nal); // could inline this (see below)
					CONFIG::LOGGING
					{
						logger.info("pushed one flush nal of type "+nal.NALtype.toString());
					}
				}
				_nalData = new ByteArray();
			}
			else while(packet.bytesAvailable > 0)
			{
				var value:uint = packet.readUnsignedByte();

				// finding only 3-byte start codes is ok as trailing zeros are ignored in most (all?) cases

				switch(_scState)
				{
					case 0:
						if(value == 0x00)
							_scState = 1;
						break;
					case 1:
						if(value == 0x00)
							_scState = 2;
						else
							_scState = 0;
						break;
					case 2:
						if(value == 0x00)	// more than 2 zeros... no problem
						{
							// state stays at 2
							break;
						}
						else if(value == 0x01)
						{
							// perf
							_nalData.writeBytes(packet, dStart, packet.position-dStart);
							dStart = packet.position;
							// at this point we have the NAL data plus the *next* start code in _nalData
							// unless there was no previous NAL in which case _nalData is either empty or has the leading zeros, if any
							if(_nalData.length > 4) // require >1 byte of payload
							{
								_nalData.length -= 3; // trim off the 0 0 1 (might be one more zero, but in H.264 that's ok)
								nal = new HTTPStreamingH264NALU(_nalData);
								if(nal.NALtype != 0)
								{
									nals.push(nal); // could inline this as well, rather than stacking and processing later in the function
								}
							}
							else
							{
								CONFIG::LOGGING
								{
									logger.warn("length too short! = " + _nalData.length.toString());
								}
							}
							_nalData = new ByteArray(); // and start collecting into the next one
							_scState = 0; // got one, now go back to looking
							break;
						}
						else
						{
							_scState = 0; // go back to looking
							break;
						}
						// notreached
						break;
					default:
						// shouldn't ever get here
						_scState = 0;
						break;
				} // switch _scState
			} // while bytesAvailable

			if(!flush && packet.position-dStart > 0)
				_nalData.writeBytes(packet, dStart, packet.position-dStart);

			// find  SPS + PPS if we can
			for each(nal in nals)
			{
				switch(nal.NALtype)
				{
					case 7:
						spsNAL = nal;
						break;
					case 8:
						ppsNAL = nal;
						break;
					default:
						break;
				}
			}

			var tags:Vector.<FLVTagVideo> = new Vector.<FLVTagVideo>;
			var tag:FLVTagVideo;
			var avccTag:FLVTagVideo = null;
			var avcc:ByteArray = new ByteArray();

			// note that this breaks if the sps and pps are in different segments that we process

			if(spsNAL && ppsNAL)
			{
				var spsLength:Number = spsNAL.length;
				var ppsLength:Number = ppsNAL.length;
				tag = new FLVTagVideo();

				tag.timestamp = _timestamp;
				tag.codecID = FLVTagVideo.CODEC_ID_AVC;
				tag.frameType = FLVTagVideo.FRAME_TYPE_KEYFRAME;
				tag.avcPacketType = FLVTagVideo.AVC_PACKET_TYPE_SEQUENCE_HEADER;

				avcc.writeByte(0x01); // avcC version 1
				// profile, compatibility, level
				avcc.writeBytes(spsNAL.NALdata, 1, 3);
				avcc.writeByte(0xff); // 111111 + 2 bit NAL size - 1
				avcc.writeByte(0xe1); // number of SPS
				avcc.writeByte(spsLength >> 8); // 16-bit SPS byte count
				avcc.writeByte(spsLength);
				avcc.writeBytes(spsNAL.NALdata, 0, spsLength); // the SPS
				avcc.writeByte(0x01); // number of PPS
				avcc.writeByte(ppsLength >> 8); // 16-bit PPS byte count
				avcc.writeByte(ppsLength);
				avcc.writeBytes(ppsNAL.NALdata, 0, ppsLength);

				tag.data = avcc;

				tags.push(tag);
				avccTag = tag;

				spsNAL = null;
				ppsNAL = null;
			}

			for each(nal in nals)
			{
				if(nal.NALtype == 9)	// AUD -  should read the flags in here too, perhaps
				{
					// close the last _vTag and start a new one
					if(_vTag && _vTagData.length == 0){
						; // warnings =|
						CONFIG::LOGGING
						{
							logger.warn("zero-length vtag"); // can't happen if we are writing the AUDs in
							if(avccTag)
								logger.info(" avccts "+avccTag.timestamp.toString()+" vtagts "+_vTag.timestamp.toString());
						}
					}

					if(_vTag && _vTagData.length > 0)
					{
						_vTag.data = _vTagData; // set at end (see below)
						tags.push(_vTag);
						if(avccTag)
						{
							avccTag.timestamp = _vTag.timestamp;
							avccTag = null;
						}
					}
					_vTag = new FLVTagVideo();
					_vTagData = new ByteArray(); // we assemble the nalus outside, set at end

					_vTagData.writeUnsignedInt(nal.length);
					_vTagData.writeBytes(nal.NALdata); // start with this very NAL, an AUD (XXX not sure this is needed)

					_vTag.codecID = FLVTagVideo.CODEC_ID_AVC;
					_vTag.frameType = FLVTagVideo.FRAME_TYPE_INTER; // adjust to keyframe later
					_vTag.avcPacketType = FLVTagVideo.AVC_PACKET_TYPE_NALU;
					_vTag.timestamp = _timestamp;
					_vTag.avcCompositionTimeOffset = _compositionTime;
				}
				else if(nal.NALtype != 7 && nal.NALtype != 8)
				{
					if(_vTag == null)
					{
						CONFIG::LOGGING
						{
							logger.info("needed to create vtag");
						}
						_vTag = new FLVTagVideo();
						_vTagData = new ByteArray(); // we assemble the nalus outside, set at end
						_vTag.codecID = FLVTagVideo.CODEC_ID_AVC;
						_vTag.frameType = FLVTagVideo.FRAME_TYPE_INTER; // adjust to keyframe later
						_vTag.avcPacketType = FLVTagVideo.AVC_PACKET_TYPE_NALU;
						_vTag.timestamp = _timestamp;
						_vTag.avcCompositionTimeOffset = _compositionTime;
					}

					if(nal.NALtype == 5) // if keyframe
					{
						_vTag.frameType = FLVTagVideo.FRAME_TYPE_KEYFRAME;
					}

					_vTagData.writeUnsignedInt(nal.length);
					_vTagData.writeBytes(nal.NALdata);
				}
			}

			if(flush)
			{
				CONFIG::LOGGING
				{
					logger.info(" *** VIDEO FLUSH CALLED");
				}
				if(_vTag && _vTagData.length > 0)
				{
					_vTag.data = _vTagData; // set at end (see below)
					tags.push(_vTag);
					if(avccTag)
					{
						avccTag.timestamp = _vTag.timestamp;
						avccTag = null;
					}

					CONFIG::LOGGING
					{
						logger.info("flushing one vtag");
					}
				}

				_vTag = null; // can't start new one, don't have the info
			}

			var tagData:ByteArray = new ByteArray();

			for each(tag in tags)
			{
				tag.write(tagData);
			}

			return tagData;
		}

		CONFIG::LOGGING
		{
			private var logger:Logger = Log.getLogger('org.denivip.osmf.net.httpstreaming.hls.HTTPStreamingMP2PESVideo') as Logger;
		}

	} // class
} // package

/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the at.matthew.httpstreaming package.
 *
 * The Initial Developer of the Original Code is
 * Matthew Kaufman.
 * Portions created by the Initial Developer are Copyright (C) 2011
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * ***** END LICENSE BLOCK ***** */

package org.denivip.osmf.net.httpstreaming.hls
{
	import flash.utils.ByteArray;

	import org.osmf.logging.Log;
	import org.osmf.logging.Logger;
	import org.osmf.net.httpstreaming.flv.FLVTagVideo;

	internal class HTTPStreamingMP2PESVideo extends HTTPStreamingMP2PESBase
	{
		private var _nalData:ByteArray;

		private var _vTag:FLVTagVideo;
		private var _vTagData:ByteArray;
		private var _scState:int;

		private var spsNAL:HTTPStreamingH264NALU = null;
		private var ppsNAL:HTTPStreamingH264NALU = null;

		public function HTTPStreamingMP2PESVideo()
		{
			_scState = 0;
			_nalData = new ByteArray();
			_vTag = null;
			_vTagData = null;
		}

		override public function processES(pusi:Boolean, packet:ByteArray, flush:Boolean = false): ByteArray
		{
			if(pusi)
			{
				// start of a new PES packet
				var startCode:uint =  packet.readUnsignedInt();
				if(startCode != 0x1e0 && startCode != 0x1ea && startCode != 0x1bd)
				{
					throw new Error("PES start code not found or not AAC/AVC");
				}
				// Ignore packet length and marker bits.
				packet.position += 3;
				// Need PTS and DTS
				var flags:uint = (packet.readUnsignedByte() & 0xc0) >> 6;
				CONFIG::LOGGING
				{
					if(flags != 0x03) {
						logger.warn("video PES packet without DTS");
					}
				}

				if(flags != 0x03 && flags != 0x02 && flags != 0x00)
				{
					throw new Error("video PES packet without PTS cannot be decoded");
				}
				// Check PES header length
				var length:uint = packet.readUnsignedByte();
				var pts:Number =
					uint((packet.readUnsignedByte() & 0x0e) << 29) +
					uint((packet.readUnsignedShort() & 0xfffe) << 14) +
					uint((packet.readUnsignedShort() & 0xfffe) >> 1);

				length -= 5;

				var timestamp:Number;
				if(flags == 0x03)
				{
					var dts:Number =
						uint((packet.readUnsignedByte() & 0x0e) << 29) +
						uint((packet.readUnsignedShort() & 0xfffe) << 14) +
						uint((packet.readUnsignedShort() & 0xfffe) >> 1);

					timestamp = Math.round(dts/90);
					_compositionTime =  Math.round(pts/90) - timestamp;
					length -= 5;
				}
				else
				{
					timestamp = Math.round(pts/90);
					_compositionTime = 0;
				}

				if(!_timestampReseted) {
					_offset += timestamp - _prevTimestamp;
				}

				if (_isDiscontunity || (!_streamOffsetSet)) {// && _prevTimestamp == 0)) { -- in most cases _prevTimestamp (like any timestamps in stream) can't be 0.
					/*if(timestamp > 0) {
						_offset += timestamp;
					}*/
					_timestamp = _initialTimestamp;
					_streamOffsetSet = true;
				}else{
					_timestamp = _initialTimestamp + _offset;
				}

				_prevTimestamp = timestamp;
				_timestampReseted = false;
				_isDiscontunity = false;

				// Skip other header data.
				packet.position += length;
			}

			if(!flush)
				var dStart:uint = packet.position;	// assume that the copy will be from start-of-data

			var nals:Vector.<HTTPStreamingH264NALU> = new Vector.<HTTPStreamingH264NALU>;
			var nal:HTTPStreamingH264NALU;

			if(flush)
			{
				nal = new HTTPStreamingH264NALU(_nalData); // full length to end, don't need to trim last 3 bytes
				if(nal.NALtype != 0)
				{
					nals.push(nal); // could inline this (see below)
					CONFIG::LOGGING
					{
						logger.info("pushed one flush nal of type "+nal.NALtype.toString());
					}
				}
				_nalData = new ByteArray();
			}
			else while(packet.bytesAvailable > 0)
			{
				var value:uint = packet.readUnsignedByte();

				// finding only 3-byte start codes is ok as trailing zeros are ignored in most (all?) cases

				switch(_scState)
				{
					case 0:
						if(value == 0x00)
							_scState = 1;
						break;
					case 1:
						if(value == 0x00)
							_scState = 2;
						else
							_scState = 0;
						break;
					case 2:
						if(value == 0x00)	// more than 2 zeros... no problem
						{
							// state stays at 2
							break;
						}
						else if(value == 0x01)
						{
							// perf
							_nalData.writeBytes(packet, dStart, packet.position-dStart);
							dStart = packet.position;
							// at this point we have the NAL data plus the *next* start code in _nalData
							// unless there was no previous NAL in which case _nalData is either empty or has the leading zeros, if any
							if(_nalData.length > 4) // require >1 byte of payload
							{
								_nalData.length -= 3; // trim off the 0 0 1 (might be one more zero, but in H.264 that's ok)
								nal = new HTTPStreamingH264NALU(_nalData);
								if(nal.NALtype != 0)
								{
									nals.push(nal); // could inline this as well, rather than stacking and processing later in the function
								}
							}
							else
							{
								CONFIG::LOGGING
								{
									logger.warn("length too short! = " + _nalData.length.toString());
								}
							}
							_nalData = new ByteArray(); // and start collecting into the next one
							_scState = 0; // got one, now go back to looking
							break;
						}
						else
						{
							_scState = 0; // go back to looking
							break;
						}
						// notreached
						break;
					default:
						// shouldn't ever get here
						_scState = 0;
						break;
				} // switch _scState
			} // while bytesAvailable

			if(!flush && packet.position-dStart > 0)
				_nalData.writeBytes(packet, dStart, packet.position-dStart);

			// find  SPS + PPS if we can
			for each(nal in nals)
			{
				switch(nal.NALtype)
				{
					case 7:
						spsNAL = nal;
						break;
					case 8:
						ppsNAL = nal;
						break;
					default:
						break;
				}
			}

			var tags:Vector.<FLVTagVideo> = new Vector.<FLVTagVideo>;
			var tag:FLVTagVideo;
			var avccTag:FLVTagVideo = null;
			var avcc:ByteArray = new ByteArray();

			// note that this breaks if the sps and pps are in different segments that we process

			if(spsNAL && ppsNAL)
			{
				var spsLength:Number = spsNAL.length;
				var ppsLength:Number = ppsNAL.length;
				tag = new FLVTagVideo();

				tag.timestamp = _timestamp;
				tag.codecID = FLVTagVideo.CODEC_ID_AVC;
				tag.frameType = FLVTagVideo.FRAME_TYPE_KEYFRAME;
				tag.avcPacketType = FLVTagVideo.AVC_PACKET_TYPE_SEQUENCE_HEADER;

				avcc.writeByte(0x01); // avcC version 1
				// profile, compatibility, level
				avcc.writeBytes(spsNAL.NALdata, 1, 3);
				avcc.writeByte(0xff); // 111111 + 2 bit NAL size - 1
				avcc.writeByte(0xe1); // number of SPS
				avcc.writeByte(spsLength >> 8); // 16-bit SPS byte count
				avcc.writeByte(spsLength);
				avcc.writeBytes(spsNAL.NALdata, 0, spsLength); // the SPS
				avcc.writeByte(0x01); // number of PPS
				avcc.writeByte(ppsLength >> 8); // 16-bit PPS byte count
				avcc.writeByte(ppsLength);
				avcc.writeBytes(ppsNAL.NALdata, 0, ppsLength);

				tag.data = avcc;

				tags.push(tag);
				avccTag = tag;

				spsNAL = null;
				ppsNAL = null;
			}

			for each(nal in nals)
			{
				if(nal.NALtype == 9)	// AUD -  should read the flags in here too, perhaps
				{
					// close the last _vTag and start a new one
					if(_vTag && _vTagData.length == 0){
						; // warnings =|
						CONFIG::LOGGING
						{
							logger.warn("zero-length vtag"); // can't happen if we are writing the AUDs in
							if(avccTag)
								logger.info(" avccts "+avccTag.timestamp.toString()+" vtagts "+_vTag.timestamp.toString());
						}
					}

					if(_vTag && _vTagData.length > 0)
					{
						_vTag.data = _vTagData; // set at end (see below)
						tags.push(_vTag);
						if(avccTag)
						{
							avccTag.timestamp = _vTag.timestamp;
							avccTag = null;
						}
					}
					_vTag = new FLVTagVideo();
					_vTagData = new ByteArray(); // we assemble the nalus outside, set at end

					_vTagData.writeUnsignedInt(nal.length);
					_vTagData.writeBytes(nal.NALdata); // start with this very NAL, an AUD (XXX not sure this is needed)

					_vTag.codecID = FLVTagVideo.CODEC_ID_AVC;
					_vTag.frameType = FLVTagVideo.FRAME_TYPE_INTER; // adjust to keyframe later
					_vTag.avcPacketType = FLVTagVideo.AVC_PACKET_TYPE_NALU;
					_vTag.timestamp = _timestamp;
					_vTag.avcCompositionTimeOffset = _compositionTime;
				}
				else if(nal.NALtype != 7 && nal.NALtype != 8)
				{
					if(_vTag == null)
					{
						CONFIG::LOGGING
						{
							logger.info("needed to create vtag");
						}
						_vTag = new FLVTagVideo();
						_vTagData = new ByteArray(); // we assemble the nalus outside, set at end
						_vTag.codecID = FLVTagVideo.CODEC_ID_AVC;
						_vTag.frameType = FLVTagVideo.FRAME_TYPE_INTER; // adjust to keyframe later
						_vTag.avcPacketType = FLVTagVideo.AVC_PACKET_TYPE_NALU;
						_vTag.timestamp = _timestamp;
						_vTag.avcCompositionTimeOffset = _compositionTime;
					}

					if(nal.NALtype == 5) // if keyframe
					{
						_vTag.frameType = FLVTagVideo.FRAME_TYPE_KEYFRAME;
					}

					_vTagData.writeUnsignedInt(nal.length);
					_vTagData.writeBytes(nal.NALdata);
				}
			}

			if(flush)
			{
				CONFIG::LOGGING
				{
					logger.info(" *** VIDEO FLUSH CALLED");
				}
				if(_vTag && _vTagData.length > 0)
				{
					_vTag.data = _vTagData; // set at end (see below)
					tags.push(_vTag);
					if(avccTag)
					{
						avccTag.timestamp = _vTag.timestamp;
						avccTag = null;
					}

					CONFIG::LOGGING
					{
						logger.info("flushing one vtag");
					}
				}

				_vTag = null; // can't start new one, don't have the info
			}

			var tagData:ByteArray = new ByteArray();

			for each(tag in tags)
			{
				tag.write(tagData);
			}

			return tagData;
		}

		CONFIG::LOGGING
		{
			private var logger:Logger = Log.getLogger('org.denivip.osmf.net.httpstreaming.hls.HTTPStreamingMP2PESVideo') as Logger;
		}

	} // class
} // package

Update HTTPStreamingMP2PESVideo.as

Update HTTPStreamingMP2PESVideo.as


/*
Copyright 2009, Matthew Eernisse (mde@fleegix.org) and Slide, Inc.

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

package org.windmill {
  // FIXME:
  // Relying on implicit imports of org.windmill.*
  // to avoid infinite recursion in build script
  import flash.utils.*;
  import mx.core.Application;
  import flash.display.Stage;
  import flash.display.DisplayObject;
  import flash.external.ExternalInterface;

  public class Windmill {
    public static var context:*; // A reference to the Stage
    public static var controllerMethods:Array = [];
    public static var assertMethods:Array = [];
    public static var packages:Object = {
      controller: {
        // Ref to the namespace, since you can't
        // do it via string lookup
        packageRef: org.windmill.WMController,
        // Gets filled with the list of public methods --
        // used to generate the wrapped methods exposed
        // via ExternalInterface
        methodNames: []
      },
      assert: {
        packageRef: org.windmill.WMAssert,
        methodNames: []
      }
    };

    public function Windmill():void {}

    // Initializes the Windmill Flash code
    // 1. Saves a reference to the stage in 'context'
    //    this is the equivalent of the window obj in
    //    Windmill's JS impl. See WMLocator to see how
    //    it's used
    // 2. Does some introspection/metaprogramming to
    //    expose all the public methods in WMController
    //    and WMAsserts through the ExternalInterface
    //    as wrapped functions that return either the
    //    Boolean true, or the Error object if an error
    //    happens (as in the case of all failed tests)
    // 3. Exposes the start/stop method of WMExplorer
    //    to turn on and off the explorer
    public static function init(config:Object):void {
      var methodName:String;
      var item:*;
      var descr:XML;
      // Returns a wrapped version of the method that returns
      // the Error obj to JS-land instead of actually throwing
      var genExtFunc:Function = function (func:Function):Function {
        return function (...args):* {
          try {
            return func.apply(null, args);
          }
          catch (e:Error) {
            return e;
          }
        }
      }
      // A reference to the Stage
      // ----------------
      if (!(config.context is Stage || config.context is Application)) {
        throw new Error('Windmill.context must be a reference to the Application or Stage.');
      }
      context = config.context;

      // Expose controller and assert methods
      // ----------------
      for (var key:String in packages) {
        // Introspect all the public packages
        // to expose via ExternalInterface
        descr = flash.utils.describeType(
            packages[key].packageRef);
        for each (item in descr..method) {
          packages[key].methodNames.push(item.@name.toXMLString());
        }
        // Expose public packages via ExternalInterface
        // 'dragDropOnCoords' becomes 'wm_dragDropOnCoords'
        // The exposed method is wrapped in a try/catch
        // that returns the Error obj to JS instead of throwing
        for each (methodName in packages[key].methodNames) {
          ExternalInterface.addCallback('wm_' + methodName,
              genExtFunc(packages[key].packageRef[methodName]));
        }
      }

      // Other misc ExternalInterface methods
      var miscMethods:Object = {
        explorerStart: WMExplorer.start,
        explorerStop: WMExplorer.stop,
        recorderStart: WMRecorder.start,
        recorderStop: WMRecorder.stop
      }
      // Don't care what order these happen in
      for (methodName in miscMethods) {
        ExternalInterface.addCallback('wm_' + methodName,
            genExtFunc(miscMethods[methodName]));
      }
    }

    public static function getStage():Stage {
      var context:* = Windmill.context;
      var stage:Stage;
      if (context is Application) {
        stage = context.stage;
      }
      else if (context is Stage) {
        stage = context;
      }
      else {
        throw new Error('Windmill.context must be a reference to an Application or Stage.' +
            ' Perhaps Windmill.init has not run yet.');
      }
      return stage;
    }

    public static function getTopLevel():DisplayObject {
      var topLevel:*;
      var context:* = Windmill.context;
      if (context is Application) {
        topLevel = context.parent;
      }
      else if (context is Stage) {
        topLevel = context;
      }
      else {
        throw new Error('Windmill.context must be a reference to an Application or Stage.' +
            ' Perhaps Windmill.init has not run yet.');
      }
      return topLevel;
    }
  }
}

/*
Copyright 2009, Matthew Eernisse (mde@fleegix.org) and Slide, Inc.

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

package org.windmill {
  // FIXME:
  // Relying on implicit imports of org.windmill.*
  // to avoid infinite recursion in build script
  import flash.utils.*;
  import mx.core.Application;
  import flash.display.Sprite;
  import flash.display.Stage;
  import flash.display.DisplayObject;
  import flash.external.ExternalInterface;

  public class Windmill extends Sprite {
    public static var context:*; // A reference to the Stage
    public static var controllerMethods:Array = [];
    public static var assertMethods:Array = [];
    public static var packages:Object = {
      controller: {
        // Ref to the namespace, since you can't
        // do it via string lookup
        packageRef: org.windmill.WMController,
        // Gets filled with the list of public methods --
        // used to generate the wrapped methods exposed
        // via ExternalInterface
        methodNames: []
      },
      assert: {
        packageRef: org.windmill.WMAssert,
        methodNames: []
      }
    };

    public function Windmill():void {}

    // Initializes the Windmill Flash code
    // 1. Saves a reference to the stage in 'context'
    //    this is the equivalent of the window obj in
    //    Windmill's JS impl. See WMLocator to see how
    //    it's used
    // 2. Does some introspection/metaprogramming to
    //    expose all the public methods in WMController
    //    and WMAsserts through the ExternalInterface
    //    as wrapped functions that return either the
    //    Boolean true, or the Error object if an error
    //    happens (as in the case of all failed tests)
    // 3. Exposes the start/stop method of WMExplorer
    //    to turn on and off the explorer
    public static function init(config:Object):void {
      var methodName:String;
      var item:*;
      var descr:XML;
      // Returns a wrapped version of the method that returns
      // the Error obj to JS-land instead of actually throwing
      var genExtFunc:Function = function (func:Function):Function {
        return function (...args):* {
          try {
            return func.apply(null, args);
          }
          catch (e:Error) {
            return e;
          }
        }
      }
      // A reference to the Stage
      // ----------------
      if (!(config.context is Stage || config.context is Application)) {
        throw new Error('Windmill.context must be a reference to the Application or Stage.');
      }
      context = config.context;

      // Expose controller and assert methods
      // ----------------
      for (var key:String in packages) {
        // Introspect all the public packages
        // to expose via ExternalInterface
        descr = flash.utils.describeType(
            packages[key].packageRef);
        for each (item in descr..method) {
          packages[key].methodNames.push(item.@name.toXMLString());
        }
        // Expose public packages via ExternalInterface
        // 'dragDropOnCoords' becomes 'wm_dragDropOnCoords'
        // The exposed method is wrapped in a try/catch
        // that returns the Error obj to JS instead of throwing
        for each (methodName in packages[key].methodNames) {
          ExternalInterface.addCallback('wm_' + methodName,
              genExtFunc(packages[key].packageRef[methodName]));
        }
      }

      // Other misc ExternalInterface methods
      var miscMethods:Object = {
        explorerStart: WMExplorer.start,
        explorerStop: WMExplorer.stop,
        recorderStart: WMRecorder.start,
        recorderStop: WMRecorder.stop
      }
      // Don't care what order these happen in
      for (methodName in miscMethods) {
        ExternalInterface.addCallback('wm_' + methodName,
            genExtFunc(miscMethods[methodName]));
      }
    }

    public static function getStage():Stage {
      var context:* = Windmill.context;
      var stage:Stage;
      if (context is Application) {
        stage = context.stage;
      }
      else if (context is Stage) {
        stage = context;
      }
      else {
        throw new Error('Windmill.context must be a reference to an Application or Stage.' +
            ' Perhaps Windmill.init has not run yet.');
      }
      return stage;
    }

    public static function getTopLevel():DisplayObject {
      var topLevel:*;
      var context:* = Windmill.context;
      if (context is Application) {
        topLevel = context.parent;
      }
      else if (context is Stage) {
        topLevel = context;
      }
      else {
        throw new Error('Windmill.context must be a reference to an Application or Stage.' +
            ' Perhaps Windmill.init has not run yet.');
      }
      return topLevel;
    }
  }
}

Make Windmill base lib a subclass of Sprite so it can be dynamically loaded.


package dolly {

import dolly.core.dolly_internal;
import dolly.data.CompositeCopyableClass;

import mx.collections.ArrayCollection;
import mx.collections.ArrayList;

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

use namespace dolly_internal;

public class CopyingOfCompositeCopyableClassTest {

	private var compositeCopyableClass:CompositeCopyableClass;
	private var compositeCopyableClassType:Type;

	[Before]
	public function before():void {
		compositeCopyableClass = new CompositeCopyableClass();
		compositeCopyableClass.array = [1, 2, 3, 4, 5];
		compositeCopyableClass.arrayList = new ArrayList([1, 2, 3, 4, 5]);
		compositeCopyableClass.arrayCollection = new ArrayCollection([1, 2, 3, 4, 5]);

		compositeCopyableClassType = Type.forInstance(compositeCopyableClass);
	}

	[After]
	public function after():void {
		compositeCopyableClass = null;
		compositeCopyableClassType = null;
	}

	[Test]
	public function findingAllWritableFieldsForType():void {
		const writableFields:Vector.<Field> = Copier.findCopyableFieldsForType(compositeCopyableClassType);
		assertNotNull(writableFields);
		assertEquals(4, writableFields.length);
	}
}
}

package dolly {

import dolly.core.dolly_internal;
import dolly.data.CompositeCopyableClass;

import mx.collections.ArrayCollection;
import mx.collections.ArrayList;

import org.as3commons.reflect.Field;
import org.as3commons.reflect.Type;
import org.flexunit.asserts.assertEquals;
import org.flexunit.asserts.assertFalse;
import org.flexunit.asserts.assertNotNull;
import org.hamcrest.assertThat;
import org.hamcrest.collection.array;
import org.hamcrest.collection.arrayWithSize;
import org.hamcrest.collection.everyItem;
import org.hamcrest.core.isA;
import org.hamcrest.object.equalTo;

use namespace dolly_internal;

public class CopyingOfCompositeCopyableClassTest {

	private var compositeCopyableClass:CompositeCopyableClass;
	private var compositeCopyableClassType:Type;

	[Before]
	public function before():void {
		compositeCopyableClass = new CompositeCopyableClass();
		compositeCopyableClass.array = [1, 2, 3, 4, 5];
		compositeCopyableClass.arrayList = new ArrayList([1, 2, 3, 4, 5]);
		compositeCopyableClass.arrayCollection = new ArrayCollection([1, 2, 3, 4, 5]);

		compositeCopyableClassType = Type.forInstance(compositeCopyableClass);
	}

	[After]
	public function after():void {
		compositeCopyableClass = null;
		compositeCopyableClassType = null;
	}

	[Test]
	public function findingAllWritableFieldsForType():void {
		const writableFields:Vector.<Field> = Copier.findCopyableFieldsForType(compositeCopyableClassType);
		assertNotNull(writableFields);
		assertEquals(4, writableFields.length);
	}

	[Test]
	public function copyingOfArray():void {
		const copy:CompositeCopyableClass = Copier.copy(compositeCopyableClass);

		assertNotNull(copy.array);
		assertThat(copy.array, arrayWithSize(5));
		assertThat(copy.array, compositeCopyableClass.array);
		assertFalse(copy.array == compositeCopyableClass.array);
		assertThat(copy.array, everyItem(isA(Number)));
		assertThat(copy.array, array(equalTo(1), equalTo(2), equalTo(3), equalTo(4), equalTo(5)));
	}
}
}

Test for copying Array in CompositeCloneableClass.


package
{
	import com.amanitadesign.steam.FRESteamWorks;
	import com.amanitadesign.steam.SteamConstants;
	import com.amanitadesign.steam.SteamEvent;

	import flash.desktop.NativeApplication;
	import flash.display.SimpleButton;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.utils.ByteArray;

	public class FRESteamWorksTest extends Sprite
	{
		public var Steamworks:FRESteamWorks = new FRESteamWorks();
		public var tf:TextField;
		public function FRESteamWorksTest()
		{
			tf = new TextField();
			tf.width = stage.stageWidth;
			tf.height = stage.stageHeight;
			addChild(tf);

			tf.addEventListener(MouseEvent.MOUSE_DOWN, onClick);

			Steamworks.addEventListener(SteamEvent.STEAM_RESPONSE, onSteamResponse);
			NativeApplication.nativeApplication.addEventListener(Event.EXITING, onExit);
			try {
				if(Steamworks.init()){
					log("STEAMWORKS API is available\n");

					//comment.. current stats and achievement ids are from steam example app which is provided with their SDK
					log("isAchievement('ACH_WIN_ONE_GAME') == "+Steamworks.isAchievement("ACH_WIN_ONE_GAME"));
					log("isAchievement('ACH_TRAVEL_FAR_SINGLE') == "+Steamworks.isAchievement("ACH_TRAVEL_FAR_SINGLE"));
					log("setStatFloat('FeetTraveled') == "+Steamworks.setStatFloat('FeetTraveled', 21.3));
					log("setStatInt('NumGames', 2) == "+Steamworks.setStatInt('NumGames', 2));
					Steamworks.storeStats();
					log("getStatInt('NumGames') == "+Steamworks.getStatInt('NumGames'));
					log("getStatFloat('FeetTraveled') == "+Steamworks.getStatFloat('FeetTraveled'));

					log("setCloudEnabledForApp(false) == "+Steamworks.setCloudEnabledForApp(false) );
					log("setCloudEnabledForApp(true) == "+Steamworks.setCloudEnabledForApp(true) );
					log("isCloudEnabledForApp() == "+Steamworks.isCloudEnabledForApp() );
					log("getFileCount() == "+Steamworks.getFileCount() );
					log("fileExists('test.txt') == "+Steamworks.fileExists('test.txt') );

					//comment.. writing to app with id 480 is somehow not working, but works with our real appId
					log("writeFileToCloud('test.txt','hello steam') == "+writeFileToCloud('test.txt','hello steam'));
					log("readFileFromCloud('test.txt') == "+readFileFromCloud('test.txt') );
					//-----------

					//Steamworks.requestStats();
					Steamworks.resetAllStats(true);
				}else {
					tf.appendText("STEAMWORKS API is NOT available\n");
				}
			} catch(e:Error) {
				tf.appendText("*** ERROR ***");
				tf.appendText(e.message);
			}

		}
		private function log(value:String):void{
			tf.appendText(value+"\n");
			tf.scrollV = tf.maxScrollV;
		}
		public function writeFileToCloud(fileName:String, data:String):Boolean {
			var dataOut:ByteArray = new ByteArray();
			dataOut.writeUTFBytes(data);
			return Steamworks.fileWrite(fileName, dataOut);
		}

		public function readFileFromCloud(fileName:String):String {
			var dataIn:ByteArray = new ByteArray();
			var result:String;
			dataIn.position = 0;
			dataIn.length = Steamworks.getFileSize(fileName);

			if(dataIn.length>0 && Steamworks.fileRead(fileName,dataIn)){
				result = dataIn.readUTFBytes(dataIn.length);
			}
			return result;
		}

		public function onClick(e:MouseEvent):void{
			log("--click--");
			if(Steamworks.isReady){
				if(!Steamworks.isAchievement("ACH_WIN_ONE_GAME")) {
					log("setAchievement('ACH_WIN_ONE_GAME') == "+Steamworks.setAchievement("ACH_WIN_ONE_GAME"));
				} else {
					log("clearAchievement('ACH_WIN_ONE_GAME') == "+Steamworks.clearAchievement("ACH_WIN_ONE_GAME"));
				}
				if(Steamworks.fileExists('test.txt')){
					log("readFileFromCloud('test.txt') == "+readFileFromCloud('test.txt') );
					log("Steamworks.fileDelete('test.txt') == "+Steamworks.fileDelete('test.txt'));
				} else {
					log("writeFileToCloud('test.txt','click') == "+writeFileToCloud('test.txt','click'));
				}
				//Steamworks.storeStats();
			} else {
				log("not able to set achievement\n");
			}
		}

		public function onSteamResponse(e:SteamEvent):void{
			switch(e.req_type){
				case SteamConstants.RESPONSE_OnUserStatsStored:
					log("RESPONSE_OnUserStatsStored: "+e.response);
					break;
				case SteamConstants.RESPONSE_OnUserStatsReceived:
					log("RESPONSE_OnUserStatsReceived: "+e.response);
					break;
				case SteamConstants.RESPONSE_OnAchievementStored:
					log("RESPONSE_OnAchievementStored: "+e.response);
					break;
				default:
					log("STEAMresponse type:"+e.req_type+" response:"+e.response);
			}
		}

		public function onExit(e:Event):void{
			log("Exiting application, cleaning up");
			Steamworks.dispose();
		}
	}
}

package
{
	import com.amanitadesign.steam.FRESteamWorks;
	import com.amanitadesign.steam.SteamConstants;
	import com.amanitadesign.steam.SteamEvent;

	import flash.desktop.NativeApplication;
	import flash.display.SimpleButton;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.utils.ByteArray;

	public class FRESteamWorksTest extends Sprite
	{
		public var Steamworks:FRESteamWorks = new FRESteamWorks();
		public var tf:TextField;
		public function FRESteamWorksTest()
		{
			tf = new TextField();
			tf.width = stage.stageWidth;
			tf.height = stage.stageHeight;
			addChild(tf);

			tf.addEventListener(MouseEvent.MOUSE_DOWN, onClick);

			Steamworks.addEventListener(SteamEvent.STEAM_RESPONSE, onSteamResponse);
			NativeApplication.nativeApplication.addEventListener(Event.EXITING, onExit);
			try {
				if(Steamworks.init()){
					log("STEAMWORKS API is available\n");

					//comment.. current stats and achievement ids are from steam example app which is provided with their SDK
					log("isAchievement('ACH_WIN_ONE_GAME') == "+Steamworks.isAchievement("ACH_WIN_ONE_GAME"));
					log("isAchievement('ACH_TRAVEL_FAR_SINGLE') == "+Steamworks.isAchievement("ACH_TRAVEL_FAR_SINGLE"));
					log("setStatFloat('FeetTraveled') == "+Steamworks.setStatFloat('FeetTraveled', 21.3));
					log("setStatInt('NumGames', 2) == "+Steamworks.setStatInt('NumGames', 2));
					Steamworks.storeStats();
					log("getStatInt('NumGames') == "+Steamworks.getStatInt('NumGames'));
					log("getStatFloat('FeetTraveled') == "+Steamworks.getStatFloat('FeetTraveled'));

					log("setCloudEnabledForApp(false) == "+Steamworks.setCloudEnabledForApp(false) );
					log("setCloudEnabledForApp(true) == "+Steamworks.setCloudEnabledForApp(true) );
					log("isCloudEnabledForApp() == "+Steamworks.isCloudEnabledForApp() );
					log("getFileCount() == "+Steamworks.getFileCount() );
					log("fileExists('test.txt') == "+Steamworks.fileExists('test.txt') );

					//comment.. writing to app with id 480 is somehow not working, but works with our real appId
					log("writeFileToCloud('test.txt','hello steam') == "+writeFileToCloud('test.txt','hello steam'));
					log("readFileFromCloud('test.txt') == "+readFileFromCloud('test.txt') );
					//-----------

					//Steamworks.requestStats();
					Steamworks.resetAllStats(true);
				}else {
					tf.appendText("STEAMWORKS API is NOT available\n");
				}
			} catch(e:Error) {
				tf.appendText("*** ERROR ***");
				tf.appendText(e.message + "\n");
				tf.appendText(e.getStackTrace() + "\n");
			}

		}
		private function log(value:String):void{
			tf.appendText(value+"\n");
			tf.scrollV = tf.maxScrollV;
		}
		public function writeFileToCloud(fileName:String, data:String):Boolean {
			var dataOut:ByteArray = new ByteArray();
			dataOut.writeUTFBytes(data);
			return Steamworks.fileWrite(fileName, dataOut);
		}

		public function readFileFromCloud(fileName:String):String {
			var dataIn:ByteArray = new ByteArray();
			var result:String;
			dataIn.position = 0;
			dataIn.length = Steamworks.getFileSize(fileName);

			if(dataIn.length>0 && Steamworks.fileRead(fileName,dataIn)){
				result = dataIn.readUTFBytes(dataIn.length);
			}
			return result;
		}

		public function onClick(e:MouseEvent):void{
			log("--click--");
			if(Steamworks.isReady){
				if(!Steamworks.isAchievement("ACH_WIN_ONE_GAME")) {
					log("setAchievement('ACH_WIN_ONE_GAME') == "+Steamworks.setAchievement("ACH_WIN_ONE_GAME"));
				} else {
					log("clearAchievement('ACH_WIN_ONE_GAME') == "+Steamworks.clearAchievement("ACH_WIN_ONE_GAME"));
				}
				if(Steamworks.fileExists('test.txt')){
					log("readFileFromCloud('test.txt') == "+readFileFromCloud('test.txt') );
					log("Steamworks.fileDelete('test.txt') == "+Steamworks.fileDelete('test.txt'));
				} else {
					log("writeFileToCloud('test.txt','click') == "+writeFileToCloud('test.txt','click'));
				}
				//Steamworks.storeStats();
			} else {
				log("not able to set achievement\n");
			}
		}

		public function onSteamResponse(e:SteamEvent):void{
			switch(e.req_type){
				case SteamConstants.RESPONSE_OnUserStatsStored:
					log("RESPONSE_OnUserStatsStored: "+e.response);
					break;
				case SteamConstants.RESPONSE_OnUserStatsReceived:
					log("RESPONSE_OnUserStatsReceived: "+e.response);
					break;
				case SteamConstants.RESPONSE_OnAchievementStored:
					log("RESPONSE_OnAchievementStored: "+e.response);
					break;
				default:
					log("STEAMresponse type:"+e.req_type+" response:"+e.response);
			}
		}

		public function onExit(e:Event):void{
			log("Exiting application, cleaning up");
			Steamworks.dispose();
		}
	}
}

Print stack trace when error occurs in test program


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

package com.freshplanet.ane.AirAACPlayer
{
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.StatusEvent;
    import flash.external.ExtensionContext;
    import flash.system.Capabilities;

    public class AirAACPlayer extends EventDispatcher
    {
        // --------------------------------------------------------------------------------------//
        //                                                                                //
        //                                     PUBLIC API                                        //
        //                                                                                //
        // --------------------------------------------------------------------------------------//

        public static const AAC_PLAYER_PREPARED:String = "AAC_PLAYER_PREPARED";

        /** AirAACPlayer is supported on Android devices. */
        public static function get isSupported():Boolean
        {
            var isAndroid:Boolean = (Capabilities.manufacturer.indexOf("Android") != -1)
            return isAndroid;
        }

        public function AirAACPlayer()
        {
            _context = ExtensionContext.createExtensionContext(EXTENSION_ID, null);
            if (!_context)
            {
                log("ERROR - Extension context is null. Please check if extension.xml is setup correctly.");
                return;
            }
            _context.addEventListener(StatusEvent.STATUS, onStatus);
        }

        public var logEnabled:Boolean = true;

        /**
        * Load a music stream url
        * @param url:String
        */
        public function loadUrl(url:String):void
        {
            _context.call("loadUrl", url);
        }

        /**
        * Start playing the stream.
        * If the playback has been paused before, it will continue from this point.
        * @param startTime:int the start time in milliseconds
        */
        public function play(startTime:int=0):void
        {
            _context.call("play", startTime);
        }

        /**
        * Pause the playback
        */
        public function pause():void
        {
            _context.call("pause");
        }

        /**
        * Stop the playback
        */
        public function stop():void
        {
            _context.call("stop");
        }

        /**
        * Close the stream and release.
        * Note that loadUrl() has to be called again before replaying if close has been called.
        */
        public function close():void
        {
            _context.call("close");
        }

        /**
        * Length in milliseconds
        */
        public function get length():int
        {
            return _context.call("getLength") as int;
        }

        /**
        * Progress in milliseconds
        */
        public function get progress():int
        {
            return _context.call("getProgress") as int;
        }

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

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

        private static var _instance:AirAACPlayer;

        private var _context:ExtensionContext;

        private function onStatus( event:StatusEvent ):void
        {
            if (event.code == "LOGGING") // Simple log message
            {
                log(event.level);
            }
            else if (event.code == AAC_PLAYER_PREPARED)
            {
                dispatchEvent(new Event(event.code));
            }
        }

        private function log( message:String ):void
        {
            if (logEnabled) trace("[AirAACPlayer] " + message);
        }
    }
}

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

package com.freshplanet.ane.AirAACPlayer
{
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.StatusEvent;
    import flash.external.ExtensionContext;
    import flash.system.Capabilities;

    public class AirAACPlayer extends EventDispatcher
    {
        // --------------------------------------------------------------------------------------//
        //                                                                                //
        //                                     PUBLIC API                                        //
        //                                                                                //
        // --------------------------------------------------------------------------------------//

        public static const AAC_PLAYER_PREPARED:String = "AAC_PLAYER_PREPARED";

        /** AirAACPlayer is supported on Android devices. */
        public static function get isSupported():Boolean
        {
            var isAndroid:Boolean = (Capabilities.manufacturer.indexOf("Android") != -1)
            return isAndroid;
        }

        public function AirAACPlayer()
        {
            _context = ExtensionContext.createExtensionContext(EXTENSION_ID, null);
            if (!_context)
            {
                log("ERROR - Extension context is null. Please check if extension.xml is setup correctly.");
                return;
            }
            _context.addEventListener(StatusEvent.STATUS, onStatus);
        }

        public var logEnabled:Boolean = true;

        /**
        * Load a music stream url
        * @param url:String
        */
        public function loadUrl(url:String):void
        {
            _context.call("loadUrl", url);
        }

        /**
        * Start playing the stream.
        * If the playback has been paused before, it will continue from this point.
        * @param startTime:int the start time in milliseconds
        */
        public function play(startTime:int=0):void
        {
            _context.call("play", startTime);
        }

        /**
        * Pause the playback
        */
        public function pause():void
        {
            _context.call("pause");
        }

        /**
        * Stop the playback
        */
        public function stop():void
        {
            _context.call("stop");
        }

        /**
        * Close the stream and release.
        * Note that loadUrl() has to be called again before replaying if close has been called.
        */
        public function close():void
        {
            _context.call("close");
        }

        /**
        * Length in milliseconds
        */
        public function get length():int
        {
            return _context.call("getLength") as int;
        }

        /**
        * Progress in milliseconds
        */
        public function get progress():int
        {
            return _context.call("getProgress") as int;
        }

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

        private static const EXTENSION_ID:String = "com.freshplanet.AirAACPlayer";
        private var _context:ExtensionContext;

        private function onStatus( event:StatusEvent ):void
        {
            if (event.code == "LOGGING") // Simple log message
            {
                log(event.level);
            }
            else if (event.code == AAC_PLAYER_PREPARED)
            {
                dispatchEvent(new Event(event.code));
            }
        }

        private function log( message:String ):void
        {
            if (logEnabled) trace("[AirAACPlayer] " + message);
        }
    }
}

Remove instance property

Remove instance property