/*
 *  FRESteamWorks.h
 *  This file is part of FRESteamWorks.
 *
 *  Created by David ´Oldes´ Oliva on 3/29/12.
 *  Contributors: Ventero <http://github.com/Ventero>
 *  Copyright (c) 2012 Amanita Design. All rights reserved.
 *  Copyright (c) 2012-2013 Level Up Labs, LLC. All rights reserved.
 */

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

	import flash.desktop.NativeApplication;
	import flash.display.SimpleButton;
	import flash.display.Sprite;
	import flash.display.StageDisplayState;
	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;

		private var _buttonPos:int = 5;
		private var _appId:uint;

		public function FRESteamWorksTest()
		{
			tf = new TextField();
			tf.x = 160;
			tf.width = stage.stageWidth - tf.x;
			tf.height = stage.stageHeight;
			addChild(tf);

			addButton("Check stats/achievements", checkAchievements);
			addButton("Toggle achievement", toggleAchievement);
			addButton("Toggle cloud enabled", toggleCloudEnabled);
			addButton("Toggle file", toggleFile);
			addButton("Publish file", publishFile);
			addButton("Toggle fullscreen", toggleFullscreen);
			addButton("Show Friends overlay", activateOverlay);
			addButton("List subscribed files", enumerateSubscribedFiles);

			Steamworks.addEventListener(SteamEvent.STEAM_RESPONSE, onSteamResponse);
			NativeApplication.nativeApplication.addEventListener(Event.EXITING, onExit);
			try {
				//Steamworks.useCrashHandler(480, "1.0", "Feb 20 2013", "21:42:20");
				if(!Steamworks.init()){
					log("STEAMWORKS API is NOT available");
					return;
				}

				log("STEAMWORKS API is available\n");
				log("User ID: " + Steamworks.getUserID());
				_appId = Steamworks.getAppID();
				log("App ID: " + _appId);
				log("Persona name: " + Steamworks.getPersonaName());
				log("isCloudEnabledForApp() == "+Steamworks.isCloudEnabledForApp() );
				log("getFileCount() == "+Steamworks.getFileCount() );
				log("fileExists('test.txt') == "+Steamworks.fileExists('test.txt') );

				Steamworks.resetAllStats(true);
			} catch(e:Error) {
				log("*** ERROR ***");
				log(e.message);
				log(e.getStackTrace());
			}

		}
		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;
		}

		private function checkAchievements(e:Event = null):void {
			if(!Steamworks.isReady) return;

			// current stats and achievement ids are from steam example app
			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'));
		}

		private function toggleAchievement(e:Event = null):void{
			if(!Steamworks.isReady) return;

			var result:Boolean = Steamworks.isAchievement("ACH_WIN_ONE_GAME");
			log("isAchievement('ACH_WIN_ONE_GAME') == " + result);
			if(!result) {
				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"));
			}
		}

		private function toggleCloudEnabled(e:Event = null):void {
			if(!Steamworks.isReady) return;

			var enabled:Boolean = Steamworks.isCloudEnabledForApp();
			log("isCloudEnabledForApp() == " + enabled);
			log("setCloudEnabledForApp(" + !enabled + ") == " + Steamworks.setCloudEnabledForApp(!enabled));
			log("isCloudEnabledForApp() == " + Steamworks.isCloudEnabledForApp());
		}

		private function toggleFile(e:Event = null):void {
			if(!Steamworks.isReady) return;

			var result:Boolean = Steamworks.fileExists('test.txt');
			log("fileExists('test.txt') == " + result);
			if(result){
				log("readFileFromCloud('test.txt') == "+readFileFromCloud('test.txt') );
				log("fileDelete('test.txt') == "+Steamworks.fileDelete('test.txt'));
			} else {
				log("writeFileToCloud('test.txt','click') == "+writeFileToCloud('test.txt','click'));
			}
		}

		private function publishFile(e:Event = null):void {
			if(!Steamworks.isReady) return;

			var res:Boolean = Steamworks.publishWorkshopFile("test.txt", "", _appId,
				"Test.txt", "Test.txt", WorkshopConstants.VISIBILITY_Private,
				["TestTag"], WorkshopConstants.FILETYPE_Community);
			log("publishWorkshopFile('test.txt' ...) == " + res);
		}

		private function toggleFullscreen(e:Event = null):void {
			if(stage.displayState == StageDisplayState.NORMAL)
				stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
			else
				stage.displayState = StageDisplayState.NORMAL;
		}

		private function activateOverlay(e:Event = null):void {
			if(!Steamworks.isReady) return;

			log("isOverlayEnabled() == " + Steamworks.isOverlayEnabled());
			log("activateGameOverlay('Friends') == " + Steamworks.activateGameOverlay("Friends"));
			log("isOverlayEnabled() == " + Steamworks.isOverlayEnabled());
		}

		private function enumerateSubscribedFiles(e:Event = null):void {
			if(!Steamworks.isReady) return;

			log("enumerateUserSubscribedFiles(0) == " + Steamworks.enumerateUserSubscribedFiles(0));
		}

		private 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;
				case SteamConstants.RESPONSE_OnPublishWorkshopFile:
					log("RESPONSE_OnPublishWorkshopFile: " + e.response);
					var file:String = Steamworks.publishWorkshopFileResult();
					log("File published as " + file);
					log("subscribePublishedFile(...) == " + Steamworks.subscribePublishedFile(file));
					break;
				case SteamConstants.RESPONSE_OnEnumerateUserSubscribedFiles:
					log("RESPONSE_OnEnumerateUserSubscribedFiles: " + e.response);
					var result:SubscribedFilesResult = Steamworks.enumerateUserSubscribedFilesResult();
					log("User subscribed files: " + result.resultsReturned + "/" + result.totalResults);
					for(var i:int = 0; i < result.resultsReturned; i++)
						log(i + ": " + result.publishedFileId[i] + " (" + result.timeSubscribed[i] + ")");
					break;
				default:
					log("STEAMresponse type:"+e.req_type+" response:"+e.response);
			}
		}

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

		private function addButton(label:String, callback:Function):void {
			var button:Sprite = new Sprite();
			button.graphics.beginFill(0xaaaaaa);
			button.graphics.drawRoundRect(0, 0, 150, 30, 5, 5);
			button.graphics.endFill();
			button.buttonMode = true;
			button.useHandCursor = true;
			button.addEventListener(MouseEvent.CLICK, callback);
			button.x = 5;
			button.y = _buttonPos;
			_buttonPos += button.height + 5;

			var text:TextField = new TextField();
			text.text = label;
			text.width = 140;
			text.height = 25;
			text.x = 5;
			text.y = 5;
			text.mouseEnabled = false;

			button.addChild(text);
			addChild(button);
		}
	}
}

/*
 *  FRESteamWorks.h
 *  This file is part of FRESteamWorks.
 *
 *  Created by David ´Oldes´ Oliva on 3/29/12.
 *  Contributors: Ventero <http://github.com/Ventero>
 *  Copyright (c) 2012 Amanita Design. All rights reserved.
 *  Copyright (c) 2012-2013 Level Up Labs, LLC. All rights reserved.
 */

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

	import flash.desktop.NativeApplication;
	import flash.display.SimpleButton;
	import flash.display.Sprite;
	import flash.display.StageDisplayState;
	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;

		private var _buttonPos:int = 5;
		private var _appId:uint;

		public function FRESteamWorksTest()
		{
			tf = new TextField();
			tf.x = 160;
			tf.width = stage.stageWidth - tf.x;
			tf.height = stage.stageHeight;
			addChild(tf);

			addButton("Check stats/achievements", checkAchievements);
			addButton("Toggle achievement", toggleAchievement);
			addButton("Toggle cloud enabled", toggleCloudEnabled);
			addButton("Toggle file", toggleFile);
			addButton("Publish file", publishFile);
			addButton("Toggle fullscreen", toggleFullscreen);
			addButton("Show Friends overlay", activateOverlay);
			addButton("List subscribed files", enumerateSubscribedFiles);

			Steamworks.addEventListener(SteamEvent.STEAM_RESPONSE, onSteamResponse);
			NativeApplication.nativeApplication.addEventListener(Event.EXITING, onExit);
			try {
				//Steamworks.useCrashHandler(480, "1.0", "Feb 20 2013", "21:42:20");
				if(!Steamworks.init()){
					log("STEAMWORKS API is NOT available");
					return;
				}

				log("STEAMWORKS API is available\n");
				log("User ID: " + Steamworks.getUserID());
				_appId = Steamworks.getAppID();
				log("App ID: " + _appId);
				log("Persona name: " + Steamworks.getPersonaName());
				log("isCloudEnabledForApp() == "+Steamworks.isCloudEnabledForApp());
				log("getFileCount() == "+Steamworks.getFileCount());
				log("fileExists('test.txt') == "+Steamworks.fileExists('test.txt'));
				log("getDLCCount() == " + Steamworks.getDLCCount());

				Steamworks.resetAllStats(true);
			} catch(e:Error) {
				log("*** ERROR ***");
				log(e.message);
				log(e.getStackTrace());
			}

		}
		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;
		}

		private function checkAchievements(e:Event = null):void {
			if(!Steamworks.isReady) return;

			// current stats and achievement ids are from steam example app
			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'));
		}

		private function toggleAchievement(e:Event = null):void{
			if(!Steamworks.isReady) return;

			var result:Boolean = Steamworks.isAchievement("ACH_WIN_ONE_GAME");
			log("isAchievement('ACH_WIN_ONE_GAME') == " + result);
			if(!result) {
				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"));
			}
		}

		private function toggleCloudEnabled(e:Event = null):void {
			if(!Steamworks.isReady) return;

			var enabled:Boolean = Steamworks.isCloudEnabledForApp();
			log("isCloudEnabledForApp() == " + enabled);
			log("setCloudEnabledForApp(" + !enabled + ") == " + Steamworks.setCloudEnabledForApp(!enabled));
			log("isCloudEnabledForApp() == " + Steamworks.isCloudEnabledForApp());
		}

		private function toggleFile(e:Event = null):void {
			if(!Steamworks.isReady) return;

			var result:Boolean = Steamworks.fileExists('test.txt');
			log("fileExists('test.txt') == " + result);
			if(result){
				log("readFileFromCloud('test.txt') == "+readFileFromCloud('test.txt') );
				log("fileDelete('test.txt') == "+Steamworks.fileDelete('test.txt'));
			} else {
				log("writeFileToCloud('test.txt','click') == "+writeFileToCloud('test.txt','click'));
			}
		}

		private function publishFile(e:Event = null):void {
			if(!Steamworks.isReady) return;

			var res:Boolean = Steamworks.publishWorkshopFile("test.txt", "", _appId,
				"Test.txt", "Test.txt", WorkshopConstants.VISIBILITY_Private,
				["TestTag"], WorkshopConstants.FILETYPE_Community);
			log("publishWorkshopFile('test.txt' ...) == " + res);
		}

		private function toggleFullscreen(e:Event = null):void {
			if(stage.displayState == StageDisplayState.NORMAL)
				stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
			else
				stage.displayState = StageDisplayState.NORMAL;
		}

		private function activateOverlay(e:Event = null):void {
			if(!Steamworks.isReady) return;

			log("isOverlayEnabled() == " + Steamworks.isOverlayEnabled());
			log("activateGameOverlay('Friends') == " + Steamworks.activateGameOverlay("Friends"));
			log("isOverlayEnabled() == " + Steamworks.isOverlayEnabled());
		}

		private function enumerateSubscribedFiles(e:Event = null):void {
			if(!Steamworks.isReady) return;

			log("enumerateUserSubscribedFiles(0) == " + Steamworks.enumerateUserSubscribedFiles(0));
		}

		private 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;
				case SteamConstants.RESPONSE_OnPublishWorkshopFile:
					log("RESPONSE_OnPublishWorkshopFile: " + e.response);
					var file:String = Steamworks.publishWorkshopFileResult();
					log("File published as " + file);
					log("subscribePublishedFile(...) == " + Steamworks.subscribePublishedFile(file));
					break;
				case SteamConstants.RESPONSE_OnEnumerateUserSubscribedFiles:
					log("RESPONSE_OnEnumerateUserSubscribedFiles: " + e.response);
					var result:SubscribedFilesResult = Steamworks.enumerateUserSubscribedFilesResult();
					log("User subscribed files: " + result.resultsReturned + "/" + result.totalResults);
					for(var i:int = 0; i < result.resultsReturned; i++)
						log(i + ": " + result.publishedFileId[i] + " (" + result.timeSubscribed[i] + ")");
					break;
				default:
					log("STEAMresponse type:"+e.req_type+" response:"+e.response);
			}
		}

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

		private function addButton(label:String, callback:Function):void {
			var button:Sprite = new Sprite();
			button.graphics.beginFill(0xaaaaaa);
			button.graphics.drawRoundRect(0, 0, 150, 30, 5, 5);
			button.graphics.endFill();
			button.buttonMode = true;
			button.useHandCursor = true;
			button.addEventListener(MouseEvent.CLICK, callback);
			button.x = 5;
			button.y = _buttonPos;
			_buttonPos += button.height + 5;

			var text:TextField = new TextField();
			text.text = label;
			text.width = 140;
			text.height = 25;
			text.x = 5;
			text.y = 5;
			text.mouseEnabled = false;

			button.addChild(text);
			addChild(button);
		}
	}
}

Add test for getDLCCount

Add test for getDLCCount


#include "LevelManager.as"

LevelManager@ levelManager_;
Scene@ scene_;
bool onQuit_ = false;

void Start()
{

	SetWindowTitleAndIcon();

	CreateDebugHud();

	SubscribeToEvents();
	CreateLevel();

}

void CreateDebugHud()
{
	// Get default style
	XMLFile@ xmlFile = cache.GetResource("XMLFile", "UI/DefaultStyle.xml");
	if (xmlFile is null)
		return;

	// Create debug HUD
	DebugHud@ debugHud = engine.CreateDebugHud();
	debugHud.defaultStyle = xmlFile;
}

void SetWindowTitleAndIcon()
{
    graphics.windowIcon = cache.GetResource("Image","Resources/Textures/drone_anarchy_icon.png");
    graphics.windowTitle = "Drone Anarchy";
}

void CreateLevel()
{

	XMLFile@ file = cache.GetResource("XMLFile", "Resources/Objects/Scene.xml");
	scene_ = Scene();
	scene_.LoadXML(file.root);
	@levelManager_ = cast<LevelManager>(scene_.CreateScriptObject(scriptFile, "LevelOneManager"));
	levelManager_.InitialiseAndActivate();

}

void SubscribeToEvents()
{
	SubscribeToEvent("KeyDown","HandleKeyDown");
	SubscribeToEvent("Update", "HandleUpdate");
	SubscribeToEvent("MouseMove", "HandleMouseMove");
	SubscribeToEvent("MouseButtonDown", "HandleMouseClick");
	SubscribeToEvent("SoundFinished", "HandleSoundFinished");
}

void HandleKeyDown(StringHash eventType, VariantMap& eventData)
{
	int key = eventData["key"].GetInt();

	if(key == KEY_ESC)
		onQuit_ = true;
	else if(key == KEY_F2)
		debugHud.ToggleAll();
	else
	{
		eventData["ID"] = EVT_KEYDOWN;
		levelManager_.HandleLevelEvent(eventData);
	}

}

void HandleUpdate(StringHash eventType, VariantMap& eventData)
{
	if(onQuit_)
	{
		engine.Exit();
	}
	else
	{
		eventData["ID"] = EVT_UPDATE;
		levelManager_.HandleLevelEvent(eventData);

	}
}

void HandleMouseMove(StringHash eventType, VariantMap& eventData)
{
	eventData["ID"] = EVT_MOUSEMOVE;
	levelManager_.HandleLevelEvent(eventData);
}

void HandleMouseClick(StringHash eventType, VariantMap& eventData)
{
	eventData["ID"] = EVT_MOUSECLICK;
	levelManager_.HandleLevelEvent(eventData);
}

void HandleSoundFinished(StringHash eventType, VariantMap& eventData)
{
	eventData["ID"] = EVT_SOUNDFINISH;
	levelManager_.HandleLevelEvent(eventData);
}

Trim space

Trim space


package ageofai.map.astar {

    import ageofai.map.geom.IntPoint;
	import flash.utils.Dictionary;

	public class AStar {
		private var width:int;
		private var height:int;

		private var start:AStarNode;
		private var goal:AStarNode;

		private var map:Vector.<Vector.<AStarNode>>;

		public var open:Vector.<AStarNode>;

		public var closed:Vector.<AStarNode>;

		private var dist:Function = distEuclidian;
		//private var dist:Function = distManhattan;

		private static const COST_ORTHOGONAL:Number = 1;
		private static const COST_DIAGONAL:Number = 1.35;

		public static var cachedMaps:Dictionary;

		function AStar(map:IAStarSearchable, start:IntPoint, goal:IntPoint) {
			width = map.getWidth();
			height = map.getHeight();

			this.start = new AStarNode(start.x, start.y);
			this.goal = new AStarNode(goal.x, goal.y);

			if (cachedMaps == null) {
				cachedMaps = new Dictionary(true);
			}

			this.map = cachedMaps[map];
			if (this.map == null) {
				this.map = createMap(map);
				cachedMaps[map] = this.map;
			} else {
				cleanMap(this.map);
			}
		}

		public function solve():Vector.<IntPoint> {
			var i:int, mneighbors:Vector.<AStarNode>, neighborCount:int;

			open = new Vector.<AStarNode>();
			closed = new Vector.<AStarNode>();

			var node:AStarNode = start;
			node.h = dist(goal);
			open[open.length] = node;

			var solved:Boolean = false;

			if (!goal.equals(start) && !map[goal.x - 1][goal.y].walkable && !map[goal.x - 1][goal.y - 1].walkable &&
					!map[goal.x][goal.y - 1].walkable && !map[goal.x + 1][goal.y - 1].walkable &&
					!map[goal.x + 1][goal.y].walkable && !map[goal.x + 1][goal.y + 1].walkable &&
					!map[goal.x][goal.y + 1].walkable && !map[goal.x - 1][goal.y + 1].walkable) {

				return null;
			}
			while (!solved) {
				open.sort(sortVector);
				if (open.length <= 0) break;
				node = open.shift();
				closed[closed.length] = node;

				if (node.x == goal.x && node.y == goal.y) {
					solved = true;
					break;
				}

				mneighbors = neighbors(node);
				neighborCount = mneighbors.length;
				for (i = 0; i < neighborCount; i++) {
					var n:AStarNode = mneighbors[i];

					if (open.indexOf(n) == -1 && closed.indexOf(n) == -1) {
						open[open.length] = n;
						n.parent = node;
						n.h = dist(n);
//						n.g = node.g;
					} else {
						var f:Number = n.g + node.g + n.h;
//						trace(n.x, n.y, n.g, n.h, node.g);
						if (f < n.f) {
							n.parent = node;
							n.g = node.g;
						}
					}
				}

			}

			if (solved) {
				i = 0;
				var solution:Vector.<IntPoint> = new Vector.<IntPoint>();
				solution[0] = new IntPoint(node.x, node.y);
				while (node.parent && node.parent != start) {
					node = node.parent;
					solution[++i] = new IntPoint(node.x, node.y);
				}
//				solution[++i] = new UIntPoint(node.x, node.y);
				solution[++i] = new IntPoint(start.x, start.y);;

				return solution;
			} else {
				return null;
			}
		}

		private function sortVector(x:AStarNode, y:AStarNode):int {
			return (x.f >= y.f) ? 1 : -1;
		}

		private function distManhattan(n1:AStarNode, n2:AStarNode=null):Number {
			if (n2 == null) n2 = goal;
			return Math.abs(n1.x-n2.x)+Math.abs(n1.y-n2.y);
		}

		private function distEuclidian(n1:AStarNode, n2:AStarNode=null):Number {
			if (n2 == null) n2 = goal;
			return Math.sqrt(Math.pow((n1.x - n2.x), 2) + Math.pow((n1.y - n2.y), 2));
		}

		private function neighbors(node:AStarNode):Vector.<AStarNode> {
			var x:int = node.x, y:int = node.y, i:int = -1;
			var n:AStarNode;
			var a:Vector.<AStarNode> = new Vector.<AStarNode>();

			// N
			if (x > 0) {
				n = map[x-1][y];
				if (n.walkable) {
					n.g += COST_ORTHOGONAL;
					a[++i] = n;
				}
			}

			// E
			if (x < width-1) {
				n = map[x+1][y];
				if (n.walkable) {
					n.g += COST_ORTHOGONAL;
					a[++i] = n;
				}
			}

			// N
			if (y > 0) {
				n = map[x][y-1];
				if (n.walkable) {
					n.g += COST_ORTHOGONAL;
					a[++i] = n;
				}
			}

			// S
			if (y < height-1) {
				n = map[x][y+1];
				if (n.walkable) {
					n.g += COST_ORTHOGONAL;
					a[++i] = n;
				}
			}

			// NW
			if (x > 0 && y > 0) {
				n = map[x-1][y-1];
				if (n.walkable && map[x-1][y].walkable && map[x][y-1].walkable) {
					n.g += COST_DIAGONAL;
					a[++i] = n;
				}
			}

			// NE
			if (x < width-1 && y > 0) {
				n = map[x+1][y-1];
				if (n.walkable && map[x+1][y].walkable && map[x][y-1].walkable) {
					n.g += COST_DIAGONAL;
					a[++i] = n;
				}
			}

			// SW
			if (x > 0 && y < height-1) {
				n = map[x-1][y+1];
				if (n.walkable && map[x-1][y].walkable && map[x][y+1].walkable) {
					n.g += COST_DIAGONAL;
					a[++i] = n;
				}
			}

			// SE
			if (x < width-1 && y < height-1) {
				n = map[x+1][y+1];
				if (n.walkable && map[x+1][y].walkable && map[x][y+1].walkable) {
					n.g += COST_DIAGONAL;
					a[++i] = n;
				}
			}

			return a;

		}

		private function cleanMap(map:Vector.<Vector.<AStarNode>>):void {
			for (var x:int = 0; x < width; x++) {
				for (var y:int = 0; y < height; y++) {
					var node:AStarNode = map[x][y];
					node.g = 0;
					node.h = 0;
					node.parent = null;
				}
			}
		}

		private function createMap(map:IAStarSearchable):Vector.<Vector.<AStarNode>> {
			var a:Vector.<Vector.<AStarNode>> = new Vector.<Vector.<AStarNode>>(width);

			for (var x:int = 0; x < width; x++) {
				a[x] = new Vector.<AStarNode>(height);
				for (var y:int = 0; y < height; y++) {
					var node:AStarNode = new AStarNode(x, y, map.isWalkable(x, y));
					a[x][y] = node;
				}
			}

			return a;
		}
	}
}

package ageofai.map.astar {

    import ageofai.map.geom.IntPoint;
	import flash.utils.Dictionary;

	public class AStar {
		private var width:int;
		private var height:int;

		private var start:AStarNode;
		private var goal:AStarNode;

		private var map:Vector.<Vector.<AStarNode>>;

		public var open:Vector.<AStarNode>;

		public var closed:Vector.<AStarNode>;

		private var dist:Function = distEuclidian;
		//private var dist:Function = distManhattan;

		private static const COST_ORTHOGONAL:Number = 1;
		private static const COST_DIAGONAL:Number = 1.35;

		public static var cachedMaps:Dictionary;

		function AStar(map:IAStarSearchable, start:IntPoint, goal:IntPoint) {
			width = map.getWidth();
			height = map.getHeight();

			this.start = new AStarNode(start.x, start.y);
			this.goal = new AStarNode(goal.x, goal.y);

			if (cachedMaps == null) {
				cachedMaps = new Dictionary(true);
			}

			this.map = cachedMaps[map];
			if (this.map == null) {
				this.map = createMap(map);
				cachedMaps[map] = this.map;
			} else {
				cleanMap(this.map);
			}
		}

		public function solve():Vector.<IntPoint> {
			var i:int, mneighbors:Vector.<AStarNode>, neighborCount:int;

			open = new Vector.<AStarNode>();
			closed = new Vector.<AStarNode>();

			var node:AStarNode = start;
			node.h = dist(goal);
			open[open.length] = node;

			var solved:Boolean = false;

			if (!goal.equals(start)) {
                var accessible:Boolean;
                for (i = goal.x - 1; i != goal.x + 1; i++)
                {
                    for (var j:int = goal.y - 1; j != goal.y + 1; j++)
                    {
                        if (i == goal.x && j == goal.y) continue;
                        if (i >= 0 && j >= 0 && i < this.width && j < this.height && this.map[i][j].walkable)
                        {
                            accessible = true;
                            break;
                        }
                    }
                    if (accessible) break;
                }

                if (!accessible) return null;
			}
			while (!solved) {
				open.sort(sortVector);
				if (open.length <= 0) break;
				node = open.shift();
				closed[closed.length] = node;

				if (node.x == goal.x && node.y == goal.y) {
					solved = true;
					break;
				}

				mneighbors = neighbors(node);
				neighborCount = mneighbors.length;
				for (i = 0; i < neighborCount; i++) {
					var n:AStarNode = mneighbors[i];

					if (open.indexOf(n) == -1 && closed.indexOf(n) == -1) {
						open[open.length] = n;
						n.parent = node;
						n.h = dist(n);
//						n.g = node.g;
					} else {
						var f:Number = n.g + node.g + n.h;
//						trace(n.x, n.y, n.g, n.h, node.g);
						if (f < n.f) {
							n.parent = node;
							n.g = node.g;
						}
					}
				}

			}

			if (solved) {
				i = 0;
				var solution:Vector.<IntPoint> = new Vector.<IntPoint>();
				solution[0] = new IntPoint(node.x, node.y);
				while (node.parent && node.parent != start) {
					node = node.parent;
					solution[++i] = new IntPoint(node.x, node.y);
				}
//				solution[++i] = new UIntPoint(node.x, node.y);
				solution[++i] = new IntPoint(start.x, start.y);;

				return solution;
			} else {
				return null;
			}
		}

		private function sortVector(x:AStarNode, y:AStarNode):int {
			return (x.f >= y.f) ? 1 : -1;
		}

		private function distManhattan(n1:AStarNode, n2:AStarNode=null):Number {
			if (n2 == null) n2 = goal;
			return Math.abs(n1.x-n2.x)+Math.abs(n1.y-n2.y);
		}

		private function distEuclidian(n1:AStarNode, n2:AStarNode=null):Number {
			if (n2 == null) n2 = goal;
			return Math.sqrt(Math.pow((n1.x - n2.x), 2) + Math.pow((n1.y - n2.y), 2));
		}

		private function neighbors(node:AStarNode):Vector.<AStarNode> {
			var x:int = node.x, y:int = node.y, i:int = -1;
			var n:AStarNode;
			var a:Vector.<AStarNode> = new Vector.<AStarNode>();

			// N
			if (x > 0) {
				n = map[x-1][y];
				if (n.walkable) {
					n.g += COST_ORTHOGONAL;
					a[++i] = n;
				}
			}

			// E
			if (x < width-1) {
				n = map[x+1][y];
				if (n.walkable) {
					n.g += COST_ORTHOGONAL;
					a[++i] = n;
				}
			}

			// N
			if (y > 0) {
				n = map[x][y-1];
				if (n.walkable) {
					n.g += COST_ORTHOGONAL;
					a[++i] = n;
				}
			}

			// S
			if (y < height-1) {
				n = map[x][y+1];
				if (n.walkable) {
					n.g += COST_ORTHOGONAL;
					a[++i] = n;
				}
			}

			// NW
			if (x > 0 && y > 0) {
				n = map[x-1][y-1];
				if (n.walkable && map[x-1][y].walkable && map[x][y-1].walkable) {
					n.g += COST_DIAGONAL;
					a[++i] = n;
				}
			}

			// NE
			if (x < width-1 && y > 0) {
				n = map[x+1][y-1];
				if (n.walkable && map[x+1][y].walkable && map[x][y-1].walkable) {
					n.g += COST_DIAGONAL;
					a[++i] = n;
				}
			}

			// SW
			if (x > 0 && y < height-1) {
				n = map[x-1][y+1];
				if (n.walkable && map[x-1][y].walkable && map[x][y+1].walkable) {
					n.g += COST_DIAGONAL;
					a[++i] = n;
				}
			}

			// SE
			if (x < width-1 && y < height-1) {
				n = map[x+1][y+1];
				if (n.walkable && map[x+1][y].walkable && map[x][y+1].walkable) {
					n.g += COST_DIAGONAL;
					a[++i] = n;
				}
			}

			return a;

		}

		private function cleanMap(map:Vector.<Vector.<AStarNode>>):void {
			for (var x:int = 0; x < width; x++) {
				for (var y:int = 0; y < height; y++) {
					var node:AStarNode = map[x][y];
					node.g = 0;
					node.h = 0;
					node.parent = null;
				}
			}
		}

		private function createMap(map:IAStarSearchable):Vector.<Vector.<AStarNode>> {
			var a:Vector.<Vector.<AStarNode>> = new Vector.<Vector.<AStarNode>>(width);

			for (var x:int = 0; x < width; x++) {
				a[x] = new Vector.<AStarNode>(height);
				for (var y:int = 0; y < height; y++) {
					var node:AStarNode = new AStarNode(x, y, map.isWalkable(x, y));
					a[x][y] = node;
				}
			}

			return a;
		}
	}
}

Fix astar bug

Fix astar bug


/* ***** BEGIN LICENSE BLOCK *****
 *
 * This file is part of Weave.
 *
 * The Initial Developer of Weave is the Institute for Visualization
 * and Perception Research at the University of Massachusetts Lowell.
 * Portions created by the Initial Developer are Copyright (C) 2008-2015
 * the Initial Developer. All Rights Reserved.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * ***** END LICENSE BLOCK ***** */

package weavejs.util
{
	import weavejs.WeaveAPI;
	import weavejs.api.core.IDisposableObject;
	import weavejs.api.core.ILinkableObject;

	/**
	 * Use this when you need a Promise chain to depend on ILinkableObjects and resolve multiple times.
	 *
	 * Adds support for depend(...linkableObjects)
	 */
	public class WeavePromise implements IDisposableObject
	{
		/**
		 * @param relevantContext This parameter may be null.  If the relevantContext object is disposed, the promise will be disabled.
		 * @param resolver A function like function(resolve:Function, reject:Function):void which carries out the promise.
		 *                 If no resolver is given, setResult() or setError() should be called externally.
		 */
		public function WeavePromise(relevantContext:Object, resolver:Function = null)
		{
			if (relevantContext is WeavePromise)
			{
				// this is a child promise
				this.rootPromise = (relevantContext as WeavePromise).rootPromise;
				this.relevantContext = relevantContext = this.rootPromise.relevantContext;
			}
			else
			{
				// this is a new root promise
				this.rootPromise = this;
				this.relevantContext = relevantContext;
			}

			if (relevantContext)
				Weave.disposableChild(relevantContext, this);

			if (resolver != null)
			{
				setBusy(true);
				resolver(this.setResult, this.setError);
			}
		}

		private static function noop(value:Object):Object { return value; }

		private var rootPromise:WeavePromise;
		protected var relevantContext:Object;
		private var result:* = undefined;
		private var error:* = undefined;
		private var handlers:Array = []; // array of Handler objects
		private var dependencies:Array = [];

		/**
		 * @return This WeavePromise
		 */
		public function setResult(result:Object):WeavePromise
		{
			if (Weave.wasDisposed(relevantContext))
			{
				setBusy(false);
				return this;
			}

			this.result = undefined;
			this.error = undefined;

			if (result is JS.Promise)
			{
				result.then(setResult, setError);
			}
			else if (result is WeavePromise)
			{
				(result as WeavePromise).then(setResult, setError);
			}
			else
			{
				this.result = result as Object;
				callHandlers();
			}

			return this;
		}

		public function getResult():Object
		{
			return result;
		}

		/**
		 * @return This WeavePromise
		 */
		public function setError(error:Object):WeavePromise
		{
			if (Weave.wasDisposed(relevantContext))
			{
				setBusy(false);
				return this;
			}

			this.result = undefined;
			this.error = error;

			callHandlers();

			return this;
		}

		public function getError():Object
		{
			return error;
		}

		private function setBusy(busy:Boolean):void
		{
			if (busy)
			{
				WeaveAPI.ProgressIndicator.addTask(rootPromise, relevantContext as ILinkableObject);
			}
			else
			{
				WeaveAPI.ProgressIndicator.removeTask(rootPromise);
			}
		}

		private function callHandlers(newHandlersOnly:Boolean = false):void
		{
			if (dependencies.some(Weave.isBusy))
			{
				if (handlers.length)
					setBusy(true);
				return;
			}

			// if there are no more handlers, remove the task
			if (handlers.length == 0)
				setBusy(false);

			if (Weave.wasDisposed(relevantContext))
			{
				setBusy(false);
				return;
			}

			for (var i:int = 0; i < handlers.length; i++)
			{
				var handler:WeavePromiseHandler = handlers[i];
				if (newHandlersOnly && handler.wasCalled)
					continue;
				if (result !== undefined)
					handler.onResult(result);
				else if (error !== undefined)
					handler.onError(error);
			}
		}

		public function then(onFulfilled:Function = null, onRejected:Function = null):WeavePromise
		{
			if (onFulfilled == null)
				onFulfilled = noop;
			if (onRejected == null)
				onRejected = noop;

			var next:WeavePromise = new WeavePromise(this);
			next.result = undefined;
			handlers.push(new WeavePromiseHandler(onFulfilled, onRejected, next));

			if (result !== undefined || error !== undefined)
			{
				// callLater will not call the function if the context was disposed
				WeaveAPI.Scheduler.callLater(relevantContext, callHandlers, [true]);
				setBusy(true);
			}

			return next;
		}

		public function depend(...linkableObjects):WeavePromise
		{
			if (linkableObjects.length)
			{
				setBusy(true);
			}
			for each (var dependency:ILinkableObject in linkableObjects)
			{
				Weave.getCallbacks(dependency).addGroupedCallback(relevantContext, callHandlers, true);
			}
			return this;
		}

		public function getPromise():Object
		{
			var var_resolve:Function, var_reject:Function;
			var promise:Object = new JS.Promise(function(resolve:Function, reject:Function):void {
				var_resolve = resolve;
				var_reject = reject;
			});
			then(var_resolve, var_reject);
			return promise;
		}

		public function dispose():void
		{
			handlers.length = 0;
			setBusy(false);
		}
	}
}

/* ***** BEGIN LICENSE BLOCK *****
 *
 * This file is part of Weave.
 *
 * The Initial Developer of Weave is the Institute for Visualization
 * and Perception Research at the University of Massachusetts Lowell.
 * Portions created by the Initial Developer are Copyright (C) 2008-2015
 * the Initial Developer. All Rights Reserved.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * ***** END LICENSE BLOCK ***** */

package weavejs.util
{
	import weavejs.WeaveAPI;
	import weavejs.api.core.IDisposableObject;
	import weavejs.api.core.ILinkableObject;

	/**
	 * Use this when you need a Promise chain to depend on ILinkableObjects and resolve multiple times.
	 *
	 * Adds support for depend(...linkableObjects)
	 */
	public class WeavePromise implements IDisposableObject
	{
		/**
		 * @param relevantContext This parameter may be null.  If the relevantContext object is disposed, the promise will be disabled.
		 * @param resolver A function like function(resolve:Function, reject:Function):void which carries out the promise.
		 *                 If no resolver is given, setResult() or setError() should be called externally.
		 */
		public function WeavePromise(relevantContext:Object, resolver:Function = null)
		{
			if (relevantContext is WeavePromise)
			{
				// this is a child promise
				this.rootPromise = (relevantContext as WeavePromise).rootPromise;
				this.relevantContext = relevantContext = this.rootPromise.relevantContext;
			}
			else
			{
				// this is a new root promise
				this.rootPromise = this;
				this.relevantContext = relevantContext;
			}

			if (relevantContext)
				Weave.disposableChild(relevantContext, this);

			if (resolver != null)
			{
				setBusy(true);
				resolver(this.setResult, this.setError);
			}
		}

		private static function noop(value:Object):Object { return value; }

		private var rootPromise:WeavePromise;
		protected var relevantContext:Object;
		private var result:* = undefined;
		private var error:* = undefined;
		private var handlers:Array = []; // array of Handler objects
		private var dependencies:Array = [];

		/**
		 * @return This WeavePromise
		 */
		public function setResult(result:Object):WeavePromise
		{
			if (Weave.wasDisposed(relevantContext))
			{
				setBusy(false);
				return this;
			}

			this.result = undefined;
			this.error = undefined;

			if (result is JS.Promise)
			{
				result.then(setResult, setError);
			}
			else if (result is WeavePromise)
			{
				(result as WeavePromise).then(setResult, setError);
			}
			else
			{
				this.result = result as Object;
				callHandlers();
			}

			return this;
		}

		public function getResult():Object
		{
			return result;
		}

		/**
		 * @return This WeavePromise
		 */
		public function setError(error:Object):WeavePromise
		{
			if (Weave.wasDisposed(relevantContext))
			{
				setBusy(false);
				return this;
			}

			this.result = undefined;
			this.error = error as Object;

			callHandlers();

			return this;
		}

		public function getError():Object
		{
			return error;
		}

		private function setBusy(busy:Boolean):void
		{
			if (busy)
			{
				WeaveAPI.ProgressIndicator.addTask(rootPromise, relevantContext as ILinkableObject);
			}
			else
			{
				WeaveAPI.ProgressIndicator.removeTask(rootPromise);
			}
		}

		private function callHandlers(newHandlersOnly:Boolean = false):void
		{
			if (dependencies.some(Weave.isBusy))
			{
				if (handlers.length)
					setBusy(true);
				return;
			}

			// if there are no more handlers, remove the task
			if (handlers.length == 0)
				setBusy(false);

			if (Weave.wasDisposed(relevantContext))
			{
				setBusy(false);
				return;
			}

			for (var i:int = 0; i < handlers.length; i++)
			{
				var handler:WeavePromiseHandler = handlers[i];
				if (newHandlersOnly && handler.wasCalled)
					continue;
				if (result !== undefined)
					handler.onResult(result);
				else if (error !== undefined)
					handler.onError(error);
			}
		}

		public function then(onFulfilled:Function = null, onRejected:Function = null):WeavePromise
		{
			if (onFulfilled == null)
				onFulfilled = noop;
			if (onRejected == null)
				onRejected = noop;

			var next:WeavePromise = new WeavePromise(this);
			next.result = undefined;
			handlers.push(new WeavePromiseHandler(onFulfilled, onRejected, next));

			if (result !== undefined || error !== undefined)
			{
				// callLater will not call the function if the context was disposed
				WeaveAPI.Scheduler.callLater(relevantContext, callHandlers, [true]);
				setBusy(true);
			}

			return next;
		}

		public function depend(...linkableObjects):WeavePromise
		{
			if (linkableObjects.length)
			{
				setBusy(true);
			}
			for each (var dependency:ILinkableObject in linkableObjects)
			{
				Weave.getCallbacks(dependency).addGroupedCallback(relevantContext, callHandlers, true);
			}
			return this;
		}

		public function getPromise():Object
		{
			var var_resolve:Function, var_reject:Function;
			var promise:Object = new JS.Promise(function(resolve:Function, reject:Function):void {
				var_resolve = resolve;
				var_reject = reject;
			});
			then(var_resolve, var_reject);
			return promise;
		}

		public function dispose():void
		{
			handlers.length = 0;
			setBusy(false);
		}
	}
}

add explicit cast in place of lost implicit cast


package aerys.minko.scene.node
{
	import aerys.minko.ns.minko_scene;
	import aerys.minko.render.Effect;
	import aerys.minko.render.Viewport;
	import aerys.minko.scene.controller.scene.RenderingController;
	import aerys.minko.scene.node.camera.AbstractCamera;
	import aerys.minko.type.Signal;
	import aerys.minko.type.binding.DataBindings;
	import aerys.minko.type.binding.DataProvider;
	import aerys.minko.type.enum.DataProviderUsage;
	import aerys.minko.type.loader.AssetsLibrary;

	import flash.display.BitmapData;
	import flash.utils.Dictionary;
	import flash.utils.getTimer;

	/**
	 * Scene objects are the root of any 3D scene.
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public final class Scene extends Group
	{
		use namespace minko_scene;

		minko_scene var _camera		: AbstractCamera;

		private var _renderingCtrl	: RenderingController;

		private var _properties		: DataProvider;
		private var _bindings		: DataBindings;

		private var _numTriangles	: uint;

		private var _enterFrame		: Signal;
		private var _renderingBegin	: Signal;
		private var _renderingEnd	: Signal;
		private var _exitFrame		: Signal;

		private var _assets				: AssetsLibrary;

		public function get assets() : AssetsLibrary
		{
			return _assets;
		}

		public function get activeCamera() : AbstractCamera
		{
			return _camera;
		}

		public function get numPasses() : uint
		{
			return _renderingCtrl.numPasses;
		}

		public function get numEnabledPasses() : uint
		{
			return _renderingCtrl.numEnabledPasses;
		}

		public function get numTriangles() : uint
		{
			return _numTriangles;
		}

		public function get postProcessingEffect() : Effect
		{
			return _renderingCtrl.postProcessingEffect;
		}
		public function set postProcessingEffect(value : Effect) : void
		{
			_renderingCtrl.postProcessingEffect = value;
		}

		public function get postProcessingProperties() : DataProvider
		{
			return _renderingCtrl.postProcessingProperties;
		}

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

				_properties = value;

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

		public function get bindings() : DataBindings
		{
			return _bindings;
		}

		/**
		 * The signal executed when the viewport is about to start rendering a frame.
		 * Callback functions for this signal should accept the following arguments:
		 *

		 *
viewport : Viewport, the viewport who starts rendering the frame

		 *

		 * @return
		 *
		 */
		public function get enterFrame() : Signal
		{
			return _enterFrame;
		}

		/**
		 * The signal executed when the viewport is done rendering a frame.
		 * Callback functions for this signal should accept the following arguments:
		 *

		 *
viewport : Viewport, the viewport who just finished rendering the frame

		 *

		 * @return
		 *
		 */
		public function get exitFrame() : Signal
		{
			return _exitFrame;
		}

		public function get renderingBegin() : Signal
		{
			return _renderingBegin;
		}

		public function get renderingEnd() : Signal
		{
			return _renderingEnd;
		}

		public function Scene(...children)
		{
			super(children);
		}

		override protected function initialize() : void
		{
			_bindings 					= new DataBindings(this);
			_assets						= new AssetsLibrary();
			this.properties 			= new DataProvider(DataProviderUsage.EXCLUSIVE);

			super.initialize();
		}

		override protected function initializeSignals() : void
		{
			super.initializeSignals();

			_enterFrame			= new Signal('Scene.enterFrame');
			_renderingBegin 	= new Signal('Scene.renderingBegin');
			_renderingEnd 		= new Signal('Scene.renderingEnd');
			_exitFrame 			= new Signal('Scene.exitFrame');
		}

		override protected function initializeSignalHandlers() : void
		{
			super.initializeSignalHandlers();

			added.add(addedHandler);
		}

		override protected function initializeContollers() : void
		{
			_renderingCtrl = new RenderingController();
			addController(_renderingCtrl);

			super.initializeContollers();
		}

		public function render(viewport : Viewport, destination : BitmapData = null) : void
		{
			_enterFrame.execute(this, viewport, destination, getTimer());
			if (viewport.ready && viewport.visible)
			{
				_renderingBegin.execute(this, viewport, destination, getTimer());
				_numTriangles = _renderingCtrl.render(viewport, destination);
				_renderingEnd.execute(this, viewport, destination, getTimer());
			}
			_exitFrame.execute(this, viewport, destination, getTimer());
		}

		private function addedHandler(child : ISceneNode, parent : Group) : void
		{
			throw new Error();
		}
	}
}

fix coding style

fix coding style


import Drawable;
import Lobe;
import Core;

class Brain{
    static var brain = new Array();
    var mSelectionManager:SelectionManager;
    static function makenewlobe(){
      var newmov=(new Lobe(_root,_root.getNextHighestDepth()));
      var topleft = new Point(100,40);
      var botright = new Point(200,140);
      newmov.commitBox(topleft, botright, 0);
              var keyListener = {};
        keyListener.onKeyDown = function()
        {
            var k = Key.getCode();
            if(k == Key.DELETEKEY){
                Brain.makenewlobe();
            }
        };
    }
    function Brain (root_mc:MovieClip) {
       mSelectionManager = new SelectionManager(root_mc);
    }
}

import Drawable;
import Lobe;
import Core;

class Brain{
    static var brain = new Array();
    var mSelectionManager:SelectionManager;
    static function makenewlobe(){
      var newmov=(new Lobe(_root,_root.getNextHighestDepth()));
      var topleft = new Point(100,40);
      var botright = new Point(200,140);
      newmov.commitBox(topleft, botright, 0);
    }

    function Brain (root_mc:MovieClip) {
       mSelectionManager = new SelectionManager(root_mc);
               var keyListener = {};
        keyListener.onKeyDown = function()
        {
            var k = Key.getCode();
            if(k == Key.DELETEKEY){
                Brain.makenewlobe();
            }
        };
        Key.addListener( keyListener );
    }
}

Delete is now a non-core function

Delete is now a non-core function

git-svn-id: f772d44cbf86d9968f12179c1556189f5afcea6e@658 e0ac87d7-b42b-0410-9034-8248a05cb448


package
{
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.text.TextField;
    import flash.text.TextFormat;
    import flash.net.Socket;
    import flash.events.Event;
    import flash.events.IOErrorEvent;
    import flash.events.ProgressEvent;
    import flash.events.SecurityErrorEvent;
    import flash.utils.ByteArray;
    import flash.utils.setTimeout;

    public class swfcat extends Sprite
    {
        /* David's relay (nickname 3VXRyxz67OeRoqHn) that also serves a
           crossdomain policy. */
        private const DEFAULT_TOR_ADDR:Object = {
            host: "173.255.221.44",
            port: 9001
        };
        private const DEFAULT_FACILITATOR_ADDR:Object = {
            host: "173.255.221.44",
            port: 9002
        };

        private const MAX_NUM_PROXY_PAIRS:uint = 1;

        // Milliseconds.
        private const FACILITATOR_POLL_INTERVAL:int = 10000;

        // Bytes per second. Set to undefined to disable limit.
        public const RATE_LIMIT:Number = 10 * 1024;
        // Seconds.
        private const RATE_LIMIT_HISTORY:Number = 5.0;

        // Socket to facilitator.
        private var s_f:Socket;

        /* TextField for debug output. */
        private var output_text:TextField;

        private var fac_addr:Object;

        /* Number of proxy pairs currently connected (up to
           MAX_NUM_PROXY_PAIRS). */
        private var num_proxy_pairs:int = 0;
        /* Number of proxy pairs ever connected. */
        private var total_proxy_pairs:int = 0;

        public var rate_limit:RateLimit;

        /* Badge with a client counter */
        [Embed(source="badge_con_counter.png")]
        private var BadgeImage:Class;
        private var client_count_tf:TextField;
        private var client_count_fmt:TextFormat;

        public function puts(s:String):void
        {
            output_text.appendText(s + "\n");
            output_text.scrollV = output_text.maxScrollV;
        }

        public function update_client_count():void
        {
            if (String(total_proxy_pairs).length == 1)
                client_count_tf.text = "0" + String(total_proxy_pairs);
            else
                client_count_tf.text = String(total_proxy_pairs);
        }

        public function swfcat()
        {
            // Absolute positioning.
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;

            output_text = new TextField();
            output_text.width = stage.stageWidth;
            output_text.height = stage.stageHeight;
            output_text.background = true;
            output_text.backgroundColor = 0x001f0f;
            output_text.textColor = 0x44cc44;

            /* Setup client counter for badge. */
            client_count_fmt = new TextFormat();
            client_count_fmt.color = 0xFFFFFF;
            client_count_fmt.align = "center";
            client_count_fmt.font = "courier-new";
            client_count_fmt.bold = true;
            client_count_fmt.size = 10;
            client_count_tf = new TextField();
            client_count_tf.width = 20;
            client_count_tf.height = 17;
            client_count_tf.background = false;
            client_count_tf.defaultTextFormat = client_count_fmt;
            client_count_tf.x=47;
            client_count_tf.y=3;

            /* Update the client counter on badge. */
            update_client_count();

            if (RATE_LIMIT)
                rate_limit = new BucketRateLimit(RATE_LIMIT * RATE_LIMIT_HISTORY, RATE_LIMIT_HISTORY);
            else
                rate_limit = new RateUnlimit();

            puts("Starting.");
            // Wait until the query string parameters are loaded.
            this.loaderInfo.addEventListener(Event.COMPLETE, loaderinfo_complete);
        }

        private function loaderinfo_complete(e:Event):void
        {
            var fac_spec:String;

            puts("Parameters loaded.");

            if (this.loaderInfo.parameters["debug"])
                addChild(output_text);
            else {
                addChild(new BadgeImage());
                /* Tried unsuccessfully to add counter to badge. */
                /* For now, need two addChilds :( */
                addChild(client_count_tf);
            }

            fac_spec = this.loaderInfo.parameters["facilitator"];
            if (fac_spec) {
                puts("Facilitator spec: \"" + fac_spec + "\"");
                fac_addr = parse_addr_spec(fac_spec);
                if (!fac_addr) {
                    puts("Error: Facilitator spec must be in the form \"host:port\".");
                    return;
                }
            } else {
                fac_addr = DEFAULT_FACILITATOR_ADDR;
            }

            main();
        }

        /* The main logic begins here, after start-up issues are taken care of. */
        private function main():void
        {
            if (num_proxy_pairs >= MAX_NUM_PROXY_PAIRS) {
                setTimeout(main, FACILITATOR_POLL_INTERVAL);
                return;
            }

            s_f = new Socket();

            s_f.addEventListener(Event.CONNECT, fac_connected);
            s_f.addEventListener(Event.CLOSE, function (e:Event):void {
                puts("Facilitator: closed connection.");
                setTimeout(main, FACILITATOR_POLL_INTERVAL);
            });
            s_f.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
                puts("Facilitator: I/O error: " + e.text + ".");
            });
            s_f.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
                puts("Facilitator: security error: " + e.text + ".");
            });

            puts("Facilitator: connecting to " + fac_addr.host + ":" + fac_addr.port + ".");
            s_f.connect(fac_addr.host, fac_addr.port);
        }

        private function fac_connected(e:Event):void
        {
            puts("Facilitator: connected.");

            s_f.addEventListener(ProgressEvent.SOCKET_DATA, fac_data);

            s_f.writeUTFBytes("GET / HTTP/1.0\r\n\r\n");
        }

        private function fac_data(e:ProgressEvent):void
        {
            var client_spec:String;
            var client_addr:Object;
            var proxy_pair:Object;

            client_spec = s_f.readMultiByte(e.bytesLoaded, "utf-8");
            puts("Facilitator: got \"" + client_spec + "\".");

            client_addr = parse_addr_spec(client_spec);
            if (!client_addr) {
                puts("Error: Client spec must be in the form \"host:port\".");
                return;
            }

            num_proxy_pairs++;
            total_proxy_pairs++;
            proxy_pair = new ProxyPair(this, client_addr, DEFAULT_TOR_ADDR);
            proxy_pair.addEventListener(Event.COMPLETE, function(e:Event):void {
                proxy_pair.log("Complete.");
                num_proxy_pairs--;
            });
            proxy_pair.connect();

            /* Update the client count on the badge. */
            update_client_count();
        }

        /* Parse an address in the form "host:port". Returns an Object with
           keys "host" (String) and "port" (int). Returns null on error. */
        private static function parse_addr_spec(spec:String):Object
        {
            var parts:Array;
            var addr:Object;

            parts = spec.split(":", 2);
            if (parts.length != 2 || !parseInt(parts[1]))
                return null;
            addr = {}
            addr.host = parts[0];
            addr.port = parseInt(parts[1]);

            return addr;
        }
    }
}

import flash.display.Sprite;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;
import flash.net.Socket;
import flash.utils.ByteArray;
import flash.utils.clearTimeout;
import flash.utils.getTimer;
import flash.utils.setTimeout;

class RateLimit
{
    public function RateLimit()
    {
    }

    public function update(n:Number):Boolean
    {
        return true;
    }

    public function when():Number
    {
        return 0.0;
    }

    public function is_limited():Boolean
    {
        return false;
    }
}

class RateUnlimit extends RateLimit
{
    public function RateUnlimit()
    {
    }

    public override function update(n:Number):Boolean
    {
        return true;
    }

    public override function when():Number
    {
        return 0.0;
    }

    public override function is_limited():Boolean
    {
        return false;
    }
}

class BucketRateLimit extends RateLimit
{
    private var amount:Number;
    private var capacity:Number;
    private var time:Number;
    private var last_update:uint;

    public function BucketRateLimit(capacity:Number, time:Number)
    {
        this.amount = 0.0;
        /* capacity / time is the rate we are aiming for. */
        this.capacity = capacity;
        this.time = time;
        this.last_update = getTimer();
    }

    private function age():void
    {
        var now:uint;
        var delta:Number;

        now = getTimer();
        delta = (now - last_update) / 1000.0;
        last_update = now;

        amount -= delta * capacity / time;
        if (amount < 0.0)
            amount = 0.0;
    }

    public override function update(n:Number):Boolean
    {
        age();
        amount += n;

        return amount <= capacity;
    }

    public override function when():Number
    {
        age();
        return (amount - capacity) / (capacity / time);
    }

    public override function is_limited():Boolean
    {
        age();
        return amount > capacity;
    }
}

/* An instance of a client-relay connection. */
class ProxyPair extends EventDispatcher
{
    // Address ({host, port}) of client.
    private var addr_c:Object;
    // Address ({host, port}) of relay.
    private var addr_r:Object;

    // Socket to client.
    private var s_c:Socket;
    // Socket to relay.
    private var s_r:Socket;

    // Parent swfcat, for UI updates and rate meter.
    private var ui:swfcat;

    // Pending byte read counts for relay and client sockets.
    private var r2c_schedule:Array;
    private var c2r_schedule:Array;
    // Callback id.
    private var flush_id:uint;

    public function log(msg:String):void
    {
        ui.puts(id() + ": " + msg)
    }

    // String describing this pair for output.
    public function id():String
    {
        return "<" + this.addr_c.host + ":" + this.addr_c.port +
            "," + this.addr_r.host + ":" + this.addr_r.port + ">";
    }

    public function ProxyPair(ui:swfcat, addr_c:Object, addr_r:Object)
    {
        this.ui = ui;
        this.addr_c = addr_c;
        this.addr_r = addr_r;

        this.c2r_schedule = [];
        this.r2c_schedule = [];
    }

    public function connect():void
    {
        s_r = new Socket();

        s_r.addEventListener(Event.CONNECT, tor_connected);
        s_r.addEventListener(Event.CLOSE, function (e:Event):void {
            log("Tor: closed.");
            if (s_c.connected)
                s_c.close();
            dispatchEvent(new Event(Event.COMPLETE));
        });
        s_r.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
            log("Tor: I/O error: " + e.text + ".");
            if (s_c.connected)
                s_c.close();
            dispatchEvent(new Event(Event.COMPLETE));
        });
        s_r.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
            log("Tor: security error: " + e.text + ".");
            if (s_c.connected)
                s_c.close();
            dispatchEvent(new Event(Event.COMPLETE));
        });
        s_r.addEventListener(ProgressEvent.SOCKET_DATA, relay_to_client);

        log("Tor: connecting to " + addr_r.host + ":" + addr_r.port + ".");
        s_r.connect(addr_r.host, addr_r.port);
    }

    private function tor_connected(e:Event):void
    {
        log("Tor: connected.");

        s_c = new Socket();

        s_c.addEventListener(Event.CONNECT, client_connected);
        s_c.addEventListener(Event.CLOSE, function (e:Event):void {
            log("Client: closed.");
            if (s_r.connected)
                s_r.close();
            dispatchEvent(new Event(Event.COMPLETE));
        });
        s_c.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
            log("Client: I/O error: " + e.text + ".");
            if (s_r.connected)
                s_r.close();
            dispatchEvent(new Event(Event.COMPLETE));
        });
        s_c.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
            log("Client: security error: " + e.text + ".");
            if (s_r.connected)
                s_r.close();
            dispatchEvent(new Event(Event.COMPLETE));
        });
        s_c.addEventListener(ProgressEvent.SOCKET_DATA, client_to_relay);

        log("Client: connecting to " + addr_c.host + ":" + addr_c.port + ".");
        s_c.connect(addr_c.host, addr_c.port);
    }

    private function relay_to_client(e:ProgressEvent):void
    {
        r2c_schedule.push(e.bytesLoaded);
        flush();
    }

    private function client_to_relay(e:ProgressEvent):void
    {
        c2r_schedule.push(e.bytesLoaded);
        flush();
    }

    private function client_connected(e:Event):void
    {
        log("Client: connected.");
    }

    private function transfer_chunk(s_from:Socket, s_to:Socket, n:uint,
        label:String):void
    {
        var bytes:ByteArray;

        bytes = new ByteArray();
        s_from.readBytes(bytes, 0, n);
        s_to.writeBytes(bytes);
        ui.rate_limit.update(n);
        log(label + ": read " + bytes.length + ".");
    }

    /* Send as much data as the rate limit currently allows. */
    private function flush():void
    {
        if (flush_id)
            clearTimeout(flush_id);
        flush_id = undefined;

        if (!(s_r.connected && s_c.connected))
            /* Can't do anything until both sockets are connected. */
            return;

        while (!ui.rate_limit.is_limited() &&
               (r2c_schedule.length > 0 || c2r_schedule.length > 0)) {
            if (r2c_schedule.length > 0)
                transfer_chunk(s_r, s_c, r2c_schedule.shift(), "Tor");
            if (c2r_schedule.length > 0)
                transfer_chunk(s_c, s_r, c2r_schedule.shift(), "Client");
        }

        /* Call again when safe, if necessary. */
        if (r2c_schedule.length > 0 || c2r_schedule.length > 0)
            flush_id = setTimeout(flush, ui.rate_limit.when() * 1000);
    }
}

package
{
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.text.TextField;
    import flash.text.TextFormat;
    import flash.net.Socket;
    import flash.events.Event;
    import flash.events.IOErrorEvent;
    import flash.events.ProgressEvent;
    import flash.events.SecurityErrorEvent;
    import flash.utils.ByteArray;
    import flash.utils.setTimeout;

    public class swfcat extends Sprite
    {
        /* David's relay (nickname 3VXRyxz67OeRoqHn) that also serves a
           crossdomain policy. */
        private const DEFAULT_TOR_ADDR:Object = {
            host: "173.255.221.44",
            port: 9001
        };
        private const DEFAULT_FACILITATOR_ADDR:Object = {
            host: "173.255.221.44",
            port: 9002
        };

        private const MAX_NUM_PROXY_PAIRS:uint = 1;

        // Milliseconds.
        private const FACILITATOR_POLL_INTERVAL:int = 10000;

        // Bytes per second. Set to undefined to disable limit.
        public const RATE_LIMIT:Number = undefined;
        // Seconds.
        private const RATE_LIMIT_HISTORY:Number = 5.0;

        // Socket to facilitator.
        private var s_f:Socket;

        /* TextField for debug output. */
        private var output_text:TextField;

        private var fac_addr:Object;

        /* Number of proxy pairs currently connected (up to
           MAX_NUM_PROXY_PAIRS). */
        private var num_proxy_pairs:int = 0;
        /* Number of proxy pairs ever connected. */
        private var total_proxy_pairs:int = 0;

        public var rate_limit:RateLimit;

        /* Badge with a client counter */
        [Embed(source="badge_con_counter.png")]
        private var BadgeImage:Class;
        private var client_count_tf:TextField;
        private var client_count_fmt:TextFormat;

        public function puts(s:String):void
        {
            output_text.appendText(s + "\n");
            output_text.scrollV = output_text.maxScrollV;
        }

        public function update_client_count():void
        {
            if (String(total_proxy_pairs).length == 1)
                client_count_tf.text = "0" + String(total_proxy_pairs);
            else
                client_count_tf.text = String(total_proxy_pairs);
        }

        public function swfcat()
        {
            // Absolute positioning.
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;

            output_text = new TextField();
            output_text.width = stage.stageWidth;
            output_text.height = stage.stageHeight;
            output_text.background = true;
            output_text.backgroundColor = 0x001f0f;
            output_text.textColor = 0x44cc44;

            /* Setup client counter for badge. */
            client_count_fmt = new TextFormat();
            client_count_fmt.color = 0xFFFFFF;
            client_count_fmt.align = "center";
            client_count_fmt.font = "courier-new";
            client_count_fmt.bold = true;
            client_count_fmt.size = 10;
            client_count_tf = new TextField();
            client_count_tf.width = 20;
            client_count_tf.height = 17;
            client_count_tf.background = false;
            client_count_tf.defaultTextFormat = client_count_fmt;
            client_count_tf.x=47;
            client_count_tf.y=3;

            /* Update the client counter on badge. */
            update_client_count();

            if (RATE_LIMIT)
                rate_limit = new BucketRateLimit(RATE_LIMIT * RATE_LIMIT_HISTORY, RATE_LIMIT_HISTORY);
            else
                rate_limit = new RateUnlimit();

            puts("Starting.");
            // Wait until the query string parameters are loaded.
            this.loaderInfo.addEventListener(Event.COMPLETE, loaderinfo_complete);
        }

        private function loaderinfo_complete(e:Event):void
        {
            var fac_spec:String;

            puts("Parameters loaded.");

            if (this.loaderInfo.parameters["debug"])
                addChild(output_text);
            else {
                addChild(new BadgeImage());
                /* Tried unsuccessfully to add counter to badge. */
                /* For now, need two addChilds :( */
                addChild(client_count_tf);
            }

            fac_spec = this.loaderInfo.parameters["facilitator"];
            if (fac_spec) {
                puts("Facilitator spec: \"" + fac_spec + "\"");
                fac_addr = parse_addr_spec(fac_spec);
                if (!fac_addr) {
                    puts("Error: Facilitator spec must be in the form \"host:port\".");
                    return;
                }
            } else {
                fac_addr = DEFAULT_FACILITATOR_ADDR;
            }

            main();
        }

        /* The main logic begins here, after start-up issues are taken care of. */
        private function main():void
        {
            if (num_proxy_pairs >= MAX_NUM_PROXY_PAIRS) {
                setTimeout(main, FACILITATOR_POLL_INTERVAL);
                return;
            }

            s_f = new Socket();

            s_f.addEventListener(Event.CONNECT, fac_connected);
            s_f.addEventListener(Event.CLOSE, function (e:Event):void {
                puts("Facilitator: closed connection.");
                setTimeout(main, FACILITATOR_POLL_INTERVAL);
            });
            s_f.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
                puts("Facilitator: I/O error: " + e.text + ".");
            });
            s_f.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
                puts("Facilitator: security error: " + e.text + ".");
            });

            puts("Facilitator: connecting to " + fac_addr.host + ":" + fac_addr.port + ".");
            s_f.connect(fac_addr.host, fac_addr.port);
        }

        private function fac_connected(e:Event):void
        {
            puts("Facilitator: connected.");

            s_f.addEventListener(ProgressEvent.SOCKET_DATA, fac_data);

            s_f.writeUTFBytes("GET / HTTP/1.0\r\n\r\n");
        }

        private function fac_data(e:ProgressEvent):void
        {
            var client_spec:String;
            var client_addr:Object;
            var proxy_pair:Object;

            client_spec = s_f.readMultiByte(e.bytesLoaded, "utf-8");
            puts("Facilitator: got \"" + client_spec + "\".");

            client_addr = parse_addr_spec(client_spec);
            if (!client_addr) {
                puts("Error: Client spec must be in the form \"host:port\".");
                return;
            }

            num_proxy_pairs++;
            total_proxy_pairs++;
            proxy_pair = new ProxyPair(this, client_addr, DEFAULT_TOR_ADDR);
            proxy_pair.addEventListener(Event.COMPLETE, function(e:Event):void {
                proxy_pair.log("Complete.");
                num_proxy_pairs--;
            });
            proxy_pair.connect();

            /* Update the client count on the badge. */
            update_client_count();
        }

        /* Parse an address in the form "host:port". Returns an Object with
           keys "host" (String) and "port" (int). Returns null on error. */
        private static function parse_addr_spec(spec:String):Object
        {
            var parts:Array;
            var addr:Object;

            parts = spec.split(":", 2);
            if (parts.length != 2 || !parseInt(parts[1]))
                return null;
            addr = {}
            addr.host = parts[0];
            addr.port = parseInt(parts[1]);

            return addr;
        }
    }
}

import flash.display.Sprite;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;
import flash.net.Socket;
import flash.utils.ByteArray;
import flash.utils.clearTimeout;
import flash.utils.getTimer;
import flash.utils.setTimeout;

class RateLimit
{
    public function RateLimit()
    {
    }

    public function update(n:Number):Boolean
    {
        return true;
    }

    public function when():Number
    {
        return 0.0;
    }

    public function is_limited():Boolean
    {
        return false;
    }
}

class RateUnlimit extends RateLimit
{
    public function RateUnlimit()
    {
    }

    public override function update(n:Number):Boolean
    {
        return true;
    }

    public override function when():Number
    {
        return 0.0;
    }

    public override function is_limited():Boolean
    {
        return false;
    }
}

class BucketRateLimit extends RateLimit
{
    private var amount:Number;
    private var capacity:Number;
    private var time:Number;
    private var last_update:uint;

    public function BucketRateLimit(capacity:Number, time:Number)
    {
        this.amount = 0.0;
        /* capacity / time is the rate we are aiming for. */
        this.capacity = capacity;
        this.time = time;
        this.last_update = getTimer();
    }

    private function age():void
    {
        var now:uint;
        var delta:Number;

        now = getTimer();
        delta = (now - last_update) / 1000.0;
        last_update = now;

        amount -= delta * capacity / time;
        if (amount < 0.0)
            amount = 0.0;
    }

    public override function update(n:Number):Boolean
    {
        age();
        amount += n;

        return amount <= capacity;
    }

    public override function when():Number
    {
        age();
        return (amount - capacity) / (capacity / time);
    }

    public override function is_limited():Boolean
    {
        age();
        return amount > capacity;
    }
}

/* An instance of a client-relay connection. */
class ProxyPair extends EventDispatcher
{
    // Address ({host, port}) of client.
    private var addr_c:Object;
    // Address ({host, port}) of relay.
    private var addr_r:Object;

    // Socket to client.
    private var s_c:Socket;
    // Socket to relay.
    private var s_r:Socket;

    // Parent swfcat, for UI updates and rate meter.
    private var ui:swfcat;

    // Pending byte read counts for relay and client sockets.
    private var r2c_schedule:Array;
    private var c2r_schedule:Array;
    // Callback id.
    private var flush_id:uint;

    public function log(msg:String):void
    {
        ui.puts(id() + ": " + msg)
    }

    // String describing this pair for output.
    public function id():String
    {
        return "<" + this.addr_c.host + ":" + this.addr_c.port +
            "," + this.addr_r.host + ":" + this.addr_r.port + ">";
    }

    public function ProxyPair(ui:swfcat, addr_c:Object, addr_r:Object)
    {
        this.ui = ui;
        this.addr_c = addr_c;
        this.addr_r = addr_r;

        this.c2r_schedule = [];
        this.r2c_schedule = [];
    }

    public function connect():void
    {
        s_r = new Socket();

        s_r.addEventListener(Event.CONNECT, tor_connected);
        s_r.addEventListener(Event.CLOSE, function (e:Event):void {
            log("Tor: closed.");
            if (s_c.connected)
                s_c.close();
            dispatchEvent(new Event(Event.COMPLETE));
        });
        s_r.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
            log("Tor: I/O error: " + e.text + ".");
            if (s_c.connected)
                s_c.close();
            dispatchEvent(new Event(Event.COMPLETE));
        });
        s_r.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
            log("Tor: security error: " + e.text + ".");
            if (s_c.connected)
                s_c.close();
            dispatchEvent(new Event(Event.COMPLETE));
        });
        s_r.addEventListener(ProgressEvent.SOCKET_DATA, relay_to_client);

        log("Tor: connecting to " + addr_r.host + ":" + addr_r.port + ".");
        s_r.connect(addr_r.host, addr_r.port);
    }

    private function tor_connected(e:Event):void
    {
        log("Tor: connected.");

        s_c = new Socket();

        s_c.addEventListener(Event.CONNECT, client_connected);
        s_c.addEventListener(Event.CLOSE, function (e:Event):void {
            log("Client: closed.");
            if (s_r.connected)
                s_r.close();
            dispatchEvent(new Event(Event.COMPLETE));
        });
        s_c.addEventListener(IOErrorEvent.IO_ERROR, function (e:IOErrorEvent):void {
            log("Client: I/O error: " + e.text + ".");
            if (s_r.connected)
                s_r.close();
            dispatchEvent(new Event(Event.COMPLETE));
        });
        s_c.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void {
            log("Client: security error: " + e.text + ".");
            if (s_r.connected)
                s_r.close();
            dispatchEvent(new Event(Event.COMPLETE));
        });
        s_c.addEventListener(ProgressEvent.SOCKET_DATA, client_to_relay);

        log("Client: connecting to " + addr_c.host + ":" + addr_c.port + ".");
        s_c.connect(addr_c.host, addr_c.port);
    }

    private function relay_to_client(e:ProgressEvent):void
    {
        r2c_schedule.push(e.bytesLoaded);
        flush();
    }

    private function client_to_relay(e:ProgressEvent):void
    {
        c2r_schedule.push(e.bytesLoaded);
        flush();
    }

    private function client_connected(e:Event):void
    {
        log("Client: connected.");
    }

    private function transfer_chunk(s_from:Socket, s_to:Socket, n:uint,
        label:String):void
    {
        var bytes:ByteArray;

        bytes = new ByteArray();
        s_from.readBytes(bytes, 0, n);
        s_to.writeBytes(bytes);
        ui.rate_limit.update(n);
        log(label + ": read " + bytes.length + ".");
    }

    /* Send as much data as the rate limit currently allows. */
    private function flush():void
    {
        if (flush_id)
            clearTimeout(flush_id);
        flush_id = undefined;

        if (!(s_r.connected && s_c.connected))
            /* Can't do anything until both sockets are connected. */
            return;

        while (!ui.rate_limit.is_limited() &&
               (r2c_schedule.length > 0 || c2r_schedule.length > 0)) {
            if (r2c_schedule.length > 0)
                transfer_chunk(s_r, s_c, r2c_schedule.shift(), "Tor");
            if (c2r_schedule.length > 0)
                transfer_chunk(s_c, s_r, c2r_schedule.shift(), "Client");
        }

        /* Call again when safe, if necessary. */
        if (r2c_schedule.length > 0 || c2r_schedule.length > 0)
            flush_id = setTimeout(flush, ui.rate_limit.when() * 1000);
    }
}

Disable the bandwidth limit.

Disable the bandwidth limit.


package com.mangui.HLS.muxing {

    import com.mangui.HLS.muxing.*;
    import com.mangui.HLS.utils.*;
    import flash.utils.ByteArray;

    /** Representation of a Packetized Elementary Stream. **/
    public class PES {

        /** Timescale of pts/dts is 90khz. **/
        public static var TIMESCALE:Number = 90;

        /** Is it AAC audio or AVC video. **/
        public var audio:Boolean;
        /** The PES data (including headers). **/
        public var data:ByteArray;
        /** Start of the payload. **/
        public var payload:Number;
        /** Timestamp from the PTS header. **/
        public var pts:Number;
        /** Timestamp from the DTS header. **/
        public var dts:Number;

        /** Save the first chunk of PES data. **/
        public function PES(dat:ByteArray,aud:Boolean) {
            data = dat;
            audio = aud;
        };

        /** Append PES data from additional TS packets. **/
        public function append(dat:ByteArray):void {
            data.writeBytes(dat,0,0);
        };

        /** When all data is appended, parse the PES headers. **/
        public function parse():void {
            data.position = 0;
            // Start code prefix and packet ID.
            var prefix:Number = data.readUnsignedInt();
            if((audio && (prefix > 448 || prefix < 445)) ||
                (!audio && prefix != 480 && prefix != 490)) {
                throw new Error("PES start code not found or not AAC/AVC: " + prefix);
            }
            // Ignore packet length and marker bits.
            data.position += 3;
            // Check for PTS
            var flags:uint = (data.readUnsignedByte() & 192) >> 6;
            if(flags != 2 && flags != 3) {
                throw new Error("No PTS/DTS in this PES packet");
            }
            // Check PES header length
            var length:uint = data.readUnsignedByte();
            // Grab the timestamp from PTS data (spread out over 5 bytes):
            // XXXX---X -------- -------X -------- -------X
            var _pts:uint = ((data.readUnsignedByte() & 14) << 29) +
                ((data.readUnsignedShort() & 65534) << 14) +
                ((data.readUnsignedShort() & 65534) >> 1);
            length -= 5;
            var _dts:uint = _pts;
            if(flags == 3) {
                // Grab the DTS (like PTS)
                _dts = ((data.readUnsignedByte() & 14) << 29) +
                    ((data.readUnsignedShort() & 65534) << 14) +
                    ((data.readUnsignedShort() & 65534) >> 1);
                length -= 5;
            }
            pts = Math.round(_pts / PES.TIMESCALE);
            dts = Math.round(_dts / PES.TIMESCALE);
            // Skip other header data and parse payload.
            data.position += length;
            payload = data.position;
        };

    }

}

package com.mangui.HLS.muxing {

    import com.mangui.HLS.muxing.*;
    import com.mangui.HLS.utils.*;
    import flash.utils.ByteArray;

    /** Representation of a Packetized Elementary Stream. **/
    public class PES {

        /** Timescale of pts/dts is 90khz. **/
        public static var TIMESCALE:Number = 90;

        /** Is it AAC audio or AVC video. **/
        public var audio:Boolean;
        /** The PES data (including headers). **/
        public var data:ByteArray;
        /** Start of the payload. **/
        public var payload:Number;
        /** Timestamp from the PTS header. **/
        public var pts:Number;
        /** Timestamp from the DTS header. **/
        public var dts:Number;

        /** Save the first chunk of PES data. **/
        public function PES(dat:ByteArray,aud:Boolean) {
            data = dat;
            audio = aud;
        };

        /** Append PES data from additional TS packets. **/
        public function append(dat:ByteArray):void {
            data.writeBytes(dat,0,0);
        };

        /** When all data is appended, parse the PES headers. **/
        public function parse():void {
            data.position = 0;
            // Start code prefix and packet ID.
            var prefix:Number = data.readUnsignedInt();
            if((audio && (prefix > 448 || prefix < 445)) ||
                (!audio && prefix != 480 && prefix != 490)) {
                throw new Error("PES start code not found or not AAC/AVC: " + prefix);
            }
            // Ignore packet length and marker bits.
            data.position += 3;
            // Check for PTS
            var flags:uint = (data.readUnsignedByte() & 192) >> 6;
            if(flags != 2 && flags != 3) {
                throw new Error("No PTS/DTS in this PES packet");
            }
            // Check PES header length
            var length:uint = data.readUnsignedByte();
            // Grab the timestamp from PTS data (spread out over 5 bytes):
            // XXXX---X -------- -------X -------- -------X

            var _pts:Number = ((data.readUnsignedByte() & 0x0e) << 29) +
                ((data.readUnsignedShort() >> 1) << 15) +
                 (data.readUnsignedShort() >> 1);
            length -= 5;
            var _dts:Number = _pts;
            if(flags == 3) {
                // Grab the DTS (like PTS)
                _dts = ((data.readUnsignedByte() & 0x0e) << 29) +
                ((data.readUnsignedShort() >> 1) << 15) +
                 (data.readUnsignedShort() >> 1);
                length -= 5;
            }
            pts = Math.round(_pts / PES.TIMESCALE);
            dts = Math.round(_dts / PES.TIMESCALE);
            // Skip other header data and parse payload.
            data.position += length;
            payload = data.position;
        };

    }

}

fix PTS/DTS parsing, allow negative values