//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

package com.threerings.presents.util {

import com.threerings.util.Log;

import com.threerings.presents.dobj.DObject;
import com.threerings.presents.dobj.DObjectManager;
import com.threerings.presents.dobj.ObjectAccessError;
import com.threerings.presents.dobj.Subscriber;

/**
 * A class that safely handles the asynchronous subscription to a distributed object when it is not
 * know if the subscription will complete before the subscriber decides they no longer wish to be
 * subscribed.
 */
public class SafeSubscriber implements Subscriber
{
    /**
     * Creates a safe subscriber for the specified distributed object which will interact with the
     * supplied callback functions.
     *
     * @param onAvailable a function to be called when the object in question is available. Looks
     * like: function (obj :DObject) :void
     * @param onFailure a function to be called if the subscription request fails. Looks like:
     * function (oid :int, error :ObjectAccessError) :void
     */
    public function SafeSubscriber (oid :int, onAvailable :Function, onFailure :Function)
    {
        // make sure they're not fucking us around
        if (oid <= 0) {
            throw new ArgumentError("Invalid oid provided to safesub [oid=" + oid + "]");
        }
        if (subscriber == null) {
            throw new ArgumentError("Null subscriber provided to safesub [oid=" + oid + "]");
        }

        _oid = oid;
        _onAvailable = onAvailable;
        _onFailure = onFailure;
    }

    /**
     * Returns true if we are currently subscribed to our object (or in the process of obtaining a
     * subscription).
     */
    public function isActive () :Boolean
    {
        return _active;
    }

    /**
     * Initiates the subscription process.
     */
    public function subscribe (omgr :DObjectManager) :void
    {
        if (_active) {
            log.warning("Active safesub asked to resubscribe " + this);
            return;
        }

        // note that we are now again in the "wishing to be subscribed" state
        _active = true;

        // make sure we dont have an object reference (which should be logically impossible)
        if (_object != null) {
            log.warning("Incroyable! A safesub has an object and was non-active!? " + this);
            // make do in the face of insanity
            _onAvailable(_object);
            return;
        }

        if (_pending) {
            // we were previously asked to subscribe, then they asked to unsubscribe and now
            // they've asked to subscribe again, all before the original subscription even
            // completed; we need do nothing here except as the original subscription request will
            // eventually come through and all will be well
            return;
        }

        // we're not pending and we just became active, that means we need to request to subscribe
        // to our object
        _pending = true;
        omgr.subscribeToObject(_oid, this);
    }

    /**
     * Terminates the object subscription. If the initial subscription has not yet completed, the
     * desire to terminate will be noted and the subscription will be terminated as soon as it
     * completes.
     */
    public function unsubscribe (omgr :DObjectManager) :void
    {
        if (!_active) {
            // we may be non-active and have no object which could mean that subscription failed;
            // in which case we don't want to complain about anything, just quietly ignore the
            // unsubscribe request
            if (_object == null && !_pending) {
                return;
            }
            log.warning("Inactive safesub asked to unsubscribe " + this);
            Log.dumpStack();
        }

        // note that we no longer desire to be subscribed
        _active = false;

        if (_pending) {
            // make sure we don't have an object reference
            if (_object != null) {
                log.warning("Have an object and am pending!? " + this, new Error());
            } else {
                // nothing to do but wait for the subscription to complete at which point we'll
                // pitch the object post-haste
                return;
            }
        }

        // make sure we have our object
        if (_object == null) {
            log.warning("Was active and not pending yet have no object!? " + this, new Error());
            // nothing to do since we're apparently already unsubscribed
            return;
        }

        // finally effect our unsubscription
        _object = null;
        omgr.unsubscribeFromObject(_oid, this);
    }

    // documentation inherited from interface
    public function objectAvailable (object :DObject) :void
    {
        // make sure life is not too cruel
        if (_object != null) {
            log.warning("Our object came available but we've already got one!? " + this);
            // go ahead and pitch the old one, God knows what's going on
            _object = null;
        }
        if (!_pending) {
            log.warning("Our object came available but we're not pending!? " + this);
            // go with our badselves, it's the only way
        }

        // we're no longer pending
        _pending = false;

        // if we are no longer active, we don't want this damned thing
        if (!_active) {
            var omgr :DObjectManager = object.getManager();
            // if the object's manager is null, that means the object is already destroyed and we
            // need not trouble ourselves with unsubscription as it has already been pitched
            if (omgr != null) {
                omgr.unsubscribeFromObject(_oid, this);
            }
            return;
        }

        // otherwise the air is fresh and clean and we can do our job
        _object = object;
        _onAvailable(object);
    }

    // documentation inherited from interface
    public function requestFailed (oid :int, cause :ObjectAccessError) :void
    {
        // do the right thing with our pending state
        if (!_pending) {
            log.warning("Criminy creole! Our subscribe failed but we're not pending!? " + this);
            // go with our badselves, it's the only way
        }
        _pending = false;

        // if we're active, let our subscriber know that the shit hit the fan
        if (_active) {
            // deactivate ourselves as we never got our object (and thus the real subscriber need
            // not call unsubscribe())
            _active = false;
            _onFailure(oid, cause);
        }
    }

    /**
     * Returns a string representation of this instance.
     */
    public function toString () :String
    {
        return "[oid=" + _oid + ", active=" + _active + ", pending=" + _pending + "]";
    }

    protected var _oid :int
    protected var _onAvailable :Function;
    protected var _onFailure :Function;
    protected var _object :DObject;;
    protected var _active :Boolean;
    protected var _pending :Boolean;

    private static const log :Log = Log.getLog(SafeSubscriber);
}
}

//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

package com.threerings.presents.util {

import com.threerings.util.Log;

import com.threerings.presents.dobj.DObject;
import com.threerings.presents.dobj.DObjectManager;
import com.threerings.presents.dobj.ObjectAccessError;
import com.threerings.presents.dobj.Subscriber;

/**
 * A class that safely handles the asynchronous subscription to a distributed object when it is not
 * know if the subscription will complete before the subscriber decides they no longer wish to be
 * subscribed.
 */
public class SafeSubscriber implements Subscriber
{
    /**
     * Creates a safe subscriber for the specified distributed object which will interact with the
     * supplied callback functions.
     *
     * @param onAvailable a function to be called when the object in question is available. Looks
     * like: function (obj :DObject) :void
     * @param onFailure a function to be called if the subscription request fails. Looks like:
     * function (oid :int, error :ObjectAccessError) :void
     */
    public function SafeSubscriber (oid :int, onAvailable :Function, onFailure :Function)
    {
        // make sure they're not fucking us around
        if (oid <= 0) {
            throw new ArgumentError("Invalid oid provided to safesub [oid=" + oid + "]");
        }
        if (onAvailable == null) {
            throw new ArgumentError("Null onAvailable provided to safesub [oid=" + oid + "]");
        }
        if (onFailure == null) {
            throw new ArgumentError("Null onFailure provided to safesub [oid=" + oid + "]");
        }

        _oid = oid;
        _onAvailable = onAvailable;
        _onFailure = onFailure;
    }

    /**
     * Returns true if we are currently subscribed to our object (or in the process of obtaining a
     * subscription).
     */
    public function isActive () :Boolean
    {
        return _active;
    }

    /**
     * Initiates the subscription process.
     */
    public function subscribe (omgr :DObjectManager) :void
    {
        if (_active) {
            log.warning("Active safesub asked to resubscribe " + this);
            return;
        }

        // note that we are now again in the "wishing to be subscribed" state
        _active = true;

        // make sure we dont have an object reference (which should be logically impossible)
        if (_object != null) {
            log.warning("Incroyable! A safesub has an object and was non-active!? " + this);
            // make do in the face of insanity
            _onAvailable(_object);
            return;
        }

        if (_pending) {
            // we were previously asked to subscribe, then they asked to unsubscribe and now
            // they've asked to subscribe again, all before the original subscription even
            // completed; we need do nothing here except as the original subscription request will
            // eventually come through and all will be well
            return;
        }

        // we're not pending and we just became active, that means we need to request to subscribe
        // to our object
        _pending = true;
        omgr.subscribeToObject(_oid, this);
    }

    /**
     * Terminates the object subscription. If the initial subscription has not yet completed, the
     * desire to terminate will be noted and the subscription will be terminated as soon as it
     * completes.
     */
    public function unsubscribe (omgr :DObjectManager) :void
    {
        if (!_active) {
            // we may be non-active and have no object which could mean that subscription failed;
            // in which case we don't want to complain about anything, just quietly ignore the
            // unsubscribe request
            if (_object == null && !_pending) {
                return;
            }
            log.warning("Inactive safesub asked to unsubscribe " + this);
            Log.dumpStack();
        }

        // note that we no longer desire to be subscribed
        _active = false;

        if (_pending) {
            // make sure we don't have an object reference
            if (_object != null) {
                log.warning("Have an object and am pending!? " + this, new Error());
            } else {
                // nothing to do but wait for the subscription to complete at which point we'll
                // pitch the object post-haste
                return;
            }
        }

        // make sure we have our object
        if (_object == null) {
            log.warning("Was active and not pending yet have no object!? " + this, new Error());
            // nothing to do since we're apparently already unsubscribed
            return;
        }

        // finally effect our unsubscription
        _object = null;
        omgr.unsubscribeFromObject(_oid, this);
    }

    // documentation inherited from interface
    public function objectAvailable (object :DObject) :void
    {
        // make sure life is not too cruel
        if (_object != null) {
            log.warning("Our object came available but we've already got one!? " + this);
            // go ahead and pitch the old one, God knows what's going on
            _object = null;
        }
        if (!_pending) {
            log.warning("Our object came available but we're not pending!? " + this);
            // go with our badselves, it's the only way
        }

        // we're no longer pending
        _pending = false;

        // if we are no longer active, we don't want this damned thing
        if (!_active) {
            var omgr :DObjectManager = object.getManager();
            // if the object's manager is null, that means the object is already destroyed and we
            // need not trouble ourselves with unsubscription as it has already been pitched
            if (omgr != null) {
                omgr.unsubscribeFromObject(_oid, this);
            }
            return;
        }

        // otherwise the air is fresh and clean and we can do our job
        _object = object;
        _onAvailable(object);
    }

    // documentation inherited from interface
    public function requestFailed (oid :int, cause :ObjectAccessError) :void
    {
        // do the right thing with our pending state
        if (!_pending) {
            log.warning("Criminy creole! Our subscribe failed but we're not pending!? " + this);
            // go with our badselves, it's the only way
        }
        _pending = false;

        // if we're active, let our subscriber know that the shit hit the fan
        if (_active) {
            // deactivate ourselves as we never got our object (and thus the real subscriber need
            // not call unsubscribe())
            _active = false;
            _onFailure(oid, cause);
        }
    }

    /**
     * Returns a string representation of this instance.
     */
    public function toString () :String
    {
        return "[oid=" + _oid + ", active=" + _active + ", pending=" + _pending + "]";
    }

    protected var _oid :int
    protected var _onAvailable :Function;
    protected var _onFailure :Function;
    protected var _object :DObject;;
    protected var _active :Boolean;
    protected var _pending :Boolean;

    private static const log :Log = Log.getLog(SafeSubscriber);
}
}

Check the right things in our Preconditions.

git-svn-id: a1a4b28b82a3276cc491891159dd9963a0a72fae@5720 542714f4-19e9-0310-aa3c-eee0fc999fb1


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

package com.freshplanet.ane.AirAACPlayer
{
	import com.freshplanet.ane.AirAACPlayer.enums.AirAACPlayerState;
	import com.freshplanet.ane.AirAACPlayer.events.AirAACPlayerErrorEvent;
	import com.freshplanet.ane.AirAACPlayer.events.AirAACPlayerEvent;

    import flash.events.EventDispatcher;
    import flash.events.StatusEvent;
    import flash.external.ExtensionContext;
    import flash.system.Capabilities;

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

	    /**
	     * If true, logs will be displayed at the Actionscript level.
	     */
	    public function get logEnabled() : Boolean {
		    return _logEnabled;
	    }

	    public function set logEnabled( value : Boolean ) : void {
		    _logEnabled = value;
	    }

	    /** AirAACPlayer is supported on iOS and Android devices. */
	    public static function get isSupported():Boolean {
		    return isAndroid || isIOS;
	    }

	    /**
	     * Create AirAACPlayer instance
	     * @param url file or remote sound URL
	     */
	    public function AirAACPlayer(url:String) {
		    if (!isSupported) return;

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

	    /**
	     * Load sound
	     */
	    public function load():void {
		    if (!isSupported || state != AirAACPlayerState.INITIAL) return;
		    _state = AirAACPlayerState.LOADING;
		    _context.call("AirAACPlayer_load", _url);
	    }

	    /**
	     * Dispose AirAACPlayer
	     */
	    public function dispose():void {
		    if (!isSupported || state == AirAACPlayerState.DISPOSED) return;

		    _state = AirAACPlayerState.DISPOSED;
            _context.call("AirAACPlayer_dispose");
		    _context.dispose();
		    _context = null;
	    }

	    /**
	     * Current player url
	     */
	    public function get url():String {
		    return _url;
	    }

	    /**
	     * Get AirAACPlayer state
	     */
	    public function get state():AirAACPlayerState {
		    return _state;
	    }

	    /**
	     * Duration in milliseconds
	     */
	    public function get duration():int {
		    if (!isSupported || state != AirAACPlayerState.READY) return -1;
		    return _context.call("AirAACPlayer_getDuration") as int;
	    }

	    /**
	     * Progress in milliseconds
	     */
	    public function get progress():int {
		    if (!isSupported || state != AirAACPlayerState.READY) return -1;
		    return _context.call("AirAACPlayer_getProgress") as int;
	    }

	    /**
	     * Set the media volume.
	     * @param volume:Number float between 0.0 and 1.0
	     */
	    public function set volume(volume:Number):void {
		    if (!isSupported || state != AirAACPlayerState.READY) return;
		    _context.call("AirAACPlayer_setVolume", volume);
	    }

	    /**
	     * Start playing the stream.
	     * If the playback has been paused before, it will continue from this point.
	     * @param startTime:int the start time in milliseconds
	     */
	    public function play(startTime:int = 0):void {
		    if (!isSupported || state != AirAACPlayerState.READY) return;
		    startTime = Math.max(0, Math.min(duration, startTime));
		    _context.call("AirAACPlayer_play", startTime);
	    }

	    /** Pause the playback */
	    public function pause():void {
		    if (!isSupported || state != AirAACPlayerState.READY) return;
		    _context.call("AirAACPlayer_pause");
	    }

	    /** Stop the playback and move the play head to the beginning of the file */
	    public function stop():void {
		    if (!isSupported || state != AirAACPlayerState.READY) return;
		    _context.call("AirAACPlayer_stop");
	    }

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

		private static const EXTENSION_ID:String = "com.freshplanet.ane.AirAACPlayer";
	    private var _logEnabled:Boolean = true;
		private var _context:ExtensionContext;
		private var _state:AirAACPlayerState = AirAACPlayerState.INITIAL;
		private var _url:String;

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

        private function onStatus(event:StatusEvent):void {
			if (state == AirAACPlayerState.DISPOSED) return;

            if (event.code == "log") {
                log(event.level);
            }
            else if (event.code == AirAACPlayerEvent.AAC_PLAYER_DOWNLOAD) {
	            dispatchEvent(new AirAACPlayerEvent(event.code, int(event.level)));
            }
            else if (event.code == AirAACPlayerEvent.AAC_PLAYER_PREPARED) {
				_state = AirAACPlayerState.READY;
	            dispatchEvent(new AirAACPlayerEvent(event.code));
            }
            else if (event.code == AirAACPlayerErrorEvent.AAC_PLAYER_ERROR) {
				_state = AirAACPlayerState.ERROR;
	            dispatchEvent(new AirAACPlayerErrorEvent(event.code, event.level));
            }
            else if (event.code == AirAACPlayerEvent.AAC_PLAYER_PLAYBACK_FINISHED) {
	            dispatchEvent(new AirAACPlayerEvent(event.code));
            }
        }

	    private static function get isIOS():Boolean {
		    return Capabilities.manufacturer.indexOf("iOS") > -1;
	    }

	    private static function get isAndroid():Boolean {
		    return Capabilities.manufacturer.indexOf("Android") > -1;
	    }
    }
}

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

package com.freshplanet.ane.AirAACPlayer
{
	import com.freshplanet.ane.AirAACPlayer.enums.AirAACPlayerState;
	import com.freshplanet.ane.AirAACPlayer.events.AirAACPlayerErrorEvent;
	import com.freshplanet.ane.AirAACPlayer.events.AirAACPlayerEvent;

    import flash.events.EventDispatcher;
    import flash.events.StatusEvent;
    import flash.external.ExtensionContext;
    import flash.system.Capabilities;

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

	    /**
	     * If true, logs will be displayed at the Actionscript level.
	     */
	    public function get logEnabled() : Boolean {
		    return _logEnabled;
	    }

	    public function set logEnabled( value : Boolean ) : void {
		    _logEnabled = value;
	    }

	    /** AirAACPlayer is supported on iOS and Android devices. */
	    public static function get isSupported():Boolean {
		    return isAndroid || isIOS;
	    }

	    /**
	     * Create AirAACPlayer instance
	     * @param url file or remote sound URL
	     */
	    public function AirAACPlayer(url:String) {
		    if (!isSupported) return;

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

	    /**
	     * Load sound
	     */
	    public function load():void {
		    if (!isSupported || state != AirAACPlayerState.INITIAL) return;
		    _state = AirAACPlayerState.LOADING;
		    _context.call("AirAACPlayer_load", _url);
	    }

	    /**
	     * Dispose AirAACPlayer
	     */
	    public function dispose():void {
		    if (!isSupported || state == AirAACPlayerState.DISPOSED) return;

		    _state = AirAACPlayerState.DISPOSED;
            _context.call("AirAACPlayer_dispose");
		    _context.dispose();
		    _context = null;
	    }

	    /**
	     * Current player url
	     */
	    public function get url():String {
		    return _url;
	    }

	    /**
	     * Get AirAACPlayer state
	     */
	    public function get state():AirAACPlayerState {
		    return _state;
	    }

	    /**
	     * Duration in milliseconds
	     */
	    public function get duration():int {
		    if (!isSupported || state != AirAACPlayerState.READY) return -1;
		    return _context.call("AirAACPlayer_getDuration") as int;
	    }

	    /**
	     * Progress in milliseconds
	     */
	    public function get progress():int {
		    if (!isSupported || state != AirAACPlayerState.READY) return -1;
		    return _context.call("AirAACPlayer_getProgress") as int;
	    }

	    /**
	     * Set the media volume.
	     * @param volume:Number float between 0.0 and 1.0
	     */
	    public function set volume(volume:Number):void {
		    if (!isSupported || state != AirAACPlayerState.READY) return;
		    _context.call("AirAACPlayer_setVolume", volume);
	    }

	    /**
	     * Start playing the stream.
	     * If the playback has been paused before, it will continue from this point.
	     * @param startTime:int the start time in milliseconds
	     */
	    public function play(startTime:int = 0, mode:int = 0):void {
		    if (!isSupported || state != AirAACPlayerState.READY) return;
		    startTime = Math.max(0, Math.min(duration, startTime));
			if (isIOS) {
				_context.call("AirAACPlayer_play", startTime, mode ? mode : _playbackCategory);
			} else {
				_context.call("AirAACPlayer_play", startTime);
			}
	    }

	    /** Pause the playback */
	    public function pause():void {
		    if (!isSupported || state != AirAACPlayerState.READY) return;
		    _context.call("AirAACPlayer_pause");
	    }

	    /** Stop the playback and move the play head to the beginning of the file */
	    public function stop():void {
		    if (!isSupported || state != AirAACPlayerState.READY) return;
		    _context.call("AirAACPlayer_stop");
	    }

		public static const PLAYBACK_MODE_AMBIENT:int = 1
		public static const PLAYBACK_MODE_SOLO_AMBIENT:int = 2;
		public static const PLAYBACK_MODE_MEDIA:int = 3;
		private static var _playbackCategory:int = 0;
	    public static function setPlaybackCategory(mode:int = 0):void
	    {
	    	_playbackCategory = mode
	    }

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

		private static const EXTENSION_ID:String = "com.freshplanet.ane.AirAACPlayer";
	    private var _logEnabled:Boolean = true;
		private var _context:ExtensionContext;
		private var _state:AirAACPlayerState = AirAACPlayerState.INITIAL;
		private var _url:String;

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

        private function onStatus(event:StatusEvent):void {
			if (state == AirAACPlayerState.DISPOSED) return;

            if (event.code == "log") {
                log(event.level);
            }
            else if (event.code == AirAACPlayerEvent.AAC_PLAYER_DOWNLOAD) {
	            dispatchEvent(new AirAACPlayerEvent(event.code, int(event.level)));
            }
            else if (event.code == AirAACPlayerEvent.AAC_PLAYER_PREPARED) {
				_state = AirAACPlayerState.READY;
	            dispatchEvent(new AirAACPlayerEvent(event.code));
            }
            else if (event.code == AirAACPlayerErrorEvent.AAC_PLAYER_ERROR) {
				_state = AirAACPlayerState.ERROR;
	            dispatchEvent(new AirAACPlayerErrorEvent(event.code, event.level));
            }
            else if (event.code == AirAACPlayerEvent.AAC_PLAYER_PLAYBACK_FINISHED) {
	            dispatchEvent(new AirAACPlayerEvent(event.code));
            }
        }

	    private static function get isIOS():Boolean {
		    return Capabilities.manufacturer.indexOf("iOS") > -1;
	    }

	    private static function get isAndroid():Boolean {
		    return Capabilities.manufacturer.indexOf("Android") > -1;
	    }
    }
}

support a 'global' playback category on ios (only updates when playing sounds)


/**
 * User: MerlinDS
 * Date: 18.07.2014
 * Time: 17:42
 */
package com.merlinds.miracle_tool.viewer {
	import com.bit101.components.List;
	import com.bit101.components.PushButton;
	import com.merlinds.miracle.Miracle;
	import com.merlinds.miracle.animations.AnimationHelper;
	import com.merlinds.miracle.display.MiracleDisplayObject;
	import com.merlinds.miracle.utils.Asset;
	import com.merlinds.miracle.utils.MafReader;
	import com.merlinds.miracle_tool.models.AppModel;

	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.filesystem.File;
	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;
	import flash.net.FileFilter;
	import flash.utils.ByteArray;

	[SWF(backgroundColor="0x333333", frameRate=60)]
	public class ViewerView extends Sprite {

		private var _model:AppModel;
		private var _startBtn:PushButton;
		private var _texture:ByteArray;
		private var _animation:ByteArray;
		private var _fileName:String;
		private var _list:List;
		private var _instance:MiracleDisplayObject;

		public function ViewerView(model:AppModel = null) {
			super();
			_model = model;
			if(_model == null){
				_model = new AppModel();
			}

			this.addEventListener(Event.ADDED_TO_STAGE, this.initialize);
		}
		//==============================================================================
		//{region							PUBLIC METHODS
		//} endregion PUBLIC METHODS ===================================================

		//==============================================================================
		//{region						PRIVATE\PROTECTED METHODS
		private function initialize(event:Event):void {
			this.removeEventListener(event.type, this.initialize);
			this.stage.scaleMode = StageScaleMode.NO_SCALE;
			this.stage.align = StageAlign.TOP_LEFT;
			_startBtn = new PushButton(this, this.stage.stageWidth >> 1, this.stage.stageHeight >> 1,
					"Start", this.startBtnHandler );
		}

		function clear():void
		{
			if(_animation != null) _animation.clear();
			if(_texture != null) _texture.clear();
			_texture = null;
			_animation = null;
			_fileName = null;
		}

		private function startHandler():void {
			trace("Miracle was started");
			var maf:Asset = new Asset(_fileName + ".maf", _animation);
			var mtf:Asset = new Asset(_fileName + ".mtf", _texture);
			Miracle.createScene(new <Asset>[maf, mtf], this.createdHandler, 1);
		}

		private function createdHandler():void {
			trace("Scene created");
			this.getAnimationList();
		}

		private function getAnimationList():void {
			var mafReader = new MafReader();
			mafReader.execute(_animation, 1);
			var animationsName:Array = [];
			for each(var animation:AnimationHelper in mafReader.animations)
			{
				animationsName.push(animation.name);
			}
			trace("Was get animations", animationsName);
			_list = new List(this, this.stage.stageWidth - 200, 0, animationsName);
			_list.width = 200;
			_list.addEventListener(Event.SELECT, this.selectAnimationHandler);
		}

		private function getAnimation():void {
			var file:File = _model.lastFileDirection;
			file.browseForOpen("Get animation file", [new FileFilter("Miracle animation format", "*.maf")] );
			file.addEventListener(Event.SELECT, this.animationSelected);
			file.addEventListener(Event.CANCEL, this.animationSelected);
		}

		private function readAnimation(file:File):void {
			_animation = new ByteArray();
			var fileStream:FileStream = new FileStream();
			fileStream.open(file, FileMode.READ);
			fileStream.readBytes(_animation);
			fileStream.close();
		}

		private function getTexture(file:File):void {
			_fileName = file.name.substr(0, -file.extension.length - 1);
			file.browseForOpen("Get texture file", [new FileFilter("Miracle texture format", _fileName + ".mtf")] );
			file.addEventListener(Event.SELECT, this.animationSelected);
			file.addEventListener(Event.CANCEL, this.animationSelected);
		}

		private function readTexture(file:File):void {
			_texture = new ByteArray();
			var fileStream:FileStream = new FileStream();
			fileStream.open(file, FileMode.READ);
			fileStream.readBytes(_texture);
			fileStream.close();
		}

		public function startBtnHandler(event:Event):void{
			_startBtn.visible = false;
			getAnimation();
		}

		private function animationSelected(event:Event):void {
			if(event.type == Event.CANCEL)
			{
				this.clear();
				_startBtn.visible = true;
			}else
			{
				if(_animation == null)
				{
					this.readAnimation(event.target as File);
					this.getTexture(event.target as File);
				}else
				{
					this.readTexture(event.target as File);
					trace("All loaded");
					Miracle.start(this.stage, this.startHandler, true);
				}
			}
		}

		private function selectAnimationHandler(event:Event):void {
			if(_instance != null)
			{
				Miracle.scene.removeInstance(_instance);
			}
			var selected:String = _list.selectedItem as String;
			var dot:int = selected.lastIndexOf(".");
			var animation:String = selected.substr(dot+1);
			var mesh:String = selected.substr(0, dot);
			_instance = Miracle.scene.createImage(mesh, animation);
			_instance.x = this.stage.stageWidth >> 1;
			_instance.y = this.stage.stageHeight >> 1;
			_instance.visible = true;
		}
		//} endregion EVENTS HANDLERS ==================================================

		//==============================================================================
		//{region							GETTERS/SETTERS
		//} endregion GETTERS/SETTERS ==================================================
	}
}

/**
 * User: MerlinDS
 * Date: 18.07.2014
 * Time: 17:42
 */
package com.merlinds.miracle_tool.viewer {
	import com.bit101.components.List;
	import com.bit101.components.PushButton;
	import com.merlinds.miracle.Miracle;
	import com.merlinds.miracle.animations.AnimationHelper;
	import com.merlinds.miracle.display.MiracleDisplayObject;
	import com.merlinds.miracle.utils.Asset;
	import com.merlinds.miracle.utils.MafReader;
	import com.merlinds.miracle_tool.models.AppModel;

	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.filesystem.File;
	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;
	import flash.net.FileFilter;
	import flash.utils.ByteArray;

	[SWF(backgroundColor="0x333333", frameRate=60)]
	public class ViewerView extends Sprite {

		private var _model:AppModel;
		private var _startBtn:PushButton;
		private var _texture:ByteArray;
		private var _animation:ByteArray;
		private var _fileName:String;
		private var _list:List;
		private var _instance:MiracleDisplayObject;

		public function ViewerView(model:AppModel = null) {
			super();
			_model = model;
			if(_model == null){
				_model = new AppModel();
			}

			this.addEventListener(Event.ADDED_TO_STAGE, this.initialize);
		}
		//==============================================================================
		//{region							PUBLIC METHODS
		//} endregion PUBLIC METHODS ===================================================

		//==============================================================================
		//{region						PRIVATE\PROTECTED METHODS
		private function initialize(event:Event):void {
			this.removeEventListener(event.type, this.initialize);
			this.stage.scaleMode = StageScaleMode.NO_SCALE;
			this.stage.align = StageAlign.TOP_LEFT;
			_startBtn = new PushButton(this, this.stage.stageWidth >> 1, this.stage.stageHeight >> 1,
					"Start", this.startBtnHandler );
		}

		public function clear():void
		{
			if(_animation != null) _animation.clear();
			if(_texture != null) _texture.clear();
			_texture = null;
			_animation = null;
			_fileName = null;
		}

		private function startHandler():void {
			trace("Miracle was started");
			var maf:Asset = new Asset(_fileName + ".maf", _animation);
			var mtf:Asset = new Asset(_fileName + ".mtf", _texture);
			Miracle.createScene(new <Asset>[maf, mtf], this.createdHandler, 1);
		}

		private function createdHandler():void {
			trace("Scene created");
			this.getAnimationList();
		}

		private function getAnimationList():void {
			var mafReader:MafReader = new MafReader();
			mafReader.execute(_animation, 1);
			var animationsName:Array = [];
			for each(var animation:AnimationHelper in mafReader.animations)
			{
				animationsName.push(animation.name);
			}
			trace("Was get animations", animationsName);
			_list = new List(this, this.stage.stageWidth - 200, 0, animationsName);
			_list.width = 200;
			_list.addEventListener(Event.SELECT, this.selectAnimationHandler);
		}

		private function getAnimation():void {
			var file:File = _model.lastFileDirection;
			file.browseForOpen("Get animation file", [new FileFilter("Miracle animation format", "*.maf")] );
			file.addEventListener(Event.SELECT, this.animationSelected);
			file.addEventListener(Event.CANCEL, this.animationSelected);
		}

		private function readAnimation(file:File):void {
			_animation = new ByteArray();
			var fileStream:FileStream = new FileStream();
			fileStream.open(file, FileMode.READ);
			fileStream.readBytes(_animation);
			fileStream.close();
		}

		private function getTexture(file:File):void {
			_fileName = file.name.substr(0, -file.extension.length - 1);
			file.browseForOpen("Get texture file", [new FileFilter("Miracle texture format", _fileName + ".mtf")] );
			file.addEventListener(Event.SELECT, this.animationSelected);
			file.addEventListener(Event.CANCEL, this.animationSelected);
		}

		private function readTexture(file:File):void {
			_texture = new ByteArray();
			var fileStream:FileStream = new FileStream();
			fileStream.open(file, FileMode.READ);
			fileStream.readBytes(_texture);
			fileStream.close();
		}

		public function startBtnHandler(event:Event):void{
			_startBtn.visible = false;
			getAnimation();
		}

		private function animationSelected(event:Event):void {
			if(event.type == Event.CANCEL)
			{
				this.clear();
				_startBtn.visible = true;
			}else
			{
				if(_animation == null)
				{
					this.readAnimation(event.target as File);
					this.getTexture(event.target as File);
				}else
				{
					this.readTexture(event.target as File);
					trace("All loaded");
					Miracle.start(this.stage, this.startHandler, true);
				}
			}
		}

		private function selectAnimationHandler(event:Event):void {
			if(_instance != null)
			{
				Miracle.scene.removeInstance(_instance);
			}
			var selected:String = _list.selectedItem as String;
			var dot:int = selected.lastIndexOf(".");
			var animation:String = selected.substr(dot+1);
			var mesh:String = selected.substr(0, dot);
			_instance = Miracle.scene.createImage(mesh, animation);
			_instance.x = this.stage.stageWidth >> 1;
			_instance.y = this.stage.stageHeight >> 1;
			_instance.visible = true;
		}
		//} endregion EVENTS HANDLERS ==================================================

		//==============================================================================
		//{region							GETTERS/SETTERS
		//} endregion GETTERS/SETTERS ==================================================
	}
}

refactor with external config

refactor with external  config


package test.request {
  import mx.rpc.events.ResultEvent;

  import flails.request.HTTPClient;
  import flails.request.JSONFilter;
  import flails.resource.Record;
  import flails.request.ResourcePathBuilder;
  import flails.request.RequestConfig;

  import net.digitalprimates.fluint.tests.TestCase;

  public class HTTPClientTest extends TestCase {
    private var r:HTTPClient;
    private var rCheck:HTTPClient;

    override protected function setUp():void {
      var cleanup:HTTPClient = new HTTPClient(null, null, new RequestConfig())
      cleanup.addEventListener("result", asyncHandler(pendUntilComplete, 1000))
      cleanup.doGet("/posts/reset");

      var rc:RequestConfig = new RequestConfig();
      rc.baseUrl = "http://localhost:3000";

      r = new HTTPClient(new ResourcePathBuilder("posts"), new JSONFilter(), rc);
      rCheck = new HTTPClient(new ResourcePathBuilder("posts"), new JSONFilter(), rc);
    }

    public function testIndex():void {
      r.addEventListener("result", asyncHandler(function (e:ResultEvent, data:Object):void {
            var a:Array = e.result as Array;

            assertEquals(2, a.length);
            assertEquals('testFindAll #1', a[0].subject);
            assertEquals('testFindAll #1 body', a[0].body);
            assertEquals('testFindAll #2', a[1].subject);
            assertEquals('testFindAll #2 body', a[1].body);
          }, 1000));
      r.index();
    }

    public function testShow():void {
      r.addEventListener("result", asyncHandler(function (e:ResultEvent, data:Object):void {
            var p:Record = new Record;
            p.setAttributes(e.result);

            assertEquals('testFindAll #1', p.subject);
            assertEquals('testFindAll #1 body', p.body);
          }, 1500));
      r.show(1);
    }

    public function testShowNotFound():void {
      r.addEventListener("result", asyncHandler(function (e:ResultEvent, data:Object):void {
            var p:Record = new Record;
            p.setAttributes(e.result);

            assertEquals('Record Not Found', p.message);
          }, 1500));
      r.show(2349324920);
    }

    public function testCreate():void {
      r.addEventListener("result", asyncHandler(verifyCreateComplete, 1500));
      r.create({post: {subject: "creating new post", body: "creating new post with body"}});
    }

    private function verifyCreateComplete(e:ResultEvent, data:Object):void {
      rCheck.addEventListener("result", asyncHandler(function (e:ResultEvent, data:Object):void {
        var p:Record = new Record;
        p.setAttributes(e.result);

        assertEquals('creating new post', p.subject);
        assertEquals('creating new post with body', p.body);
      }, 1500));

      rCheck.show(e.result.id);
    }

    public function testUpdate():void {
      r.addEventListener("result", asyncHandler(verifyUpdateComplete, 1500));
      r.update({post: {subject: "testFindAll #2 updated", body: "testFindAll #2 body updated"}}, 2);
    }

    private function verifyUpdateComplete(e:ResultEvent, data:Object):void {
      rCheck.addEventListener("result", asyncHandler(function (e:ResultEvent, data:Object):void {
            var p:Record = new Record;
            p.setAttributes(e.result);

            assertEquals('testFindAll #2 updated', p.subject);
            assertEquals('testFindAll #2 body updated', p.body);
          }, 1500));
      rCheck.show(2);
    }

    public function testDestroy():void {
      r.addEventListener("result", asyncHandler(verifyDestroy, 1500));
      r.destroy(2);
    }

    private function verifyDestroy(e:ResultEvent, data:Object):void {
      var p:Record = new Record;
      p.setAttributes(e.result);

      assertEquals(2, p.id);

      rCheck.addEventListener("result", asyncHandler(function (e:ResultEvent, data:Object):void {
        var p2:Record = new Record;
        p2.setAttributes(e.result);

        assertEquals(null, p2.id);
      }, 1500));

      rCheck.show(p.id);
    }
  }
}

package test.request {
  import mx.rpc.events.ResultEvent;

  import flails.request.HTTPClient;
  import flails.request.JSONFilter;
  import flails.resource.Record;
  import flails.request.ResourcePathBuilder;
  import flails.request.RequestConfig;

  import net.digitalprimates.fluint.tests.TestCase;

  public class HTTPClientTest extends TestCase {
    private var r:HTTPClient;
    private var rCheck:HTTPClient;

    override protected function setUp():void {
      var cleanup:HTTPClient = new HTTPClient(null, null, new RequestConfig())
      cleanup.addEventListener("result", asyncHandler(pendUntilComplete, 1000))
      cleanup.doGet("/posts/reset");

      var rc:RequestConfig = new RequestConfig();
      rc.baseUrl = "http://localhost:3000";

      r = new HTTPClient(new ResourcePathBuilder("posts"), new JSONFilter(), rc);
      rCheck = new HTTPClient(new ResourcePathBuilder("posts"), new JSONFilter(), rc);
    }

    public function testIndex():void {
      r.addEventListener("result", asyncHandler(function (e:ResultEvent, data:Object):void {
            var a:Array = e.result as Array;

            assertEquals(2, a.length);
            assertEquals('testFindAll #1', a[0].subject);
            assertEquals('testFindAll #1 body', a[0].body);
            assertEquals('testFindAll #2', a[1].subject);
            assertEquals('testFindAll #2 body', a[1].body);
          }, 1000));
      r.index();
    }

    public function testShow():void {
      r.addEventListener("result", asyncHandler(function (e:ResultEvent, data:Object):void {
            var p:Record = new Record(e.result);

            assertEquals('testFindAll #1', p.subject);
            assertEquals('testFindAll #1 body', p.body);
          }, 1500));
      r.show(1);
    }

    public function testShowNotFound():void {
      r.addEventListener("result", asyncHandler(function (e:ResultEvent, data:Object):void {
            var p:Record = new Record(e.result);

            assertEquals('Record Not Found', p.message);
          }, 1500));
      r.show(2349324920);
    }

    public function testCreate():void {
      r.addEventListener("result", asyncHandler(verifyCreateComplete, 1500));
      r.create({post: {subject: "creating new post", body: "creating new post with body"}});
    }

    private function verifyCreateComplete(e:ResultEvent, data:Object):void {
      rCheck.addEventListener("result", asyncHandler(function (e:ResultEvent, data:Object):void {
        var p:Record = new Record(e.result);

        assertEquals('creating new post', p.subject);
        assertEquals('creating new post with body', p.body);
      }, 1500));

      rCheck.show(e.result.id);
    }

    public function testUpdate():void {
      r.addEventListener("result", asyncHandler(verifyUpdateComplete, 1500));
      r.update(2, {post: {subject: "testFindAll #2 updated", body: "testFindAll #2 body updated"}});
    }

    private function verifyUpdateComplete(e:ResultEvent, data:Object):void {
      rCheck.addEventListener("result", asyncHandler(function (e:ResultEvent, data:Object):void {
            var p:Record = new Record(e.result);

            assertEquals('testFindAll #2 updated', p.subject);
            assertEquals('testFindAll #2 body updated', p.body);
          }, 1500));
      rCheck.show(2);
    }

    public function testDestroy():void {
      r.addEventListener("result", asyncHandler(verifyDestroy, 1500));
      r.destroy(2);
    }

    private function verifyDestroy(e:ResultEvent, data:Object):void {
      var p:Record = new Record(e.result);

      assertEquals(2, p.id);

      rCheck.addEventListener("result", asyncHandler(function (e:ResultEvent, data:Object):void {
        var p2:Record = new Record;
        p2.setAttributes(e.result);

        assertEquals(null, p2.id);
      }, 1500));

      rCheck.show(p.id);
    }

  }
}

Update test fixed

Update test fixed


/* 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/. */

include "corsaair/server/spitfire/SimpleSocketServer.as";
include "corsaair/server/spitfire/SimpleSocketServer1.as";

import corsaair.server.spitfire.*;

// example1
/*
var server = new SimpleSocketServer();
*/

// example2
var server = new SimpleSocketServer1();
	server.showAddressInfo1();
	server.showAddressInfo2();
	server.showAddressInfo3();
	server.showAddressInfo3( "localhost" );

	// pass trough cloudflare
	server.showAddressInfo3( "www.corsaair.com" );

	// direct to the server
	server.showAddressInfo3( "www.as3lang.org" );

	// more example
	server.showAddressInfo3( "www.google.com" );
	server.showAddressInfo3( "www.yahoo.com" );
	server.showAddressInfo3( "www.cloudflare.com" );

	server.main();

/* 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/. */

include "corsaair/server/spitfire/SimpleSocketServer.as";
include "corsaair/server/spitfire/SimpleSocketServerSelect.as";
include "corsaair/server/spitfire/SimpleSocketServerSelect2.as";

import corsaair.server.spitfire.*;

// example1
/*
var server = new SimpleSocketServer();
    server.main();
*/

// example2
/*
var server = new SimpleSocketServerSelect();
	server.showAddressInfo1();
	server.showAddressInfo2();
	server.showAddressInfo3();
	server.showAddressInfo3( "localhost" );

	// pass trough cloudflare
	server.showAddressInfo3( "www.corsaair.com" );

	// direct to the server
	server.showAddressInfo3( "www.as3lang.org" );

	// more example
	server.showAddressInfo3( "www.google.com" );
	server.showAddressInfo3( "www.yahoo.com" );
	server.showAddressInfo3( "www.cloudflare.com" );

	server.main();
*/

// example2
var server = new SimpleSocketServerSelect2();
	server.main();

update main file

update main file

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


package {
    import flash.display.Sprite;
    import flash.display.StageScaleMode;
    import flash.display.StageAlign;
    import flash.geom.Point;

    import flash.external.ExternalInterface;

    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.media.Camera;
    import flash.media.Video;
    import flash.utils.ByteArray;
    import mx.graphics.codec.JPEGEncoder;

    import flash.events.Event;
    import flash.events.HTTPStatusEvent;
    import flash.events.IOErrorEvent;
    import flash.events.SecurityErrorEvent;
    import flash.net.URLLoader;
    import flash.net.URLRequest;

    public class CameraMan extends Sprite {

        private var videoface:Video;
        private var cam:Camera;
        private var photo:Bitmap;
        private var sendto:String;
        private var movieSize:Point;

        public function CameraMan() {
            stage.addEventListener(Event.RESIZE, configureCamera);
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;

            trace("START ME UP");
            sendto = this.loaderInfo.parameters.sendto;
            configureCamera(null);

            if (ExternalInterface.available) {
                ExternalInterface.addCallback("takePhoto", takePhoto);
                ExternalInterface.addCallback("sendPhoto", sendPhoto);
                ExternalInterface.addCallback("dropPhoto", dropPhoto);
            }
        }

        public function awesome(event:Event) : void {
            trace("~~ AWESOME " + event.target.muted);
        }

        public function createCamera(event:Event) : void {
            cam = Camera.getCamera();

            // TODO: handle a missing camera
            // TODO: handle a "dead" camera (fps = 0?)
            /* TODO: handle a muted camera? we'll only get an
             * unmuted camera to start with if they've chosen to
             * Remember Allow. If they haven't chosen Remember Deny,
             * they'll automatically get a dialog from attachCamera()
             * later.
             */

            cam.addEventListener("status", awesome);
            trace("got camera " + cam.name + ". muted: " + cam.muted
                + '. size: ' + cam.width + ',' + cam.height + '. fps: '
                + cam.currentFPS + '. max fps: ' + cam.fps + ' total cameras: ' + Camera.names.length);
            cam.setMode(stage.stageWidth, stage.stageHeight, 15);

            videoface = new Video(cam.width, cam.height);
            videoface.attachCamera(cam);
            this.addChild(videoface);
        }

        public function configureCamera(event:Event) : void {
            trace("o hai configure camera!!");

            if (stage.stageWidth == 0) {
                trace("stage is zero-width, so skip");
                return;
            }

            if (!cam)
                return this.createCamera(event);

            cam.setMode(stage.stageWidth, stage.stageHeight, 15);
            trace("Camera size is " + cam.width + ", " + cam.height);
            videoface.width = cam.width;
            videoface.height = cam.height;
        }

        public function callback(eventname:String, ... args) : void {
            eventname = "cameraman._" + eventname;
            var callargs:Array = [eventname] + args;
            if (ExternalInterface.available)
                ExternalInterface.call.apply(callargs);
        }

        public function takePhoto() : void {
            // freeze image
            try {
                var photobits:BitmapData = new BitmapData(videoface.videoWidth, videoface.videoHeight, false);
                photobits.draw(videoface);

                // Swap the video for the captured bitmap.
                photo = new Bitmap(photobits);
                this.addChild(photo);
                this.removeChild(videoface);
            } catch(err:Error) {
                trace(err.name + " " + err.message);
            }

            this.callback('tookPhoto');
        }

        public function dropPhoto() : void {
            // cancel the freezing
            try {
                this.removeChild(photo);
                photo = null;

                this.addChild(videoface);
            }
            catch (err:Error) {
                trace(err.name + " " + err.message);
            }

            this.callback('droppedPhoto');
        }

        public function sendPhoto() : void {
            try {
                // produce image file
                var peggy:JPEGEncoder = new JPEGEncoder(75.0);
                var image:ByteArray = peggy.encode(photo.bitmapData);

                // send image file to server
                var req:URLRequest = new URLRequest();
                req.url = this.sendto;
                req.method = "POST";
                req.contentType = peggy.contentType;
                req.data = image;

                var http:URLLoader = new URLLoader();
                http.addEventListener("complete", sentPhoto);
                http.addEventListener("ioError", sendingIOError);
                http.addEventListener("securityError", sendingSecurityError);
                http.addEventListener("httpStatus", sendingHttpStatus);
                http.load(req);
            } catch(err:Error) {
                trace(err.name + " " + err.message);
            }
        }

        public function sendingHttpStatus(event:HTTPStatusEvent) : void {
            trace("HTTPStatus: " + event.status + " " + event.target);
        }

        public function sendingIOError(event:IOErrorEvent) : void {
            trace("IOError: " + event.type + " " + event.text + " " + event.target + " " + event.target.bytesLoaded);
        }

        public function sendingSecurityError(event:SecurityErrorEvent) : void {
            trace("SecurityError: " + event.text + " " + event.target);
        }

        public function sentPhoto(event:Event) : void {
            var url:String = event.target.data;
            this.callback('sentPhoto', url);
        }

    }
}

package {
    import flash.display.Sprite;
    import flash.display.StageScaleMode;
    import flash.display.StageAlign;
    import flash.geom.Point;

    import flash.external.ExternalInterface;

    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.media.Camera;
    import flash.media.Video;
    import flash.utils.ByteArray;
    import mx.graphics.codec.JPEGEncoder;

    import flash.events.Event;
    import flash.events.HTTPStatusEvent;
    import flash.events.IOErrorEvent;
    import flash.events.SecurityErrorEvent;
    import flash.net.URLLoader;
    import flash.net.URLRequest;

    public class CameraMan extends Sprite {

        private var videoface:Video;
        private var cam:Camera;
        private var photo:Bitmap;
        private var cameraid:String;
        private var sendto:String;
        private var movieSize:Point;

        public function CameraMan() {
            stage.addEventListener(Event.RESIZE, configureCamera);
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;

            trace("START ME UP");
            sendto = this.loaderInfo.parameters.sendto;
            cameraid = this.loaderInfo.parameters.cameraid;
            configureCamera(null);

            if (ExternalInterface.available) {
                ExternalInterface.addCallback("takePhoto", takePhoto);
                ExternalInterface.addCallback("sendPhoto", sendPhoto);
                ExternalInterface.addCallback("dropPhoto", dropPhoto);
            }
        }

        public function awesome(event:Event) : void {
            trace("~~ AWESOME " + event.target.muted);
        }

        public function createCamera(event:Event) : void {
            cam = Camera.getCamera();

            // TODO: handle a missing camera
            // TODO: handle a "dead" camera (fps = 0?)
            /* TODO: handle a muted camera? we'll only get an
             * unmuted camera to start with if they've chosen to
             * Remember Allow. If they haven't chosen Remember Deny,
             * they'll automatically get a dialog from attachCamera()
             * later.
             */

            cam.addEventListener("status", awesome);
            trace("got camera " + cam.name + ". muted: " + cam.muted
                + '. size: ' + cam.width + ',' + cam.height + '. fps: '
                + cam.currentFPS + '. max fps: ' + cam.fps + ' total cameras: ' + Camera.names.length);
            cam.setMode(stage.stageWidth, stage.stageHeight, 15);

            videoface = new Video(cam.width, cam.height);
            videoface.attachCamera(cam);
            this.addChild(videoface);
        }

        public function configureCamera(event:Event) : void {
            trace("o hai configure camera!!");

            if (stage.stageWidth == 0) {
                trace("stage is zero-width, so skip");
                return;
            }

            if (!cam)
                return this.createCamera(event);

            cam.setMode(stage.stageWidth, stage.stageHeight, 15);
            trace("Camera size is " + cam.width + ", " + cam.height);
            videoface.width = cam.width;
            videoface.height = cam.height;
        }

        public function callback(eventname:String, ... args) : void {
            eventname = "cameraman.cameras['" + cameraid + "']._" + eventname;
            trace("Calling back to " + eventname + " with: " + args);
            args.unshift(eventname);
            if (ExternalInterface.available)
                ExternalInterface.call.apply(null, args);
        }

        public function takePhoto() : void {
            // freeze image
            try {
                var photobits:BitmapData = new BitmapData(videoface.videoWidth, videoface.videoHeight, false);
                photobits.draw(videoface);

                // Swap the video for the captured bitmap.
                photo = new Bitmap(photobits);
                this.addChild(photo);
                this.removeChild(videoface);
            } catch(err:Error) {
                trace(err.name + " " + err.message);
            }

            this.callback('tookPhoto');
        }

        public function dropPhoto() : void {
            // cancel the freezing
            try {
                this.removeChild(photo);
                photo = null;

                this.addChild(videoface);
            }
            catch (err:Error) {
                trace(err.name + " " + err.message);
            }

            this.callback('droppedPhoto');
        }

        public function sendPhoto() : void {
            try {
                // produce image file
                var peggy:JPEGEncoder = new JPEGEncoder(75.0);
                var image:ByteArray = peggy.encode(photo.bitmapData);

                // send image file to server
                var req:URLRequest = new URLRequest();
                req.url = this.sendto;
                req.method = "POST";
                req.contentType = peggy.contentType;
                req.data = image;

                var http:URLLoader = new URLLoader();
                http.addEventListener("complete", sentPhoto);
                http.addEventListener("ioError", sendingIOError);
                http.addEventListener("securityError", sendingSecurityError);
                http.addEventListener("httpStatus", sendingHttpStatus);
                http.load(req);
            } catch(err:Error) {
                trace(err.name + " " + err.message);
            }
        }

        public function sendingHttpStatus(event:HTTPStatusEvent) : void {
            trace("HTTPStatus: " + event.status + " " + event.target);
        }

        public function sendingIOError(event:IOErrorEvent) : void {
            trace("IOError: " + event.type + " " + event.text + " " + event.target + " " + event.target.bytesLoaded);
            this.callback('errorSending', 'IO error: ' + event.text);
        }

        public function sendingSecurityError(event:SecurityErrorEvent) : void {
            trace("SecurityError: " + event.text + " " + event.target);
            this.callback('errorSending', 'Security error: ' + event.text);
        }

        public function sentPhoto(event:Event) : void {
            var url:String = event.target.data;
            this.callback('sentPhoto', url);
        }

    }
}

Use apply() properly Call back into a particular camera by cameraid Call back out on IO or security error when sending


package {
    import flash.display.Sprite;
    import flash.display.StageScaleMode;
    import flash.display.StageAlign;
    import flash.geom.Point;

    import flash.external.ExternalInterface;

    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.media.Camera;
    import flash.media.Video;
    import flash.utils.ByteArray;
    import mx.graphics.codec.JPEGEncoder;

    import flash.events.Event;
    import flash.events.HTTPStatusEvent;
    import flash.events.IOErrorEvent;
    import flash.events.SecurityErrorEvent;
    import flash.net.URLLoader;
    import flash.net.URLRequest;

    public class CameraMan extends Sprite {

        private var videoface:Video;
        private var cam:Camera;
        private var photo:BitmapData;
        private var sendto:String;
        private var movieSize:Point;

        public function CameraMan() {
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;

            trace("START ME UP");
            this.loaderInfo.addEventListener("init", init);

            if (ExternalInterface.available) {
                ExternalInterface.addCallback("takePhoto", takePhoto);
                ExternalInterface.addCallback("sendPhoto", sendPhoto);
            }
        }

        public function init(event:Event) : void {
            trace("initizing");
            sendto = this.loaderInfo.parameters.sendto;

            movieSize = new Point(this.loaderInfo.width, this.loaderInfo.height);
            trace("Movie size is " + this.loaderInfo.width + ", " + this.loaderInfo.height);

            cam = Camera.getCamera();
            cam.setMode(movieSize.x, movieSize.y, 15);
            trace("Camera size is " + cam.width + ", " + cam.height);

            videoface = new Video(cam.width, cam.height);
            videoface.attachCamera(cam);

            this.addChild(videoface);
        }

        public function takePhoto() : void {
            // freeze image
            try {
                photo = new BitmapData(videoface.videoWidth, videoface.videoHeight, false);
                photo.draw(videoface);

                // Swap the video for the captured bitmap.
                var bitty:Bitmap = new Bitmap(photo);
                this.addChild(bitty);
                this.removeChild(videoface);
            } catch(err:Error) {
                trace(err.name + " " + err.message);
            }

            if (ExternalInterface.available) {
                ExternalInterface.call('cameraman._tookPhoto');
            }
        }

        public function sendPhoto() : void {
            try {
                // produce image file
                var peggy:JPEGEncoder = new JPEGEncoder(75.0);
                var image:ByteArray = peggy.encode(photo);

                // send image file to server
                var req:URLRequest = new URLRequest();
                req.url = this.sendto;
                req.method = "POST";
                req.contentType = peggy.contentType;
                req.data = image;

                var http:URLLoader = new URLLoader();
                http.addEventListener("complete", sentPhoto);
                http.addEventListener("ioError", sendingIOError);
                http.addEventListener("securityError", sendingSecurityError);
                http.addEventListener("httpStatus", sendingHttpStatus);
                http.load(req);
            } catch(err:Error) {
                trace(err.name + " " + err.message);
            }
        }

        public function sendingHttpStatus(event:HTTPStatusEvent) : void {
            trace("HTTPStatus: " + event.status + " " + event.target);
        }

        public function sendingIOError(event:IOErrorEvent) : void {
            trace("IOError: " + event.type + " " + event.text + " " + event.target + " " + event.target.bytesLoaded);
        }

        public function sendingSecurityError(event:SecurityErrorEvent) : void {
            trace("SecurityError: " + event.text + " " + event.target);
        }

        public function sentPhoto(event:Event) : void {
            var url:String = event.target.data;
            if (ExternalInterface.available)
                ExternalInterface.call('cameraman._sentPhoto', url);
        }

    }
}

package {
    import flash.display.Sprite;
    import flash.display.StageScaleMode;
    import flash.display.StageAlign;
    import flash.geom.Point;

    import flash.external.ExternalInterface;

    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.media.Camera;
    import flash.media.Video;
    import flash.utils.ByteArray;
    import mx.graphics.codec.JPEGEncoder;

    import flash.events.Event;
    import flash.events.HTTPStatusEvent;
    import flash.events.IOErrorEvent;
    import flash.events.SecurityErrorEvent;
    import flash.net.URLLoader;
    import flash.net.URLRequest;

    public class CameraMan extends Sprite {

        private var videoface:Video;
        private var cam:Camera;
        private var photo:BitmapData;
        private var sendto:String;
        private var movieSize:Point;

        public function CameraMan() {
            stage.addEventListener(Event.RESIZE, configureCamera);
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;

            trace("START ME UP");
            sendto = this.loaderInfo.parameters.sendto;
            configureCamera(null);

            if (ExternalInterface.available) {
                ExternalInterface.addCallback("takePhoto", takePhoto);
                ExternalInterface.addCallback("sendPhoto", sendPhoto);
            }
        }

        public function awesome(event:Event) : void {
            trace("~~ AWESOME " + event.target.muted);
        }

        public function createCamera(event:Event) : void {
            cam = Camera.getCamera();
            cam.addEventListener("status", awesome);
            trace("got camera " + cam.name + ". muted: " + cam.muted
                + '. size: ' + cam.width + ',' + cam.height + '. fps: '
                + cam.currentFPS + '. max fps: ' + cam.fps + ' total cameras: ' + Camera.names.length);
            cam.setMode(stage.stageWidth, stage.stageHeight, 15);

            videoface = new Video(cam.width, cam.height);
            videoface.attachCamera(cam);
            this.addChild(videoface);
        }

        public function configureCamera(event:Event) : void {
            trace("o hai configure camera!!");

            if (stage.stageWidth == 0) {
                trace("stage is zero-width, so skip");
                return;
            }

            if (!cam)
                return this.createCamera(event);

            cam.setMode(stage.stageWidth, stage.stageHeight, 15);
            trace("Camera size is " + cam.width + ", " + cam.height);
            videoface.width = cam.width;
            videoface.height = cam.height;
        }

        public function takePhoto() : void {
            // freeze image
            try {
                photo = new BitmapData(videoface.videoWidth, videoface.videoHeight, false);
                photo.draw(videoface);

                // Swap the video for the captured bitmap.
                var bitty:Bitmap = new Bitmap(photo);
                this.addChild(bitty);
                this.removeChild(videoface);
            } catch(err:Error) {
                trace(err.name + " " + err.message);
            }

            if (ExternalInterface.available) {
                ExternalInterface.call('cameraman._tookPhoto');
            }
        }

        public function sendPhoto() : void {
            try {
                // produce image file
                var peggy:JPEGEncoder = new JPEGEncoder(75.0);
                var image:ByteArray = peggy.encode(photo);

                // send image file to server
                var req:URLRequest = new URLRequest();
                req.url = this.sendto;
                req.method = "POST";
                req.contentType = peggy.contentType;
                req.data = image;

                var http:URLLoader = new URLLoader();
                http.addEventListener("complete", sentPhoto);
                http.addEventListener("ioError", sendingIOError);
                http.addEventListener("securityError", sendingSecurityError);
                http.addEventListener("httpStatus", sendingHttpStatus);
                http.load(req);
            } catch(err:Error) {
                trace(err.name + " " + err.message);
            }
        }

        public function sendingHttpStatus(event:HTTPStatusEvent) : void {
            trace("HTTPStatus: " + event.status + " " + event.target);
        }

        public function sendingIOError(event:IOErrorEvent) : void {
            trace("IOError: " + event.type + " " + event.text + " " + event.target + " " + event.target.bytesLoaded);
        }

        public function sendingSecurityError(event:SecurityErrorEvent) : void {
            trace("SecurityError: " + event.text + " " + event.target);
        }

        public function sentPhoto(event:Event) : void {
            var url:String = event.target.data;
            if (ExternalInterface.available)
                ExternalInterface.call('cameraman._sentPhoto', url);
        }

    }
}

Set up the camera opportunistically, either in the constructor or on the stage resize event


//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import com.threerings.util.Enum;

public final class DeviceType extends Enum
{
    public static const IPHONE :DeviceType = new DeviceType("IPHONE", "iPhone", "", 480, 320);
    public static const IPHONE_RETINA :DeviceType = new DeviceType("IPHONE_RETINA", "iPhone Retina",
        "@2x", 960, 640);
    public static const IPAD :DeviceType = new DeviceType("IPAD", "iPad", "", 1024, 768);
    public static const IPAD_RETINA :DeviceType = new DeviceType("IPAD_RETINA", "iPad Retina",
        "", 2048, 1536);

    finishedEnumerating(DeviceType);

    public function get displayName () :String { return _displayName; }

    public function get extension () :String { return _extension; }

    public function get resWidth () :int { return _resWidth; }

    public function get resHeight () :int { return _resHeight; }

    public function DeviceType (name :String, displayName :String, extension :String,
        resWidth :int, resHeight :int) {
        super(name);
        _displayName = displayName;
        _extension = extension;
        _resWidth = resWidth;
        _resHeight = resHeight;
    }

    public static function valueOf (name :String) :DeviceType {
        return Enum.valueOf(DeviceType, name) as DeviceType;
    }

    public static function values () :Array { return Enum.values(DeviceType); }

    protected var _displayName :String;
    protected var _extension :String;
    protected var _resWidth :int;
    protected var _resHeight :int;
}
}

//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import com.threerings.util.Enum;

public final class DeviceType extends Enum
{
    public static const IPHONE :DeviceType = new DeviceType("IPHONE", "iPhone", "", 480, 320);
    public static const IPHONE_RETINA :DeviceType = new DeviceType("IPHONE_RETINA", "iPhone Retina",
        "@2x", 960, 640);
    public static const IPAD :DeviceType = new DeviceType("IPAD", "iPad", "", 1024, 768);
    public static const IPAD_RETINA :DeviceType = new DeviceType("IPAD_RETINA", "iPad Retina",
        "", 2048, 1536);
    public static const NOD_TEMP :DeviceType = new DeviceType("NOD_TEMP", "Nod-temp", "", 960*2.67,
        640*2.67);

    finishedEnumerating(DeviceType);

    public function get displayName () :String { return _displayName; }

    public function get extension () :String { return _extension; }

    public function get resWidth () :int { return _resWidth; }

    public function get resHeight () :int { return _resHeight; }

    public function DeviceType (name :String, displayName :String, extension :String,
        resWidth :int, resHeight :int) {
        super(name);
        _displayName = displayName;
        _extension = extension;
        _resWidth = resWidth;
        _resHeight = resHeight;
    }

    public static function valueOf (name :String) :DeviceType {
        return Enum.valueOf(DeviceType, name) as DeviceType;
    }

    public static function values () :Array { return Enum.values(DeviceType); }

    protected var _displayName :String;
    protected var _extension :String;
    protected var _resWidth :int;
    protected var _resHeight :int;
}
}

add a very temporary Nod-specific DeviceType

DeviceType is going to be ripped out soon and replaced with a more
flexible scaling system.


package aerys.minko.render.shader.part.phong
{
	import aerys.minko.ns.minko_lighting;
	import aerys.minko.render.geometry.stream.format.VertexComponent;
	import aerys.minko.render.material.basic.BasicProperties;
	import aerys.minko.render.material.phong.PhongProperties;
	import aerys.minko.render.shader.SFloat;
	import aerys.minko.render.shader.Shader;
	import aerys.minko.render.shader.part.ParallaxMappingShaderPart;
	import aerys.minko.render.shader.part.ShaderPart;
	import aerys.minko.render.shader.part.animation.VertexAnimationShaderPart;
	import aerys.minko.scene.data.LightDataProvider;
	import aerys.minko.type.enum.NormalMappingType;
	import aerys.minko.type.enum.SamplerFiltering;
	import aerys.minko.type.enum.SamplerMipMapping;
	import aerys.minko.type.enum.TriangleCulling;

	public class LightAwareShaderPart extends ShaderPart
	{
		use namespace minko_lighting;

		private var _vertexAnimationShaderPart	: VertexAnimationShaderPart;
		private var _parallaxMappingShaderPart	: ParallaxMappingShaderPart;

		private function get vertexAnimationShaderPart() : VertexAnimationShaderPart
		{
			_vertexAnimationShaderPart ||= new VertexAnimationShaderPart(main);
			return _vertexAnimationShaderPart;
		}

		private function get parallaxMappingShaderPart() : ParallaxMappingShaderPart
		{
			_parallaxMappingShaderPart ||= new ParallaxMappingShaderPart(main);
			return _parallaxMappingShaderPart;
		}

		protected function get vsLocalPosition() : SFloat
		{
			return vertexAnimationShaderPart.getAnimatedVertexPosition();
		}

		protected function get fsLocalPosition() : SFloat
		{
			return interpolate(vsLocalPosition);
		}

		protected function get fsUV() : SFloat
		{
			var result : SFloat = getVertexAttribute(VertexComponent.UV);

			if (meshBindings.propertyExists(BasicProperties.UV_SCALE))
				result.scaleBy(meshBindings.getParameter(BasicProperties.UV_SCALE, 2));

			if (meshBindings.propertyExists(BasicProperties.UV_OFFSET))
				result.incrementBy(meshBindings.getParameter(BasicProperties.UV_OFFSET, 2));

			result = interpolate(result.xy);

			var normalMappingType : uint = meshBindings.getConstant(
				PhongProperties.NORMAL_MAPPING_TYPE, NormalMappingType.NONE
			);

			switch (normalMappingType)
			{
				case NormalMappingType.NONE:
				case NormalMappingType.NORMAL:
					return result;

				case NormalMappingType.PARALLAX:
					return parallaxMappingShaderPart.getSteepParallaxMappedUV(result);

				default:
					throw new Error('Unknown normal mapping type.');
			}
		}

		protected function get vsWorldPosition() : SFloat
		{
			return localToWorld(vsLocalPosition);
		}

		protected function get fsWorldPosition() : SFloat
		{
			return interpolate(vsWorldPosition);
		}

		protected function get vsLocalNormal() : SFloat
		{
			return vertexAnimationShaderPart.getAnimatedVertexNormal();
		}

		protected function get vsWorldNormal() : SFloat
		{
			var v : SFloat = deltaLocalToWorld(vsLocalNormal);
			return normalize(v.xyz);
		}

		protected function get fsLocalNormal() : SFloat
		{
			return normalize(interpolate(vsLocalNormal));
		}

		protected function get fsWorldNormal() : SFloat
		{
			return normalize(interpolate(deltaLocalToWorld(vsLocalNormal)));
		}

		protected function get vsLocalTangent() : SFloat
		{
			var vertexTangent : SFloat = vertexAnimationShaderPart.getAnimatedVertexTangent();

			if (meshBindings.getConstant(BasicProperties.TRIANGLE_CULLING, TriangleCulling.BACK) != TriangleCulling.BACK)
				vertexTangent.negate();

			return vertexTangent;
		}

		protected function get fsLocalTangent() : SFloat
		{
			return interpolate(fsLocalTangent);
		}

		protected function get fsTangentNormal() : SFloat
		{
			var normalMappingType : uint = meshBindings.getConstant(
                PhongProperties.NORMAL_MAPPING_TYPE,
                NormalMappingType.NONE
            );

			switch (normalMappingType)
			{
				case NormalMappingType.NONE:
					return normalize(deltaLocalToTangent(fsLocalNormal));

				case NormalMappingType.NORMAL:
				case NormalMappingType.PARALLAX:
					var fsNormalMap	: SFloat = meshBindings.getTextureParameter(
						PhongProperties.NORMAL_MAP,
						meshBindings.getConstant('normalFiltering', SamplerFiltering.LINEAR),
						meshBindings.getConstant('normalMipMapping', SamplerMipMapping.LINEAR)
					);
					var fsPixel		: SFloat = sampleTexture(fsNormalMap, fsUV);

                    fsPixel.scaleBy(2).decrementBy(1);

					return normalize(fsPixel.rgb);

				default:
					throw new Error('Invalid normap mapping type value');
			}
		}

		public function LightAwareShaderPart(main : Shader)
		{
			super(main);
		}

		protected function deltaLocalToTangent(v : SFloat) : SFloat
		{
			var vsLocalNormal	: SFloat = this.vsLocalNormal;
			var vsLocalTangent	: SFloat = this.vsLocalTangent;
			var vsLocalBinormal	: SFloat = crossProduct(vsLocalNormal, vsLocalTangent);

			return float3(
				dotProduct3(v, vsLocalTangent),
				dotProduct3(v, vsLocalBinormal),
				dotProduct3(v, vsLocalNormal)
			);
		}

		protected function deltaWorldToTangent(v : SFloat) : SFloat
		{
			return deltaLocalToTangent(deltaWorldToLocal(v));
		}

		protected function lightPropertyExists(lightId : uint, name : String) : Boolean
		{
			return sceneBindings.propertyExists(
				LightDataProvider.getLightPropertyName(name, lightId)
			);
		}

		protected function getLightConstant(lightId         : uint,
                                            name            : String,
                                            defaultValue    : Object = null) : *
		{
			return sceneBindings.getConstant(
				LightDataProvider.getLightPropertyName(name, lightId),
				defaultValue
			);
		}

		protected function getLightParameter(lightId : uint, name : String, size : uint) : SFloat
		{
			return sceneBindings.getParameter(
				LightDataProvider.getLightPropertyName(name, lightId),
				size
			);
		}

		protected function getLightTextureParameter(lightId		: uint,
													name		: String,
													filter		: uint = 1,
													mipmap		: uint = 0,
													wrapping	: uint = 1,
													dimension	: uint = 0) : SFloat
		{
			return sceneBindings.getTextureParameter(
				LightDataProvider.getLightPropertyName(name, lightId),
				filter,
				mipmap,
				wrapping,
				dimension
			);
		}

	}
}

fix coding style

fix coding style


package dolly.utils {
import dolly.core.dolly_internal;

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

import org.flexunit.assertThat;
import org.flexunit.asserts.assertEquals;
import org.flexunit.asserts.assertFalse;
import org.flexunit.asserts.assertNotNull;
import org.flexunit.asserts.assertTrue;
import org.hamcrest.collection.array;
import org.hamcrest.collection.arrayWithSize;
import org.hamcrest.collection.everyItem;
import org.hamcrest.core.isA;
import org.hamcrest.object.equalTo;

use namespace dolly_internal;

public class PropertyUtilTests {

	private var sourceObj:Object;
	private var targetObj:Object;

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

		targetObj = {};
	}

	[After]
	public function after():void {
		sourceObj = targetObj = null;
	}

	[Test]
	public function copyingOfArray():void {
		PropertyUtil.copyArray(sourceObj, targetObj, "array");

		assertThat(targetObj.array, arrayWithSize(5));
		assertThat(targetObj.array, sourceObj.array);
		assertTrue(targetObj.array != sourceObj.array);
		assertThat(targetObj.array, everyItem(isA(Number)));
		assertThat(targetObj.array, array(equalTo(0), equalTo(1), equalTo(2), equalTo(3), equalTo(4)));
	}

	[Test]
	public function copyingOfArrayList():void {
		PropertyUtil.copyArrayList(sourceObj, targetObj, "arrayList");

		const targetArrayList:ArrayList = targetObj.arrayList;

		assertNotNull(targetArrayList);
		assertFalse(targetObj.arrayList == sourceObj.arrayList);
		assertEquals(targetArrayList.length, 5);
		assertEquals(targetArrayList.getItemAt(0), 0);
		assertEquals(targetArrayList.getItemAt(1), 1);
		assertEquals(targetArrayList.getItemAt(2), 2);
		assertEquals(targetArrayList.getItemAt(3), 3);
		assertEquals(targetArrayList.getItemAt(4), 4);
	}
}
}

package dolly.utils {
import dolly.core.dolly_internal;

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

import org.flexunit.assertThat;
import org.flexunit.asserts.assertEquals;
import org.flexunit.asserts.assertFalse;
import org.flexunit.asserts.assertNotNull;
import org.flexunit.asserts.assertTrue;
import org.hamcrest.collection.array;
import org.hamcrest.collection.arrayWithSize;
import org.hamcrest.collection.everyItem;
import org.hamcrest.core.isA;
import org.hamcrest.object.equalTo;

use namespace dolly_internal;

public class PropertyUtilTests {

	private var sourceObj:Object;
	private var targetObj:Object;

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

		targetObj = {};
	}

	[After]
	public function after():void {
		sourceObj = targetObj = null;
	}

	[Test]
	public function copyingOfArray():void {
		PropertyUtil.copyArray(sourceObj, targetObj, "array");

		assertThat(targetObj.array, arrayWithSize(5));
		assertThat(targetObj.array, sourceObj.array);
		assertTrue(targetObj.array != sourceObj.array);
		assertThat(targetObj.array, everyItem(isA(Number)));
		assertThat(targetObj.array, array(equalTo(0), equalTo(1), equalTo(2), equalTo(3), equalTo(4)));
	}

	[Test]
	public function copyingOfArrayList():void {
		PropertyUtil.copyArrayList(sourceObj, targetObj, "arrayList");

		const targetArrayList:ArrayList = targetObj.arrayList;

		assertNotNull(targetArrayList);
		assertFalse(targetObj.arrayList == sourceObj.arrayList);
		assertEquals(targetArrayList.length, 5);
		assertEquals(targetArrayList.getItemAt(0), 0);
		assertEquals(targetArrayList.getItemAt(1), 1);
		assertEquals(targetArrayList.getItemAt(2), 2);
		assertEquals(targetArrayList.getItemAt(3), 3);
		assertEquals(targetArrayList.getItemAt(4), 4);
	}

	[Test]
	public function copyingOfArrayCollection():void {
		PropertyUtil.copyArrayCollection(sourceObj, targetObj, "arrayCollection");

		const targetArrayCollection:ArrayCollection = targetObj.arrayCollection;

		assertNotNull(targetArrayCollection);
		assertFalse(targetObj.arrayList == sourceObj.arrayList);
		assertEquals(targetArrayCollection.length, 5);
		assertEquals(targetArrayCollection.getItemAt(0), 0);
		assertEquals(targetArrayCollection.getItemAt(1), 1);
		assertEquals(targetArrayCollection.getItemAt(2), 2);
		assertEquals(targetArrayCollection.getItemAt(3), 3);
		assertEquals(targetArrayCollection.getItemAt(4), 4);
	}
}
}

Test for PropertyUtil.copyArrayCollection() method.


/* 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/. */

include "corsaair/server/spitfire/SimpleSocketServer.as";
include "corsaair/server/spitfire/SimpleSocketServerSelect.as";
include "corsaair/server/spitfire/SimpleSocketServerSelect2.as";

import corsaair.server.spitfire.*;

// example1
/*
var server = new SimpleSocketServer();
    server.main();
*/

// example2
/*
var server = new SimpleSocketServerSelect();
	server.showAddressInfo1();
	server.showAddressInfo2();
	server.showAddressInfo3();
	server.showAddressInfo3( "localhost" );

	// pass trough cloudflare
	server.showAddressInfo3( "www.corsaair.com" );

	// direct to the server
	server.showAddressInfo3( "www.as3lang.org" );

	// more example
	server.showAddressInfo3( "www.google.com" );
	server.showAddressInfo3( "www.yahoo.com" );
	server.showAddressInfo3( "www.cloudflare.com" );

	server.main();
*/

// example2
var server = new SimpleSocketServerSelect2();
	server.main();

/* 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/. */

include "corsaair/server/spitfire/SimpleSocketServer.as";
include "corsaair/server/spitfire/SimpleSocketServerSelect.as";
include "corsaair/server/spitfire/SimpleSocketServerSelect2.as";

import corsaair.server.spitfire.*;

// example1
/*
var server = new SimpleSocketServer();
    server.main();
*/

// example2
/*
var server = new SimpleSocketServerSelect();
    server.showAddressInfo1();
    server.showAddressInfo2();
    server.showAddressInfo3();
    server.showAddressInfo3( "localhost" );

    // pass trough cloudflare
    server.showAddressInfo3( "www.corsaair.com" );

    // direct to the server
    server.showAddressInfo3( "www.as3lang.org" );

    // more example
    server.showAddressInfo3( "www.google.com" );
    server.showAddressInfo3( "www.yahoo.com" );
    server.showAddressInfo3( "www.cloudflare.com" );

    server.main();
*/

// example3
var server = new SimpleSocketServerSelect2();
    server.main();

update main file

update main file

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


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

class idiomesAnimation extends Movieclip
        {

  private var arrayLang_arr:Array = new Array ("cat", "es", "en", "fr");

			function idiomesAnimation():Void
		{

			this.onEnterFrame = this.enterSlide;

		}

	private function enterSlide()
                {

			arrayLang_arr[0].slideTo('0', '-40', 0.6, 'easeInOutBack', 1);
			arrayLang_arr[1].slideTo('0', '-40', 0.8, 'easeInOutBack', 1.1);
			arrayLang_arr[2].slideTo('0', '-40', 0.9, 'easeInOutBack', 1.2);
			arrayLang_arr[3].slideTo('0', '-40', 1, 'easeInOutBack', 1.3);

			return this;

		}

	public function IdiomesColour()
		{

			this.onRelease = this arrayColour;

			target = this.arrayLang_arr[i];
			target._tint = 0x8DC60D;

			return this;

		}

	private function arrayColour()
		{

			for ( var:i ; arrayLang_arr[i] <4; i++)
			{
				this.colorTo("#628D22", 0.3, "easeOutCirc");
				_parent.colorTo('#4b4b4b', 1, 'linear', .2);

			}

		}

	}

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

class idiomesAnimation extends Movieclip
        {

  private var arrayLang_arr:Array = new Array ("cat", "es", "en", "fr");

			function idiomesAnimation():Void
		{

			this.onEnterFrame = this.enterSlide;

		}

	private function onSlideIN()
		{
			this.stop();
			this.onEnterFrame = this.enterSlide;

		}

	private function enterSlide()
                {

			arrayLang_arr[0].slideTo('0', '-40', 0.6, 'easeInOutBack', 1);
			arrayLang_arr[1].slideTo('0', '-40', 0.8, 'easeInOutBack', 1.1);
			arrayLang_arr[2].slideTo('0', '-40', 0.9, 'easeInOutBack', 1.2);
			arrayLang_arr[3].slideTo('0', '-40', 1, 'easeInOutBack', 1.3);

		}

	public function IdiomesColour()
		{

			this.onRelease = this arrayColour;

			target = this.arrayLang_arr[i];
			target._tint = 0x8DC60D;

			return this;

		}

	private function arrayColour()
		{

			for ( var:i ; arrayLang_arr[i] <4; i++)
			{
				this.colorTo("#628D22", 0.3, "easeOutCirc");
				_parent.colorTo('#4b4b4b', 1, 'linear', .2);

			}

		}

	}

Update idiomesAnimation.as

Update idiomesAnimation.as


shared class Player: ScriptObject
{
	float RestingFriction;
	float MovingFriction;

	float pitch_;
	float yaw_;
	Node@ cameraMount_;

	Vector3 debugDirection_;

	Player()
	{
		pitch_ = 0.0f;
		yaw_ = 0.0f;
		RestingFriction = MovingFriction = 2.0f;
	}

	void Start()
	{
		SubscribeToEvent("KeyDown", "HandleKeyDown");
		SubscribeToEvent("PostRenderUpdate", "HandlePostRenderUpdate");
	}

	void DelayedStart()
	{
		cameraMount_ = node.GetChild("CameraMount", true);
	}

	void Update(float timestep)
	{
		const float MOVEMENT_STRENGTH = 20.0f;
		const float MOUSE_SENSITIVITY = 0.1f;

		IntVector2 mouseMove = input.mouseMove;
		yaw_ += MOUSE_SENSITIVITY * mouseMove.x;
		pitch_ += MOUSE_SENSITIVITY * mouseMove.y;
		pitch_ = Clamp(pitch_, -15.0f, 15.0f);
		cameraMount_.rotation = Quaternion(pitch_, yaw_, 0.0f);

		Vector3 direction = Vector3::ZERO;
		if (input.keyDown[KEY_W] || input.keyDown[KEY_UP])
		{
			direction += Vector3::FORWARD;
		}
		if (input.keyDown[KEY_S] || input.keyDown[KEY_DOWN])
		{
			direction += Vector3::BACK;
		}
		if (input.keyDown[KEY_A] || input.keyDown[KEY_LEFT])
		{
			direction += Vector3::LEFT;
		}
		if (input.keyDown[KEY_D] || input.keyDown[KEY_RIGHT])
		{
			direction += Vector3::RIGHT;
		}

		RigidBody@ rigidBody = node.GetComponent("RigidBody");
		if (direction != Vector3::ZERO)
		{
			Quaternion dirRotation = Quaternion(0.0f, yaw_, 0.0f);
			direction = dirRotation * direction;
			debugDirection_ = direction;
			direction *= MOVEMENT_STRENGTH;

			rigidBody.friction = MovingFriction;
			rigidBody.ApplyForce(direction);
		}
		else
		{
			rigidBody.friction = RestingFriction;
		}

	}

	void Save(Serializer& serializer)
	{
		serializer.WriteFloat(MovingFriction);
		serializer.WriteFloat(RestingFriction);
	}

	void Load(Deserializer& deserializer)
	{
		MovingFriction = deserializer.ReadFloat();
		RestingFriction = deserializer.ReadFloat();
	}

	void Stop()
	{
	}

	void HandleKeyDown(StringHash type, VariantMap& data)
	{
		if (data["Key"] == KEY_ESCAPE)
		{
			engine.Exit();
		}
	}

	void HandlePostRenderUpdate(StringHash type, VariantMap& data)
	{
		if (input.keyDown[KEY_P])
		{
			DebugRenderer@ debugRenderer = node.scene.GetComponent("DebugRenderer");
			PhysicsWorld@ world = node.scene.GetComponent("PhysicsWorld");

			Vector3 origin = node.position + Vector3::UP;
			Vector3 target = node.position + debugDirection_ * 2 + Vector3::UP;

			debugRenderer.AddLine(origin, target, Color(1.0, 0, 0));
			world.DrawDebugGeometry(debugRenderer, true);
		}
	}
}

shared class Player: ScriptObject
{
	float RestingFriction;
	float MovingFriction;

	float pitch_;
	float yaw_;
	Quaternion modelRotation_;
	Node@ cameraMountNode_;
	Node@ modelNode_;

	Vector3 debugDirection_;

	Player()
	{
		pitch_ = 0.0f;
		yaw_ = 0.0f;
		RestingFriction = MovingFriction = 2.0f;
	}

	void Start()
	{
		SubscribeToEvent("KeyDown", "HandleKeyDown");
		SubscribeToEvent("PostRenderUpdate", "HandlePostRenderUpdate");
	}

	void DelayedStart()
	{
		cameraMountNode_ = node.GetChild("CameraMount", true);
		modelNode_ = node.GetChild("Model", true);
		modelRotation_ = modelNode_.rotation;
	}

	void Update(float timestep)
	{
		const float MOVEMENT_STRENGTH = 20.0f;
		const float MOVEMENT_MARGIN = 0.1f;
		const float MOUSE_SENSITIVITY = 0.1f;

		IntVector2 mouseMove = input.mouseMove;
		yaw_ += MOUSE_SENSITIVITY * mouseMove.x;
		pitch_ += MOUSE_SENSITIVITY * mouseMove.y;
		pitch_ = Clamp(pitch_, -15.0f, 15.0f);
		cameraMountNode_.rotation = Quaternion(pitch_, yaw_, 0.0f);

		Vector3 direction = Vector3::ZERO;
		if (input.keyDown[KEY_W] || input.keyDown[KEY_UP])
		{
			direction += Vector3::FORWARD;
		}
		if (input.keyDown[KEY_S] || input.keyDown[KEY_DOWN])
		{
			direction += Vector3::BACK;
		}
		if (input.keyDown[KEY_A] || input.keyDown[KEY_LEFT])
		{
			direction += Vector3::LEFT;
		}
		if (input.keyDown[KEY_D] || input.keyDown[KEY_RIGHT])
		{
			direction += Vector3::RIGHT;
		}

		RigidBody@ rigidBody = node.GetComponent("RigidBody");
		if (direction != Vector3::ZERO)
		{
			Quaternion dirRotation = Quaternion(0.0f, yaw_, 0.0f);
			direction = dirRotation * direction;
			debugDirection_ = direction;
			direction *= MOVEMENT_STRENGTH;

			rigidBody.friction = MovingFriction;
			rigidBody.ApplyForce(direction);
		}
		else
		{
			rigidBody.friction = RestingFriction;
		}

		if (rigidBody.linearVelocity.lengthSquared > MOVEMENT_MARGIN)
		{
			Vector3 lateralVelocity = Vector3(rigidBody.linearVelocity.x, 0, rigidBody.linearVelocity.z);
			Quaternion lateralRotation;
			lateralRotation.FromLookRotation(lateralVelocity, Vector3::UP);
			lateralRotation = lateralRotation * modelRotation_;
			modelNode_.rotation = modelNode_.rotation.Nlerp(lateralRotation, 0.3, true);
		}
	}

	void Save(Serializer& serializer)
	{
		serializer.WriteFloat(MovingFriction);
		serializer.WriteFloat(RestingFriction);
	}

	void Load(Deserializer& deserializer)
	{
		MovingFriction = deserializer.ReadFloat();
		RestingFriction = deserializer.ReadFloat();
	}

	void Stop()
	{
	}

	void HandleKeyDown(StringHash type, VariantMap& data)
	{
		if (data["Key"] == KEY_ESCAPE)
		{
			engine.Exit();
		}
	}

	void HandlePostRenderUpdate(StringHash type, VariantMap& data)
	{
		if (input.keyDown[KEY_P])
		{
			DebugRenderer@ debugRenderer = node.scene.GetComponent("DebugRenderer");
			PhysicsWorld@ world = node.scene.GetComponent("PhysicsWorld");

			Vector3 origin = node.position + Vector3::UP;
			Vector3 moveTarget = origin + debugDirection_ * 2;
			Vector3 faceTarget = (modelNode_.rotation * Vector3::FORWARD) * 3 + origin;

			debugRenderer.AddLine(origin, faceTarget, Color(0, 1, 0));
			debugRenderer.AddLine(origin, moveTarget, Color(1.0, 0, 0));
			world.DrawDebugGeometry(debugRenderer, true);
		}
	}
}

Add rotation to the player movement

Add rotation to the player movement