// vim: tabstop=4 shiftwidth=4

// Copyright (c) 2010 , NetEase.com,Inc. All rights reserved.
// Copyright (c) 2012 , Yang Bo. All rights reserved.
//
// Author: Yang Bo (pop.atry@gmail.com)
//
// Use, modification and distribution are subject to the "New BSD License"
// as listed at <url: http://www.opensource.org/licenses/bsd-license.php >.

package com.netease.protobuf {
	import flash.errors.*
	import flash.utils.*
	/**
	 * @private
	 */
	public final class ReadUtils {
		public static function skip(input:IDataInput, wireType:uint):void {
			switch (wireType) {
			case WireType.VARINT:
				while (input.readUnsignedByte() > 0x80) {}
				break
			case WireType.FIXED_64_BIT:
				input.readInt()
				input.readInt()
				break
			case WireType.LENGTH_DELIMITED:
				for (var i:uint = read$TYPE_UINT32(input); i != 0; i--) {
					input.readByte()
				}
				break
			case WireType.FIXED_32_BIT:
				input.readInt()
				break
			default:
				throw new IOError("Invalid wire type: " + wireType)
			}
		}
		public static function read$TYPE_DOUBLE(input:IDataInput):Number {
			return input.readDouble()
		}
		public static function read$TYPE_FLOAT(input:IDataInput):Number {
			return input.readFloat()
		}
		public static function read$TYPE_INT64(input:IDataInput):Int64 {
			const result:Int64 = new Int64
			var b:uint
			var i:uint = 0
			for (;; i += 7) {
				b = input.readUnsignedByte()
				if (i == 28) {
					break
				} else {
					if (b >= 0x80) {
						result.low |= ((b & 0x7f) << i)
					} else {
						result.low |= (b << i)
						return result
					}
				}
			}
			if (b >= 0x80) {
				b &= 0x7f
				result.low |= (b << i)
				result.high = b >>> 4
			} else {
				result.low |= (b << i)
				result.high = b >>> 4
				return result
			}
			for (i = 3;; i += 7) {
				b = input.readUnsignedByte()
				if (i < 32) {
					if (b >= 0x80) {
						result.high |= ((b & 0x7f) << i)
					} else {
						result.high |= (b << i)
						break
					}
				}
			}
			return result
		}
		public static function read$TYPE_UINT64(input:IDataInput):UInt64 {
			const result:UInt64 = new UInt64
			var b:uint
			var i:uint = 0
			for (;; i += 7) {
				b = input.readUnsignedByte()
				if (i == 28) {
					break
				} else {
					if (b >= 0x80) {
						result.low |= ((b & 0x7f) << i)
					} else {
						result.low |= (b << i)
						return result
					}
				}
			}
			if (b >= 0x80) {
				b &= 0x7f
				result.low |= (b << i)
				result.high = b >>> 4
			} else {
				result.low |= (b << i)
				result.high = b >>> 4
				return result
			}
			for (i = 3;; i += 7) {
				b = input.readUnsignedByte()
				if (i < 32) {
					if (b >= 0x80) {
						result.high |= ((b & 0x7f) << i)
					} else {
						result.high |= (b << i)
						break
					}
				}
			}
			return result
		}
		public static function read$TYPE_INT32(input:IDataInput):int {
			return int(read$TYPE_UINT32(input))
		}
		public static function read$TYPE_FIXED64(input:IDataInput):UInt64 {
			const result:UInt64 = new UInt64
			result.low = input.readUnsignedInt()
			result.high = input.readUnsignedInt()
			return result
		}
		public static function read$TYPE_FIXED32(input:IDataInput):uint {
			return input.readUnsignedInt()
		}
		public static function read$TYPE_BOOL(input:IDataInput):Boolean {
			return read$TYPE_UINT32(input) != 0
		}
		public static function read$TYPE_STRING(input:IDataInput):String {
			const length:uint = read$TYPE_UINT32(input)
			return input.readUTFBytes(length)
		}
		public static function read$TYPE_BYTES(input:IDataInput):ByteArray {
			const result:ByteArray = new ByteArray
			const length:uint = read$TYPE_UINT32(input)
			if (length > 0) {
				input.readBytes(result, 0, length)
			}
			return result
		}
		public static function read$TYPE_UINT32(input:IDataInput):uint {
			var result:uint = 0
			for (var i:uint = 0;; i += 7) {
				const b:uint = input.readUnsignedByte()
				if (i < 32) {
					if (b >= 0x80) {
						result |= ((b & 0x7f) << i)
					} else {
						result |= (b << i)
						break
					}
				} else {
					while (input.readUnsignedByte() >= 0x80) {}
					break
				}
			}
			return result
		}
		public static function read$TYPE_ENUM(input:IDataInput):int {
			return read$TYPE_INT32(input)
		}
		public static function read$TYPE_SFIXED32(input:IDataInput):int {
			return input.readInt()
		}
		public static function read$TYPE_SFIXED64(input:IDataInput):Int64 {
			const result:Int64 = new Int64
			result.low = input.readUnsignedInt()
			result.high = input.readInt()
			return result
		}
		public static function read$TYPE_SINT32(input:IDataInput):int {
			return ZigZag.decode32(read$TYPE_UINT32(input))
		}
		public static function read$TYPE_SINT64(input:IDataInput):Int64 {
			const result:Int64 = read$TYPE_INT64(input)
			const low:uint = result.low
			const high:uint = result.high
			result.low = ZigZag.decode64low(low, high)
			result.high = ZigZag.decode64high(low, high)
			return result
		}
		public static function read$TYPE_MESSAGE(input:IDataInput,
				message:Message):Message {
			const length:uint = read$TYPE_UINT32(input)
			if (input.bytesAvailable < length) {
				throw new IOError("Invalid message length: " + length)
			}
			const bytesAfterSlice:uint = input.bytesAvailable - length
			message.used_by_generated_code::readFromSlice(input, bytesAfterSlice)
			if (input.bytesAvailable != bytesAfterSlice) {
				throw new IOError("Invalid nested message")
			}
			return message
		}
		public static function readPackedRepeated(input:IDataInput,
				readFuntion:Function, value:Array):void {
			const length:uint = read$TYPE_UINT32(input)
			if (input.bytesAvailable < length) {
				throw new IOError("Invalid message length: " + length)
			}
			const bytesAfterSlice:uint = input.bytesAvailable - length
			while (input.bytesAvailable > bytesAfterSlice) {
				value.push(readFuntion(input))
			}
			if (input.bytesAvailable != bytesAfterSlice) {
				throw new IOError("Invalid packed repeated data")
			}
		}
	}
}

// vim: tabstop=4 shiftwidth=4

// Copyright (c) 2010 , NetEase.com,Inc. All rights reserved.
// Copyright (c) 2012 , Yang Bo. All rights reserved.
//
// Author: Yang Bo (pop.atry@gmail.com)
//
// Use, modification and distribution are subject to the "New BSD License"
// as listed at <url: http://www.opensource.org/licenses/bsd-license.php >.

package com.netease.protobuf {
	import flash.errors.*
	import flash.utils.*
	/**
	 * @private
	 */
	public final class ReadUtils {
		public static function skip(input:IDataInput, wireType:uint):void {
			switch (wireType) {
			case WireType.VARINT:
				while (input.readUnsignedByte() >= 0x80) {}
				break
			case WireType.FIXED_64_BIT:
				input.readInt()
				input.readInt()
				break
			case WireType.LENGTH_DELIMITED:
				for (var i:uint = read$TYPE_UINT32(input); i != 0; i--) {
					input.readByte()
				}
				break
			case WireType.FIXED_32_BIT:
				input.readInt()
				break
			default:
				throw new IOError("Invalid wire type: " + wireType)
			}
		}
		public static function read$TYPE_DOUBLE(input:IDataInput):Number {
			return input.readDouble()
		}
		public static function read$TYPE_FLOAT(input:IDataInput):Number {
			return input.readFloat()
		}
		public static function read$TYPE_INT64(input:IDataInput):Int64 {
			const result:Int64 = new Int64
			var b:uint
			var i:uint = 0
			for (;; i += 7) {
				b = input.readUnsignedByte()
				if (i == 28) {
					break
				} else {
					if (b >= 0x80) {
						result.low |= ((b & 0x7f) << i)
					} else {
						result.low |= (b << i)
						return result
					}
				}
			}
			if (b >= 0x80) {
				b &= 0x7f
				result.low |= (b << i)
				result.high = b >>> 4
			} else {
				result.low |= (b << i)
				result.high = b >>> 4
				return result
			}
			for (i = 3;; i += 7) {
				b = input.readUnsignedByte()
				if (i < 32) {
					if (b >= 0x80) {
						result.high |= ((b & 0x7f) << i)
					} else {
						result.high |= (b << i)
						break
					}
				}
			}
			return result
		}
		public static function read$TYPE_UINT64(input:IDataInput):UInt64 {
			const result:UInt64 = new UInt64
			var b:uint
			var i:uint = 0
			for (;; i += 7) {
				b = input.readUnsignedByte()
				if (i == 28) {
					break
				} else {
					if (b >= 0x80) {
						result.low |= ((b & 0x7f) << i)
					} else {
						result.low |= (b << i)
						return result
					}
				}
			}
			if (b >= 0x80) {
				b &= 0x7f
				result.low |= (b << i)
				result.high = b >>> 4
			} else {
				result.low |= (b << i)
				result.high = b >>> 4
				return result
			}
			for (i = 3;; i += 7) {
				b = input.readUnsignedByte()
				if (i < 32) {
					if (b >= 0x80) {
						result.high |= ((b & 0x7f) << i)
					} else {
						result.high |= (b << i)
						break
					}
				}
			}
			return result
		}
		public static function read$TYPE_INT32(input:IDataInput):int {
			return int(read$TYPE_UINT32(input))
		}
		public static function read$TYPE_FIXED64(input:IDataInput):UInt64 {
			const result:UInt64 = new UInt64
			result.low = input.readUnsignedInt()
			result.high = input.readUnsignedInt()
			return result
		}
		public static function read$TYPE_FIXED32(input:IDataInput):uint {
			return input.readUnsignedInt()
		}
		public static function read$TYPE_BOOL(input:IDataInput):Boolean {
			return read$TYPE_UINT32(input) != 0
		}
		public static function read$TYPE_STRING(input:IDataInput):String {
			const length:uint = read$TYPE_UINT32(input)
			return input.readUTFBytes(length)
		}
		public static function read$TYPE_BYTES(input:IDataInput):ByteArray {
			const result:ByteArray = new ByteArray
			const length:uint = read$TYPE_UINT32(input)
			if (length > 0) {
				input.readBytes(result, 0, length)
			}
			return result
		}
		public static function read$TYPE_UINT32(input:IDataInput):uint {
			var result:uint = 0
			for (var i:uint = 0;; i += 7) {
				const b:uint = input.readUnsignedByte()
				if (i < 32) {
					if (b >= 0x80) {
						result |= ((b & 0x7f) << i)
					} else {
						result |= (b << i)
						break
					}
				} else {
					while (input.readUnsignedByte() >= 0x80) {}
					break
				}
			}
			return result
		}
		public static function read$TYPE_ENUM(input:IDataInput):int {
			return read$TYPE_INT32(input)
		}
		public static function read$TYPE_SFIXED32(input:IDataInput):int {
			return input.readInt()
		}
		public static function read$TYPE_SFIXED64(input:IDataInput):Int64 {
			const result:Int64 = new Int64
			result.low = input.readUnsignedInt()
			result.high = input.readInt()
			return result
		}
		public static function read$TYPE_SINT32(input:IDataInput):int {
			return ZigZag.decode32(read$TYPE_UINT32(input))
		}
		public static function read$TYPE_SINT64(input:IDataInput):Int64 {
			const result:Int64 = read$TYPE_INT64(input)
			const low:uint = result.low
			const high:uint = result.high
			result.low = ZigZag.decode64low(low, high)
			result.high = ZigZag.decode64high(low, high)
			return result
		}
		public static function read$TYPE_MESSAGE(input:IDataInput,
				message:Message):Message {
			const length:uint = read$TYPE_UINT32(input)
			if (input.bytesAvailable < length) {
				throw new IOError("Invalid message length: " + length)
			}
			const bytesAfterSlice:uint = input.bytesAvailable - length
			message.used_by_generated_code::readFromSlice(input, bytesAfterSlice)
			if (input.bytesAvailable != bytesAfterSlice) {
				throw new IOError("Invalid nested message")
			}
			return message
		}
		public static function readPackedRepeated(input:IDataInput,
				readFuntion:Function, value:Array):void {
			const length:uint = read$TYPE_UINT32(input)
			if (input.bytesAvailable < length) {
				throw new IOError("Invalid message length: " + length)
			}
			const bytesAfterSlice:uint = input.bytesAvailable - length
			while (input.bytesAvailable > bytesAfterSlice) {
				value.push(readFuntion(input))
			}
			if (input.bytesAvailable != bytesAfterSlice) {
				throw new IOError("Invalid packed repeated data")
			}
		}
	}
}

Fix #35

Fix #35


/*
# Copyright (c) 2008-2010 rPath, Inc.
#
# This program is distributed under the terms of the MIT License as found
# in a file called LICENSE. If it is not present, the license
# is always available at http://www.opensource.org/licenses/mit-license.php.
#
# This program is distributed in the hope that it will be useful, but
# without any warranty; without even the implied warranty of merchantability
# or fitness for a particular purpose. See the MIT License for full details.
#
*/

package com.rpath.xobj
{

[RemoteClass]
[Bindable]
public class FilterTerm
{
    public function FilterTerm(field:String,
                               value:String,
                               operator:String = EQUAL)
    {
        super();

        this.field = field;
        this.operator = operator;
        this.value = value;
    }

    /**
     * The field/property to filter on (LHS)
     */
    public var field:String;

    /**
     * The logical operator to apply (see static consts below)
     */
    public var operator:String;

    /**
     * The value to test the field against (RHS)
     */
    public var value:String;

    public static const EQUAL:String = "EQUAL";
    public static const NOT_EQUAL:String = "NOT_EQUAL";

    public static const IS_NULL:String = "IS_NULL";
    public static const IS_NOT_NULL:String = "IS_NOT_NULL";

    public static const LESS_THAN:String = "LESS_THAN";
    public static const LESS_THAN_OR_EQUAL:String = "LESS_THAN_OR_EQUAL";
    public static const GREATER_THAN:String = "GREATER_THAN";
    public static const GREATER_THAN_OR_EQUAL:String = "GREATER_THAN_OR_EQUAL";
    public static const LIKE:String = "LIKE";
    public static const NOT_LIKE:String = "NOT_LIKE";
    public static const IN:String = "IN";
    public static const NOT_IN:String = "NOT_IN";
    public static const MATCHING:String = "MATCHING";
    public static const NOT_MATCHING:String = "NOT_MATCHING";

    public static const YES:String = "YES";
    public static const NO:String = "NO";

}
}

/*
# Copyright (c) 2008-2010 rPath, Inc.
#
# This program is distributed under the terms of the MIT License as found
# in a file called LICENSE. If it is not present, the license
# is always available at http://www.opensource.org/licenses/mit-license.php.
#
# This program is distributed in the hope that it will be useful, but
# without any warranty; without even the implied warranty of merchantability
# or fitness for a particular purpose. See the MIT License for full details.
#
*/

package com.rpath.xobj
{

[RemoteClass]
[Bindable]
public class FilterTerm
{
    public function FilterTerm(field:String,
                               value:String,
                               operator:String = EQUAL)
    {
        super();

        this.field = field;
        this.operator = operator;
        this.value = value;
    }

    /**
     * The field/property to filter on (LHS)
     */
    public var field:String;

    /**
     * The logical operator to apply (see static consts below)
     */
    public var operator:String;

    /**
     * The value to test the field against (RHS)
     */
    public var value:String;

    public static const EQUAL:String = "EQUAL";
    public static const NOT_EQUAL:String = "NOT_EQUAL";

    public static const IS_NULL:String = "IS_NULL";
    public static const IS_NOT_NULL:String = "IS_NOT_NULL";

    public static const LESS_THAN:String = "LESS_THAN";
    public static const LESS_THAN_OR_EQUAL:String = "LESS_THAN_OR_EQUAL";
    public static const GREATER_THAN:String = "GREATER_THAN";
    public static const GREATER_THAN_OR_EQUAL:String = "GREATER_THAN_OR_EQUAL";
    public static const LIKE:String = "LIKE";
    public static const NOT_LIKE:String = "NOT_LIKE";
    public static const IN:String = "IN";
    public static const NOT_IN:String = "NOT_IN";
/*  NOT YET IMPLEMENTED
    public static const MATCHING:String = "MATCHING";
    public static const NOT_MATCHING:String = "NOT_MATCHING";
*/
    public static const YES:String = "YES";
    public static const NO:String = "NO";

}
}

Remove MATCHING operator for now per RBL-8583


package com.benoitfreslon.layoutmanager {

	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.system.Capabilities;
	import flash.utils.getDefinitionByName;

	import starling.display.Button;
	import starling.display.ButtonExtended;
	import starling.display.DisplayObject;
	import starling.display.DisplayObjectContainer;
	import starling.display.Image;
	import starling.display.Quad;
	import starling.display.Sprite;
	import starling.text.TextField;
	import starling.textures.Texture;
	import starling.utils.AssetManager;

	/**
	 * Loader of Layout
	 * @version 1.04
	 * @author Benoît Freslon
	 */
	public class LayoutLoader {
		private var _movieclip : MovieClip;
		private var _displayObject : DisplayObjectContainer;
		private var _rootObject : DisplayObjectContainer;
		private var _assetManager : AssetManager;
		static public var debug : Boolean = false;
		private var onLoad : Function = function() : void {

		};

		/**
		 * Loader of Layout class.
		 */
		public function LayoutLoader() {
			super();
			debug = Capabilities.isDebugger
		}

		/**
		 * Load a layout from a MovieClip added in ActionScript.
		 * Embed a SWC file with all your layouts in your ActionScript 3.0 project and use this lib to load and display your layouts.
		 *
		 * @param	displayObject The starling.display.DisplayObject where the layout should be displayed
		 * @param	LayoutClass	The layout class Embed in the SWC file.
		 * @param	assetManager The AssetManager instance where all assets are loaded.
		 * @param	callBack The callback function when the layout is loaded and displayed.
		 */
		public function loadLayout( rootObject : DisplayObjectContainer , LayoutClass : Class , assetManager : AssetManager , callBack : Function = null ) : void {

			if ( debug )
				trace( "LayoutLoader: loadLayout" , rootObject , LayoutClass , assetManager , callBack );

			_rootObject = rootObject;
			_displayObject = rootObject;
			_assetManager = assetManager;
			_movieclip = new LayoutClass();
			_movieclip.addEventListener( Event.ENTER_FRAME , layoutLoaded );
			if ( onLoad != null )
				onLoad = callBack
		}

		public function loadLayoutIn( rootObject : DisplayObjectContainer , displayObject : DisplayObjectContainer , LayoutClass : Class , assetManager : AssetManager , callBack : Function = null ) : void {
			if ( debug )
				trace( "LayoutLoader: loadLayoutIn" , rootObject , displayObject , LayoutClass , assetManager , callBack );

			_rootObject = rootObject
			_displayObject = displayObject;
			_assetManager = assetManager;
			_movieclip = new LayoutClass();
			_movieclip.addEventListener( Event.ENTER_FRAME , layoutLoaded );
			if ( onLoad != null )
				onLoad = callBack
		}

		private function layoutLoaded( e : Event ) : void {

			if ( debug )
				trace( "LayoutLoader: layoutLoaded" );

			_movieclip.removeEventListener( Event.ENTER_FRAME , layoutLoaded );
			parseMovieClip( _movieclip , _rootObject , _displayObject );
			loaded();
		}

		private function parseMovieClip( mc : MovieClip , root : DisplayObjectContainer , container : DisplayObjectContainer ) : void {
			var child : BFObject;
			var n : int = mc.numChildren;
			for ( var i : uint = 0 ; i < n ; ++i ) {
				child = mc.getChildAt( i ) as BFObject;
				if ( child ) {

					if ( child.mainClass ) {

						var a : Array = [ ButtonExtended ];

						var objectClass : Class;
						if (debug) trace(child.className);
						if ( child.className ) {
							objectClass = getDefinitionByName( child.className ) as Class;
						} else {
							objectClass = getDefinitionByName( child.mainClass ) as Class;
						}

						var obj : DisplayObject;
						if ( child.mainClass == "starling.display.Image" ) {
							obj = addImage( objectClass , child as BFImage );
						} else if ( child.mainClass == "starling.display.ButtonExtended" ) {
							obj = addButton( objectClass , child as BFButton );
						} else if ( child.mainClass == "starling.text.TextField" ) {
							obj = addTextField( objectClass , child as BFTextField );
						} else if ( child.mainClass == "starling.display.Sprite" ) {
							obj = addSprite( objectClass , child as BFSprite );
						} else {
							throw new Error( "No mainClass defined in '" + child + "'" );
						}

						if ( child.hasOwnProperty( "params" ) ) {
							for ( var metatags : String in child.params ) {
								if ( obj.hasOwnProperty( metatags ) )
									obj[ metatags ] = child.params[ metatags ];
							}
						}
						obj.name = child.name;

						obj.x = int( child.x );
						obj.y = int( child.y );
						//obj.scaleX = child.scaleX;
						//obj.scaleY = child.scaleY;
						if ( child.flipX ) {
							obj.scaleX = -1;
						}
						if ( child.flipY ) {
							obj.scaleY = -1;
						}
						obj.alpha = child.alpha;
						obj.rotation = child.rotation;
						obj.visible = child.isVisible;

						container.addChild( obj );

						if ( obj.hasOwnProperty( "tag" ) ) {
							obj[ "tag" ] = child.tag;
						}
						if ( obj.hasOwnProperty( "userData" ) ) {
							obj[ "userData" ] = child.userData;
						}
						if ( _rootObject.hasOwnProperty( child.name ) ) {
							_rootObject[ child.name ] = obj as objectClass;
						} else if ( child.name.split( "__id" ).length == 1 && child.name.split( "instance" ).length == 1 ) {
							throw new Error( "No public property '" + child.name + "' declared in " + _rootObject );
						}
					} else {

							//trace( new Error( "No className defined " + child ) );
					}
				}
			}
		}

		private function loaded() : void {
			_assetManager = null;
			_displayObject = null;
			_movieclip = null;
			_rootObject = null;
			onLoad();
		}

		private function addImage( objectClass : Class , child : BFImage ) : Image {
			var tex : Texture = getTexture( child , child.texture , child.width , child.height )
			var img : Image = new objectClass( tex ) as Image;
			img.pivotX = int( img.width * child.pivotX );
			img.pivotY = int( img.height * child.pivotY );
			return img;
		}

		private function addSprite( objectClass : Class , child : BFSprite ) : Sprite {
			var s : Sprite = new objectClass() as Sprite;
			parseMovieClip( child as MovieClip , s as DisplayObjectContainer , s as DisplayObjectContainer );
			return s;
		}

		private function addTextField( objectClass : Class , child : BFTextField ) : TextField {
			var t : TextField = new objectClass( child.width , child.height , "" ) as TextField;
			t.autoSize = child.autoSize;
			t.fontName = child.fontName;
			t.fontSize = child.fontSize;
			t.color = child.color;
			t.hAlign = child.hAlign;
			t.vAlign = child.vAlign;
			t.bold = child.bold;
			t.italic = child.italic;
			t.border = child.border;
			t.underline = child.underline;
			t.pivotX = int( t.width * child.pivotX );
			t.pivotY = int( t.height * child.pivotY );
			var text : String = child.text;
			text = text.replace( "\\r" , "\r" );
			text = text.replace( "\\n" , "\n" );
			text = text.replace( "\\t" , "\t" );
			t.text = text;
			t.width = child.width;
			t.height = child.height;
			return t;
		}

		// TODO Parse BFButton and addChild objects inside Button
		private function addButton( objectClass : Class , child : BFButton ) : Button {
			var bt : Button = new objectClass( getTexture( child , child.upState , child.width , child.height ) ) as Button;
			bt.fontBold = child.bold;
			bt.fontColor = child.color;
			bt.fontName = child.fontName;
			bt.fontSize = child.fontSize;
			bt.alphaWhenDisabled = child.alphaWhenDisabled;
			bt.scaleWhenDown = child.scaleWhenDown;
			bt.text = child.text;
			bt.pivotX = int( bt.width * child.pivotX );
			bt.pivotY = int( bt.height * child.pivotY );

			if ( child.downState )
				bt.downState = _assetManager.getTexture( child.downState );

			if ( bt.hasOwnProperty( "overState" ) && child.overState )
				bt[ "overState" ] = _assetManager.getTexture( child.overState );

			if ( bt.hasOwnProperty( "onTouch" ) && _rootObject.hasOwnProperty( child.onTouch ) ) {
				bt[ "onTouch" ] = _rootObject[ child.onTouch ];
			} else if ( bt.hasOwnProperty( "onTouch" ) && child.onTouch != "" && !_rootObject.hasOwnProperty( child.onTouch ) ) {
				throw new Error( "The public method '" + child.onTouch + "' is not defined in " + _rootObject ) ;
			}
			return bt;
		}

		private function getTexture( child : BFObject , textureName : String , w : Number , h : Number ) : Texture {
			if ( textureName == "" ) {
				//trace( new Error( "No texture defined in '" + child + " - name: "+child.name+"' in "+_displayObject+". Default texture used." ) );
				return Texture.empty( w , h );
			} else {
				var tex : Texture = _assetManager.getTexture( textureName );
				if ( tex == null ) {
					trace( new Error( "Texture '" + textureName + "' defined in '" + child + " - name: " + child.name + "' in " + _displayObject + " doesn't exist. Default texture used." ));
					return Texture.empty( w , h );
				}
				return tex;
			}
		}
	}

}

package com.benoitfreslon.layoutmanager {

	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.system.Capabilities;
	import flash.utils.getDefinitionByName;

	import starling.display.Button;
	import starling.display.ButtonExtended;
	import starling.display.DisplayObject;
	import starling.display.DisplayObjectContainer;
	import starling.display.Image;
	import starling.display.Quad;
	import starling.display.Sprite;
	import starling.text.TextField;
	import starling.textures.Texture;
	import starling.utils.AssetManager;

	/**
	 * Loader of Layout
	 * @version 1.04
	 * @author Benoît Freslon
	 */
	public class LayoutLoader {
		private var _movieclip : MovieClip;
		private var _displayObject : DisplayObjectContainer;
		private var _rootObject : DisplayObjectContainer;
		private var _assetManager : AssetManager;
		static public var debug : Boolean = false;
		private var onLoad : Function = function() : void {

		};

		/**
		 * Loader of Layout class.
		 */
		public function LayoutLoader() {
			super();
			debug = Capabilities.isDebugger
		}

		/**
		 * Load a layout from a MovieClip added in ActionScript.
		 * Embed a SWC file with all your layouts in your ActionScript 3.0 project and use this lib to load and display your layouts.
		 *
		 * @param	displayObject The starling.display.DisplayObject where the layout should be displayed
		 * @param	LayoutClass	The layout class Embed in the SWC file.
		 * @param	assetManager The AssetManager instance where all assets are loaded.
		 * @param	callBack The callback function when the layout is loaded and displayed.
		 */
		public function loadLayout( rootObject : DisplayObjectContainer , LayoutClass : Class , assetManager : AssetManager , callBack : Function = null ) : void {

			if ( debug )
				trace( "LayoutLoader: loadLayout" , rootObject , LayoutClass , assetManager , callBack );

			_rootObject = rootObject;
			_displayObject = rootObject;
			_assetManager = assetManager;
			_movieclip = new LayoutClass();
			_movieclip.addEventListener( Event.ENTER_FRAME , layoutLoaded );
			if ( onLoad != null )
				onLoad = callBack
		}

		public function loadLayoutIn( rootObject : DisplayObjectContainer , displayObject : DisplayObjectContainer , LayoutClass : Class , assetManager : AssetManager , callBack : Function = null ) : void {
			if ( debug )
				trace( "LayoutLoader: loadLayoutIn" , rootObject , displayObject , LayoutClass , assetManager , callBack );

			_rootObject = rootObject
			_displayObject = displayObject;
			_assetManager = assetManager;
			_movieclip = new LayoutClass();
			_movieclip.addEventListener( Event.ENTER_FRAME , layoutLoaded );
			if ( onLoad != null )
				onLoad = callBack
		}

		private function layoutLoaded( e : Event ) : void {

			if ( debug )
				trace( "LayoutLoader: layoutLoaded" );

			_movieclip.removeEventListener( Event.ENTER_FRAME , layoutLoaded );
			parseMovieClip( _movieclip , _rootObject , _displayObject );
			loaded();
		}

		private function parseMovieClip( mc : MovieClip , root : DisplayObjectContainer , container : DisplayObjectContainer ) : void {
			var child : BFObject;
			var n : int = mc.numChildren;
			for ( var i : uint = 0 ; i < n ; ++i ) {
				child = mc.getChildAt( i ) as BFObject;
				if ( child ) {

					if ( child.mainClass ) {

						var a : Array = [ ButtonExtended ];

						var objectClass : Class;
						if (debug) trace("LayoutLoader: child.className",child.className);
						if ( child.className ) {
							objectClass = getDefinitionByName( child.className ) as Class;
						} else {
							objectClass = getDefinitionByName( child.mainClass ) as Class;
						}

						var obj : DisplayObject;
						if ( child.mainClass == "starling.display.Image" ) {
							obj = addImage( objectClass , child as BFImage );
						} else if ( child.mainClass == "starling.display.ButtonExtended" ) {
							obj = addButton( objectClass , child as BFButton );
						} else if ( child.mainClass == "starling.text.TextField" ) {
							obj = addTextField( objectClass , child as BFTextField );
						} else if ( child.mainClass == "starling.display.Sprite" ) {
							obj = addSprite( objectClass , child as BFSprite );
						} else {
							throw new Error( "No mainClass defined in '" + child + "'" );
						}

						if ( child.hasOwnProperty( "params" ) ) {
							for ( var metatags : String in child.params ) {
								if ( obj.hasOwnProperty( metatags ) )
									obj[ metatags ] = child.params[ metatags ];
							}
						}
						obj.name = child.name;

						obj.x = int( child.x );
						obj.y = int( child.y );
						//obj.scaleX = child.scaleX;
						//obj.scaleY = child.scaleY;
						if ( child.flipX ) {
							obj.scaleX = -1;
						}
						if ( child.flipY ) {
							obj.scaleY = -1;
						}
						obj.alpha = child.alpha;
						obj.rotation = child.rotation;
						obj.visible = child.isVisible;

						container.addChild( obj );

						if ( obj.hasOwnProperty( "tag" ) ) {
							obj[ "tag" ] = child.tag;
						}
						if ( obj.hasOwnProperty( "userData" ) ) {
							obj[ "userData" ] = child.userData;
						}
						if ( _rootObject.hasOwnProperty( child.name ) ) {
							_rootObject[ child.name ] = obj as objectClass;
						} else if ( child.name.split( "__id" ).length == 1 && child.name.split( "instance" ).length == 1 ) {
							throw new Error( "No public property '" + child.name + "' declared in " + _rootObject );
						}
					} else {

							//trace( new Error( "No className defined " + child ) );
					}
				}
			}
		}

		private function loaded() : void {
			_assetManager = null;
			_displayObject = null;
			_movieclip = null;
			_rootObject = null;
			onLoad();
		}

		private function addImage( objectClass : Class , child : BFImage ) : Image {
			var tex : Texture = getTexture( child , child.texture , child.width , child.height )
			var img : Image = new objectClass( tex ) as Image;
			img.pivotX = int( img.width * child.pivotX );
			img.pivotY = int( img.height * child.pivotY );
			return img;
		}

		private function addSprite( objectClass : Class , child : BFSprite ) : Sprite {
			var s : Sprite = new objectClass() as Sprite;
			parseMovieClip( child as MovieClip , s as DisplayObjectContainer , s as DisplayObjectContainer );
			return s;
		}

		private function addTextField( objectClass : Class , child : BFTextField ) : TextField {
			var t : TextField = new objectClass( child.width , child.height , "" ) as TextField;
			t.autoSize = child.autoSize;
			t.fontName = child.fontName;
			t.fontSize = child.fontSize;
			t.color = child.color;
			t.hAlign = child.hAlign;
			t.vAlign = child.vAlign;
			t.bold = child.bold;
			t.italic = child.italic;
			t.border = child.border;
			t.underline = child.underline;
			t.pivotX = int( t.width * child.pivotX );
			t.pivotY = int( t.height * child.pivotY );
			var text : String = child.text;
			text = text.replace( "\\r" , "\r" );
			text = text.replace( "\\n" , "\n" );
			text = text.replace( "\\t" , "\t" );
			t.text = text;
			t.width = child.width;
			t.height = child.height;
			return t;
		}

		// TODO Parse BFButton and addChild objects inside Button
		private function addButton( objectClass : Class , child : BFButton ) : Button {
			var bt : Button = new objectClass( getTexture( child , child.upState , child.width , child.height ) ) as Button;
			bt.fontBold = child.bold;
			bt.fontColor = child.color;
			bt.fontName = child.fontName;
			bt.fontSize = child.fontSize;
			bt.alphaWhenDisabled = child.alphaWhenDisabled;
			bt.scaleWhenDown = child.scaleWhenDown;
			bt.text = child.text;
			bt.pivotX = int( bt.width * child.pivotX );
			bt.pivotY = int( bt.height * child.pivotY );

			if ( child.downState )
				bt.downState = _assetManager.getTexture( child.downState );

			if ( bt.hasOwnProperty( "overState" ) && child.overState )
				bt[ "overState" ] = _assetManager.getTexture( child.overState );

			if ( bt.hasOwnProperty( "onTouch" ) && _rootObject.hasOwnProperty( child.onTouch ) ) {
				bt[ "onTouch" ] = _rootObject[ child.onTouch ];
			} else if ( bt.hasOwnProperty( "onTouch" ) && child.onTouch != "" && !_rootObject.hasOwnProperty( child.onTouch ) ) {
				throw new Error( "The public method '" + child.onTouch + "' is not defined in " + _rootObject ) ;
			}
			return bt;
		}

		private function getTexture( child : BFObject , textureName : String , w : Number , h : Number ) : Texture {
			if ( textureName == "" ) {
				//trace( new Error( "No texture defined in '" + child + " - name: "+child.name+"' in "+_displayObject+". Default texture used." ) );
				return Texture.empty( w , h );
			} else {
				var tex : Texture = _assetManager.getTexture( textureName );
				if ( tex == null ) {
					trace( new Error( "Texture '" + textureName + "' defined in '" + child + " - name: " + child.name + "' in " + _displayObject + " doesn't exist. Default texture used." ));
					return Texture.empty( w , h );
				}
				return tex;
			}
		}
	}

}

Debug message

Debug message


package{
	import flash.display.Sprite;
	import flash.net.registerClassAlias;
	import flash.text.TextField;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;

	[SWF(width="450", height="400")]
	public class flashtest extends Sprite {
		private var tf:TextField;
		public function flashtest() {
			tf = new TextField();
			tf.width = tf.height = 450;
			tf.wordWrap = true;
			addChild(tf);

			dumpValues();
			readValues();
		}

		private function dumpValues():void {
			tf.text = "";
			var b:ByteArray = new ByteArray();
			var a:Dictionary = new Dictionary();
			a["x"] = a;
			tf.appendText(a.toString() + "\n");
			tf.appendText(a["x"].toString() + "\n");
			b.writeObject(a);
			dumpByteArray(b);
		}

		private function readValues():void {
			/*
			var data:Array = [
				0x11, 0x07, 0x00,
					0x0a, 0x0b, 0x01,
						0x07, 0x62, 0x61, 0x72,
						0x04, 0x01,
						0x01,
					0x06, 0x07, 0x66, 0x6f, 0x6f,
					0x0a, 0x0b, 0x01,
						0x07, 0x62, 0x61, 0x72,
						0x04, 0x02,
						0x01,
					0x06, 0x07, 0x66, 0x6f, 0x6f,
					0x06, 0x07, 0x71, 0x75, 0x78,
					0x0a, 0x00
			];
			*/
			var data:Array = [
				0x11, 0x03, 0x00, 0x06, 0x03, 0x78, 0x00
			];
			var b:ByteArray = createByteArray(data);

			var o:* = b.readObject();
			tf.appendText(o + "\n");
			tf.appendText(o.x + "\n");
		}

		private function testExternalizable():void {
			tf.text = "";
			registerClassAlias("Foo", Foo);
			var b:ByteArray = new ByteArray();
			var f:Foo = new Foo("asd");
			var g:Foo = new Foo("bar");
			var a:Array = [f, f, g];
			b.writeObject(a);
			dumpByteArray(b);
			b.position = 0;
			var a2:Array = b.readObject();
			tf.appendText((a[0] as Foo).foo);
			tf.appendText((a[1] as Foo).foo);
			tf.appendText((a[2] as Foo).foo);
		}

		private function dumpByteArray(b:ByteArray):void {
			b.position = 0;
			tf.appendText(b.bytesAvailable + "\n");
			tf.appendText("\tv8 data {\n\t\t");
			var cnt:int = 0;
			while(b.bytesAvailable) {
				var c:String = b.readUnsignedByte().toString(16);
				if(c.length < 2) c = "0" + c;
				tf.appendText("0x" + c);
				if (b.bytesAvailable == 0) break;
				if (++cnt == 12) {
					cnt = 0;
					tf.appendText(",\n\t\t");
				} else {
					tf.appendText(", ");
				}
			}
			tf.appendText("\n\t};\n");
		}

		private function createByteArray(data:Array):ByteArray {
			var b:ByteArray = new ByteArray();

			for(var i:int = 0; i < data.length; ++i)
				b.writeByte(data[i]);

			b.position = 0;
			return b;
		}
	}
}

import flash.utils.IDataInput;
import flash.utils.IDataOutput;
import flash.utils.IExternalizable;

class Foo implements IExternalizable {
	public var foo:String;

	public function Foo(s:String = "default") {
		foo = s;
	}

	public function writeExternal(output:IDataOutput):void {
		output.writeUTF(foo);
	}

	public function readExternal(input:IDataInput):void {
		foo = input.readUTF();
	}
}

package{
	import flash.display.Sprite;
	import flash.net.registerClassAlias;
	import flash.text.TextField;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;

	[SWF(width="450", height="400")]
	public class flashtest extends Sprite {
		private var tf:TextField;
		public function flashtest() {
			tf = new TextField();
			tf.width = tf.height = 450;
			tf.wordWrap = true;
			addChild(tf);

			dumpValues();
			readValues();
		}

		private function dumpValues():void {
			tf.text = "";
			var b:ByteArray = new ByteArray();
			var a:Array = [];
			a["x"] = "x";
			b.writeObject(a);
			b.writeObject(a);
			dumpByteArray(b);
		}

		private function log(o:*):void {
			tf.appendText(o + "\n");
		}

		private function readValues():void {
			/*
			var data:Array = [
				0x11, 0x07, 0x00,
					0x0a, 0x0b, 0x01,
						0x07, 0x62, 0x61, 0x72,
						0x04, 0x01,
						0x01,
					0x06, 0x07, 0x66, 0x6f, 0x6f,
					0x0a, 0x0b, 0x01,
						0x07, 0x62, 0x61, 0x72,
						0x04, 0x02,
						0x01,
					0x06, 0x07, 0x66, 0x6f, 0x6f,
					0x06, 0x07, 0x71, 0x75, 0x78,
					0x0a, 0x00
			];
			*/
			var data:Array = [
				0x09, 0x05, 0x01,
					0x09, 0x01, 0x03, 0x78, 0x06, 0x00, 0x01,
					0x09, 0x01, 0x00, 0x06, 0x00, 0x01,
			];
			var b:ByteArray = createByteArray(data);

			var o:* = b.readObject();
			log(o); log(o.length); log(o[0].x); log(o[1].x);
		}

		private function testExternalizable():void {
			tf.text = "";
			registerClassAlias("Foo", Foo);
			var b:ByteArray = new ByteArray();
			var f:Foo = new Foo("asd");
			var g:Foo = new Foo("bar");
			var a:Array = [f, f, g];
			b.writeObject(a);
			dumpByteArray(b);
			b.position = 0;
			var a2:Array = b.readObject();
			tf.appendText((a[0] as Foo).foo);
			tf.appendText((a[1] as Foo).foo);
			tf.appendText((a[2] as Foo).foo);
		}

		private function dumpByteArray(b:ByteArray):void {
			b.position = 0;
			tf.appendText(b.bytesAvailable + "\n");
			tf.appendText("\tv8 data {\n\t\t");
			var cnt:int = 0;
			while(b.bytesAvailable) {
				var c:String = b.readUnsignedByte().toString(16);
				if(c.length < 2) c = "0" + c;
				tf.appendText("0x" + c);
				if (b.bytesAvailable == 0) break;
				if (++cnt == 12) {
					cnt = 0;
					tf.appendText(",\n\t\t");
				} else {
					tf.appendText(", ");
				}
			}
			tf.appendText("\n\t};\n");
		}

		private function createByteArray(data:Array):ByteArray {
			var b:ByteArray = new ByteArray();

			for(var i:int = 0; i < data.length; ++i)
				b.writeByte(data[i]);

			b.position = 0;
			return b;
		}
	}
}

import flash.utils.IDataInput;
import flash.utils.IDataOutput;
import flash.utils.IExternalizable;

class Foo implements IExternalizable {
	public var foo:String;

	public function Foo(s:String = "default") {
		foo = s;
	}

	public function writeExternal(output:IDataOutput):void {
		output.writeUTF(foo);
	}

	public function readExternal(input:IDataInput):void {
		foo = input.readUTF();
	}
}

Add utility function in Flash test.

Add utility function in Flash test.


package krewfw.builtin_actor.system {

    import flash.utils.Dictionary;

    import krewfw.core.KrewActor;

    /**
     * Hierarchical Finite State Machine for krewFramework.
     *
     * [Note] 後から動的に登録 State を変えるような使い方は想定していない。
     *        addState はあるが removeState のインタフェースは用意していない。
     *
     *        また、現状 KrewStateMachine に addState を行った後の state に
     *        sub state を足すような書き方にも対応していない。
     *        KrewStateMachine のコンストラクタで一度に定義してしまうことを推奨する。
     */
    //------------------------------------------------------------
    public class KrewStateMachine extends KrewActor {

        /** If trace log is annoying you, set it false. */
        public static var VERBOSE:Boolean = true;

        // key  : state id
        // value: KrewState instance
        private var _states:Dictionary = new Dictionary();

        // States with constructor argument order. Used for default 'next' settings.
        private var _rootStateList:Vector.<KrewState> = new Vector.<KrewState>();

        private var _currentState:KrewState;

        private var _listenMap:Dictionary = new Dictionary();

        //------------------------------------------------------------
        /**
         * Usage:
         * <pre>
         *     var fsm:KrewStateMachine = new KrewStateMachine([
         *         {
         *             id: "state_1",  // First element will be an initial state.
         *             enter: onEnterFunc,
         *             next: "state_2"  // Default next state is next element of this Array.
         *         },
         *
         *         new YourCustomState(),  // Instead of Object, KrewState instance is OK.
         *
         *         {
         *             id: "state_2",
         *             children: [  // State can contain sub States.
         *                 { id: "state_2_a" },
         *                 { id: "state_2_b" },
         *                 {
         *                     id : "state_2_c",
         *                     listen: {event: "event_1", to: "state_4"},
         *                     guard : guardFunc
         *                 },
         *                 {
         *                     id: "state_2_d",
         *                     listen: [  // Array is also OK.
         *                         {event: "event_2", to: "state_1"},
         *                         {event: "event_3", to: "state_2"}
         *                     ]
         *                 }
         *             ]
         *         },
         *         {
         *             id: "state_3",
         *             listen: {event: "event_1", to: "state_4"}
         *         },
         *         ...
         *     ]);
         * </pre>
         *
         * @param stateDefList Array of KrewState instances or definition objects.
         * @param funcOwner If you speciify functions with name string, pass function-owner object.
         */
        public function KrewStateMachine(stateDefList:Array=null, funcOwner:Object=null) {
            displayable = false;

            _initStates(stateDefList, funcOwner);
        }

        private function _initStates(stateDefList:Array, funcOwner:Object=null):void {
            // guard
            if (stateDefList == null) { return; }

            if (!(stateDefList is Array)) {
                throw new Error("[KrewFSM] Constructor argument must be Array.");
            }
            if (stateDefList.length == 0) { return; }

            // do init
            addInitializer(function():void {
                for each (var stateDef:* in stateDefList) {
                    addState(stateDef, funcOwner);
                }

                _setDefaultNextStates(_rootStateList);
                _setInitialState(stateDefList);
            });
        }

        private function _setInitialState(stateDefList:Array):void {
            var firstDef:* = stateDefList[0];
            var initStateId:String;

            if (firstDef is KrewState) {
                initStateId = firstDef.stateId;
            }
            else if (firstDef is Object) {
                initStateId = firstDef.id;
            }
            else {
                throw new Error("[KrewFSM] Invalid first stateDef.");
            }

            changeState(initStateId);
        }

        /**
         * next が指定されていない state について、コンストラクタで渡した定義で
         * 上から下になぞるように next を設定していく。
         * この関数は再帰で、ツリーの末端の子 state を返す
         */
        private function _setDefaultNextStates(stateList:Vector.<KrewState>):KrewState {
            if (stateList.length == 0) { return null; }

            for (var i:int = 0;  i < stateList.length;  ++i) {
                var state:KrewState = stateList[i];

                if (state.nextStateId == null) {
                    if (state.hasChildren()) {
                        state.nextStateId = state.childStates[0].stateId;
                    }
                    else if (i + 1 <= stateList.length - 1) {
                        state.nextStateId = stateList[i + 1].stateId;
                    }
                }

                if (state.hasChildren()) {
                    var edgeState:KrewState = _setDefaultNextStates(state.childStates);

                    if (edgeState.nextStateId == null) {
                        if (i + 1 <= stateList.length - 1) {
                            edgeState.nextStateId = stateList[i + 1].stateId;
                        } else {
                            return edgeState;
                        }
                    }
                }
            }

            var edgeState:KrewState = krew.last(stateList);
            if (!edgeState.hasParent()) { return null; }

            return edgeState;
        }

        protected override function onDispose():void {
            for each (var state:KrewState in _states) {
                state.eachChild(function(childState:KrewState):void {
                    childState.dispose();
                });
            }

            _states        = null;
            _rootStateList = null;
            _currentState  = null;
            _listenMap     = null;
        }

        //------------------------------------------------------------
        // public
        //------------------------------------------------------------

        /**
         * @see KrewState.addState
         */
        public function addState(stateDef:*, funcOwner:Object=null):void {
            var state:KrewState = KrewState.makeState(stateDef, funcOwner);
            _registerStateTree(state);
            _rootStateList.push(state);
        }

        public function changeState(stateId:String):void {
            if (!_states[stateId]) {
                throw new Error("[KrewFSM] stateId not registered: " + stateId);
            }

            var oldStateId:String = "null";
            var oldState:KrewState = _currentState;
            var newState:KrewState = _states[stateId];

            // Good bye old state
            if (_currentState != null) {
                oldStateId = _currentState.stateId;
                oldState.exit();
                oldState.end(newState);
            }

            // Hello new state
            _currentState = newState;
            newState.begin(oldState);
            newState.enter();

            _log("[Info] [KrewFSM] SWITCHED: " + newState.stateId + "  <-  " + oldStateId);
        }

        /**
         * If given state is current state OR parent of current state, return true.
         * For example, when current state is "A-sub", and it is child state of "A",
         * both isState("A-sub") and isState("A") returns true.
         *
         * 現在の state が指定したものか、指定したものの子 state なら true を返す。
         * 例えば現在の state "A-sub" が "A" の子 state であるとき、isState("A-sub") でも
         * isState("A") でも true が返る。
         */
        public function isState(stateName:String):Boolean {
            if (_currentState.stateId == stateName) { return true; }

            var stateIter:KrewState = _currentState;
            while (stateIter.hasParent()) {
                stateIter = stateIter.parentState;
                if (stateIter.stateId == stateName) { return true; }
            }
            return false;
        }

        public function getState(stateId:String):KrewState {
            if (!_states[stateId]) {
                throw new Error("[KrewFSM] stateId not registered: " + stateId);
            }
            return _states[stateId];
        }

        public function get currentState():KrewState {
            return _currentState;
        }

        //------------------------------------------------------------
        // called by KrewState
        //------------------------------------------------------------

        public function listenToStateEvent(event:String):void {
            if (_listenMap[event]) { return; }  // already listening by other state

            listen(event, function(args:Object):void {
                _onEvent(args, event);
            })

            _listenMap[event] = true;
        }

        public function stopListeningToStateEvent(event:String):void {
            if (!_listenMap[event]) { return; }  // already stopped by other state

            stopListening(event);

            _listenMap[event] = false;
        }

        //------------------------------------------------------------
        // called by krewFramework
        //------------------------------------------------------------

        public override function onUpdate(passedTime:Number):void {
            if (_currentState == null) { return; }

            _currentState.eachParent(function(state:KrewState):void {
                if (state.onUpdateHandler == null) { return; }
                state.onUpdateHandler(state, passedTime);
            });
        }

        //------------------------------------------------------------
        // private
        //------------------------------------------------------------

        private function _onEvent(args:Object, event:String):void {
            _currentState.onEvent(args, event);
        }

        /**
         * State を、子を含めて全て Dictionary に保持
         * （State は Composite Pattern で sub state を子に持てる）
         */
        private function _registerStateTree(state:KrewState):void {
            state.eachChild(function(aState:KrewState):void {
                _registerState(aState);
            });
        }

        // State 1 個ぶんを Dictionary に保持
        private function _registerState(state:KrewState):void {
            if (_states[state.stateId]) {
                throw new Error("[KrewFSM] stateId already registered: " + state.stateId);
            }

            _states[state.stateId] = state;
            state.stateMachine = this;
        }

        //------------------------------------------------------------
        // debug method
        //------------------------------------------------------------

        private function _log(text:String):void {
            if (!VERBOSE) { return; }
            krew.fwlog(text);
        }

        public function dumpDictionary():void {
            krew.log(krew.str.repeat("-", 50));
            krew.log(" KrewStateMachine state dictionary dump");
            krew.log(krew.str.repeat("-", 50));

            for each(var state:KrewState in _states) {
                krew.log(" - " + state.stateId);
            }
            krew.log(krew.str.repeat("^", 50));
        }

        public function dumpDictionaryVerbose():void {
            krew.log(krew.str.repeat("-", 50));
            krew.log(" KrewStateMachine state dictionary dump -v");
            krew.log(krew.str.repeat("-", 50));

            for each(var state:KrewState in _states) {
                state.dump();
            }
        }

        public function dumpState(stateId:String):void {
            _states[stateId].dump();
        }

        public function dumpStateTree():void {
            krew.log(krew.str.repeat("-", 50));
            krew.log(" KrewStateMachine state tree dump");
            krew.log(krew.str.repeat("-", 50));

            for each(var state:KrewState in _rootStateList) {
                state.dumpTree();
            }
            krew.log(krew.str.repeat("^", 50));
        }

    }
}

package krewfw.builtin_actor.system {

    import flash.utils.Dictionary;

    import krewfw.core.KrewActor;

    /**
     * Hierarchical Finite State Machine for krewFramework.
     *
     * [Note] 後から動的に登録 State を変えるような使い方は想定していない。
     *        addState はあるが removeState のインタフェースは用意していない。
     *
     *        また、現状 KrewStateMachine に addState を行った後の state に
     *        sub state を足すような書き方にも対応していない。
     *        KrewStateMachine のコンストラクタで一度に定義してしまうことを推奨する。
     */
    //------------------------------------------------------------
    public class KrewStateMachine extends KrewActor {

        /** If trace log is annoying you, set it false. */
        public static var VERBOSE:Boolean = true;

        // key  : state id
        // value: KrewState instance
        private var _states:Dictionary = new Dictionary();

        // States with constructor argument order. Used for default 'next' settings.
        private var _rootStateList:Vector.<KrewState> = new Vector.<KrewState>();

        private var _currentState:KrewState;

        private var _listenMap:Dictionary = new Dictionary();

        //------------------------------------------------------------
        /**
         * Usage:
         * <pre>
         *     var fsm:KrewStateMachine = new KrewStateMachine([
         *         {
         *             id: "state_1",  // First element will be an initial state.
         *             enter: onEnterFunc,
         *             next: "state_2"  // Default next state is next element of this Array.
         *         },
         *
         *         new YourCustomState(),  // Instead of Object, KrewState instance is OK.
         *
         *         {
         *             id: "state_2",
         *             children: [  // State can contain sub States.
         *                 { id: "state_2_a" },
         *                 { id: "state_2_b" },
         *                 {
         *                     id : "state_2_c",
         *                     listen: {event: "event_1", to: "state_4"},
         *                     guard : guardFunc
         *                 },
         *                 {
         *                     id: "state_2_d",
         *                     listen: [  // Array is also OK.
         *                         {event: "event_2", to: "state_1"},
         *                         {event: "event_3", to: "state_2"}
         *                     ]
         *                 }
         *             ]
         *         },
         *         {
         *             id: "state_3",
         *             listen: {event: "event_1", to: "state_4"}
         *         },
         *         ...
         *     ]);
         * </pre>
         *
         * @param stateDefList Array of KrewState instances or definition objects.
         * @param funcOwner If you speciify functions with name string, pass function-owner object.
         */
        public function KrewStateMachine(stateDefList:Array=null, funcOwner:Object=null) {
            displayable = false;

            _initStates(stateDefList, funcOwner);
        }

        private function _initStates(stateDefList:Array, funcOwner:Object=null):void {
            // guard
            if (stateDefList == null) { return; }

            if (!(stateDefList is Array)) {
                throw new Error("[KrewFSM] Constructor argument must be Array.");
            }
            if (stateDefList.length == 0) { return; }

            // do init
            addInitializer(function():void {
                for each (var stateDef:* in stateDefList) {
                    addState(stateDef, funcOwner);
                }

                _setDefaultNextStates(_rootStateList);
                _setInitialState(stateDefList);
            });
        }

        private function _setInitialState(stateDefList:Array):void {
            var firstDef:* = stateDefList[0];
            var initStateId:String;

            if (firstDef is KrewState) {
                initStateId = firstDef.stateId;
            }
            else if (firstDef is Object) {
                initStateId = firstDef.id;
            }
            else {
                throw new Error("[KrewFSM] Invalid first stateDef.");
            }

            changeState(initStateId);
        }

        /**
         * next が指定されていない state について、コンストラクタで渡した定義で
         * 上から下になぞるように next を設定していく。
         * この関数は再帰で、ツリーの末端の子 state を返す
         */
        private function _setDefaultNextStates(stateList:Vector.<KrewState>):KrewState {
            if (stateList.length == 0) { return null; }

            for (var i:int = 0;  i < stateList.length;  ++i) {
                var state:KrewState = stateList[i];

                if (state.nextStateId == null) {
                    if (state.hasChildren()) {
                        state.nextStateId = state.childStates[0].stateId;
                    }
                    else if (i + 1 <= stateList.length - 1) {
                        state.nextStateId = stateList[i + 1].stateId;
                    }
                }

                if (state.hasChildren()) {
                    var edgeState:KrewState = _setDefaultNextStates(state.childStates);

                    if (edgeState.nextStateId == null) {
                        if (i + 1 <= stateList.length - 1) {
                            edgeState.nextStateId = stateList[i + 1].stateId;
                        } else {
                            return edgeState;
                        }
                    }
                }
            }

            var edgeState:KrewState = krew.last(stateList);
            if (!edgeState.hasParent()) { return null; }

            return edgeState;
        }

        protected override function onDispose():void {
            for each (var state:KrewState in _states) {
                state.eachChild(function(childState:KrewState):void {
                    childState.dispose();
                });
            }

            _states        = null;
            _rootStateList = null;
            _currentState  = null;
            _listenMap     = null;
        }

        //------------------------------------------------------------
        // public
        //------------------------------------------------------------

        /**
         * @see KrewState.addState
         */
        public function addState(stateDef:*, funcOwner:Object=null):void {
            var state:KrewState = KrewState.makeState(stateDef, funcOwner);
            _registerStateTree(state);
            _rootStateList.push(state);
        }

        public function changeState(stateId:String):void {
            if (!_states[stateId]) {
                throw new Error("[KrewFSM] stateId not registered: " + stateId);
            }

            var oldStateId:String = "null";
            var oldState:KrewState = _currentState;
            var newState:KrewState = _states[stateId];

            // Good bye old state
            if (_currentState != null) {
                oldStateId = _currentState.stateId;
                oldState.exit();
                oldState.end(newState);
            }

            _log("[Info] [KrewFSM] SWITCHED: " + newState.stateId + "  <-  " + oldStateId);

            // Hello new state
            _currentState = newState;
            newState.begin(oldState);
            newState.enter();
        }

        /**
         * If given state is current state OR parent of current state, return true.
         * For example, when current state is "A-sub", and it is child state of "A",
         * both isState("A-sub") and isState("A") returns true.
         *
         * 現在の state が指定したものか、指定したものの子 state なら true を返す。
         * 例えば現在の state "A-sub" が "A" の子 state であるとき、isState("A-sub") でも
         * isState("A") でも true が返る。
         */
        public function isState(stateName:String):Boolean {
            if (_currentState.stateId == stateName) { return true; }

            var stateIter:KrewState = _currentState;
            while (stateIter.hasParent()) {
                stateIter = stateIter.parentState;
                if (stateIter.stateId == stateName) { return true; }
            }
            return false;
        }

        public function getState(stateId:String):KrewState {
            if (!_states[stateId]) {
                throw new Error("[KrewFSM] stateId not registered: " + stateId);
            }
            return _states[stateId];
        }

        public function get currentState():KrewState {
            return _currentState;
        }

        //------------------------------------------------------------
        // called by KrewState
        //------------------------------------------------------------

        public function listenToStateEvent(event:String):void {
            if (_listenMap[event]) { return; }  // already listening by other state

            listen(event, function(args:Object):void {
                _onEvent(args, event);
            })

            _listenMap[event] = true;
        }

        public function stopListeningToStateEvent(event:String):void {
            if (!_listenMap[event]) { return; }  // already stopped by other state

            stopListening(event);

            _listenMap[event] = false;
        }

        //------------------------------------------------------------
        // called by krewFramework
        //------------------------------------------------------------

        public override function onUpdate(passedTime:Number):void {
            if (_currentState == null) { return; }

            _currentState.eachParent(function(state:KrewState):void {
                if (state.onUpdateHandler == null) { return; }
                state.onUpdateHandler(state, passedTime);
            });
        }

        //------------------------------------------------------------
        // private
        //------------------------------------------------------------

        private function _onEvent(args:Object, event:String):void {
            _currentState.onEvent(args, event);
        }

        /**
         * State を、子を含めて全て Dictionary に保持
         * （State は Composite Pattern で sub state を子に持てる）
         */
        private function _registerStateTree(state:KrewState):void {
            state.eachChild(function(aState:KrewState):void {
                _registerState(aState);
            });
        }

        // State 1 個ぶんを Dictionary に保持
        private function _registerState(state:KrewState):void {
            if (_states[state.stateId]) {
                throw new Error("[KrewFSM] stateId already registered: " + state.stateId);
            }

            _states[state.stateId] = state;
            state.stateMachine = this;
        }

        //------------------------------------------------------------
        // debug method
        //------------------------------------------------------------

        private function _log(text:String):void {
            if (!VERBOSE) { return; }
            krew.fwlog(text);
        }

        public function dumpDictionary():void {
            krew.log(krew.str.repeat("-", 50));
            krew.log(" KrewStateMachine state dictionary dump");
            krew.log(krew.str.repeat("-", 50));

            for each(var state:KrewState in _states) {
                krew.log(" - " + state.stateId);
            }
            krew.log(krew.str.repeat("^", 50));
        }

        public function dumpDictionaryVerbose():void {
            krew.log(krew.str.repeat("-", 50));
            krew.log(" KrewStateMachine state dictionary dump -v");
            krew.log(krew.str.repeat("-", 50));

            for each(var state:KrewState in _states) {
                state.dump();
            }
        }

        public function dumpState(stateId:String):void {
            _states[stateId].dump();
        }

        public function dumpStateTree():void {
            krew.log(krew.str.repeat("-", 50));
            krew.log(" KrewStateMachine state tree dump");
            krew.log(krew.str.repeat("-", 50));

            for each(var state:KrewState in _rootStateList) {
                state.dumpTree();
            }
            krew.log(krew.str.repeat("^", 50));
        }

    }
}

Modify log position of KrewStateMachine

Modify log position of KrewStateMachine


package dolly {
import dolly.core.dolly_internal;
import dolly.data.CompositeCloneableClass;

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 CloningOfCompositeCloneableClassTest {

	private var compositeCloneableClass:CompositeCloneableClass;
	private var compositeCloneableClassType:Type;

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

		compositeCloneableClassType = Type.forInstance(compositeCloneableClass);
	}

	[After]
	public function after():void {
		compositeCloneableClass = null;
		compositeCloneableClassType = null;
	}

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

	[Test]
	public function cloningOfArray():void {
		const clone:CompositeCloneableClass = Cloner.clone(compositeCloneableClass);

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

package dolly {
import dolly.core.dolly_internal;
import dolly.data.CompositeCloneableClass;

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 CloningOfCompositeCloneableClassTest {

	private var compositeCloneableClass:CompositeCloneableClass;
	private var compositeCloneableClassType:Type;

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

		compositeCloneableClassType = Type.forInstance(compositeCloneableClass);
	}

	[After]
	public function after():void {
		compositeCloneableClass = null;
		compositeCloneableClassType = null;
	}

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

	[Test]
	public function cloningOfArray():void {
		const clone:CompositeCloneableClass = Cloner.clone(compositeCloneableClass);

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

	[Test]
	public function cloningOfArrayList():void {
		const clone:CompositeCloneableClass = Cloner.clone(compositeCloneableClass);

		const arrayList:ArrayList = clone.arrayList;

		assertNotNull(arrayList);
		assertFalse(clone.arrayList == compositeCloneableClass.arrayList);
		assertEquals(arrayList.length, 5);
		assertEquals(arrayList.getItemAt(0), 1);
		assertEquals(arrayList.getItemAt(1), 2);
		assertEquals(arrayList.getItemAt(2), 3);
		assertEquals(arrayList.getItemAt(3), 4);
		assertEquals(arrayList.getItemAt(4), 5);
	}
}
}

Test for cloning of ArrayList in CompositeCloneableClass.


// vim: tabstop=4 shiftwidth=4

// Copyright (c) 2010 , 杨博 (Yang Bo) All rights reserved.
//
//         pop.atry@gmail.com
//
// Use, modification and distribution are subject to the "New BSD License"
// as listed at <url: http://www.opensource.org/licenses/bsd-license.php >.

package com.netease.protobuf {
	import flash.utils.*
	public final class WriteUtils {
		public static function writeTag(output:IDataOutput,
				wireType:uint, number:uint):void {
			const varint:VarintWriter = new VarintWriter;
			varint.write(wireType, 3);
			varint.write(number, 32);
			varint.end()
			output.writeBytes(varint)
		}
		public static function write_TYPE_DOUBLE(output:IDataOutput, value:Number):void {
			output.writeDouble(value)
		}
		public static function write_TYPE_FLOAT(output:IDataOutput, value:Number):void {
			output.writeFloat(value)
		}
		public static function write_TYPE_INT64(output:IDataOutput, value:Int64):void {
			const varint:VarintWriter = new VarintWriter;
			varint.write(value.low, 32);
			varint.write(value.high, 32);
			varint.end()
			output.writeBytes(varint)
		}
		public static function write_TYPE_UINT64(output:IDataOutput, value:UInt64):void {
			const varint:VarintWriter = new VarintWriter;
			varint.write(value.low, 32);
			varint.write(value.high, 32);
			varint.end()
			output.writeBytes(varint)
		}
		public static function write_TYPE_INT32(output:IDataOutput, value:int):void {
			write_TYPE_UINT32(output, value)
		}
		public static function write_TYPE_FIXED64(output:IDataOutput, value:Int64):void {
			output.endian = Endian.LITTLE_ENDIAN
			output.writeUnsignedInt(value.low)
			output.writeInt(value.high)
		}
		public static function write_TYPE_FIXED32(output:IDataOutput, value:int):void {
			output.endian = Endian.LITTLE_ENDIAN
			output.writeInt(value)
		}
		public static function write_TYPE_BOOL(output:IDataOutput, value:Boolean):void {
			output.writeByte(value ? 1 : 0)
		}
		public static function write_TYPE_STRING(output:IDataOutput, value:String):void {
			var plb:PostposeLengthBuffer = output as PostposeLengthBuffer
			if (plb == null) {
				plb = new PostposeLengthBuffer
			}
			const i:uint = plb.beginBlock()
			plb.writeUTF(value)
			plb.endBlock(i)
			if (plb != output) {
				plb.toNormal(output)
			}
		}
		public static function write_TYPE_BYTES(output:IDataOutput, value:ByteArray):void {
			write_TYPE_UINT32(output, value.length)
			output.writeBytes(value)
		}
		public static function write_TYPE_UINT32(output:IDataOutput, value:uint):void {
			const varint:VarintWriter = new VarintWriter;
			varint.write(value, 32);
			varint.end()
			output.writeBytes(varint)
		}
		public static function write_TYPE_ENUM(output:IDataOutput, value:int):void {
			write_TYPE_INT32(output, value)
		}
		public static function write_TYPE_SFIXED32(output:IDataOutput, value:int):void {
			write_TYPE_FIXED32(output, (value >>> 31) ^ (value << 1))
		}
		public static function write_TYPE_SFIXED64(output:IDataOutput, value:Int64):void {
			output.endian = Endian.LITTLE_ENDIAN
			output.writeUnsignedInt((value.high >>> 31) ^ (value.low << 1))
			output.writeUnsignedInt((value.low >>> 31) ^ (value.high << 1))
		}
		public static function write_TYPE_SINT32(output:IDataOutput, value:int):void {
			write_TYPE_UINT32(output, (value >>> 31) ^ (value << 1))
		}
		public static function write_TYPE_SINT64(output:IDataOutput, value:Int64):void {
			const varint:VarintWriter = new VarintWriter;
			varint.write((value.high >>> 31) ^ (value.low << 1), 32);
			varint.write((value.low >>> 31) ^ (value.high << 1), 32);
			varint.end()
			output.writeBytes(varint)
		}
		public static function write_TYPE_MESSAGE(output:IDataOutput, value:IExternalizable):void {
			var plb:PostposeLengthBuffer = output as PostposeLengthBuffer
			if (plb == null) {
				plb = new PostposeLengthBuffer
			}
			const i:uint = plb.beginBlock()
			value.writeExternal(plb)
			plb.endBlock(i)
			if (plb != output) {
				plb.toNormal(output)
			}
		}
		public static function writePackedRepeated(output:IDataOutput,
				writeFunction:Function, value:Array):void {
			var plb:PostposeLengthBuffer = output as PostposeLengthBuffer
			if (plb == null) {
				plb = new PostposeLengthBuffer
			}
			const i:uint = plb.beginBlock()
			for each (var element:* in value) {
				writeFunction(plb, element)
			}
			plb.endBlock(i)
			if (plb != output) {
				plb.toNormal(output)
			}
		}
	}
}

// vim: tabstop=4 shiftwidth=4

// Copyright (c) 2010 , 杨博 (Yang Bo) All rights reserved.
//
//         pop.atry@gmail.com
//
// Use, modification and distribution are subject to the "New BSD License"
// as listed at <url: http://www.opensource.org/licenses/bsd-license.php >.

package com.netease.protobuf {
	import flash.utils.*
	public final class WriteUtils {
		public static function writeTag(output:IDataOutput,
				wireType:uint, number:uint):void {
			const varint:VarintWriter = new VarintWriter;
			varint.write(wireType, 3);
			varint.write(number, 32);
			varint.end()
			output.writeBytes(varint)
		}
		public static function write_TYPE_DOUBLE(output:IDataOutput, value:Number):void {
			output.writeDouble(value)
		}
		public static function write_TYPE_FLOAT(output:IDataOutput, value:Number):void {
			output.writeFloat(value)
		}
		public static function write_TYPE_INT64(output:IDataOutput, value:Int64):void {
			const varint:VarintWriter = new VarintWriter;
			varint.write(value.low, 32);
			varint.write(value.high, 32);
			varint.end()
			output.writeBytes(varint)
		}
		public static function write_TYPE_UINT64(output:IDataOutput, value:UInt64):void {
			const varint:VarintWriter = new VarintWriter;
			varint.write(value.low, 32);
			varint.write(value.high, 32);
			varint.end()
			output.writeBytes(varint)
		}
		public static function write_TYPE_INT32(output:IDataOutput, value:int):void {
			write_TYPE_UINT32(output, value)
		}
		public static function write_TYPE_FIXED64(output:IDataOutput, value:Int64):void {
			output.endian = Endian.LITTLE_ENDIAN
			output.writeUnsignedInt(value.low)
			output.writeInt(value.high)
		}
		public static function write_TYPE_FIXED32(output:IDataOutput, value:int):void {
			output.endian = Endian.LITTLE_ENDIAN
			output.writeInt(value)
		}
		public static function write_TYPE_BOOL(output:IDataOutput, value:Boolean):void {
			output.writeByte(value ? 1 : 0)
		}
		public static function write_TYPE_STRING(output:IDataOutput, value:String):void {
			var plb:PostposeLengthBuffer = output as PostposeLengthBuffer
			if (plb == null) {
				plb = new PostposeLengthBuffer
			}
			const i:uint = plb.beginBlock()
			plb.writeUTFBytes(value)
			plb.endBlock(i)
			if (plb != output) {
				plb.toNormal(output)
			}
		}
		public static function write_TYPE_BYTES(output:IDataOutput, value:ByteArray):void {
			write_TYPE_UINT32(output, value.length)
			output.writeBytes(value)
		}
		public static function write_TYPE_UINT32(output:IDataOutput, value:uint):void {
			const varint:VarintWriter = new VarintWriter;
			varint.write(value, 32);
			varint.end()
			output.writeBytes(varint)
		}
		public static function write_TYPE_ENUM(output:IDataOutput, value:int):void {
			write_TYPE_INT32(output, value)
		}
		public static function write_TYPE_SFIXED32(output:IDataOutput, value:int):void {
			write_TYPE_FIXED32(output, (value >>> 31) ^ (value << 1))
		}
		public static function write_TYPE_SFIXED64(output:IDataOutput, value:Int64):void {
			output.endian = Endian.LITTLE_ENDIAN
			output.writeUnsignedInt((value.high >>> 31) ^ (value.low << 1))
			output.writeUnsignedInt((value.low >>> 31) ^ (value.high << 1))
		}
		public static function write_TYPE_SINT32(output:IDataOutput, value:int):void {
			write_TYPE_UINT32(output, (value >>> 31) ^ (value << 1))
		}
		public static function write_TYPE_SINT64(output:IDataOutput, value:Int64):void {
			const varint:VarintWriter = new VarintWriter;
			varint.write((value.high >>> 31) ^ (value.low << 1), 32);
			varint.write((value.low >>> 31) ^ (value.high << 1), 32);
			varint.end()
			output.writeBytes(varint)
		}
		public static function write_TYPE_MESSAGE(output:IDataOutput, value:IExternalizable):void {
			var plb:PostposeLengthBuffer = output as PostposeLengthBuffer
			if (plb == null) {
				plb = new PostposeLengthBuffer
			}
			const i:uint = plb.beginBlock()
			value.writeExternal(plb)
			plb.endBlock(i)
			if (plb != output) {
				plb.toNormal(output)
			}
		}
		public static function writePackedRepeated(output:IDataOutput,
				writeFunction:Function, value:Array):void {
			var plb:PostposeLengthBuffer = output as PostposeLengthBuffer
			if (plb == null) {
				plb = new PostposeLengthBuffer
			}
			const i:uint = plb.beginBlock()
			for each (var element:* in value) {
				writeFunction(plb, element)
			}
			plb.endBlock(i)
			if (plb != output) {
				plb.toNormal(output)
			}
		}
	}
}

修复发送字符串时多发了前缀的 bug

修复发送字符串时多发了前缀的 bug