/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package corsaair.server.spitfire
{

    import C.errno.*;
    import C.arpa.inet.*;
    import C.netdb.*;
    import C.netinet.*;
    import C.sys.socket.*;
    import C.sys.select.*;
    import C.stdlib.*;
    import C.unistd.*;

    import flash.utils.ByteArray;

    /**
     * A simple socket server upgrade 2.
     *
     * Let's clean up the code and reorganise it into methods
     * to spearate responsibility.
     *
     */
    public class SimpleSocketServerSelect2
    {

        // the port users will be connecting to
        public const PORT:String = "3490";

        // how many pending connections queue will hold
        public const BACKLOG:uint = 10;

        private var _address:Array;   // list of addresses
        private var _info:addrinfo;   // server selected address

        private var _run:Boolean;     // run the server loop

        public var serverfd:int;      // server socket descriptor
        public var selected:int;      // selected socket descriptor
        public var connections:Array; // list of socket descriptor

        public function SimpleSocketServerSelect2()
        {
            super();

            _address    = [];
            _info       = null;
            _run        = true;
            serverfd    = -1;
            selected    = -1;
            connections = [];
        }

        /**
         * @private
         *
         * Use getaddrinfo() to obtain a list of IP addresses we can use
         * loop trough those addresses and bind to the first one we can
         *
         * Two possible outcome
         *
         * - we found an address and boudn to it
         *   we set the _info object with the address
         *   then we return the socket descriptor
         *
         * - we exhausted the list of addresses
         *   without binding to any of them
         *   then our _info object is not set
         *   we return an unusable socket descriptor
         */
        private function _getBindingSocket():int
        {

            var hints:addrinfo = new addrinfo();
                hints.ai_family   = AF_UNSPEC;
                hints.ai_socktype = SOCK_STREAM;
                hints.ai_flags    = AI_PASSIVE; // indicates we want to bind

            var info:addrinfo;

            var eaierr:CEAIrror = new CEAIrror();
            var addrlist:Array  = getaddrinfo( null, PORT, hints, eaierr );

            if( !addrlist )
            {
                throw eaierr;
            }

            var sockfd:int;
            var option:int;
            var bound:int;

            var i:uint;
            var len:uint = addrlist.length;
            for( i = 0; i < len; i++ )
            {
                info = addrlist[i];

                sockfd = socket( info.ai_family, info.ai_socktype, info.ai_protocol );
                if( sockfd == -1 )
                {
                    trace( "selectserver: socket" )
                    trace( new CError( "", errno ) );
                    continue;
                }

                option = setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, 1 );
                if( option == -1 )
                {
                    trace( "setsockopt" );
                    trace( new CError( "", errno ) );
                    exit( 1 );
                }

                bound = bind( sockfd, info.ai_addr );
                if( bound == -1 )
                {
                    close( sockfd );
                    trace( "selectserver: bind" );
                    trace( new CError( "", errno ) );
                    continue;
                }

                // we save the selected addrinfo
                _info = info;
                break;
            }

            // we merge the addresses found into our list of address
            _address = _address.concat( addrlist );

            // we return the socket descriptor
            return sockfd;
        }

        /**
         * @private
         *
         * Loop trough all the clients connections.
         *
         * Yes this is how we do multiplexing I/O
         * without really using select()
         *
         * All the secret is with isReadable()
         * from that point we know we can read on
         * the socket and this lead to 2 clear paths
         *
         * - the server
         *   reading on the server socket means
         *   accepting a new connection with accept()
         *
         * - the clients
         *   reading on a client socket means
         *   reading data from the client with recv()
         *
         * IMPORTANT:
         * both accept() and recv() are blocking
         * which means you can freeze your server loop
         * if something is misshandled or take too long
         * (this will be explained in the next example)
         */
        private function _loopConnections():void
        {
            var i:uint;
            var len:uint = connections.length;

            for( i = 0; i < len; i++ )
            {
                selected = connections[i];

                if( isReadable( selected ) )
                {

                    if( selected == serverfd )
                    {
                        _handleNewConnections();
                    }
                    else
                    {
                        _handleClientData();
                    }

                }

            }

        }

        /**
         * @private
         *
         * Block on accept()
         * if accepted
         * - add the new socket descriptor to the connections
         * - send a welcome message to the client
         */
        private function _handleNewConnections():void
        {
            // handle new connections

            var new_fd:int;  // newly accept()ed socket descriptor
            var client_addr:sockaddr_in = new sockaddr_in();

            new_fd = accept( serverfd, client_addr );

            if( new_fd == -1 )
            {
                trace( "accept" );
                trace( new CError( "", errno ) );
            }
            else
            {
                connections.push( new_fd );

                var s:String = inet_ntop( client_addr.sin_family, client_addr );
                trace( "selectserver: new connection from " + s  + ", socket " + new_fd );

                var msg_out:String = "Hello, world!\n";
                var bytes_out:ByteArray = new ByteArray();
                    bytes_out.writeUTFBytes( msg_out );
                    bytes_out.position = 0;

                var sent:int = send( new_fd, bytes_out );
                if( sent == -1 )
                {
                    trace( "send" );
                    trace( new CError( "", errno ) );
                }
                else
                {
                    trace( "sent " + sent + " bytes to the client " + new_fd );
                }

            }
        }

        /**
         * @private
         *
         * Block on recv()
         * if receiving data
         * - write the data to the server log
         * - check for the "shutdown" command
         *
         * How do we know we are not receiving data ?
         * if you try to recv() on a disconected client
         * you will automatically recevie 0 which means
         * the client disconnected or hung up.
         * Or you will receive a negative integer
         * for signalling an error.
         *
         * In both case, we want to close the socket ot the client
         * and remove it from the connections list.
         */
        private function _handleClientData():void
        {
            // handle data from a client

            var msg_in:String;
            var bytes_in:ByteArray = new ByteArray();

            var received:int = recv( selected, bytes_in );
            if( received <= 0 )
            {
                // got error or connection closed by client
                if( received == 0 )
                {
                    // connection closed
                    trace( "selectserver: socket " + selected + " hung up" );
                }
                else
                {
                    trace( "recv" );
                    trace( new CError( "", errno ) );
                }

                close( selected ); // bye!

                // remove from master set
                _removeClient( selected );
            }
            else
            {
                // we got some data from a client
                trace( "received " + received + " bytes from client " + selected );
                bytes_in.position = 0;
                msg_in = bytes_in.readUTFBytes( bytes_in.length );
                msg_in = msg_in.split( "\n" ).join( "" );
                trace( selected + " : " + msg_in );

                if( msg_in == "shutdown" )
                {
                    trace( "selectserver: received 'shutdown' command" );
                    _run = false;
                }
            }
        }

        /**
         * @private
         *
         * add a client to list of connections
         * so far a 'client' is only the integer of a socket descriptor
         *
         * a client can be as well the current server than a remobe client
         */
        private function _addClient( sd:int ):void
        {
            connections.push( sd );
        }

        /**
         * @private
         *
         * remove a client from the list of connections
         */
        private function _removeClient( sd:int ):void
        {
            /* Note:
               protection from removing the server socket descriptor
               which would disconnect/crash all other clients
            */
            if( sd == serverfd )
            {
                return;
            }

            var i:uint;
            var len:uint = connections.length;
            var desc:int;
            for( i = 0; i < len; i++ )
            {
                desc = connections[i];
                if( desc == sd )
                {
                    connections.splice( i, 1 );
                }
            }
        }

        /**
         * @private
         *
         * close the socket descriptor and remove it from the list of connections
         * we use that to clean after ourselves
         * but in most case if the server process were to crash
         * all the descriptor would be automatically closed as
         * they depend on this process.
         *
         * Alternatively you can also use this to disconnect all or parts of the clients.
         */
        private function _closeAndRemoveAllClients( removeServer:Boolean = false ):void
        {
            var i:uint;
            var desc:int;
            for( i = 0; i < connections.length; i++ )
            {
                desc = connections[i];

                if( !removeServer && (desc == serverfd) )
                {
                    continue;
                }

                trace( "selectserver: terminate " + desc );
                close( desc );
                connections.splice( i, 1 );
                i = 0; //rewind
            }
        }

        public function main():void
        {
            /* Note:
               find our IP address and bind thesocket to it
               in general the IP will be 0.0.0.0
               which means listen on all interfaces
            */
            serverfd = _getBindingSocket();

            /* Note:
               Verify that we have selected an address
               if not it is a fatal error.
               eg. the loop trough the address info
               did not find an address
            */
            if( _info == null )
            {
                trace( "selectserver: failed to bind" );
                exit( 1 );
            }

            /* Note:
               The last part of the server setup is to listen()
               which means "I'm ready to receive data".

               If the server can not listen it is a fatal error.

               About BACKLOG
               see http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html
               the backlog is here to limit the queue of incoming connections
               it will not handle multiple connections
               eg. that's the difference between queueing and multiplexing

               The backlog argument provides a hint to the implementation
               which the implementation shall use to limit the number of
               outstanding connections in the socket's listen queue.
               Implementations may impose a limit on backlog and silently
               reduce the specified value.
               Normally, a larger backlog argument value shall result in
               a larger or equal length of the listen queue.
               Implementations shall support values of backlog up to SOMAXCONN,
               defined in `C.sys.socket`.
            */
            var listening:int = listen( serverfd, BACKLOG );
            if( listening == -1 )
            {
                trace( "listen" );
                trace( new CError( "", errno ) );
                exit( 1 );
            }

            trace( "selectserver: waiting for connections..." );

            // the server is always the first client to be added to the connections
            _addClient( serverfd );
            trace( "selectserver: server on socket " + serverfd );

            /* Note:
               main server loop

               Keep the server looping as long as
               run == true

               hopefully now the loop is easier to read :)
            */
            while( _run )
            {

                _loopConnections();

            }

            trace( "selectserver: connections left [" + connections + "]" );
            _closeAndRemoveAllClients();

            trace( "shutting down server" );
            shutdown( serverfd, SHUT_RDWR );
            close( serverfd );

            exit( 0 );

        }

    }
}

add updated select server, cleaner version

git-svn-id: 44dac414ef660a76a1e627c7b7c0e36d248d62e4@20 c2cce57b-6cbb-4450-ba62-5fdab5196ef5


/* -*- Mode: java; indent-tabs-mode: nil -*- */
/*
   Compiled with:
   java -jar utils/asc.jar -import playerglobal.abc -swf Template,100,100,10 test/swfs/test_TemplateTest.as

   This template is for writing test SWFs using pure AS3. It allows for testing
   UI events, screen and program state using the Shumway test harness.
*/

package {

    import flash.display.Sprite;
    import flash.events.Event;

    public class TemplateTest extends Sprite {
        public var loader;
        public function TemplateTest() {
            var child = new TestObject();
            addChild(child);
            addEventListener(Event.ENTER_FRAME, child.enterFrameHandler);
        }
    }
}

import flash.display.*;
import flash.events.*;
import flash.net.*;

class TestObject extends Sprite {
    private var color: uint = 0xFFCC00;
    private var pos: uint   = 10;
    private var size: uint  = 80;

    /*
      In the constructor, install event listeners for testing events, and
      construct and add child objects.
    */
    public function TestObject() {
    }

    private var frameCount = 0;

    /*
      In the enterFrameHandler, make API calls per frame to test both
      screen and program side-effects.
    */
    function enterFrameHandler(event:Event):void {
        frameCount++;
        var target = event.target;
        var loader = target.loader;
        switch (frameCount) {
        case 1:
            (function () {
                /*
                  Log test results in the standard format shown here to allow
                  for easy linking with monitor programs.
                */
                var result = true ? "PASS" : "FAIL";
                trace(result + ": test::Template/method ()");
                trace(result + ": test::Template/get name ()");
                trace(result + ": test::Template/set name ()");
            })();
            break;
        default:
            /*
              Remove enterFrameHandler when done.
            */
            parent.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
            break;
        }
    }
}

Add template for writing SWF unit tests

Add template for writing SWF unit tests


/*
The RTMFPSocket class provides a socket-like interface around RTMFP
NetConnection and NetStream. Each RTMFPSocket contains one NetConnection and two
NetStreams, one for reading and one for writing.

To create a listening socket:
    var rs:RTMFPSocket = new RTMFPSocket(url, key);
    rs.addEventListener(Event.COMPLETE, function (e:Event):void {
        // rs.id is set and can be sent out of band to the client.
    });
    rs.addEventListener(RTMFPSocket.ACCEPT_EVENT, function (e:Event):void {
        // rs.peer_id is the ID of the connected client.
    });
    rs.listen();
To connect to a listening socket:
    // Receive peer_id out of band.
    var rs:RTMFPSocket = new RTMFPSocket(url, key);
    rs.addEventListener(Event.CONNECT, function (e:Event):void {
        // rs.id and rs.peer_id are now set.
    });
*/

package
{
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.IOErrorEvent;
    import flash.events.NetStatusEvent;
    import flash.events.ProgressEvent;
    import flash.net.NetConnection;
    import flash.net.NetStream;
    import flash.utils.ByteArray;

    public class RTMFPSocket extends EventDispatcher
    {
        public static const ACCEPT_EVENT:String = "accept";

        public var connected:Boolean;

        private var nc:NetConnection;
        private var incoming:NetStream;
        private var outgoing:NetStream;

        /* Cache to hold the peer ID between when connect is called and the
           NetConnection exists. */
        private var connect_peer_id:String;

        private var buffer:ByteArray;

        private var cirrus_url:String;
        private var cirrus_key:String;

        public function RTMFPSocket(cirrus_url:String, cirrus_key:String)
        {
            connected = false;

            buffer = new ByteArray();

            this.cirrus_url = cirrus_url;
            this.cirrus_key = cirrus_key;

            nc = new NetConnection();
        }

        public function get id():String
        {
            return nc.nearID;
        }

        public function get peer_id():String
        {
            return incoming.farID;
        }

        /* NetStatusEvents that aren't handled more specifically in
           listen_netstatus_event or connect_netstatus_event. */
        private function generic_netstatus_event(e:NetStatusEvent):void
        {
            switch (e.info.code) {
            case "NetConnection.Connect.Closed":
                dispatchEvent(new Event(Event.CLOSE));
                break;
            case "NetStream.Connect.Closed":
                connected = false;
                close();
                break;
            default:
                var event:IOErrorEvent = new IOErrorEvent(IOErrorEvent.IO_ERROR);
                event.text = e.info.code;
                dispatchEvent(event);
                break;
            }
        }

        private function listen_netstatus_event(e:NetStatusEvent):void
        {
            switch (e.info.code) {
            case "NetConnection.Connect.Success":
                outgoing = new NetStream(nc, NetStream.DIRECT_CONNECTIONS);
                outgoing.client = {
                    onPeerConnect: listen_onpeerconnect
                };
                outgoing.publish("server");

                /* listen is complete, ready to accept. */
                dispatchEvent(new Event(Event.COMPLETE));
                break;
            case "NetStream.Connect.Success":
                break;
            default:
                return generic_netstatus_event(e);
                break;
            }
        }

        private function listen_onpeerconnect(peer:NetStream):Boolean {
            incoming = new NetStream(nc, peer.farID);
            incoming.client = {
                r: receive_data
            };
            incoming.play("client");

            connected = true;
            dispatchEvent(new Event(ACCEPT_EVENT));

            return true;
        }

        private function connect_netstatus_event(e:NetStatusEvent):void
        {
            switch (e.info.code) {
            case "NetConnection.Connect.Success":
                outgoing = new NetStream(nc, NetStream.DIRECT_CONNECTIONS);
                outgoing.publish("client");

                incoming = new NetStream(nc, connect_peer_id);
                incoming.client = {
                    r: receive_data
                };
                incoming.play("server");
                break;
            case "NetStream.Connect.Success":
                connected = true;
                dispatchEvent(new Event(Event.CONNECT));
                break;
            default:
                return generic_netstatus_event(e);
                break;
            }
        }

        /* Function called back when the other side does a send. */
        private function receive_data(bytes:ByteArray):void {
            var event:ProgressEvent;

            event = new ProgressEvent(ProgressEvent.SOCKET_DATA);
            event.bytesLoaded = bytes.bytesAvailable;

            bytes.readBytes(buffer, buffer.length, bytes.bytesAvailable);
            if (bytes.bytesAvailable == 0) {
                /* Reclaim memory space. */
                bytes.position = 0;
                bytes.length = 0;
            }

            dispatchEvent(event);
        }

        public function listen():void
        {
            nc.addEventListener(NetStatusEvent.NET_STATUS, listen_netstatus_event);
            nc.connect(cirrus_url, cirrus_key);
        }

        public function connect(peer_id:String):void
        {
            /* Store for later reading by connect_netstatus_event. */
            this.connect_peer_id = peer_id;

            nc.addEventListener(NetStatusEvent.NET_STATUS, connect_netstatus_event);
            nc.connect(cirrus_url, cirrus_key);
        }

        public function close():void
        {
            outgoing.close();
            incoming.close();
            nc.close();
        }

        public function readBytes(output:ByteArray, offset:uint = 0, length:uint = 0):void
        {
            buffer.readBytes(output, offset, length);
        }

        public function writeBytes(input:ByteArray, offset:uint = 0, length:uint = 0):void
        {
            var sendbuf:ByteArray;

            /* Read into a new buffer, in case offset and length do not
               completely span input. */
            sendbuf = new ByteArray();
            sendbuf.writeBytes(input, offset, length);

            /* Use a short method name because it's sent over the wire. */
            outgoing.send("r", sendbuf);
        }
    }
}

Add an RTMFPSocket class.

Add an RTMFPSocket class.


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

package org.flintparticles.twoD.actions
{
	import org.flintparticles.common.actions.ActionBase;
	import org.flintparticles.common.emitters.Emitter;
	import org.flintparticles.common.initializers.Initializer;
	import org.flintparticles.common.particles.Particle;
	import org.flintparticles.twoD.particles.Particle2D;
	import org.flintparticles.twoD.zones.Zone2D;

	import flash.geom.Point;

	[DefaultProperty("zone")]

	/**
	 * The TweenToCurrentPosition action adjusts the particle's position between two
	 * locations as it ages. The start location is a random point within the specified
	 * zone, and the end location is the particle's position when it is created or added
	 * to the emitter. The current position is relative to the particle's energy,
	 * which changes as the particle ages in accordance with the energy easing
	 * function used. This action should be used in conjunction with the Age action.
	 */

	public class TweenToCurrentPosition extends ActionBase implements Initializer
	{
		private var _zone : Zone2D;

		/**
		 * The constructor creates a TweenToCurrentPosition action for use by an emitter.
		 * To add a TweenToCurrentPosition to all particles created by an emitter, use the
		 * emitter's addAction method.
		 *
		 * @see org.flintparticles.common.emitters.Emitter#addAction()
		 *
		 * @param zone The zone for the particle's position when its energy is 0.
		 */
		public function TweenToCurrentPosition( zone : Zone2D )
		{
			_zone = zone;
			priority = -10;
		}

		/**
		 * The zone for the particle's position when its energy is 0.
		 */
		public function get zone() : Zone2D
		{
			return _zone;
		}

		public function set zone( value : Zone2D ) : void
		{
			_zone = value;
		}

		/**
		 *
		 */
		override public function addedToEmitter( emitter : Emitter ) : void
		{
			if ( !emitter.hasInitializer( this ) )
			{
				emitter.addInitializer( this );
			}
		}

		override public function removedFromEmitter( emitter : Emitter ) : void
		{
			emitter.removeInitializer( this );
		}

		/**
		 *
		 */
		public function initialize( emitter : Emitter, particle : Particle ) : void
		{
			var p : Particle2D = Particle2D( particle );
			var pt : Point = _zone.getLocation();
			var data : TweenToPositionData = new TweenToPositionData( pt.x, pt.y, p.x, p.y );
			p.dictionary[this] = data;
		}

		/**
		 * Calculates the current position of the particle based on it's energy.
		 *
		 *
This method is called by the emitter and need not be called by the
		 * user.

		 *
		 * @param emitter The Emitter that created the particle.
		 * @param particle The particle to be updated.
		 * @param time The duration of the frame - used for time based updates.
		 *
		 * @see org.flintparticles.common.actions.Action#update()
		 */
		override public function update( emitter : Emitter, particle : Particle, time : Number ) : void
		{
			var p : Particle2D = Particle2D( particle );
			if ( !p.dictionary[this] )
			{
				initialize( emitter, particle );
			}
			var data : TweenToPositionData = p.dictionary[this];
			p.x = data.endX + data.diffX * p.energy;
			p.y = data.endY + data.diffY * p.energy;
		}
	}
}

class TweenToPositionData
{
	public var diffX : Number;
	public var diffY : Number;
	public var endX : Number;
	public var endY : Number;

	public function TweenToPositionData( startX : Number, startY : Number, endX : Number, endY : Number )
	{
		this.diffX = startX - endX;
		this.diffY = startY - endY;
		this.endX = endX;
		this.endY = endY;
	}
}

Add TweenToCurrentPosition 2d Action

Add TweenToCurrentPosition 2d Action


void enter(entity_impl& out owner) {
    owner.get_animation_component().blend_ani("walk_backward");
}

void update(float delta_time, entity_impl& out owner) {

}

void leave(entity_impl& out owner) {

}

add character state for backwards walking.


package aerys.minko.render.resource.texture
{
	import aerys.minko.render.resource.texture.TextureResource;

	import flash.display.BitmapData;
	import flash.geom.Rectangle;
	import flash.utils.Dictionary;

	public class TextureAtlas extends TextureResource
	{
		private var _nodes					: Array				= new Array();
		private var _empty					: Array				= new Array();
		private var _size	 				: uint 				= 0;
		private var _atlasBitmapData		: BitmapData		= null;
		private var _bitmapDataToRectangle	: Dictionary 		= new Dictionary();

		public function TextureAtlas(size 				: uint 		= 2048,
									 transparent 		: Boolean 	= true,
									 backgroundColor 	: uint 		= 0x000000)
		{
			_size 				= size;
			_nodes[0] 			= new Rectangle(0, 0, _size, _size);
			_atlasBitmapData 	= new BitmapData(_size, _size, transparent, backgroundColor);
			setContentFromBitmapData(_atlasBitmapData, true);
		}

		public function get atlasBitmapData():BitmapData
		{
			return _atlasBitmapData;
		}

		public function get bitmapDataToRectangle():Dictionary
		{
			return _bitmapDataToRectangle;
		}

		public function addBitmapData(bitmapData : BitmapData) : Rectangle
		{
			var rectangle : Rectangle	= getRectangle(bitmapData.width, bitmapData.height);

			if (rectangle == null)
				return null;

			_atlasBitmapData.copyPixels(bitmapData, bitmapData.rect, rectangle.topLeft);
			setContentFromBitmapData(_atlasBitmapData, true);

			_bitmapDataToRectangle[bitmapData] = rectangle.clone();

			return _bitmapDataToRectangle[bitmapData];
		}

		private function getRectangle(width : uint, height : uint, rootId : int = 0) : Rectangle
		{
			var node 	: Rectangle = _nodes[rootId];
			var first	: Rectangle	= _nodes[int(rootId * 2 + 1)];
			var second	: Rectangle	= _nodes[int(rootId * 2 + 2)];
			if (!first && !second)
			{
				if (_empty[rootId] === false || width > node.width || height > node.height)
					return null;

				if (width == node.width && height == node.height)
				{
					_empty[rootId] = false;

					return node;
				}
				else
				{
					var dw : uint = node.width - width;
					var dh : uint = node.height - height;

					if (dw > dh)
					{
						first = new Rectangle(node.left, node.top,
							width, node.height);
						second = new Rectangle(node.left + width, node.top,
							node.width - width, node.height);
					}
					else
					{
						first = new Rectangle(node.left, node.top,
							node.width, height);
						second = new Rectangle(node.left, node.top + height,
							node.width, node.height - height);
					}

					_nodes[int(rootId * 2 + 1)] = first;
					_nodes[int(rootId * 2 + 2)] = second;

					return getRectangle(width, height, rootId * 2 + 1);
				}
			}

			if ((node = getRectangle(width, height, rootId * 2 + 1)))
				return node;

			return getRectangle(width, height, rootId * 2 + 2);
		}
	}
}

Add TextureAtlas

Add TextureAtlas


/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package corsaair.server.spitfire
{

    import C.errno.*;
    import C.arpa.inet.*;
    import C.netdb.*;
    import C.netinet.*;
    import C.sys.socket.*;
    import C.sys.select.*;
    import C.stdlib.*;
    import C.unistd.*;

    import flash.utils.ByteArray;
    import flash.utils.Dictionary;

    /**
     * A simple socket server upgrade 3.
     *
     * Let's see special cases:
     *
     * - how to slow down your server loop ?
     *
     * - what happen when a client block
     *   your server loop ?
     */
    public class SimpleSocketServerSelect3
    {

        // the port users will be connecting to
        public const PORT:String = "3490";

        // how many pending connections queue will hold
        public const BACKLOG:uint = 10;

        private var _address:Array;   // list of addresses
        private var _info:addrinfo;   // server selected address

        private var _run:Boolean;     // run the server loop

        public var serverfd:int;      // server socket descriptor
        public var selected:int;      // selected socket descriptor
        public var connections:Array; // list of socket descriptor

        /* Note:
           bascially a map of clients using thesocket descriptor as the key
           clients[ socket desc ] = { nickname: "test" }
        */
        public var clients:Dictionary; // list of clients informations

        /* Note:
           allow to slow down the pace of the server loop

           time is expressed in milliseconds
              0 - do not sleep
           1000 - sleep 1 sec
        */
        public var sleepTime:uint;

        public function SimpleSocketServerSelect3()
        {
            super();

            _address    = [];
            _info       = null;
            _run        = true;
            serverfd    = -1;
            selected    = -1;
            connections = [];
            clients     = new Dictionary();
            sleepTime   = 0; // 0 means "do not sleep"
        }

        private function _getBindingSocket():int
        {

            var hints:addrinfo = new addrinfo();
                hints.ai_family   = AF_UNSPEC;
                hints.ai_socktype = SOCK_STREAM;
                hints.ai_flags    = AI_PASSIVE; // indicates we want to bind

            var info:addrinfo;

            var eaierr:CEAIrror = new CEAIrror();
            var addrlist:Array  = getaddrinfo( null, PORT, hints, eaierr );

            if( !addrlist )
            {
                throw eaierr;
            }

            var sockfd:int;
            var option:int;
            var bound:int;

            var i:uint;
            var len:uint = addrlist.length;
            for( i = 0; i < len; i++ )
            {
                info = addrlist[i];

                sockfd = socket( info.ai_family, info.ai_socktype, info.ai_protocol );
                if( sockfd == -1 )
                {
                    trace( "selectserver: socket" )
                    trace( new CError( "", errno ) );
                    continue;
                }

                option = setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, 1 );
                if( option == -1 )
                {
                    trace( "setsockopt" );
                    trace( new CError( "", errno ) );
                    exit( 1 );
                }

                bound = bind( sockfd, info.ai_addr );
                if( bound == -1 )
                {
                    close( sockfd );
                    trace( "selectserver: bind" );
                    trace( new CError( "", errno ) );
                    continue;
                }

                // we save the selected addrinfo
                _info = info;
                break;
            }

            // we merge the addresses found into our list of address
            _address = _address.concat( addrlist );

            // we return the socket descriptor
            return sockfd;
        }

        private function _loopConnections():void
        {
            var i:uint;
            var len:uint = connections.length;

            for( i = 0; i < len; i++ )
            {
                selected = connections[i];

                if( isReadable( selected ) )
                {

                    if( selected == serverfd )
                    {
                        _handleNewConnections();
                    }
                    else
                    {
                        _handleClientData();
                    }

                }

            }

        }

        private function _handleNewConnections():void
        {
            // handle new connections

            var new_fd:int;  // newly accept()ed socket descriptor
            var client_addr:sockaddr_in = new sockaddr_in();

            new_fd = accept( serverfd, client_addr );

            if( new_fd == -1 )
            {
                trace( "accept" );
                trace( new CError( "", errno ) );
            }
            else
            {
                _addClient( new_fd );

                var s:String = inet_ntop( client_addr.sin_family, client_addr );
                trace( "selectserver: new connection from " + s  + ", socket " + new_fd );

                var msg_out:String = "Hello, world!\n";
                var bytes_out:ByteArray = new ByteArray();
                    bytes_out.writeUTFBytes( msg_out );
                    bytes_out.position = 0;

                var sent:int = send( new_fd, bytes_out );
                if( sent == -1 )
                {
                    trace( "send" );
                    trace( new CError( "", errno ) );
                }
                else
                {
                    trace( "sent " + sent + " bytes to the client " + new_fd );
                }

                registerNewArrival( new_fd );
            }
        }

        private function _handleClientData():void
        {
            // handle data from a client

            var msg_in:String;
            var bytes_in:ByteArray = new ByteArray();

            var received:int = recv( selected, bytes_in );
            if( received <= 0 )
            {
                // got error or connection closed by client
                if( received == 0 )
                {
                    // connection closed
                    trace( "selectserver: socket " + selected + " hung up" );
                }
                else
                {
                    trace( "recv" );
                    trace( new CError( "", errno ) );
                }

                close( selected ); // bye!

                // remove from master set
                _removeClient( selected );
            }
            else
            {
                // we got some data from a client
                trace( "received " + received + " bytes from client " + selected );
                bytes_in.position = 0;
                msg_in = bytes_in.readUTFBytes( bytes_in.length );
                msg_in = msg_in.split( "\n" ).join( "" );

                /* Note:
                   If the nickname is not empty that means the client registered
                   and so we use this nickname instead of the socket id
                */
                if( clients[selected].nickname != "" )
                {
                    trace( clients[selected].nickname + " : " + msg_in );
                }
                else
                {
                    trace( selected + " : " + msg_in );
                }

                if( msg_in == "shutdown" )
                {
                    trace( "selectserver: received 'shutdown' command" );
                    _run = false;
                }
            }
        }

        private function _addClient( sd:int, name:String = "" ):void
        {
            connections.push( sd );
            clients[ sd ] = { nickname: name };
        }

        private function _removeClient( sd:int ):void
        {
            /* Note:
               protection from removing the server socket descriptor
               which would disconnect/crash all other clients
            */
            if( sd == serverfd )
            {
                return;
            }

            var i:uint;
            var len:uint = connections.length;
            var desc:int;
            for( i = 0; i < len; i++ )
            {
                desc = connections[i];
                if( desc == sd )
                {
                    connections.splice( i, 1 );
                    delete clients[ sd ];
                }
            }
        }

        private function _closeAndRemoveAllClients( removeServer:Boolean = false ):void
        {
            var i:uint;
            var desc:int;
            for( i = 0; i < connections.length; i++ )
            {
                desc = connections[i];

                if( !removeServer && (desc == serverfd) )
                {
                    continue;
                }

                if( clients[desc].nickname != "" )
                {
                    trace( "selectserver: terminate " + clients[desc].nickname + " (" + desc + ")" );
                }
                else
                {
                    trace( "selectserver: terminate " + desc );
                }

                close( desc );              // close the socket
                connections.splice( i, 1 ); // remove the socket from the connections list
                delete clients[desc];       // delete the socket key for the clients data
                i = 0; //rewind
            }
        }

        /**
         * Register a new connected client.
         */
        public function registerNewArrival( clientfd:int ):void
        {
            /* Note:
               For some reason we decided that each new socket clients
               had to register with a nickname

               - send a question
               - wait for the answer

               IMPORTANT:
               yes our server does support multiplexing
               meaning we can deal with multiple clients connections
               but here we want to illustrate a particular flaw
               each connection is blocking

               so even if we iterate trough each clients
               that means we need to wait for a client to be processed
               before being able to process the next client

               here, as long as the client does not register
               it will block ALL the other clients
               to either connect and register, send messages or commands, etc.
            */

            var msg_welcome:String = "What is your nickname?\n";
            var bytes_welcome:ByteArray = new ByteArray();
                bytes_welcome.writeUTFBytes( msg_welcome );
                bytes_welcome.position = 0;
            var welcome:int = send( clientfd, bytes_welcome );
            if( welcome == -1 )
            {
                trace( "selectserver: welcome sent" );
                trace( new CError( "", errno ) );
                close( clientfd );
                _removeClient( clientfd );
                return;
            }

            trace( "selectserver: wait for nickname ..." );
            var bytes_answer:ByteArray = new ByteArray();
            var nickname:String;
            var n:int;
            while( true )
            {
                n = recv( clientfd, bytes_answer );
                if( n <= 0 )
                {
                    // got error or connection closed by client
                    if( n == 0 )
                    {
                        // connection closed
                        trace( "selectserver: socket " + clientfd + " hung up" );
                    }
                    else
                    {
                        trace( "recv" );
                        trace( new CError( "", errno ) );
                    }

                    close( clientfd );
                    _removeClient( clientfd );
                    break;
                }
                else
                {
                    bytes_answer.position = 0;
                    nickname = bytes_answer.readUTFBytes( n );
                    nickname = nickname.split( "\n" ).join( "" );
                    clients[ clientfd ].nickname = nickname;

                    trace( "selectserver: socket " + clientfd + " registered as " + nickname );
                    break;
                }
            }
        }

        public function main():void
        {
            serverfd = _getBindingSocket();

            if( _info == null )
            {
                trace( "selectserver: failed to bind" );
                exit( 1 );
            }

            var listening:int = listen( serverfd, BACKLOG );
            if( listening == -1 )
            {
                trace( "listen" );
                trace( new CError( "", errno ) );
                exit( 1 );
            }

            trace( "selectserver: waiting for connections..." );

            // the server is always the first client to be added to the connections
            _addClient( serverfd, "server" );
            trace( "selectserver: server on socket " + serverfd );

            var frame:uint = 0;

            // main server loop
            while( _run )
            {
                //trace( "selectserver: main loop" );
                trace( "selectserver: main loop " + frame++ );

                _loopConnections();

                if( sleepTime > 0 )
                {
                    sleep( sleepTime );
                }
            }

            trace( "selectserver: connections left [" + connections + "]" );
            _closeAndRemoveAllClients();

            trace( "shutting down server" );
            shutdown( serverfd, SHUT_RDWR );
            close( serverfd );

            exit( 0 );

        }

    }
}

add example to show how to slow down the server and what happen when client block

git-svn-id: 44dac414ef660a76a1e627c7b7c0e36d248d62e4@27 c2cce57b-6cbb-4450-ba62-5fdab5196ef5


package aerys.minko.render.shader.compiler
{
    public final class ShaderCompilerError extends Error
    {
        public static const TOO_MANY_VERTEX_OPERATIONS            : uint  = 1 << 0;
        public static const TOO_MANY_VERTEX_CONSTANTS             : uint  = 1 << 1;
        public static const TOO_MANY_VERTEX_TEMPORARIES           : uint  = 1 << 2;
        public static const TOO_MANY_VERTEX_ATTRIBUTES            : uint  = 1 << 3;

        public static const TOO_MANY_VARYINGS                     : uint  = 1 << 4;

        public static const TOO_MANY_FRAGMENT_OPERATIONS          : uint  = 1 << 5;
        public static const TOO_MANY_FRAGMENT_CONSTANTS           : uint  = 1 << 6;
        public static const TOO_MANY_FRAGMENT_TEMPORARIES         : uint  = 1 << 7;

        public static const TOO_MANY_FRAGMENT_SAMPLERS    : uint  = 1 << 8;

        public static const OUT_OF_REGISTERS                      : uint  =
              TOO_MANY_VERTEX_CONSTANTS
            | TOO_MANY_VERTEX_TEMPORARIES
            | TOO_MANY_VERTEX_ATTRIBUTES
            | TOO_MANY_FRAGMENT_CONSTANTS
            | TOO_MANY_FRAGMENT_TEMPORARIES
            | TOO_MANY_FRAGMENT_SAMPLERS;

        public function ShaderCompilerError(id : uint = 0)
        {
            super(message, id);
        }
    }
}

add missing ShaderCompilerError class

add missing ShaderCompilerError class


var f = function() {
  switch (0) {
  case 0:
	  trace('PASS');
	  break;
  }
};

f();
trace('OK');

Add switch test for compiler

Add switch test for compiler


package aerys.minko.scene.controller.mesh
{
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.data.MeshVisibilityDataProvider;
	import aerys.minko.scene.node.Camera;
	import aerys.minko.scene.node.Mesh;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.type.binding.DataBindings;
	import aerys.minko.type.bounding.FrustumCulling;
	import aerys.minko.type.math.Frustum;
	import aerys.minko.type.math.Matrix4x4;

	/**
	 * The MeshVisibilityController watches the Mesh and the active Camera of a Scene
	 * to determine whether the object is actually inside the view frustum or not.
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public final class VisibilityController extends AbstractController
	{
		private static const STATE_UNDEFINED	: uint	= 0;
		private static const STATE_INSIDE		: uint	= 1;
		private static const STATE_OUTSIDE		: uint	= 2;

		private var _mesh			: Mesh							= null;
		private var _state			: uint							= 0;

		private var _visibilityData	: MeshVisibilityDataProvider	= new MeshVisibilityDataProvider();

		public function get visible() : Boolean
		{
			return _visibilityData.visible;
		}
		public function set visible(value : Boolean) : void
		{
			_visibilityData.visible = value;
		}

		public function get frustumCulling() : uint
		{
			return _visibilityData.frustumCulling;
		}
		public function set frustumCulling(value : uint) : void
		{
			_visibilityData.frustumCulling = value;
		}

		public function get insideFrustum() : Boolean
		{
			return _visibilityData.inFrustum;
		}

		public function VisibilityController()
		{
			super(Mesh);

			initialize();
		}

		private function initialize() : void
		{
			targetAdded.add(targetAddedHandler);
			targetRemoved.add(targetRemovedHandler);
		}

		private function targetAddedHandler(ctrl	: VisibilityController,
											target	: Mesh) : void
		{
			if (_mesh != null)
				throw new Error();

			_mesh = target;

			target.addedToScene.add(meshAddedToSceneHandler);
			target.removedFromScene.add(meshRemovedFromSceneHandler);
			target.bindings.addProvider(_visibilityData);

			if (target.root is Scene)
				meshAddedToSceneHandler(target, target.root as Scene);
		}

		private function targetRemovedHandler(ctrl		: VisibilityController,
											  target	: Mesh) : void
		{
			_mesh = null;

			target.addedToScene.remove(meshAddedToSceneHandler);
			target.removedFromScene.remove(meshRemovedFromSceneHandler);
			target.bindings.removeProvider(_visibilityData);

			if (target.root is Scene)
				meshRemovedFromSceneHandler(target, target.root as Scene);
		}

		private function meshAddedToSceneHandler(mesh	: Mesh,
												 scene	: Scene) : void
		{
			scene.bindings.addCallback('worldToView', worldToViewChangedHandler);
			mesh.localToWorld.changed.add(meshLocalToWorldChangedHandler);
		}

		private function meshRemovedFromSceneHandler(mesh	: Mesh,
													 scene	: Scene) : void
		{
			scene.bindings.removeCallback('worldToView', worldToViewChangedHandler);
			mesh.localToWorld.changed.remove(meshLocalToWorldChangedHandler);
		}

		private function worldToViewChangedHandler(bindings		: DataBindings,
												   propertyName	: String,
												   oldValue		: Matrix4x4,
												   newValue		: Matrix4x4) : void
		{
			testCulling();
		}

		private function meshLocalToWorldChangedHandler(transform	: Matrix4x4) : void
		{
			testCulling();
		}

		private function testCulling() : void
		{
			var culling	: uint	= _visibilityData.frustumCulling;

			/*if (culling != FrustumCulling.DISABLED && _mesh.geometry.boundingBox)
			{
				var camera : Camera = (_mesh.root as Scene).activeCamera;

				if (!camera)
					return ;

				culling = camera.cameraData.frustum.testBoundingVolume(
					_mesh.geometry,
					_mesh.localToWorld,
					culling
				);

				var inside : Boolean = culling != Frustum.OUTSIDE;

				if (inside && _state != STATE_INSIDE)
				{
					_visibilityData.inFrustum = true;
					_state = STATE_INSIDE;
				}
				else if (!inside && _state != STATE_OUTSIDE)
				{
					_visibilityData.inFrustum = false;
					_state = STATE_OUTSIDE;
				}
			}*/
		}

		override public function clone() : AbstractController
		{
			var clone : VisibilityController = new VisibilityController();

			clone._visibilityData = _visibilityData.clone() as MeshVisibilityDataProvider;

			return clone;
		}

	}
}

rename MeshVisibilityController into VisibilityController


package Classes
{
	public class Textbox
	{
		public var contents:String;

		public function Textbox()
		{
			contents="";
		}
		public function Textbox(text)
		{
			contents=text;
		}
		public setContents(text)
		{
			contents=text;
		}
	}
}

Create a dummy textbox class for the sole purpose of writing the XML loader


package dolly.data {

[Copyable]
public class CopyableSubclass extends CopyableClass {

	public static var staticProperty2:String = "Value of second-level static property.";

	private var _writableField2:String = "Value of second-level writable field.";

	public var property2:String = "Value of second-level public property.";

	public function CopyableSubclass() {
		super();
	}

	public function get writableField2():String {
		return _writableField2;
	}

	public function set writableField2(value:String):void {
		_writableField2 = value;
	}

	public function get readOnlyField2():String {
		return "Value of second-level read-only field.";
	}
}
}

Create new data class for testing: CopyableSubclass.


package dolly.core.metadata {
public class MetadataName {

	public static const CLONEABLE:String = "cloneable";
	public static const COPYABLE:String = "copyable";
}
}

Add Enum class MetadataName.

Add Enum class MetadataName.


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

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;

use namespace dolly_internal;

public class CopyingOfPropertyLevelCopyableCloneableClassTest {

	private var propertyLevelCopyableCloneableClass:PropertyLevelCopyableCloneableClass;
	private var propertyLevelCopyableCloneableClassType:Type;

	[Before]
	public function before():void {
		propertyLevelCopyableCloneableClass = new PropertyLevelCopyableCloneableClass();
		propertyLevelCopyableCloneableClass.property1 = "property1 value";
		propertyLevelCopyableCloneableClass.property2 = "property2 value";
		propertyLevelCopyableCloneableClass.writableField1 = "writableField1 value";

		propertyLevelCopyableCloneableClassType = Type.forInstance(propertyLevelCopyableCloneableClass);
	}

	[After]
	public function after():void {
		propertyLevelCopyableCloneableClass = null;
		propertyLevelCopyableCloneableClassType = null;
	}

	[Test]
	public function findingAllCopyableFieldsForType():void {
		const copyableFields:Vector.<Field> = Copier.findCopyableFieldsForType(propertyLevelCopyableCloneableClassType);
		assertNotNull(copyableFields);
		assertEquals(2, copyableFields.length);
		assertNotNull(copyableFields[0]);
		assertNotNull(copyableFields[1]);
	}

	[Test]
	public function copyingByCopier():void {
		const copyInstance:PropertyLevelCopyableCloneableClass = Copier.copy(propertyLevelCopyableCloneableClass);
		assertNotNull(copyInstance);
		assertNotNull(copyInstance.property1);
		assertEquals(copyInstance.property1, propertyLevelCopyableCloneableClass.property1);
		assertNotNull(copyInstance.property2);
		assertFalse(copyInstance.property2 == propertyLevelCopyableCloneableClass.property2);
		assertNotNull(copyInstance.writableField1);
		assertEquals(copyInstance.writableField1, propertyLevelCopyableCloneableClass.writableField1);
	}

	[Test]
	public function copyingByCopyFunction():void {
		const copyInstance:PropertyLevelCopyableCloneableClass = copy(propertyLevelCopyableCloneableClass);
		assertNotNull(copyInstance);
		assertNotNull(copyInstance.property1);
		assertEquals(copyInstance.property1, propertyLevelCopyableCloneableClass.property1);
		assertNotNull(copyInstance.property2);
		assertFalse(copyInstance.property2 == propertyLevelCopyableCloneableClass.property2);
		assertNotNull(copyInstance.writableField1);
		assertEquals(copyInstance.writableField1, propertyLevelCopyableCloneableClass.writableField1);
	}
}
}

Create new test class: CopyingOfPropertyLevelCopyableCloneableClassTest.


package dolly.data {

[Copyable]
public class ClassLevelCopyableSubclass extends ClassLevelCopyable {

	private var _writableField2:String;

	public var property4:String;
	public var property5:String;

	public function ClassLevelCopyableSubclass() {
	}

	public function get writableField2():String {
		return _writableField2;
	}

	public function set writableField2(value:String):void {
		_writableField2 = value;
	}
}
}

Create data class for testing: ClassLevelCopyableSubclass.


/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package com.pivotshare.hls.loader {

    import flash.display.DisplayObject;
    import flash.events.*;
    import flash.net.*;
    import flash.utils.ByteArray;
    import flash.utils.getTimer;
    import flash.utils.Timer;
    import org.mangui.hls.constant.HLSLoaderTypes;
    import org.mangui.hls.event.HLSError;
    import org.mangui.hls.event.HLSEvent;
    import org.mangui.hls.event.HLSLoadMetrics;
    import org.mangui.hls.HLS;
    import org.mangui.hls.model.Fragment;
    import org.mangui.hls.model.FragmentData;
    import org.mangui.hls.utils.AES;

    CONFIG::LOGGING {
        import org.mangui.hls.utils.Log;
        import org.mangui.hls.utils.Hex;
    }

    /**
     * HLS Fragment Streamer, which also handles decryption.
     * Tries to parallel URLStream design pattern, but is incomplete.
     *
     * See [Reading and writing a ByteArray](http://help.adobe.com/en_US/as3/dev/WS5b3ccc516d4fbf351e63e3d118666ade46-7d54.html)
     *
     * @class    FragmentStream
     * @extends  EventDispatcher
     * @author   HGPA
     */
    public class FragmentStream extends EventDispatcher {

        /*
         * DisplayObject needed by AES decrypter.
         */
        private var _displayObject : DisplayObject;

        /*
         * Fragment being loaded.
         */
        private var _fragment : Fragment;

        /*
         * URLStream used to download current Fragment.
         */
        private var _fragmentURLStream : URLStream;

        /**
         * Create a FragmentStream.
         *
         * This constructor takes a reference to main DisplayObject, e.g. stage,
         * necessary for AES decryption control.
         *
         * TODO: It would be more appropriate to create a factory that itself
         * takes the DisplayObject (or a more flexible version of AES).
         *
         * @constructor
         * @param  {DisplayObject}  displayObject
         */
        public function FragmentStream(displayObject : DisplayObject) : void {
            _displayObject = displayObject;
        };

        /*
         * Return FragmentData of Fragment currently being downloaded.
         * Of immediate interest is the `bytes` field.
         *
         * @method getFragment
         * @return  {Fragment}
         */
        public function getFragment() : Fragment {
            return _fragment;
        }

        /*
         * Close the stream.
         *
         * @method  close
         */
        public function close() : void {
            if (_fragmentURLStream && _fragmentURLStream.connected) {
                _fragmentURLStream.close();
            }

            if (_fragment) {

                if (_fragment.data.decryptAES) {
                    _fragment.data.decryptAES.cancel();
                    _fragment.data.decryptAES = null;
                }

                // Explicitly release memory
                // http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/ByteArray.html#clear()
                _fragment.data.bytes.clear();
                _fragment.data.bytes = null;
            }
        }

        /**
         * Load a Fragment.
         *
         * This class/methods DOES NOT user reference of parameter. Instead it
         * clones the Fragment and manipulates this internally.
         *
         * @method  load
         * @param   {Fragment}   fragment  -  Fragment with details (cloned)
         * @param   {ByteArray}  key       -  Encryption Key
         * @return  {HLSLoadMetrics}
         */
        public function load(fragment : Fragment, key : ByteArray) : HLSLoadMetrics {

            // Clone Fragment, with new initilizations of deep fields
            // Passing around references is what is causing problems.
            // FragmentData is initialized as part of construction
            _fragment = new Fragment(
                fragment.url,
                fragment.duration,
                fragment.level,
                fragment.seqnum,
                fragment.start_time,
                fragment.continuity,
                fragment.program_date,
                fragment.decrypt_url,
                fragment.decrypt_iv, // We need this reference
                fragment.byterange_start_offset,
                fragment.byterange_end_offset,
                new Vector.<String>()
            )

            _fragmentURLStream = new URLStream();

            // START (LOADING) METRICS
            // Event listener callbacks enclose _metrics
            var _metrics : HLSLoadMetrics = new HLSLoadMetrics(HLSLoaderTypes.FRAGMENT_MAIN);
            _metrics.level = _fragment.level;
            _metrics.id    = _fragment.seqnum;
            _metrics.loading_request_time = getTimer();

            // String used to identify fragment in debug messages
            CONFIG::LOGGING {
                var fragmentString : String = "Fragment[" + _fragment.level + "][" + _fragment.seqnum + "]";
            }

            //
            // See `onLoadProgress` first.
            //

            /*
             * Called when Fragment is processing which may inclue decryption.
             *
             * To access data, call `Fragment.getFragment`, which will include
             * all bytes loaded to this point, with FragmentData's ByteArray
             * having the expected position
             *
             * NOTE: This was `FragmentLoader._fragDecryptProgressHandler` before refactor.
             *
             * @method  onProcess
             * @param   {ByteArray}  data  -  *Portion* of data that finished processing
             */
            var onProcess : Function = function onProcess(data : ByteArray) : void {

                // Ensure byte array pointer starts at beginning
                data.position = 0;

                var bytes : ByteArray = _fragment.data.bytes;

                // Byte Range Business
                // TODO: Confirm this is still working
                if (_fragment.byterange_start_offset != -1) {

                    _fragment.data.bytes.position = _fragment.data.bytes.length;
                    _fragment.data.bytes.writeBytes(data);

                    // if we have retrieved all the data, disconnect loader and notify fragment complete
                    if (_fragment.data.bytes.length >= _fragment.byterange_end_offset) {
                        if (_fragmentURLStream.connected) {
                            _fragmentURLStream.close();
                            onProcessComplete(null);
                        }
                    }
                } else {
                    // Append data to Fragment, but then reset position to mimic
                    // expected pattern of URLStream
                    var fragmentPosition : int = _fragment.data.bytes.position;
                    _fragment.data.bytes.position = _fragment.data.bytes.length;
                    _fragment.data.bytes.writeBytes(data);
                    _fragment.data.bytes.position = fragmentPosition;
                }

                var progressEvent : ProgressEvent = new ProgressEvent(
                    ProgressEvent.PROGRESS,
                    false,
                    false,
                    _fragment.data.bytes.length, // bytesLoaded
                    _fragment.data.bytesTotal    // bytesTotal
                    );

                dispatchEvent(progressEvent);
            }

            /*
             * Called when Fragment has completed processing.
             * May or may not include decryption.
             *
             * NOTE: This was `FragmentLoader._fragDecryptCompleteHandler`
             * before refactor.
             *
             * @method  onProcessComplete
             * @param   {ByteArray}  data  -  Portion of data finished processing
             */
            var onProcessComplete : Function = function onProcessComplete() : void {

                // END DECRYPTION METRICS
                // garbage collect AES decrypter
                if (_fragment.data.decryptAES) {
                    _metrics.decryption_end_time = getTimer();
                    var decrypt_duration : Number = _metrics.decryption_end_time - _metrics.decryption_begin_time;
                    CONFIG::LOGGING {
                        Log.debug("FragmentStream#onProcessComplete: Decrypted duration/length/speed:" +
                            decrypt_duration + "/" + _fragment.data.bytesLoaded + "/" +
                            Math.round((8000 * _fragment.data.bytesLoaded / decrypt_duration) / 1024) + " kb/s");
                    }

                    _fragment.data.decryptAES = null;
                }

                var completeEvent : Event = new ProgressEvent(Event.COMPLETE);
                dispatchEvent(completeEvent);
            }

            /*
             * Called when URLStream has download a portion of the file fragment.
             * This event callback delegates to decrypter if necessary.
             * Eventually onProcess is called when the downloaded portion has
             * finished processing.
             *
             * NOTE: Was `_fragLoadCompleteHandler` before refactor
             *
             * @param  {ProgressEvent}  evt  -  Portion of data finished processing
             */
            var onLoadProgress : Function = function onProgress(evt : ProgressEvent) : void {

                // First call of onProgress for this Fragment
                // Initilize fields in Fragment and FragmentData
                if (_fragment.data.bytes == null) {

                    _fragment.data.bytes = new ByteArray();
                    _fragment.data.bytesLoaded = 0;
                    _fragment.data.bytesTotal = evt.bytesTotal;
                    _fragment.data.flushTags();

                    // NOTE: This may be wrong, as it is only called after data
                    // has been loaded.
                    _metrics.loading_begin_time = getTimer();

                    CONFIG::LOGGING {
                        Log.debug("FragmentStream#onLoadProgress: Downloaded " +
                            fragmentString + "'s first " + evt.bytesLoaded +
                            " bytes of " + evt.bytesTotal + " Total");
                    }

                    // decrypt data if needed
                    if (_fragment.decrypt_url != null) {
                        // START DECRYPTION METRICS
                        _metrics.decryption_begin_time = getTimer();
                        CONFIG::LOGGING {
                            Log.debug("FragmentStream#onLoadProgress: " + fragmentString + " needs to be decrypted");
                        }

                        _fragment.data.decryptAES = new AES(
                            _displayObject,
                            key,
                            _fragment.decrypt_iv,
                            onProcess,
                            onProcessComplete
                            );
                    } else {
                        _fragment.data.decryptAES = null;
                    }
                }

                if (evt.bytesLoaded > _fragment.data.bytesLoaded && _fragmentURLStream.bytesAvailable > 0) {  // prevent EOF error race condition

                    // bytes from URLStream
                    var data : ByteArray = new ByteArray();
                    _fragmentURLStream.readBytes(data);

                    // Mark that bytes have been loaded, but do not store these
                    // bytes yet
                    _fragment.data.bytesLoaded += data.length;

                    if (_fragment.data.decryptAES != null) {
                        _fragment.data.decryptAES.append(data);
                    } else {
                        onProcess(data);
                    }
                }
            }

            /*
             * Called when URLStream had completed downloading.
             *
             * @param  {Event}  evt  -  Portion of data finished processing
             */
            var onLoadComplete : Function = function onLoadComplete(evt : Event) : void {
                // load complete, reset retry counter
                //_fragRetryCount = 0;
                //_fragRetryTimeout = 1000;

                if (_fragment.data.bytes == null) {
                    CONFIG::LOGGING {
                        Log.warn("FragmentStream#onLoadComplete: " + fragmentString +
                            " size is null, invalidate it and load next one");
                    }
                    //_levels[_hls.loadLevel].updateFragment(_fragCurrent.seqnum, false);
                    //_loadingState = LOADING_IDLE;

                    // TODO: Dispatch an error

                    return;
                }

                CONFIG::LOGGING {
                    Log.debug("FragmentStream#onLoadComplete: " + fragmentString +
                        " has finished downloading, but may still be decrypting");
                }

                // TODO: ???
                //_fragSkipping = false;

                // END LOADING METRICS
                _metrics.loading_end_time = getTimer();
                _metrics.size = _fragment.data.bytesLoaded;
                var _loading_duration : uint = _metrics.loading_end_time - _metrics.loading_request_time;
                CONFIG::LOGGING {
                    Log.debug("FragmentStream#onLoadComplete: Loading duration/RTT/length/speed:" +
                        _loading_duration + "/" +
                        (_metrics.loading_begin_time - _metrics.loading_request_time) + "/" +
                        _metrics.size + "/" +
                        Math.round((8000 * _metrics.size / _loading_duration) / 1024) + " kb/s");
                }

                if (_fragment.data.decryptAES) {
                    _fragment.data.decryptAES.notifycomplete(); // Calls onProcessComplete by proxy
                } else {
                    onProcessComplete();
                }
            }

            /*
             * Called when URLStream has Errored.
             * @param  {ErrorEvent}  evt  -  Portion of data finished processing
             */
            var onLoadError : Function = function onLoadError(evt : ErrorEvent) : void {

                CONFIG::LOGGING {
                    Log.error("FragmentStream#onLoadError: " + evt.text);
                }

                // Forward error
                dispatchEvent(evt);
            }

            _fragmentURLStream.addEventListener(IOErrorEvent.IO_ERROR, onLoadError);
            _fragmentURLStream.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onLoadError);
            _fragmentURLStream.addEventListener(ProgressEvent.PROGRESS, onLoadProgress);
            _fragmentURLStream.addEventListener(Event.COMPLETE, onLoadComplete);

            _fragmentURLStream.load(new URLRequest(fragment.url));

            return _metrics;
        }

    }
}

[FragmentStream] Add com.pivotshare.hls.loader.FragmentStream


// 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 {
	public final class ZigZag {
		public static function encode32(n:int):int {
			return (n << 1) ^ (n >> 31)
		}
		public static function decode32(n:int):int {
			return (n >>> 1) ^ -(n & 1)
		}
		public static function encode64low(low:uint, high:int):uint {
			return (low << 1) ^ (high >> 31)
		}
		public static function encode64high(low:uint, high:int):int {
			return (low >>> 31) ^ (high << 1) ^ (high >> 31)
		}
		public static function decode64low(low:uint, high:int):uint {
			return (high << 31) ^ (low >>> 1) ^ -(low & 1)
		}
		public static function decode64high(low:uint, high:int):int {
			return (high >>> 1) ^ -(low & 1)
		}
	}
}

添加遗漏的 ZigZag.as

添加遗漏的 ZigZag.as


package io.github.jwhile.impetus
{
    import flash.display.Sprite;
    import flash.external.ExternalInterface;

    public class Impetus extends Sprite
    {
        public function Impetus():void
        {
        }
    }
}

Add class Impetus

Add class Impetus


package dolly.utils {
public class CopyUtil {

}
}

Add empty utility class CopyUtil.

Add empty utility class CopyUtil.


package dolly.core {

public namespace dolly_internal;

}

Add namespace "dolly_internal".

Add namespace "dolly_internal".


package com.ryanberdeen.utils {
  import com.adobe.crypto.MD5Stream;

  import flash.events.Event;
  import flash.events.EventDispatcher;
  import flash.events.ProgressEvent;
  import flash.utils.ByteArray;
  import flash.utils.Timer;

  public class MD5Calculator extends EventDispatcher {
    private var timer:Timer;
    private var stream:MD5Stream;
    private var buffer:ByteArray;
    private var source:ByteArray;

    private var _md5:String;
    private var _delay:int;
    private var _chunkSize:int;

    private var dispatchProgressEvent:Boolean;

    public function MD5Calculator() {
      _delay = 1;
      _chunkSize = 51200;
    }

    public function set delay(delay:int):void {
      _delay = delay;
    }

    public function set chunkSize(chunkSize:int):void {
      _chunkSize = chunkSize;
    }

    public function get md5():String {
      return _md5;
    }

    public function calculate(source:ByteArray):void {
      this.source = source;

      dispatchProgressEvent = hasEventListener(ProgressEvent.PROGRESS);

      stream = new MD5Stream();
      buffer = new ByteArray();

      source.position = 0;

      timer = new Timer(_delay);;
      timer.addEventListener('timer', iterate);
      timer.start();
    }

    private function iterate(e:Event):void {
      if (source.bytesAvailable == 0) {
        timer.stop();
        timer = null;
        _md5 = stream.complete();
        stream = null;
        buffer = null;
        source = null;
        dispatchEvent(new Event(Event.COMPLETE));
        return;
      }

      var length:int = Math.min(_chunkSize, source.bytesAvailable);
      buffer.length = length;
      source.readBytes(buffer, 0, length);
      stream.update(buffer);

      if (dispatchProgressEvent) {
        var progressEvent:ProgressEvent = new ProgressEvent(ProgressEvent.PROGRESS);
        progressEvent.bytesLoaded = source.position;
        progressEvent.bytesTotal = source.length
        dispatchEvent(progressEvent);
      }
    }

    public function stop():void {
      timer.stop();
    }
  }
}

add async md5 calculator utility class

add async md5 calculator utility class


package com.dotfold.dotvimstat.mediator
{
	public class MediatorTest
	{

	}
}

add mediator test

[test] add mediator test


// ActionScript file
package aerys.minko.ns
{
	public namespace minko_animation;
}

Add Animation namespace and modification for timelines

A New namespace to access confidential information inside timelines
M Each timeline has two new getter, need namespace minko_animation to use them


/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package corsaair.server.spitfire
{

    import C.errno.*;
    import C.arpa.inet.*;
    import C.netdb.*;
    import C.netinet.*;
    import C.sys.socket.*;
    import C.sys.select.*;
    import C.stdlib.*;
    import C.unistd.*;

    import flash.utils.getTimer;
    import flash.utils.ByteArray;
    import flash.utils.Dictionary;

    import flash.system.Worker;
    import flash.system.WorkerDomain;
    import flash.concurrent.Mutex;

    /**
     * A simple socket server upgrade 5.
     *
     * If you look back at the very first example
     * you will notcie that at that time we totally ignored
     * something named fork() in the C source code
     *
     * fork() is a very convenient C function in the POSIX world
     * which allow to create a new process (child process)
     * that is an exact copy of the calling process (parent process)
     * see: http://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html
     *
     * in server.c we can see
     * if (!fork()) { // this is the child process
     *      close(sockfd); // child doesn't need the listener
     *      if (send(new_fd, "Hello, world!", 13, 0) == -1)
     *          perror("send");
     *      close(new_fd);
     *      exit(0);
     *  }
     *
     * In Redtamarin we deliberately decided to not support fork()
     * mainly because it works only with true POSIX systems
     * like Linux and Mac OS X but fail miserably under Windows
     * but also because we run our code inse a VM (AVM2)
     * and we can not as easily copy our process like that.
     *
     * But wait we have something as good as fork()
     * and which work everywhere, something called workers.
     *
     * Here how we want tto manage it for now:
     * var server = new SimpleSocketServerSelect5();
     *     server.sleepTime = 1000;
     *
     *     if( Worker.current.isPrimordial )
     *     {
     *         server.main();
     *     }
     *     else
     *     {
     *         server.registerNewArrival();
     *     }
     *
     * basically, if we are the server we want to run main()
     * and if we are a client connecting we want to run registerNewArrival()
     *
     * But workers and fork() does not work exactly the same
     * even if a background worker will create a virtual copy of the VM (AVM2)
     * sharing data works differently.
     *
     * The main point is to be able to extract the part thart is blocking forever
     * outside of the main process.
     *
     * Here, our registration is something that can block forever
     * so for this part we want to run a worker so the worker will block
     * while our main server will not block.
     */
    public class SimpleSocketServerSelect5
    {

        // the port users will be connecting to
        public const PORT:String = "3490";

        // how many pending connections queue will hold
        public const BACKLOG:uint = 10;

        private var _address:Array;   // list of addresses
        private var _info:addrinfo;   // server selected address

        private var _run:Boolean;     // run the server loop

        public var serverfd:int;      // server socket descriptor
        public var selected:int;      // selected socket descriptor
        public var connections:Array; // list of socket descriptor

        public var clients:Dictionary; // list of clients informations
        public var sleepTime:uint; // time is expressed in milliseconds

        private var _mutex:Mutex;
        public var sharedData:ByteArray;

        public function SimpleSocketServerSelect5()
        {
            super();

            _address    = [];
            _info       = null;
            _run        = true;
            serverfd    = -1;
            selected    = -1;
            connections = [];
            clients     = new Dictionary();
            sleepTime   = 0; // 0 means "do not sleep"
            sharedData  = new ByteArray();
            sharedData.shareable = true;
        }

        private function _getBindingSocket():int
        {

            var hints:addrinfo = new addrinfo();
                hints.ai_family   = AF_UNSPEC;
                hints.ai_socktype = SOCK_STREAM;
                hints.ai_flags    = AI_PASSIVE; // indicates we want to bind

            var info:addrinfo;

            var eaierr:CEAIrror = new CEAIrror();
            var addrlist:Array  = getaddrinfo( null, PORT, hints, eaierr );

            if( !addrlist )
            {
                throw eaierr;
            }

            var sockfd:int;
            var option:int;
            var bound:int;

            var i:uint;
            var len:uint = addrlist.length;
            for( i = 0; i < len; i++ )
            {
                info = addrlist[i];

                sockfd = socket( info.ai_family, info.ai_socktype, info.ai_protocol );
                if( sockfd == -1 )
                {
                    trace( "selectserver: socket" )
                    trace( new CError( "", errno ) );
                    continue;
                }

                option = setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, 1 );
                if( option == -1 )
                {
                    trace( "setsockopt" );
                    trace( new CError( "", errno ) );
                    exit( 1 );
                }

                bound = bind( sockfd, info.ai_addr );
                if( bound == -1 )
                {
                    close( sockfd );
                    trace( "selectserver: bind" );
                    trace( new CError( "", errno ) );
                    continue;
                }

                // we save the selected addrinfo
                _info = info;
                break;
            }

            // we merge the addresses found into our list of address
            _address = _address.concat( addrlist );

            // we return the socket descriptor
            return sockfd;
        }

        private function _loopConnections():void
        {
            var i:uint;
            var len:uint = connections.length;

            for( i = 0; i < len; i++ )
            {
                selected = connections[i];

                if( isReadable( selected ) )
                {

                    if( selected == serverfd )
                    {
                        _handleNewConnections();
                    }
                    else
                    {
                        _handleClientData();
                    }

                }

            }

        }

        private function _handleNewConnections():void
        {
            // handle new connections

            var new_fd:int;  // newly accept()ed socket descriptor
            var client_addr:sockaddr_in = new sockaddr_in();

            new_fd = accept( serverfd, client_addr );

            if( new_fd == -1 )
            {
                trace( "accept" );
                trace( new CError( "", errno ) );
            }
            else
            {
                _addClient( new_fd );

                var s:String = inet_ntop( client_addr.sin_family, client_addr );
                trace( "selectserver: new connection from " + s  + ", socket " + new_fd );

                var msg_out:String = "Hello, world!\n";
                var bytes_out:ByteArray = new ByteArray();
                    bytes_out.writeUTFBytes( msg_out );
                    bytes_out.position = 0;

                var sent:int = send( new_fd, bytes_out );
                if( sent == -1 )
                {
                    trace( "send" );
                    trace( new CError( "", errno ) );
                }
                else
                {
                    trace( "sent " + sent + " bytes to the client " + new_fd );
                }

                //registerNewArrival( new_fd );

                /* Note:
                   It's here that we split the process
                   by creating a worker
                */
                trace( "setup worker and start it" );
                var newArrival:Worker = WorkerDomain.current.createWorkerFromPrimordial();
                    newArrival.setSharedProperty( "clientfd", new_fd );
                    newArrival.setSharedProperty( "mutex", _mutex );
                    newArrival.start();
            }
        }

        private function _handleClientData():void
        {
            // handle data from a client

            var msg_in:String;
            var bytes_in:ByteArray = new ByteArray();

            var received:int = recv( selected, bytes_in );
            if( received <= 0 )
            {
                // got error or connection closed by client
                if( received == 0 )
                {
                    // connection closed
                    trace( "selectserver: socket " + selected + " hung up" );
                }
                else
                {
                    trace( "recv" );
                    trace( new CError( "", errno ) );
                }

                close( selected ); // bye!

                // remove from master set
                _removeClient( selected );
            }
            else
            {
                // we got some data from a client
                trace( "received " + received + " bytes from client " + selected );
                bytes_in.position = 0;
                msg_in = bytes_in.readUTFBytes( bytes_in.length );
                msg_in = msg_in.split( "\n" ).join( "" );

                if( clients[selected].nickname != "" )
                {
                    trace( clients[selected].nickname + " : " + msg_in );
                }
                else
                {
                    trace( selected + " : " + msg_in );
                }

                if( msg_in == "shutdown" )
                {
                    trace( "selectserver: received 'shutdown' command" );
                    _run = false;
                }
            }
        }

        private function _addClient( sd:int, name:String = "" ):void
        {
            connections.push( sd );
            clients[ sd ] = { nickname: name };
        }

        private function _removeClient( sd:int ):void
        {
            if( sd == serverfd )
            {
                return;
            }

            var i:uint;
            var len:uint = connections.length;
            var desc:int;
            for( i = 0; i < len; i++ )
            {
                desc = connections[i];
                if( desc == sd )
                {
                    connections.splice( i, 1 );
                    delete clients[ sd ];
                }
            }
        }

        private function _closeAndRemoveAllClients( removeServer:Boolean = false ):void
        {
            var i:uint;
            var desc:int;
            for( i = 0; i < connections.length; i++ )
            {
                desc = connections[i];

                if( !removeServer && (desc == serverfd) )
                {
                    continue;
                }

                if( clients[desc].nickname != "" )
                {
                    trace( "selectserver: terminate " + clients[desc].nickname + " (" + desc + ")" );
                }
                else
                {
                    trace( "selectserver: terminate " + desc );
                }

                close( desc );              // close the socket
                connections.splice( i, 1 ); // remove the socket from the connections list
                delete clients[desc];       // delete the socket key for the clients data
                i = 0; //rewind
            }
        }

        public function sharedTrace( message:String ):void
        {
            _mutex.lock();
            trace( message );
            _mutex.unlock();
        }

        public function getPrimordial():Worker
        {
            var wdomain:WorkerDomain = WorkerDomain.current;
            var workers:Vector.<Worker> = wdomain.listWorkers();
            var worker:Worker;
            for( var i:uint = 0; i < workers.length; i++ )
            {
                worker = workers[i];
                if( worker.isPrimordial )
                {
                    return worker;
                }
            }

            return null;
        }

        /**
         * Register a new connected client.
         */
        public function registerNewArrival():void
        {
            /* Note:
               Once we get our worker context
               we can obtain properties setup by the parent
               with getSharedProperty()

               be carefull here
               we use 2 workers
               - Worker.current: the current child or background worker
               - primordial: the parent or the primordial worker
            */
            var cworker:Worker = Worker.current;
            var primordial:Worker = getPrimordial();
            var clientfd:int  = cworker.getSharedProperty( "clientfd" );

            trace( "worker started" );
            trace( "worker.state = " + cworker.state );
            trace( "clientfd = " + clientfd );

            var msg_welcome:String = "What is your nickname?\n";
            var bytes_welcome:ByteArray = new ByteArray();
                bytes_welcome.writeUTFBytes( msg_welcome );
                bytes_welcome.position = 0;
            var welcome:int = send( clientfd, bytes_welcome );
            if( welcome == -1 )
            {
                trace( "selectserver: welcome sent" );
                trace( new CError( "", errno ) );
                close( clientfd );
                _removeClient( clientfd );
                return;
            }

            trace( "selectserver: wait for nickname ..." );
            var bytes_answer:ByteArray = new ByteArray();
            var nickname:String;
            var n:int;

            /* Note:
               we can still do a timeout
               but this time it runs isolated in a worker
               so let make it big like 60 seconds
            */
            var timeA:uint = getTimer();
            var timeB:uint;
            var diff:uint  = 0;
            var timeout:uint = 60 * 1000; // 60 sec timeout
            while( true )
            {
                timeB = getTimer();
                diff  = timeB - timeA;
                if( diff > timeout )
                {
                    trace( "selectserver: socket " + clientfd + " timed out" );
                    var bytes_bye:ByteArray = new ByteArray();
                        bytes_bye.writeUTFBytes( "You have been disconnected, bye\n" );
                    send( clientfd, bytes_bye );
                    close( clientfd );
                    _removeClient( clientfd );
                    break;
                }

                // only process if there is data in the pipe
                if( isReadable(clientfd) )
                {

                    n = recv( clientfd, bytes_answer );
                    if( n <= 0 )
                    {
                        // got error or connection closed by client
                        if( n == 0 )
                        {
                            // connection closed
                            trace( "selectserver: socket " + clientfd + " hung up" );
                        }
                        else
                        {
                            trace( "recv" );
                            trace( new CError( "", errno ) );
                        }

                        close( clientfd );
                        _removeClient( clientfd );
                        break;
                    }
                    else
                    {
                        bytes_answer.position = 0;
                        nickname = bytes_answer.readUTFBytes( n );
                        nickname = nickname.split( "\n" ).join( "" );

                        /* Note:
                           We can not use
                           clients[ clientfd ].nickname = nickname;
                           because the current var 'clients' is handled by the server
                           but we can use a little trick to set a shared property on the
                           primoridal worker (eg. the server)
                        */
                        primordial.setSharedProperty( "nickname" + clientfd  , nickname );

                        trace( "selectserver: socket " + clientfd + " registered as " + nickname );
                        break;
                    }

                }
            }

            trace( "selectserver: terminating worker" );
            var terminated:Boolean = cworker.terminate();
            trace( "selectserver: terminated = " + terminated );
        }

        private function _checkRegistration():void
        {
            /* Note:
               This can be run only from the server context
               because we need to access the 'childs' property

               and basically we use a stupid trick
               we loop trough all the connections
               to obtai nthe socket descriptor (we use it as an ID)
               and then we check the primordial worker shared property
               to see if a child has defined a nickname there

               eg.
               Server
                 |_ childs[7].nickname = ""
                => worker:
                  primordial.setSharedProperty( "nickname7", "the nickname chosen" );
                => server loop
                  nickname = primordial.getSharedProperty( "nickname7" )
                  if not empty
                  childs[7].nickname = nickname

               yes, we have no events or promises and it is a bit of a pain
               to exchange data with the workers
            */
            var primordial:Worker = Worker.current;

            for( var i:uint = 0; i < connections.length; i++ )
            {
                var clientfd:uint = connections[i];
                if( clients[clientfd].nickname == "" )
                {
                    var nickname:String = primordial.getSharedProperty( "nickname" + clientfd );
                    if( (nickname != undefined) &&
                        (nickname != 'null') &&
                        (nickname != "") )
                    {
                        clients[clientfd].nickname = nickname;
                    }
                }
            }

        }

        public function main():void
        {
            _mutex = new Mutex();

            serverfd = _getBindingSocket();

            if( _info == null )
            {
                trace( "selectserver: failed to bind" );
                exit( 1 );
            }

            var listening:int = listen( serverfd, BACKLOG );
            if( listening == -1 )
            {
                trace( "listen" );
                trace( new CError( "", errno ) );
                exit( 1 );
            }

            trace( "selectserver: waiting for connections..." );

            // the server is always the first client to be added to the connections
            _addClient( serverfd, "server" );
            trace( "selectserver: server on socket " + serverfd );

            var frame:uint = 0;

            // main server loop
            while( _run )
            {
                //trace( "selectserver: main loop" );
                trace( "selectserver: main loop " + frame++ );
                trace( "connections = " + connections.length );

                // check for new registrations
                _checkRegistration();

                _loopConnections();

                if( sleepTime > 0 )
                {
                    sleep( sleepTime );
                }
            }

            trace( "selectserver: connections left [" + connections + "]" );
            _closeAndRemoveAllClients();

            trace( "shutting down server" );
            shutdown( serverfd, SHUT_RDWR );
            close( serverfd );

            exit( 0 );

        }

    }
}

add example using workers to prevent client blocking

git-svn-id: 44dac414ef660a76a1e627c7b7c0e36d248d62e4@29 c2cce57b-6cbb-4450-ba62-5fdab5196ef5


import flash.utils.ByteArray;

var data = new ByteArray();

data.writeUTFBytes('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc hendrerit, risus vel dapibus hendrerit, augue ipsum adipiscing lorem, quis orci aliquam.');
trace(data.length);
data.deflate();
trace(data.length);
data.inflate();
trace(data.length);
trace(data.readUTFBytes(150));

Add AVM2 test case.

Add AVM2 test case.


package com.google.analytics.utils
{
    import core.version;

    public function getVersionFromString( v:String, separator:String = "." ):version
    {
        var ver:version = new version();

        if( (v == "") || (v == null) )
        {
            return ver;
        }

        if( v.indexOf( separator ) > -1 )
        {
            var values:Array = v.split( separator );
            ver.major    = parseInt( values[0] );
            ver.minor    = parseInt( values[1] );
            ver.build    = parseInt( values[2] );
            ver.revision = parseInt( values[3] );
        }
        else
        {
            ver.major = parseInt( v );
        }

        return ver;
    }
}

add utility function to help core.version convert from a string