##                                                         -*- shell-script -*-
## urbi.as: This file is part of build-aux.
## Copyright (C) Gostai S.A.S., 2006-2008.
##
## This software is provided "as is" without warranty of any kind,
## either expressed or implied, including but not limited to the
## implied warranties of fitness for a particular purpose.
##
## See the LICENSE file for more information.
## For comments, bug reports and feedback: http://www.urbiforge.com
##

m4_pattern_allow([^URBI_SERVER$])

m4_divert_text([URBI-INIT],
[
# check_dir VARIABLE WITNESS
# --------------------------
# Check that VARIABLE contains a directory name that contains WITNESS.
check_dir ()
{
  local var=$[1]
  local witness=$[2]
  local dir
  eval "dir=\$$[1]"
  test x"$dir" != x ||
    fatal "undefined variable: $var"
  shift
  test -e "$dir" ||
    fatal "$var does not exist: $dir" "(pwd = $(pwd))"
  test -d "$dir" ||
    fatal "$var is not a directory: $dir" "(pwd = $(pwd))"
  if test x"$witness" != x; then
    test -f "$dir/$witness" ||
      fatal "$var does not contain $witness: $dir" "(pwd = $(pwd))"
  fi
}

# check_and_abs_dir VAR WITNESS
# -----------------------------
# Check that $VAR/WITNESS exists, and set VAR to $(absolute $VAR).
check_and_abs_dir ()
{
  local var=$[1]
  local witness=$[2]
  check_dir "$[@]"
  # Normalize the directory name, and as safety belts, run the same
  # tests on it.  But save time if possible.  So put in "$@" the dirs
  # to check, the last one being the actual result.
  AS_IF([! is_absolute "$val"],
	[local dir
         eval "dir=\$$[1]"
         dir=$(absolute "$val")
         check_dir "$dir" "$witness"
         eval "$var='$dir'"
         ])
}

# find_srcdir WITNESS
# -------------------
# Find the location of the src directory of the tests suite.
# Make sure the value is correct by checking for the presence of WITNESS.
find_srcdir ()
{
  # Guess srcdir if not defined.
  if test -z "$srcdir"; then
    # Try to compute it from $[0].
    srcdir=$(dirname "$[0]")
  fi

  check_dir srcdir "$[1]"
}

# find_top_builddir [POSSIBILITIES]
# ---------------------------------
# Set/check top_builddir.
# - $top_builddir   if the user wants to define it,
# - (dirname $0)/.. since that's where we are supposed to be
# - ../..           for the common case where we're in tests/my-test.dir
# - ..              if we're in tests/
# - .               if we're in top-builddir.
find_top_builddir ()
{
  if test x"$top_builddir" = x; then
    if test $[#] = 0; then
      set $(dirname "$0")/.. ../.. .. .
    fi
    for d
    do
       if test -f "$d/config.status"; then
	 top_builddir=$d
	 break
       fi
    done
  fi

  check_dir top_builddir "config.status"
}

# find_urbi_server
# ----------------
# Set URBI_SERVER to the location of urbi-server.
find_urbi_server ()
{
  case $URBI_SERVER in
    ('')
       # If URBI_SERVER is not defined, try to find one.  If we are in
       # $top_builddir/tests/TEST.dir, then look in $top_builddir/src.
       URBI_SERVER=$(find_prog "urbi-server" \
			       "$top_builddir/src${PATH_SEPARATOR}.")
       ;;

    (*[[\\/]]*) # A path, relative or absolute.  Make it absolute.
       URBI_SERVER=$(absolute "$URBI_SERVER")
       ;;

    (*) # A simple name, most certainly urbi-server.
       # Find it in the PATH.
       local res
       res=$(find_prog "$URBI_SERVER")
       # If we can't find it, then ucore-pc was probably not installed.
       # Skip.
       test x"$res" != x ||
         error 77 "cannot find $URBI_SERVER in $PATH"
       URBI_SERVER=$res
       ;;
  esac

  if test -z "$URBI_SERVER"; then
    fatal "cannot find urbi-server, please define URBI_SERVER"
  fi

  if test ! -f "$URBI_SERVER"; then
    fatal "cannot find urbi-server, please check \$URBI_SERVER: $URBI_SERVER"
  fi

  # Check its version.
  if ! run "Server version" "$URBI_SERVER" --version >&3; then
    fatal "cannot run $URBI_SERVER --version"
  fi
}

# spawn_urbi_server FLAGS
# -----------------------
# Spawn an $URBI_SERVER in back-ground, registering it as the child "server".
# Wait until the server.port file is created.  Make it fatal if this does
# not happen with 10s.
spawn_urbi_server ()
{
  rm -f server.port
  local flags="--port 0 --port-file server.port $*"
  local cmd="$(instrument "server.val") $URBI_SERVER $flags"
  echo "$cmd" >server.cmd
  $cmd </dev/null >server.out 2>server.err &
  children_register server

  # Wait for the port file to be completed: it must have one full line
  # (with \n to be sure it is complete).
  local t=0
  local tmax=8
  local dt=.5
  while test ! -f server.port || test $(wc -l <server.port) = 0;
  do
    test $t -lt $tmax ||
      fatal "$URBI_SERVER did not issue port in server.port in ${tmax}s"
    sleep $dt
    t=$(($t + $dt))
  done
}
])

##                                                         -*- shell-script -*-
## urbi.as: This file is part of build-aux.
## Copyright (C) Gostai S.A.S., 2006-2008.
##
## This software is provided "as is" without warranty of any kind,
## either expressed or implied, including but not limited to the
## implied warranties of fitness for a particular purpose.
##
## See the LICENSE file for more information.
## For comments, bug reports and feedback: http://www.urbiforge.com
##

m4_pattern_allow([^URBI_SERVER$])

m4_divert_text([URBI-INIT],
[
# check_dir VARIABLE WITNESS
# --------------------------
# Check that VARIABLE contains a directory name that contains WITNESS.
check_dir ()
{
  local var=$[1]
  local witness=$[2]
  local dir
  eval "dir=\$$[1]"
  test x"$dir" != x ||
    fatal "undefined variable: $var"
  shift
  test -e "$dir" ||
    fatal "$var does not exist: $dir" "(pwd = $(pwd))"
  test -d "$dir" ||
    fatal "$var is not a directory: $dir" "(pwd = $(pwd))"
  if test x"$witness" != x; then
    test -f "$dir/$witness" ||
      fatal "$var does not contain $witness: $dir" "(pwd = $(pwd))"
  fi
}

# check_and_abs_dir VAR WITNESS
# -----------------------------
# Check that $VAR/WITNESS exists, and set VAR to $(absolute $VAR).
check_and_abs_dir ()
{
  local var=$[1]
  local witness=$[2]
  check_dir "$[@]"
  # Normalize the directory name, and as safety belts, run the same
  # tests on it.  But save time if possible.  So put in "$@" the dirs
  # to check, the last one being the actual result.
  AS_IF([! is_absolute "$val"],
	[local dir
         eval "dir=\$$[1]"
         dir=$(absolute "$val")
         check_dir "$dir" "$witness"
         eval "$var='$dir'"
         ])
}

# find_srcdir WITNESS
# -------------------
# Find the location of the src directory of the tests suite.
# Make sure the value is correct by checking for the presence of WITNESS.
find_srcdir ()
{
  # Guess srcdir if not defined.
  if test -z "$srcdir"; then
    # Try to compute it from $[0].
    srcdir=$(dirname "$[0]")
  fi

  check_dir srcdir "$[1]"
}

# find_top_builddir [POSSIBILITIES]
# ---------------------------------
# Set/check top_builddir.
# - $top_builddir   if the user wants to define it,
# - (dirname $0)/.. since that's where we are supposed to be
# - ../..           for the common case where we're in tests/my-test.dir
# - ..              if we're in tests/
# - .               if we're in top-builddir.
find_top_builddir ()
{
  if test x"$top_builddir" = x; then
    if test $[#] = 0; then
      set $(dirname "$0")/.. ../.. .. .
    fi
    for d
    do
       if test -f "$d/config.status"; then
	 top_builddir=$d
	 break
       fi
    done
  fi

  check_dir top_builddir "config.status"
}

# find_urbi_server
# ----------------
# Set URBI_SERVER to the location of urbi-server.
find_urbi_server ()
{
  case $URBI_SERVER in
    ('')
       # If URBI_SERVER is not defined, try to find one.  If we are in
       # $top_builddir/tests/TEST.dir, then look in $top_builddir/src.
       URBI_SERVER=$(find_prog "urbi-server" \
			       "$top_builddir/src${PATH_SEPARATOR}.")
       ;;

    (*[[\\/]]*) # A path, relative or absolute.  Make it absolute.
       URBI_SERVER=$(absolute "$URBI_SERVER")
       ;;

    (*) # A simple name, most certainly urbi-server.
       # Find it in the PATH.
       local res
       res=$(find_prog "$URBI_SERVER")
       # If we can't find it, then ucore-pc was probably not installed.
       # Skip.
       test x"$res" != x ||
         error 77 "cannot find $URBI_SERVER in $PATH"
       URBI_SERVER=$res
       ;;
  esac

  if test -z "$URBI_SERVER"; then
    fatal "cannot find urbi-server, please define URBI_SERVER"
  fi

  if test ! -f "$URBI_SERVER"; then
    fatal "cannot find urbi-server, please check \$URBI_SERVER: $URBI_SERVER"
  fi

  # Check its version.
  if ! run "Server version" "$URBI_SERVER" --version >&3; then
    fatal "cannot run $URBI_SERVER --version"
  fi
}

# spawn_urbi_server FLAGS
# -----------------------
# Spawn an $URBI_SERVER in back-ground, registering it as the child "server".
# Wait until the server.port file is created.  Make it fatal if this does
# not happen with 10s.
spawn_urbi_server ()
{
  rm -f server.port
  local flags="--port 0 --port-file server.port $*"
  local cmd="$(instrument "server.val") $URBI_SERVER $flags"
  echo "$cmd" >server.cmd
  $cmd </dev/null >server.out 2>server.err &
  children_register server

  # Wait for the port file to be completed: it must have one full line
  # (with \n to be sure it is complete).
  local t=0
  local tmax=8
  local dt=.5
  while test ! -f server.port || test $(wc -l <server.port) = 0;
  do
    # test/expr don't like floating points.
    case $(echo "$t <= $tmax" | bc) in
      (1) sleep $dt
          t=$(echo "$t + $dt" | bc);;
      (0)
      fatal "$URBI_SERVER did not issue port in server.port in ${tmax}s";;
    esac
  done
}
])

test and expr have problems with floats.

	* build-aux/urbi.as: Use bc instead.


package aerys.minko.scene.controller
{
	import aerys.minko.render.Viewport;
	import aerys.minko.scene.node.ISceneNode;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.type.KeyboardManager;
	import aerys.minko.type.MouseManager;

	import flash.display.BitmapData;

	public class ScriptController extends EnterFrameController
	{
		private var _lastTime		: Number		= 0.0;
		private var _deltaTime		: Number		= 0.0;
		private var _currentTarget	: ISceneNode	= null;
		private var _viewport		: Viewport		= null;

		protected function get deltaTime() : Number
		{
			return _deltaTime;
		}

		protected function get keyboard() : KeyboardManager
		{
			return _viewport.keyboardManager;
		}

		protected function get mouse() : MouseManager
		{
			return _viewport.mouseManager;
		}

		protected function get viewport() : Viewport
		{
			return _viewport;
		}

		public function ScriptController(targetType	: Class = null)
		{
			super(targetType);

			initialize();
		}

		private function initialize() : void
		{
			var numTargets : uint = this.numTargets;

			for (var i : uint = 0; i < numTargets; ++i)
				start(getTarget(i));
		}

		override protected function sceneEnterFrameHandler(scene		: Scene,
														   viewport		: Viewport,
														   destination	: BitmapData,
														   time			: Number) : void
		{
			_viewport = viewport;
			_deltaTime = _lastTime - time;
			_lastTime = time;

			var numTargets : uint = this.numTargets;

			for (var i : uint = 0; i < numTargets; ++i)
				update(getTarget(i));
		}

		protected function start(target : ISceneNode) : void
		{
			// nothing
		}

		protected function update(target : ISceneNode) : void
		{
			// nothing
		}
	}
}

package aerys.minko.scene.controller
{
	import aerys.minko.render.Viewport;
	import aerys.minko.scene.node.ISceneNode;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.type.KeyboardManager;
	import aerys.minko.type.MouseManager;

	import flash.display.BitmapData;

	public class ScriptController extends EnterFrameController
	{
		private var _lastTime		: Number		= 0.0;
		private var _deltaTime		: Number		= 0.0;
		private var _currentTarget	: ISceneNode	= null;
		private var _viewport		: Viewport		= null;

		protected function get deltaTime() : Number
		{
			return _deltaTime;
		}

		protected function get keyboard() : KeyboardManager
		{
			return _viewport.keyboardManager;
		}

		protected function get mouse() : MouseManager
		{
			return _viewport.mouseManager;
		}

		protected function get viewport() : Viewport
		{
			return _viewport;
		}

		public function ScriptController(targetType	: Class = null)
		{
			super(targetType);

			initialize();
		}

		private function initialize() : void
		{
			var numTargets : uint = this.numTargets;

			for (var i : uint = 0; i < numTargets; ++i)
				start(getTarget(i));
		}

		override protected function sceneEnterFrameHandler(scene		: Scene,
														   viewport		: Viewport,
														   destination	: BitmapData,
														   time			: Number) : void
		{
			_viewport = viewport;
			_deltaTime = _lastTime - time;
			_lastTime = time;

			var numTargets : uint = this.numTargets;

			for (var i : uint = 0; i < numTargets; ++i)
				update(getTarget(i));
		}

		override protected function targetRemovedFromSceneHandler(target	: ISceneNode,
																  scene		: Scene) : void
		{
			super.targetRemovedFromSceneHandler(target, scene);

			var numTargets : uint = this.numTargets;

			for (var i : uint = 0; i < numTargets; ++i)
				stop(getTarget(i));
		}

		protected function start(target : ISceneNode) : void
		{
			// nothing
		}

		protected function update(target : ISceneNode) : void
		{
			// nothing
		}

		protected function stop(target : ISceneNode) : void
		{
			// nothing
		}
	}
}

add ScriptController.stop(target), called when the target is removed from the scene


/*
 * Copyright 2011 Ryan Berdeen. All rights reserved.
 * Distributed under the terms of the MIT License.
 * See accompanying file LICENSE.txt
 */

package com.ryanberdeen.echonest.api.v4.track {
  import com.ryanberdeen.echonest.api.v4.ApiSupport;
  import com.ryanberdeen.echonest.api.v4.EchoNestError;

  import flash.events.DataEvent;
  import flash.events.Event;
  import flash.net.FileReference;
  import flash.net.URLLoader;
  import flash.net.URLRequest;
  import flash.net.URLRequestMethod;
  import flash.utils.ByteArray;

  /**
  * Methods to interact with the Echo Nest track API.
  *
  *
All of the API methods in this class accept basically the same
  * parameters. The parameters parameter contains the parameters
  * to pass to the Echo Nest method. For most methods, this will be
  * id or md5.
  * The api_key parameter will always be
  * set.

  *
  *
The loaderOptions parameter contains the event listeners
  * for the loading process. Most importantly, the
  * onResponse method will be called with the
  * results of the API method. See the ApiSupport.createLoader()
  * method for a description of the loader options.

  *
  *
For a description of the response formats, see the various
  * process...Response() methods.

  *
  *
Be sure to set the apiKey property before calling any API
  * methods.

  */
  public class TrackApi extends ApiSupport {
    /**
    * Adds the standard Echo Nest Flash API event listeners to a file
    * reference.
    *
    * @param options The event listener options. See
    *        createLoader() for the list of available options.
    * @param dispatcher The file reference to add the event listeners to.
    */
    public function addFileReferenceEventListeners(options:Object, fileReference:FileReference, responseProcessor:Function, ...responseProcessorArgs):void {
      if (options.onComplete) {
        fileReference.addEventListener(Event.COMPLETE, options.onComplete);
      }

      if (options.onResponse) {
        fileReference.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, function(e:DataEvent):void {
          try {
            var responseObject:* = parseRawResponse(e.data);
            responseProcessorArgs.push(responseObject);
            var response:Object = responseProcessor.apply(responseProcessor, responseProcessorArgs);
            options.onResponse(response);
          }
          catch (e:EchoNestError) {
            if (options.onEchoNestError) {
              options.onEchoNestError(e);
            }
          }
        });
      }

      addEventListeners(options, fileReference);
    }

    /**
    * Processes the response from the upload API method.
    *
    * @param response The response to process.
    *
    * @return The result of processing the response.
    *
    * @see #upload()
    * @see #uploadFileData()
    */
    public function processUploadResponse(response:*):Object {
      return response.track;
    }

    /**
    * Invokes the Echo Nest upload API method with a file
    * reference.
    *
    *
The parameters object must include a track
    * property, which must be a FileReference that may be
    * upload()ed.

    *
    * @param parameters The parameters to include in the API request.
    * @param loaderOptions The event listener options for the loader.
    *
    * @see com.ryanberdeen.echonest.api.v3.ApiSupport#createRequest()
    * @see #processUploadResponse()
    * @see http://developer.echonest.com/docs/v4/track.html#upload
    */
    public function uploadFileReference(parameters:Object, loaderOptions:Object):URLRequest {
      var fileReference:FileReference = parameters.track;
      delete parameters.track;

      addFileReferenceEventListeners(loaderOptions, fileReference, processUploadResponse);
      var request:URLRequest = createRequest('track/upload', parameters);
      fileReference.upload(request, 'track');
      return request;
    }

    /**
    * Invokes the Echo Nest upload API method.
    *
    *
This method is for uploads using the url parameter.
    * To upload a file, use uploadFileReference().
    *
    * @param parameters The parameters to include in the API request.
    * @param loaderOptions The event listener options for the loader.
    *
    * @return The URLLoader being used to perform the API call.
    *
    * @see com.ryanberdeen.echonest.api.v4.ApiSupport#createRequest()
    * @see com.ryanberdeen.echonest.api.v4.ApiSupport#createLoader()
    * @see #processUploadResponse()
    * @see http://developer.echonest.com/docs/v4/track.html#upload
    */
    public function upload(parameters:Object, loaderOptions:Object):URLLoader {
      var request:URLRequest = createRequest('track/upload', parameters);
      request.method = URLRequestMethod.POST;
      var loader:URLLoader = createLoader(loaderOptions, processUploadResponse);
      loader.load(request);
      return loader;
    }
  }
}

/*
 * Copyright 2011 Ryan Berdeen. All rights reserved.
 * Distributed under the terms of the MIT License.
 * See accompanying file LICENSE.txt
 */

package com.ryanberdeen.echonest.api.v4.track {
  import com.adobe.serialization.json.JSON;
  import com.ryanberdeen.echonest.api.v4.ApiSupport;
  import com.ryanberdeen.echonest.api.v4.EchoNestError;

  import flash.events.DataEvent;
  import flash.events.Event;
  import flash.net.FileReference;
  import flash.net.URLLoader;
  import flash.net.URLRequest;
  import flash.net.URLRequestMethod;
  import flash.utils.ByteArray;

  /**
  * Methods to interact with the Echo Nest track API.
  *
  *
All of the API methods in this class accept basically the same
  * parameters. The parameters parameter contains the parameters
  * to pass to the Echo Nest method. For most methods, this will be
  * id or md5.
  * The api_key parameter will always be
  * set.

  *
  *
The loaderOptions parameter contains the event listeners
  * for the loading process. Most importantly, the
  * onResponse method will be called with the
  * results of the API method. See the ApiSupport.createLoader()
  * method for a description of the loader options.

  *
  *
For a description of the response formats, see the various
  * process...Response() methods.

  *
  *
Be sure to set the apiKey property before calling any API
  * methods.

  */
  public class TrackApi extends ApiSupport {
    /**
    * Adds the standard Echo Nest Flash API event listeners to a file
    * reference.
    *
    * @param options The event listener options. See
    *        createLoader() for the list of available options.
    * @param dispatcher The file reference to add the event listeners to.
    */
    public function addFileReferenceEventListeners(options:Object, fileReference:FileReference, responseProcessor:Function, ...responseProcessorArgs):void {
      // TODO document
      if (options.onOpen) {
        fileReference.addEventListener(Event.OPEN, options.onOpen);
      }

      if (options.onComplete) {
        fileReference.addEventListener(Event.COMPLETE, options.onComplete);
      }

      if (options.onResponse) {
        fileReference.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, function(e:DataEvent):void {
          try {
            var responseObject:* = parseRawResponse(e.data);
            responseProcessorArgs.push(responseObject);
            var response:Object = responseProcessor.apply(responseProcessor, responseProcessorArgs);
            options.onResponse(response);
          }
          catch (e:EchoNestError) {
            if (options.onEchoNestError) {
              options.onEchoNestError(e);
            }
          }
        });
      }

      addEventListeners(options, fileReference);
    }

    public function loadAnalysis(track:Object, loaderOptions:Object):URLLoader {
      var loader:URLLoader = new URLLoader();

      if (loaderOptions.onComplete) {
        loader.addEventListener(Event.COMPLETE, loaderOptions.onComplete);
      }

      if (loaderOptions.onResponse) {
        loader.addEventListener(Event.COMPLETE, function(e:Event):void {
          var analysis:Object = JSON.decode(loader.data);
          loaderOptions.onResponse(analysis);
        });
      }

      addEventListeners(loaderOptions, loader);

      var request:URLRequest = new URLRequest();
      request.url = track.audio_summary.analysis_url;
      loader.load(request);
      return loader;
    }

    /**
    * Processes the response from the upload API method.
    *
    * @param response The response to process.
    *
    * @return The result of processing the response.
    *
    * @see #upload()
    * @see #uploadFileData()
    */
    public function processUploadResponse(response:*):Object {
      return response.track;
    }

    /**
    * Invokes the Echo Nest upload API method with a file
    * reference.
    *
    *
The parameters object must include a track
    * property, which must be a FileReference that may be
    * upload()ed.

    *
    * @param parameters The parameters to include in the API request.
    * @param loaderOptions The event listener options for the loader.
    *
    * @see com.ryanberdeen.echonest.api.v3.ApiSupport#createRequest()
    * @see #processUploadResponse()
    * @see http://developer.echonest.com/docs/v4/track.html#upload
    */
    public function uploadFileReference(parameters:Object, loaderOptions:Object):URLRequest {
      var fileReference:FileReference = parameters.track;
      delete parameters.track;

      addFileReferenceEventListeners(loaderOptions, fileReference, processUploadResponse);
      var request:URLRequest = createRequest('track/upload', parameters);
      fileReference.upload(request, 'track');
      return request;
    }

    /**
    * Invokes the Echo Nest upload API method.
    *
    *
This method is for uploads using the url parameter.
    * To upload a file, use uploadFileReference().
    *
    * @param parameters The parameters to include in the API request.
    * @param loaderOptions The event listener options for the loader.
    *
    * @return The URLLoader being used to perform the API call.
    *
    * @see com.ryanberdeen.echonest.api.v4.ApiSupport#createRequest()
    * @see com.ryanberdeen.echonest.api.v4.ApiSupport#createLoader()
    * @see #processUploadResponse()
    * @see http://developer.echonest.com/docs/v4/track.html#upload
    */
    public function upload(parameters:Object, loaderOptions:Object):URLLoader {
      var request:URLRequest = createRequest('track/upload', parameters);
      request.method = URLRequestMethod.POST;
      var loader:URLLoader = createLoader(loaderOptions, processUploadResponse);
      loader.load(request);
      return loader;
    }
  }
}

add method to download track analysis

add method to download track analysis


//
// Flump - Copyright 2012 Three Rings Design

package flump.test {

import flash.events.TimerEvent;
import flash.utils.Timer;

import flump.display.Movie;
import flump.display.StarlingResources;
import flump.executor.Finisher;

import com.threerings.util.F;

public class RuntimePlaybackTest
{
    public static function addTests (runner :TestRunner, res :StarlingResources) :void {
        runner.run("Goto frame and label", new RuntimePlaybackTest(runner, res).gotoFrameAndLabel);
        runner.runAsync("Play, stop, loop", new RuntimePlaybackTest(runner, res).playStopLoop);
        runner.runAsync("Stop, play", new RuntimePlaybackTest(runner, res).stopPlay);
        runner.runAsync("Play when added", new RuntimePlaybackTest(runner, res).playWhenAdded);
        runner.runAsync("Play once", new RuntimePlaybackTest(runner, res).playOnce);
        runner.runAsync("Pause while removed", new RuntimePlaybackTest(runner, res).pauseWhileRemoved);
    }

    public function RuntimePlaybackTest (runner :TestRunner, res :StarlingResources) {
        _runner = runner;
        _res = res;
    }

    protected function setup (finisher :Finisher) :void {
        _finisher = finisher;
        _movie = _res.loadMovie("nesteddance");
        assert(_movie.frame == 0, "Frame starts at 0");
        assert(_movie.isPlaying, "Movie starts out playing");
        _runner.addChild(_movie);
        _movie.labelPassed.add(_labelsPassed.push);
    }

    public function gotoFrameAndLabel () :void {
        _movie = _res.loadMovie("nesteddance");
        _movie.goto("timepassed");
        assert(_movie.frame == 9);
        assert(_movie.isPlaying, "Playing changed in goto");

        _movie.stop();
        _movie.goto(_movie.frame + 1);
        assert(_movie.frame == 10);
        assert(!_movie.isPlaying, "Stopped changed in goto");

        assertThrows(F.callback(_movie.goto, _movie.frames), "Went past frames");
        assertThrows(F.callback(_movie.goto, "nonexistent label"), "Went to nonexistent label");
    }

    public function playWhenAdded (finisher :Finisher) :void {
        setup(finisher);
        delayForAtLeastOneFrame(checkAdvanced);
    }

    public function checkAdvanced () :void {
        assert(_movie.frame > 0, "Frame advances with time");
        delayForOnePlaythrough(checkAllLabelsFired);
    }

    public function checkAllLabelsFired () :void {
        _runner.removeChild(_movie);
        passedAllLabels();
        _finisher.succeed();
    }

    public function playOnce (finisher :Finisher) :void {
        setup(finisher);
        _movie.goto(0).play();
        delayForOnePlaythrough(checkPlayOnce);
    }

    public function checkPlayOnce () :void {
        passedAllLabels();
        assert(_labelsPassed.length == 4, "Only pass the labels once");
        assert(_movie.frame == _movie.frames - 1, "Play once stops at last frame");
        _runner.removeChild(_movie);
        _finisher.succeed();
    }

    public function pauseWhileRemoved (finisher :Finisher) :void {
        setup(finisher);
        delayForAtLeastOneFrame(checkAdvancedToRemove);
    }

    public function checkAdvancedToRemove () :void {
       assert(_movie.frame > 0, "Playing initially");
       assert(_labelsPassed.length == 0, "Passed labels initially?");
       _runner.removeChild(_movie);
       delayForOnePlaythrough(checkNotAdvancedWhileRemoved);
    }

    public function checkNotAdvancedWhileRemoved () :void {
        assert(_labelsPassed.length == 0, "Labels passed while removed?");
        _runner.addChild(_movie);
        delayForOnePlaythrough(checkAllLabelsFired);
    }

    public function stopPlay (finisher :Finisher) :void {
        setup(finisher);
        _movie.stop();
        delayForAtLeastOneFrame(checkNotAdvancedWhileStopped);
    }

    public function checkNotAdvancedWhileStopped () :void {
        assert(_movie.frame == 0, "Frame advanced passed while stopped?");
        _movie.goto(Movie.FIRST_FRAME).playTo("timepassed");
        delayForOnePlaythrough(checkPlayedToTimePassed);
    }

    public function checkPlayedToTimePassed () :void {
        passed(Movie.FIRST_FRAME);
        passed("timepassed");
        assert(_labelsPassed.length == 2, "Should stop at timepassed: " + _labelsPassed);
        _runner.removeChild(_movie);
        _finisher.succeed();
    }

    public function playStopLoop (finisher :Finisher) :void {
        setup(finisher);
        _movie.goto(10).play().stop().loop();
        assert(_movie.frame == 10, "Play stop or loop changed the frame");
        delayFor(2.6, checkDoublePass);
    }

    public function checkDoublePass () :void {
        passedAllLabels();
        assert(_labelsPassed.length >= 8);
        _runner.removeChild(_movie);
        _finisher.succeed();
    }

    public function passedAllLabels () :void {
        passed("timepassed");
        passed("moretimepassed");
        passed(Movie.LAST_FRAME);
        passed(Movie.FIRST_FRAME);
    }

    protected function passed (label :String) :void {
        assert(_labelsPassed.indexOf(label) != -1, "Should've passed " + label);
    }

    protected function delayForOnePlaythrough (then :Function) :void { delayFor(1.3, then); }

    protected function delayForAtLeastOneFrame (then :Function) :void { delayFor(.1, then); }

    protected function delayFor (seconds :Number, then :Function) :void {
        const t :Timer = new Timer(1000 * seconds);
        t.addEventListener(TimerEvent.TIMER, function (..._) :void { postDelay(t, then); });
        t.start();
    }

    protected function postDelay (t :Timer, then :Function) :void {
        t.stop();
        _finisher.monitor(then);
    }

    protected var _finisher :Finisher;
    protected var _movie :Movie;
    protected var _runner :TestRunner;
    protected var _res :StarlingResources;

    protected var _t :Timer = new Timer(1);
    protected const _labelsPassed :Vector.<String> = new Vector.<String>();
}
}

//
// Flump - Copyright 2012 Three Rings Design

package flump.test {

import flash.events.TimerEvent;
import flash.utils.Timer;

import flump.display.Movie;
import flump.display.StarlingResources;
import flump.executor.Finisher;

import com.threerings.util.F;

public class RuntimePlaybackTest
{
    public static function addTests (runner :TestRunner, res :StarlingResources) :void {
        runner.run("Goto frame and label", new RuntimePlaybackTest(runner, res).gotoFrameAndLabel);
        runner.runAsync("Play, stop, loop", new RuntimePlaybackTest(runner, res).playStopLoop);
        runner.runAsync("Stop, play", new RuntimePlaybackTest(runner, res).stopPlay);
        runner.runAsync("Play when added", new RuntimePlaybackTest(runner, res).playWhenAdded);
        runner.runAsync("Play once", new RuntimePlaybackTest(runner, res).playOnce);
        runner.runAsync("Pause while removed", new RuntimePlaybackTest(runner, res).pauseWhileRemoved);
    }

    public function RuntimePlaybackTest (runner :TestRunner, res :StarlingResources) {
        _runner = runner;
        _res = res;
    }

    protected function setup (finisher :Finisher) :void {
        _finisher = finisher;
        _movie = _res.loadMovie("nesteddance");
        assert(_movie.frame == 0, "Frame starts at 0");
        assert(_movie.isPlaying, "Movie starts out playing");
        _runner.addChild(_movie);
        _movie.labelPassed.add(_labelsPassed.push);
    }

    public function gotoFrameAndLabel () :void {
        _movie = _res.loadMovie("nesteddance");
        _movie.labelPassed.add(_labelsPassed.push);
        _movie.goto("timepassed");
        assert(_movie.frame == 9);
        passed("timepassed");
        assert(_labelsPassed.length == 1);
        _movie.goto("timepassed");
        assert(_labelsPassed.length == 2);
        assert(_movie.isPlaying, "Playing changed in goto");

        _movie.stop();
        _movie.goto(_movie.frame + 1);
        assert(_movie.frame == 10);
        assert(!_movie.isPlaying, "Stopped changed in goto");

        assertThrows(F.callback(_movie.goto, _movie.frames), "Went past frames");
        assertThrows(F.callback(_movie.goto, "nonexistent label"), "Went to nonexistent label");
    }

    public function playWhenAdded (finisher :Finisher) :void {
        setup(finisher);
        delayForAtLeastOneFrame(checkAdvanced);
    }

    public function checkAdvanced () :void {
        assert(_movie.frame > 0, "Frame advances with time");
        delayForOnePlaythrough(checkAllLabelsFired);
    }

    public function checkAllLabelsFired () :void {
        _runner.removeChild(_movie);
        passedAllLabels();
        _finisher.succeed();
    }

    public function playOnce (finisher :Finisher) :void {
        setup(finisher);
        _movie.goto(0).play();
        delayForOnePlaythrough(checkPlayOnce);
    }

    public function checkPlayOnce () :void {
        passedAllLabels();
        assert(_labelsPassed.length == 4, "Only pass the labels once");
        assert(_movie.frame == _movie.frames - 1, "Play once stops at last frame");
        _runner.removeChild(_movie);
        _finisher.succeed();
    }

    public function pauseWhileRemoved (finisher :Finisher) :void {
        setup(finisher);
        delayForAtLeastOneFrame(checkAdvancedToRemove);
    }

    public function checkAdvancedToRemove () :void {
       assert(_movie.frame > 0, "Playing initially");
       assert(_labelsPassed.length == 0, "Passed labels initially?");
       _runner.removeChild(_movie);
       delayForOnePlaythrough(checkNotAdvancedWhileRemoved);
    }

    public function checkNotAdvancedWhileRemoved () :void {
        assert(_labelsPassed.length == 0, "Labels passed while removed?");
        _runner.addChild(_movie);
        delayForOnePlaythrough(checkAllLabelsFired);
    }

    public function stopPlay (finisher :Finisher) :void {
        setup(finisher);
        _movie.stop();
        delayForAtLeastOneFrame(checkNotAdvancedWhileStopped);
    }

    public function checkNotAdvancedWhileStopped () :void {
        assert(_movie.frame == 0, "Frame advanced passed while stopped?");
        _movie.goto(Movie.FIRST_FRAME).playTo("timepassed");
        delayForOnePlaythrough(checkPlayedToTimePassed);
    }

    public function checkPlayedToTimePassed () :void {
        passed(Movie.FIRST_FRAME);
        passed("timepassed");
        assert(_labelsPassed.length == 2, "Should stop at timepassed: " + _labelsPassed);
        _runner.removeChild(_movie);
        _finisher.succeed();
    }

    public function playStopLoop (finisher :Finisher) :void {
        setup(finisher);
        _movie.goto(10).play().stop().loop();
        assert(_movie.frame == 10, "Play stop or loop changed the frame");
        delayFor(2.6, checkDoublePass);
    }

    public function checkDoublePass () :void {
        passedAllLabels();
        assert(_labelsPassed.length >= 8);
        _runner.removeChild(_movie);
        _finisher.succeed();
    }

    public function passedAllLabels () :void {
        passed("timepassed");
        passed("moretimepassed");
        passed(Movie.LAST_FRAME);
        passed(Movie.FIRST_FRAME);
    }

    protected function passed (label :String) :void {
        assert(_labelsPassed.indexOf(label) != -1, "Should've passed " + label);
    }

    protected function delayForOnePlaythrough (then :Function) :void { delayFor(1.3, then); }

    protected function delayForAtLeastOneFrame (then :Function) :void { delayFor(.1, then); }

    protected function delayFor (seconds :Number, then :Function) :void {
        const t :Timer = new Timer(1000 * seconds);
        t.addEventListener(TimerEvent.TIMER, function (..._) :void { postDelay(t, then); });
        t.start();
    }

    protected function postDelay (t :Timer, then :Function) :void {
        t.stop();
        _finisher.monitor(then);
    }

    protected var _finisher :Finisher;
    protected var _movie :Movie;
    protected var _runner :TestRunner;
    protected var _res :StarlingResources;

    protected var _t :Timer = new Timer(1);
    protected const _labelsPassed :Vector.<String> = new Vector.<String>();
}
}

Check that goto fires labels

Check that goto fires labels


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

package com.freshplanet.ane.AirInAppPurchase {

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

	public class InAppPurchase extends EventDispatcher {

		private var _context:ExtensionContext = null;
        private var _iosPendingPurchases:Vector.<Object> = new Vector.<Object>();

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

        private static var _instance:InAppPurchase = null;

        /**
         *
         * @param lock
         */
		public function InAppPurchase(lock:SingletonLock) {

            if (!isSupported)
                return;

            _context = ExtensionContext.createExtensionContext(EXTENSION_ID, null);

            if (!_context)
                throw Error("Extension context is null. Please check if extension.xml is setup correctly.");

            _context.addEventListener(StatusEvent.STATUS, _onStatus);
		}

        /**
         *
         */
        public static function get instance():InAppPurchase {

            if (!_instance)
                _instance = new InAppPurchase(new SingletonLock());

            return _instance;
        }

        /**
         *
         */
        public static function get isSupported():Boolean {
            return Capabilities.manufacturer.indexOf('iOS') > -1 || Capabilities.manufacturer.indexOf('Android') > -1;
        }

        /**
         *
         * @param googlePlayKey
         * @param debug
         */
		public function init(googlePlayKey:String, debug:Boolean = false):void {

            if (!isSupported)
                return;

            trace("[InAppPurchase] init library");
            _context.call("initLib", googlePlayKey, debug);
		}

        /**
         *
         * @param productId
         */
		public function makePurchase(productId:String):void {

            if (!isSupported) {

                _dispatchEvent(InAppPurchaseEvent.PURCHASE_ERROR, "InAppPurchase not supported");
                return;
            }

            trace("[InAppPurchase] purchasing", productId);
            _context.call("makePurchase", productId);
		}

        /**
         * receipt is for android device.
         * @param productId
         * @param receipt
         */
		public function removePurchaseFromQueue(productId:String, receipt:String):void {

            if (!isSupported)
                return;

            trace("[InAppPurchase] removing product from queue", productId, receipt);
            _context.call("removePurchaseFromQueue", productId, receipt);

            if (Capabilities.manufacturer.indexOf("iOS") > -1)
            {
                _iosPendingPurchases = _iosPendingPurchases.filter(function(jsonPurchase:String, index:int, purchases:Vector.<Object>):Boolean {
                    try
                    {
                        var purchase:Object = JSON.parse(jsonPurchase);
                        return JSON.stringify(purchase.receipt) != receipt;
                    }
                    catch(error:Error)
                    {
                        trace("[InAppPurchase] Couldn't parse purchase: " + jsonPurchase);
                    }
                    return false;
                });
            }
		}

        /**
         *
         * @param productsId
         * @param subscriptionIds
         */
		public function getProductsInfo(productsId:Array, subscriptionIds:Array):void {

            if (!isSupported) {

                _dispatchEvent(InAppPurchaseEvent.PRODUCT_INFO_ERROR, "InAppPurchase not supported");
                return;
            }

            trace("[InAppPurchase] get Products Info");
            _context.call("getProductsInfo", productsId, subscriptionIds);
		}

        /**
         *
         */
		public function userCanMakeAPurchase():void {

            if (!isSupported) {

                _dispatchEvent(InAppPurchaseEvent.PURCHASE_DISABLED, "InAppPurchase not supported");
                return;
            }

            trace("[InAppPurchase] check user can make a purchase");
            _context.call("userCanMakeAPurchase");
		}

        /**
         *
         */
		public function userCanMakeASubscription():void {

			if (Capabilities.manufacturer.indexOf('Android') > -1) {

				trace("[InAppPurchase] check user can make a purchase");
				_context.call("userCanMakeASubscription");
			}
            else {
                _dispatchEvent(InAppPurchaseEvent.PURCHASE_DISABLED, "subscriptions not supported");
			}
		}

        /**
         *
         * @param productId
         */
		public function makeSubscription(productId:String):void {

			if (Capabilities.manufacturer.indexOf('Android') > -1) {

				trace("[InAppPurchase] check user can make a subscription");
				_context.call("makeSubscription", productId);
			}
            else {
                _dispatchEvent(InAppPurchaseEvent.PURCHASE_ERROR, "subscriptions not supported");
			}
		}

        /**
         *
         */
		public function restoreTransactions():void {

			if (Capabilities.manufacturer.indexOf('Android') > -1)
				_context.call("restoreTransaction");
			else if (Capabilities.manufacturer.indexOf("iOS") > -1) {

				var jsonPurchases:String = "[" + _iosPendingPurchases.join(",") + "]";
				var jsonData:String = "{ \"purchases\": " + jsonPurchases + "}";

                _dispatchEvent(InAppPurchaseEvent.RESTORE_INFO_RECEIVED, jsonData);
			}
		}

        /**
         *
         */
		public function stop():void {

			if (Capabilities.manufacturer.indexOf('Android') > -1) {

				trace("[InAppPurchase] stop library");
				_context.call("stopLib");
			}
		}

        /**
         *
         * @param type
         * @param eventData
         */
        private function _dispatchEvent(type:String, eventData:String):void {
            this.dispatchEvent(new InAppPurchaseEvent(type, eventData))
        }

        /**
         *
         * @param event
         */
		private function _onStatus(event:StatusEvent):void {

			trace(event);

            if (event.code == InAppPurchaseEvent.PURCHASE_SUCCESSFUL && Capabilities.manufacturer.indexOf("iOS") > -1)
                _iosPendingPurchases.push(event.level);

            _dispatchEvent(event.code, event.level);
		}
	}
}

class SingletonLock {}

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

package com.freshplanet.ane.AirInAppPurchase {

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

	public class InAppPurchase extends EventDispatcher {

		private var _context:ExtensionContext = null;
        private var _iosPendingPurchases:Vector.<Object> = new Vector.<Object>();

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

        private static var _instance:InAppPurchase = null;

        /**
         *
         * @param lock
         */
		public function InAppPurchase(lock:SingletonLock) {

            if (!isSupported)
                return;

            _context = ExtensionContext.createExtensionContext(EXTENSION_ID, null);

            if (!_context)
                throw Error("Extension context is null. Please check if extension.xml is setup correctly.");

            _context.addEventListener(StatusEvent.STATUS, _onStatus);
		}

        /**
         *
         */
        public static function get instance():InAppPurchase {

            if (!_instance)
                _instance = new InAppPurchase(new SingletonLock());

            return _instance;
        }

        /**
         *
         */
        public static function get isSupported():Boolean {
            return Capabilities.manufacturer.indexOf('iOS') > -1 || Capabilities.manufacturer.indexOf('Android') > -1;
        }

        /**
         *
         * @param googlePlayKey
         * @param debug
         */
		public function init(googlePlayKey:String, debug:Boolean = false):void {

            if (!isSupported)
                return;

            trace("[InAppPurchase] init library");
            _context.call("initLib", googlePlayKey, debug);
		}

        /**
         *
         * @param productId
         */
		public function makePurchase(productId:String):void {

            if (!isSupported) {

                _dispatchEvent(InAppPurchaseEvent.PURCHASE_ERROR, "InAppPurchase not supported");
                return;
            }

            trace("[InAppPurchase] purchasing", productId);
            _context.call("makePurchase", productId);
		}

        /**
         * receipt is for android device.
         * @param productId
         * @param receipt
         */
		public function removePurchaseFromQueue(productId:String, receipt:String):void {

            if (!isSupported)
                return;

            trace("[InAppPurchase] removing product from queue", productId, receipt);
            _context.call("removePurchaseFromQueue", productId, receipt);

            if (Capabilities.manufacturer.indexOf("iOS") > -1)
            {
                _iosPendingPurchases = _iosPendingPurchases.filter(function(jsonPurchase:String, index:int, purchases:Vector.<Object>):Boolean {
                    try
                    {
                        var purchase:Object = JSON.parse(jsonPurchase);
                        return JSON.stringify(purchase.receipt) != receipt;
                    }
                    catch(error:Error)
                    {
                        trace("[InAppPurchase] Couldn't parse purchase: " + jsonPurchase);
                    }
                    return false;
                });
            }
		}

        /**
         *
         * @param productsId
         * @param subscriptionIds
         */
		public function getProductsInfo(productsId:Array, subscriptionIds:Array):void {

            if (!isSupported) {

                _dispatchEvent(InAppPurchaseEvent.PRODUCT_INFO_ERROR, "InAppPurchase not supported");
                return;
            }

            trace("[InAppPurchase] get Products Info");
            _context.call("getProductsInfo", productsId, subscriptionIds);
		}

        /**
         * PURCHASE_ERROR
         * PURCHASE_ERROR
         * @param productId
         */
		public function makeSubscription(productId:String):void {

			if (Capabilities.manufacturer.indexOf('Android') > -1) {

				trace("[InAppPurchase] check user can make a subscription");
				_context.call("makeSubscription", productId);
			}
            else {
                _dispatchEvent(InAppPurchaseEvent.PURCHASE_ERROR, "subscriptions not supported");
			}
		}

        /**
         * RESTORE_INFO_RECEIVED
         */
		public function restoreTransactions():void {

			if (Capabilities.manufacturer.indexOf('Android') > -1)
				_context.call("restoreTransaction");
			else if (Capabilities.manufacturer.indexOf("iOS") > -1) {

				var jsonPurchases:String = "[" + _iosPendingPurchases.join(",") + "]";
				var jsonData:String = "{ \"purchases\": " + jsonPurchases + "}";

                _dispatchEvent(InAppPurchaseEvent.RESTORE_INFO_RECEIVED, jsonData);
			}
		}

        /**
         *
         * @param type
         * @param eventData
         */
        private function _dispatchEvent(type:String, eventData:String):void {
            this.dispatchEvent(new InAppPurchaseEvent(type, eventData))
        }

        /**
         *
         * @param event
         */
		private function _onStatus(event:StatusEvent):void {

			trace(event);

            if (event.code == InAppPurchaseEvent.PURCHASE_SUCCESSFUL && Capabilities.manufacturer.indexOf("iOS") > -1)
                _iosPendingPurchases.push(event.level);

            _dispatchEvent(event.code, event.level);
		}
	}
}

class SingletonLock {}

remove unused methods

remove unused methods


package aerys.minko.render.effect.vertex
{
	import aerys.minko.render.RenderTarget;
	import aerys.minko.render.effect.basic.BasicShader;
	import aerys.minko.render.shader.SFloat;
	import aerys.minko.type.stream.format.VertexComponent;

	public class VertexUVShader extends BasicShader
	{

		public function VertexUVShader(target 	: RenderTarget 	= null,
									   priority	: Number		= 0)
		{
			super(target, priority);
		}

		override protected function getPixelColor() : SFloat
		{
			var uv 				: SFloat = getVertexAttribute(VertexComponent.UV);
			var interpolatedUv 	: SFloat = normalize(interpolate(uv));

			return float4(interpolatedUv.x, interpolatedUv.y, 0, 1);
		}

	}
}

package aerys.minko.render.effect.vertex
{
	import aerys.minko.render.RenderTarget;
	import aerys.minko.render.effect.basic.BasicProperties;
	import aerys.minko.render.effect.basic.BasicShader;
	import aerys.minko.render.shader.SFloat;
	import aerys.minko.type.stream.format.VertexComponent;

	public class VertexUVShader extends BasicShader
	{

		public function VertexUVShader(target 	: RenderTarget 	= null,
									   priority	: Number		= 0)
		{
			super(target, priority);
		}

		override protected function getPixelColor() : SFloat
		{
			var uv 				: SFloat = getVertexAttribute(VertexComponent.UV);

			if (meshBindings.propertyExists(BasicProperties.DIFFUSE_UV_SCALE))
				uv.scaleBy(meshBindings.getParameter(BasicProperties.DIFFUSE_UV_SCALE, 2));

			if (meshBindings.propertyExists(BasicProperties.DIFFUSE_UV_OFFSET))
				uv.incrementBy(meshBindings.getParameter(BasicProperties.DIFFUSE_UV_OFFSET, 2));

			var interpolatedUv 	: SFloat = fractional(interpolate(uv));

			return float4(interpolatedUv.x, interpolatedUv.y, 0, 1);
		}

	}
}

Fix Vertex uvs shader

Fix Vertex uvs shader

A Support of uvoffset and uvscale in the vertex uvs shader
M Use a fractional instruction to fix the shader


package aerys.minko.render.resource.texture
{
	import aerys.minko.render.resource.Context3DResource;
	import aerys.minko.type.enum.SamplerFormat;

	import flash.display.BitmapData;
	import flash.display3D.Context3DTextureFormat;
	import flash.display3D.textures.Texture;
	import flash.display3D.textures.TextureBase;
	import flash.geom.Matrix;
	import flash.utils.ByteArray;

	/**
	 * @inheritdoc
	 * @author Jean-Marc Le Roux
	 *
	 */
	public class TextureResource implements ITextureResource
	{
		private static const MAX_SIZE					: uint		= 2048;
		private static const TMP_MATRIX					: Matrix	= new Matrix();
		private static const FORMAT_BGRA				: String	= Context3DTextureFormat.BGRA
		private static const FORMAT_COMPRESSED			: String	= Context3DTextureFormat.COMPRESSED;
		private static const FORMAT_COMPRESSED_ALPHA 	: String 	= Context3DTextureFormat.COMPRESSED_ALPHA;

		private static const TEXTURE_FORMAT_TO_SAMPLER	: Array 	= []
		{
			TEXTURE_FORMAT_TO_SAMPLER[FORMAT_BGRA] 				= SamplerFormat.RGBA;
			TEXTURE_FORMAT_TO_SAMPLER[FORMAT_COMPRESSED] 		= SamplerFormat.COMPRESSED;
			TEXTURE_FORMAT_TO_SAMPLER[FORMAT_COMPRESSED_ALPHA] 	= SamplerFormat.COMPRESSED_ALPHA;
		}

		private var _texture		: Texture		= null;
		private var _mipmap			: Boolean		= false;

		private var _bitmapData		: BitmapData	= null;
		private var _atf			: ByteArray		= null;
		private var _atfFormat		: uint			= 0;
		private var _format 		: String 		= FORMAT_BGRA;

		private var _width			: Number		= 0;
		private var _height			: Number		= 0;

		private var _update			: Boolean		= false;

		public function get format() : uint
		{
			return TEXTURE_FORMAT_TO_SAMPLER[_format];
		}

        public function get mipMapping() : Boolean
        {
            return _mipmap;
        }

		public function get width() : uint
		{
			return _width;
		}

		public function get height() : uint
		{
			return _height;
		}

		public function TextureResource(width   : uint  = 0,
                                        height  : uint  = 0)
		{
            _width = width;
            _height = height;
		}

		public function setContentFromBitmapData(bitmapData	: BitmapData,
								   				 mipmap		: Boolean,
												 downSample	: Boolean	= false) : void
		{
			var bitmapWidth		: uint 	= bitmapData.width;
			var bitmapHeight	: uint 	= bitmapData.height;
			var w				: int	= 0;
			var h				: int	= 0;

			if (downSample)
			{
				w = 1 << Math.floor(Math.log(bitmapWidth) * Math.LOG2E);
				h = 1 << Math.floor(Math.log(bitmapHeight) * Math.LOG2E);
			}
			else
			{
				w = 1 << Math.ceil(Math.log(bitmapWidth) * Math.LOG2E);
				h = 1 << Math.ceil(Math.log(bitmapHeight) * Math.LOG2E);
			}

			if (w > MAX_SIZE)
				w = MAX_SIZE;
			if (h > MAX_SIZE)
				h = MAX_SIZE;

			if (_bitmapData == null || _bitmapData.width != w || _bitmapData.height != h)
				_bitmapData	= new BitmapData(w, h, bitmapData.transparent, 0);

			if (w != bitmapWidth || h != bitmapHeight)
			{
				TMP_MATRIX.identity();
				TMP_MATRIX.scale(w / bitmapWidth, h / bitmapHeight);
				_bitmapData.draw(bitmapData, TMP_MATRIX);
			}
			else
			{
				_bitmapData.draw(bitmapData);
			}

			if (_texture
				&& (mipmap != _mipmap
					|| bitmapData.width != _width
					|| bitmapData.height != _height))
			{
				_texture.dispose();
				_texture = null;
			}

			_width = _bitmapData.width;
			_height = _bitmapData.height;

			_mipmap	= mipmap;
			_update	= true;
		}

		public function setContentFromATF(atf : ByteArray) : void
		{
			_atf			= atf;
			_bitmapData		= null;
			_update 		= true;

			var oldWidth	: Number = _width;
			var oldHeight	: Number = _height;
			var oldMipmap	: Boolean = _mipmap;

			atf.position 	= 6;

			var formatByte 	: uint = atf.readUnsignedByte();

			_atfFormat 		= formatByte & 7;
			_width 			= 1 << atf.readUnsignedByte();
			_height 		= 1 << atf.readUnsignedByte();
			_mipmap 		= atf.readUnsignedByte() > 1;

			atf.position 	= 0;

			if (_atfFormat == 5)
				_format = FORMAT_COMPRESSED_ALPHA;
			else if (_atfFormat == 3)
				_format = FORMAT_COMPRESSED;

			if (_texture
				&& (oldMipmap != _mipmap
					|| oldWidth != _width
					|| oldHeight != _height))
			{
				_texture.dispose();
				_texture = null;
			}
		}

		public function getTexture(context : Context3DResource) : TextureBase
		{
			if (!_texture && _width && _height)
			{
				if (_texture)
					_texture.dispose();

				_texture = context.createTexture(
					_width,
					_height,
					_format,
					_bitmapData == null && _atf == null
				);
			}

			if (_update)
			{
				_update = false;
				uploadBitmapDataWithMipMaps();
			}

			_atf = null;
			_bitmapData = null;

			return _texture;
		}

		private function uploadBitmapDataWithMipMaps() : void
		{
			if (_bitmapData)
			{
				if (_mipmap)
				{
					var level 		: uint 			= 0;
					var size		: uint 			= _width > _height ? _width : _height;
					var transparent	: Boolean		= _bitmapData.transparent;
					var tmp 		: BitmapData 	= new BitmapData(size, size, transparent, 0);
					var transform 	: Matrix		= new Matrix();

					while (size >= 1)
					{
						tmp.draw(_bitmapData, transform, null, null, null, true);
						_texture.uploadFromBitmapData(tmp, level);

						transform.scale(.5, .5);
						level++;
						size >>= 1;

						if (tmp.transparent)
							tmp.fillRect(tmp.rect, 0);
					}

					tmp.dispose();
				}
				else
				{
					_texture.uploadFromBitmapData(_bitmapData, 0);
				}

				_bitmapData.dispose();
			}
			else if (_atf)
			{
				_texture.uploadCompressedTextureFromByteArray(_atf, 0);
			}
		}

		public function dispose() : void
		{
			if (_texture)
			{
				_texture.dispose();
				_texture = null;
			}
		}
	}
}

package aerys.minko.render.resource.texture
{
	import aerys.minko.render.resource.Context3DResource;
	import aerys.minko.type.enum.SamplerFormat;

	import flash.display.BitmapData;
	import flash.display3D.textures.Texture;
	import flash.display3D.textures.TextureBase;
	import flash.geom.Matrix;
	import flash.utils.ByteArray;

	/**
	 * @inheritdoc
	 * @author Jean-Marc Le Roux
	 *
	 */
	public class TextureResource implements ITextureResource
	{
		private static const MAX_SIZE					: uint		= 2048;
		private static const TMP_MATRIX					: Matrix	= new Matrix();
		private static const FORMAT_BGRA				: String	= 'bgra';
		private static const FORMAT_COMPRESSED			: String	= 'compressed';
		private static const FORMAT_COMPRESSED_ALPHA 	: String 	= 'compressedAlpha';

		private static const TEXTURE_FORMAT_TO_SAMPLER	: Array 	= []
		{
			TEXTURE_FORMAT_TO_SAMPLER[FORMAT_BGRA] 				= SamplerFormat.RGBA;
			TEXTURE_FORMAT_TO_SAMPLER[FORMAT_COMPRESSED] 		= SamplerFormat.COMPRESSED;
			TEXTURE_FORMAT_TO_SAMPLER[FORMAT_COMPRESSED_ALPHA] 	= SamplerFormat.COMPRESSED_ALPHA;
		}

		private var _texture		: Texture;
		private var _mipmap			: Boolean;

		private var _bitmapData		: BitmapData;
		private var _atf			: ByteArray;
		private var _atfFormat		: uint;
		private var _format 		: String;

		private var _width			: Number;
		private var _height			: Number;

		private var _update			: Boolean;

		public function get format() : uint
		{
			return TEXTURE_FORMAT_TO_SAMPLER[_format];
		}

        public function get mipMapping() : Boolean
        {
            return _mipmap;
        }

		public function get width() : uint
		{
			return _width;
		}

		public function get height() : uint
		{
			return _height;
		}

		public function TextureResource(width   : uint  = 0,
                                        height  : uint  = 0)
		{
            _width = width;
            _height = height;
			_format = FORMAT_BGRA;
		}

		public function setContentFromBitmapData(bitmapData	: BitmapData,
								   				 mipmap		: Boolean,
												 downSample	: Boolean	= false) : void
		{
			var bitmapWidth		: uint 	= bitmapData.width;
			var bitmapHeight	: uint 	= bitmapData.height;
			var w				: int	= 0;
			var h				: int	= 0;

			if (downSample)
			{
				w = 1 << Math.floor(Math.log(bitmapWidth) * Math.LOG2E);
				h = 1 << Math.floor(Math.log(bitmapHeight) * Math.LOG2E);
			}
			else
			{
				w = 1 << Math.ceil(Math.log(bitmapWidth) * Math.LOG2E);
				h = 1 << Math.ceil(Math.log(bitmapHeight) * Math.LOG2E);
			}

			if (w > MAX_SIZE)
				w = MAX_SIZE;
			if (h > MAX_SIZE)
				h = MAX_SIZE;

			if (_bitmapData == null || _bitmapData.width != w || _bitmapData.height != h)
				_bitmapData	= new BitmapData(w, h, bitmapData.transparent, 0);

			if (w != bitmapWidth || h != bitmapHeight)
			{
				TMP_MATRIX.identity();
				TMP_MATRIX.scale(w / bitmapWidth, h / bitmapHeight);
				_bitmapData.draw(bitmapData, TMP_MATRIX);
			}
			else
			{
				_bitmapData.draw(bitmapData);
			}

			if (_texture
				&& (_format	!= FORMAT_BGRA
					|| mipmap != _mipmap
					|| bitmapData.width != _width
					|| bitmapData.height != _height))
			{
				_texture.dispose();
				_texture = null;
			}

			_width = _bitmapData.width;
			_height = _bitmapData.height;
			_format = FORMAT_BGRA;

			_mipmap	= mipmap;
			_update	= true;
		}

		public function setContentFromATF(atf : ByteArray) : void
		{
			_atf			= atf;
			_bitmapData		= null;
			_update 		= true;

			var oldWidth	: Number = _width;
			var oldHeight	: Number = _height;
			var oldMipmap	: Boolean = _mipmap;
			var oldFormat	: String = _format;

			atf.position 	= 6;

			var formatByte 	: uint = atf.readUnsignedByte();

			_atfFormat 		= formatByte & 7;
			_width 			= 1 << atf.readUnsignedByte();
			_height 		= 1 << atf.readUnsignedByte();
			_mipmap 		= atf.readUnsignedByte() > 1;

			atf.position 	= 0;

			if (_atfFormat == 5)
				_format = FORMAT_COMPRESSED_ALPHA;
			else if (_atfFormat == 3)
				_format = FORMAT_COMPRESSED;
			else
				_format = FORMAT_BGRA;

			if (_texture
				&& (oldFormat != _format
					|| oldMipmap != _mipmap
					|| oldWidth != _width
					|| oldHeight != _height))
			{
				_texture.dispose();
				_texture = null;
			}
		}

		public function getTexture(context : Context3DResource) : TextureBase
		{
			if (!_texture && _width && _height)
			{
				if (_texture)
					_texture.dispose();

				_texture = context.createTexture(
					_width,
					_height,
					_format,
					_bitmapData == null && _atf == null
				);
			}

			if (_update)
			{
				_update = false;
				uploadBitmapDataWithMipMaps();
			}

			_atf = null;
			_bitmapData = null;

			return _texture;
		}

		private function uploadBitmapDataWithMipMaps() : void
		{
			if (_bitmapData)
			{
				if (_mipmap)
				{
					var level 		: uint 			= 0;
					var size		: uint 			= _width > _height ? _width : _height;
					var transparent	: Boolean		= _bitmapData.transparent;
					var tmp 		: BitmapData 	= new BitmapData(size, size, transparent, 0);
					var transform 	: Matrix		= new Matrix();

					while (size >= 1)
					{
						tmp.draw(_bitmapData, transform, null, null, null, true);
						_texture.uploadFromBitmapData(tmp, level);

						transform.scale(.5, .5);
						level++;
						size >>= 1;

						if (tmp.transparent)
							tmp.fillRect(tmp.rect, 0);
					}

					tmp.dispose();
				}
				else
				{
					_texture.uploadFromBitmapData(_bitmapData, 0);
				}

				_bitmapData.dispose();
			}
			else if (_atf)
			{
				_texture.uploadCompressedTextureFromByteArray(_atf, 0);
			}
		}

		public function dispose() : void
		{
			if (_texture)
			{
				_texture.dispose();
				_texture = null;
			}
		}
	}
}

use string literals for texture formats to avoid compatibility issues


////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package org.apache.flex.core
{
	import mx.states.State;

	import org.apache.flex.core.IMXMLDocument;
    import org.apache.flex.core.ValuesManager;
	import org.apache.flex.events.Event;
	import org.apache.flex.events.ValueChangeEvent;
	import org.apache.flex.utils.MXMLDataInterpreter;

    /**
     *  Indicates that the state change has completed.  All properties
     *  that need to change have been changed, and all transitinos
     *  that need to run have completed.  However, any deferred work
     *  may not be completed, and the screen may not be updated until
     *  code stops executing.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
     */
    [Event(name="stateChangeComplete", type="org.apache.flex.events.Event")]

    /**
     *  Indicates that the initialization of the container is complete.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
     */
    [Event(name="initComplete", type="org.apache.flex.events.Event")]

    /**
     *  Indicates that the children of the container is have been added.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
     */
    [Event(name="childrenAdded", type="org.apache.flex.events.Event")]

	[DefaultProperty("mxmlContent")]

    /**
     *  The ContainerBase class is the base class for most containers
     *  in FlexJS.  It is usable as the root tag of MXML
     *  documents and UI controls and containers are added to it.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
     */
	public class ContainerBase extends UIBase implements IMXMLDocument
	{
        /**
         *  Constructor.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function ContainerBase()
		{
			super();
		}

        /**
         *  A ContainerBase doesn't create its children until it is added to
         *  a parent.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		override public function addedToParent():void
		{
			// each MXML file can also have styles in fx:Style block
			ValuesManager.valuesImpl.init(this);

			super.addedToParent();

			MXMLDataInterpreter.generateMXMLInstances(_mxmlDocument, this, MXMLDescriptor);

			dispatchEvent(new Event("initComplete"))
			dispatchEvent(new Event("childrenAdded"));
		}

        private var _mxmlDescriptor:Array;
        private var _mxmlDocument:Object = this;

        /**
         *  @copy org.apache.flex.core.Application#MXMLDescriptor
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function get MXMLDescriptor():Array
		{
			return _mxmlDescriptor;
		}

        /**
         *  @private
         */
        public function setMXMLDescriptor(document:Object, value:Array):void
        {
            _mxmlDocument = document;
            _mxmlDescriptor = value;
        }

        /**
         *  @copy org.apache.flex.core.Application#generateMXMLAttributes()
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function generateMXMLAttributes(data:Array):void
		{
            MXMLDataInterpreter.generateMXMLProperties(this, data);
		}

        /**
         *  @copy org.apache.flex.core.ItemRendererClassFactory#mxmlContent
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public var mxmlContent:Array;

        private var _states:Array;

        /**
         *  The array of view states. These should
         *  be instances of mx.states.State.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public function get states():Array
        {
            return _states;
        }

        /**
         *  @private
         */
        public function set states(value:Array):void
        {
            _states = value;
            _currentState = _states[0].name;

			try{
				if (getBeadByType(IStatesImpl) == null)
					addBead(new (ValuesManager.valuesImpl.getValue(this, "iStatesImpl")) as IBead);
			}
			//TODO:  Need to handle this case more gracefully
			catch(e:Error)
			{
				trace(e.message);
			}

        }

        /**
         *  true if the array of states
         *  contains a state with this name.
         *
         *  @param state The state namem.
         *  @return True if state in state array
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public function hasState(state:String):Boolean
        {
            for each (var s:State in _states)
            {
                if (s.name == state)
                    return true;
            }
            return false;
        }

        private var _currentState:String;

        [Bindable("currentStateChange")]
        /**
         *  The name of the current state.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public function get currentState():String
        {
            return _currentState;
        }

        /**
         *  @private
         */
        public function set currentState(value:String):void
        {
            var event:ValueChangeEvent = new ValueChangeEvent("currentStateChange", false, false, _currentState, value)
            _currentState = value;
            dispatchEvent(event);
        }

        private var _transitions:Array;

        /**
         *  The array of transitions.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public function get transitions():Array
        {
            return _transitions;
        }

        /**
         *  @private
         */
        public function set transitions(value:Array):void
        {
            _transitions = value;
        }

    }
}

////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package org.apache.flex.core
{
	import mx.states.State;

	import org.apache.flex.core.IMXMLDocument;
    import org.apache.flex.core.ValuesManager;
	import org.apache.flex.events.Event;
	import org.apache.flex.events.ValueChangeEvent;
	import org.apache.flex.utils.MXMLDataInterpreter;

    /**
     *  Indicates that the state change has completed.  All properties
     *  that need to change have been changed, and all transitinos
     *  that need to run have completed.  However, any deferred work
     *  may not be completed, and the screen may not be updated until
     *  code stops executing.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
     */
    [Event(name="stateChangeComplete", type="org.apache.flex.events.Event")]

    /**
     *  Indicates that the initialization of the container is complete.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
     */
    [Event(name="initComplete", type="org.apache.flex.events.Event")]

    /**
     *  Indicates that the children of the container is have been added.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
     */
    [Event(name="childrenAdded", type="org.apache.flex.events.Event")]

	[DefaultProperty("mxmlContent")]

    /**
     *  The ContainerBase class is the base class for most containers
     *  in FlexJS.  It is usable as the root tag of MXML
     *  documents and UI controls and containers are added to it.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
     */
	public class ContainerBase extends UIBase implements IMXMLDocument, IStatesObject
	{
        /**
         *  Constructor.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function ContainerBase()
		{
			super();
		}

        /**
         *  A ContainerBase doesn't create its children until it is added to
         *  a parent.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		override public function addedToParent():void
		{
			// each MXML file can also have styles in fx:Style block
			ValuesManager.valuesImpl.init(this);

			super.addedToParent();

			MXMLDataInterpreter.generateMXMLInstances(_mxmlDocument, this, MXMLDescriptor);

			dispatchEvent(new Event("initComplete"))
			dispatchEvent(new Event("childrenAdded"));
		}

        private var _mxmlDescriptor:Array;
        private var _mxmlDocument:Object = this;

        /**
         *  @copy org.apache.flex.core.Application#MXMLDescriptor
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function get MXMLDescriptor():Array
		{
			return _mxmlDescriptor;
		}

        /**
         *  @private
         */
        public function setMXMLDescriptor(document:Object, value:Array):void
        {
            _mxmlDocument = document;
            _mxmlDescriptor = value;
        }

        /**
         *  @copy org.apache.flex.core.Application#generateMXMLAttributes()
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function generateMXMLAttributes(data:Array):void
		{
            MXMLDataInterpreter.generateMXMLProperties(this, data);
		}

        /**
         *  @copy org.apache.flex.core.ItemRendererClassFactory#mxmlContent
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public var mxmlContent:Array;

        private var _states:Array;

        /**
         *  The array of view states. These should
         *  be instances of mx.states.State.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public function get states():Array
        {
            return _states;
        }

        /**
         *  @private
         */
        public function set states(value:Array):void
        {
            _states = value;
            _currentState = _states[0].name;

			try{
				if (getBeadByType(IStatesImpl) == null)
					addBead(new (ValuesManager.valuesImpl.getValue(this, "iStatesImpl")) as IBead);
			}
			//TODO:  Need to handle this case more gracefully
			catch(e:Error)
			{
				trace(e.message);
			}

        }

        /**
         *  true if the array of states
         *  contains a state with this name.
         *
         *  @param state The state namem.
         *  @return True if state in state array
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public function hasState(state:String):Boolean
        {
            for each (var s:State in _states)
            {
                if (s.name == state)
                    return true;
            }
            return false;
        }

        private var _currentState:String;

        [Bindable("currentStateChange")]
        /**
         *  The name of the current state.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public function get currentState():String
        {
            return _currentState;
        }

        /**
         *  @private
         */
        public function set currentState(value:String):void
        {
            var event:ValueChangeEvent = new ValueChangeEvent("currentStateChange", false, false, _currentState, value)
            _currentState = value;
            dispatchEvent(event);
        }

        private var _transitions:Array;

        /**
         *  The array of transitions.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public function get transitions():Array
        {
            return _transitions;
        }

        /**
         *  @private
         */
        public function set transitions(value:Array):void
        {
            _transitions = value;
        }

    }
}

handle initial state

handle initial state


package com.kaltura.hls.manifest
{
	import com.hurlant.util.Hex;
	import com.kaltura.hls.crypto.FastAESKey;

	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;
	import flash.utils.getTimer;

	CONFIG::LOGGING
	{
		import org.osmf.logging.Logger;
        import org.osmf.logging.Log;
	}

	/**
	 * HLSManifestEncryptionKey is used to parse AES decryption key data from a m3u8
	 * manifest, load the specified key file into memory, and use the key data to decrypt
	 * audio and video streams. It supports AES-128 encryption with #PKCS7 padding, and uses
	 * explicitly passed in Initialization Vectors.
	 */

	public class HLSManifestEncryptionKey extends EventDispatcher
	{
        CONFIG::LOGGING
        {
            private static const logger:Logger = Log.getLogger("com.kaltura.hls.manifest.HLSManifestEncryptionKey");
        }

		private static const LOADER_CACHE:Dictionary = new Dictionary();
		private var _key:FastAESKey;
		public var usePadding:Boolean = false;
		public var iv:String = "";
		public var url:String = "";
		private var iv0 : uint;
		private var iv1 : uint;
		private var iv2 : uint;
		private var iv3 : uint;

		// Keep track of the segments this key applies to
		public var startSegmentId:uint = 0;
		public var endSegmentId:uint = uint.MAX_VALUE;

		private var _keyData:ByteArray;

		public var isLoading:Boolean = false;

		public function HLSManifestEncryptionKey()
		{

		}

		public function get isLoaded():Boolean { return _keyData != null; }

		public override function toString():String
		{
			return "[HLSManifestEncryptionKey start=" + startSegmentId +", end=" + endSegmentId + ", iv=" + iv + ", url=" + url + ", loaded=" + isLoaded + "]";
		}

		public static function fromParams( params:String ):HLSManifestEncryptionKey
		{
			var result:HLSManifestEncryptionKey = new HLSManifestEncryptionKey();

			var tokens:Array = KeyParamParser.parseParams( params );
			var tokenCount:int = tokens.length;

			for ( var i:int = 0; i < tokenCount; i += 2 )
			{
				var name:String = tokens[ i ];
				var value:String = tokens[ i + 1 ];

				switch ( name )
				{
					case "URI" :
						result.url = value;
						break;

					case "IV" :
						result.iv = value;
						break;
				}

			}

			return result;
		}

		/**
		 * Creates an initialization vector from the passed in uint ID, usually
		 * a segment ID.
		 */
		public static function createIVFromID( id:uint ):ByteArray
		{
			var result:ByteArray = new ByteArray();
			result.writeUnsignedInt( 0 );
			result.writeUnsignedInt( 0 );
			result.writeUnsignedInt( 0 );
			result.writeUnsignedInt( id );
			return result;
		}

		public static function clearLoaderCache():void
		{
			for ( var key:String in LOADER_CACHE ) delete LOADER_CACHE[ key ];
		}

		/**
		 * Decrypts a video or audio stream using AES-128 with the provided initialization vector.
		 */

		public function decrypt( data:ByteArray, iv:ByteArray ):ByteArray
		{
			//logger.debug("got " + data.length + " bytes");
			if(data.length == 0)
				return data;

			var startTime:uint = getTimer();
			_key = new FastAESKey(_keyData);
			iv.position = 0;
			iv0 = iv.readUnsignedInt();
			iv1 = iv.readUnsignedInt();
			iv2 = iv.readUnsignedInt();
			iv3 = iv.readUnsignedInt();
			data.position = 0;
			data = _decryptCBC(data,data.length);
			if ( usePadding ){
				data = unpad( data );
			}
		//	logger.debug( "DECRYPTION OF " + data.length + " BYTES TOOK " + ( getTimer() - startTime ) + " MS" );
			return data;
		}

		/* Cypher Block Chaining Decryption, refer to
		* http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_
		* for algorithm description
		*/
		private function _decryptCBC(crypt : ByteArray, len : uint) : ByteArray {
			var src : Vector.<uint> = new Vector.<uint>(4);
			var dst : Vector.<uint> = new Vector.<uint>(4);
			var decrypt : ByteArray = new ByteArray();
			decrypt.length = len;

			for (var i : uint = 0; i < len / 16; i++) {
				// read src byte array
				src[0] = crypt.readUnsignedInt();
				src[1] = crypt.readUnsignedInt();
				src[2] = crypt.readUnsignedInt();
				src[3] = crypt.readUnsignedInt();

				// AES decrypt src vector into dst vector
				_key.decrypt128(src, dst);

				// CBC : write output = XOR(decrypted,IV)
				decrypt.writeUnsignedInt(dst[0] ^ iv0);
				decrypt.writeUnsignedInt(dst[1] ^ iv1);
				decrypt.writeUnsignedInt(dst[2] ^ iv2);
				decrypt.writeUnsignedInt(dst[3] ^ iv3);

				// CBC : next IV = (input)
				iv0 = src[0];
				iv1 = src[1];
				iv2 = src[2];
				iv3 = src[3];
			}
			return decrypt;
		}
		public function unpad(bytesToUnpad : ByteArray) : ByteArray {
			if ((bytesToUnpad.length % 16) != 0)
			{
				throw new Error("PKCS#5::unpad: ByteArray.length isn't a multiple of the blockSize");
				return a;
			}

			const paddingValue:int = bytesToUnpad[bytesToUnpad.length - 1];
			var doUnpad:Boolean = true;
			for (var i:int = 0; i<paddingValue; i++) {
				var readValue:int = bytesToUnpad[bytesToUnpad.length - (1 + i)];
				if (paddingValue != readValue)
				{
					//throw new Error("PKCS#5:unpad: Invalid padding value. expected [" + paddingValue + "], found [" + readValue + "]");
					//break;
					doUnpad = false;
					//Break to make sure we don't underrun the byte array with a byte value bigger than 16
					break;
				}
			}

			if(doUnpad)
			{
				//subtract paddingValue + 1 since the value is one less than the number of padded bytes
				bytesToUnpad.length -= paddingValue + 1;
			}

			return bytesToUnpad;
		}

		public function retrieveStoredIV():ByteArray
		{
			CONFIG::LOGGING
			{
				logger.debug("IV of " + iv + " for " + url + ", key=" + Hex.fromArray(_keyData));
			}
			return Hex.toArray( iv );
		}

		private static function getLoader( url:String ):URLLoader
		{
			if ( LOADER_CACHE[ url ] != null ) return LOADER_CACHE[ url ] as URLLoader;
			var newLoader:URLLoader = new URLLoader();
			newLoader.dataFormat = URLLoaderDataFormat.BINARY;
			newLoader.load( new URLRequest( url ) );
			LOADER_CACHE[ url ] = newLoader;
			return newLoader;
		}

		public function load():void
		{
			isLoading = true;

			if ( isLoaded ) throw new Error( "Already loaded!" );
			var loader:URLLoader = getLoader( url );
			if ( loader.bytesTotal > 0 && loader.bytesLoaded == loader.bytesTotal ) onLoad();
			else loader.addEventListener( Event.COMPLETE, onLoad );
		}

		private function onLoad( e:Event = null ):void
		{
			isLoading = false;

			CONFIG::LOGGING
			{
				logger.debug("KEY LOADED! " + url);
			}

			var loader:URLLoader = getLoader( url );
			_keyData = loader.data as ByteArray;
			loader.removeEventListener( Event.COMPLETE, onLoad );
			dispatchEvent( new Event( Event.COMPLETE ) );
		}
	}
}

class KeyParamParser
{
	private static const STATE_PARSE_NAME:String = "ParseName";
	private static const STATE_BEGIN_PARSE_VALUE:String = "BeginParseValue";
	private static const STATE_PARSE_VALUE:String = "ParseValue";

	public static function parseParams( paramString:String ):Array
	{
		var result:Array = [];
		var cursor:int = 0;
		var state:String = STATE_PARSE_NAME;
		var accum:String = "";
		var usingQuotes:Boolean = false;

		while ( cursor < paramString.length )
		{
			var char:String = paramString.charAt( cursor );
			switch ( state )
			{
				case STATE_PARSE_NAME:

					if ( char == '=' )
					{
						result.push( accum );
						accum = "";
						state = STATE_BEGIN_PARSE_VALUE;
					}
					else accum += char;
					break;

				case STATE_BEGIN_PARSE_VALUE:

					if ( char == '"' ) usingQuotes = true;
					else accum += char;
					state = STATE_PARSE_VALUE;
					break;

				case STATE_PARSE_VALUE:

					if ( !usingQuotes && char == ',' )
					{
						result.push( accum );
						accum = "";
						state = STATE_PARSE_NAME;
						break;
					}

					if ( usingQuotes && char == '"' )
					{
						usingQuotes = false;
						break;
					}

					accum += char;
					break;
			}

			cursor++;

			if ( cursor == paramString.length ) result.push( accum );
		}

		return result;
	}
}

package com.kaltura.hls.manifest
{
	import com.hurlant.util.Hex;
	import com.kaltura.hls.crypto.FastAESKey;

	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;
	import flash.utils.getTimer;

	CONFIG::LOGGING
	{
		import org.osmf.logging.Logger;
        import org.osmf.logging.Log;
	}

	/**
	 * HLSManifestEncryptionKey is used to parse AES decryption key data from a m3u8
	 * manifest, load the specified key file into memory, and use the key data to decrypt
	 * audio and video streams. It supports AES-128 encryption with #PKCS7 padding, and uses
	 * explicitly passed in Initialization Vectors.
	 */

	public class HLSManifestEncryptionKey extends EventDispatcher
	{
        CONFIG::LOGGING
        {
            private static const logger:Logger = Log.getLogger("com.kaltura.hls.manifest.HLSManifestEncryptionKey");
        }

		private static const LOADER_CACHE:Dictionary = new Dictionary();
		private var _key:FastAESKey;
		public var usePadding:Boolean = false;
		public var iv:String = "";
		public var url:String = "";
		private var iv0 : uint;
		private var iv1 : uint;
		private var iv2 : uint;
		private var iv3 : uint;

		// Keep track of the segments this key applies to
		public var startSegmentId:uint = 0;
		public var endSegmentId:uint = uint.MAX_VALUE;

		private var _keyData:ByteArray;

		public var isLoading:Boolean = false;

		public function HLSManifestEncryptionKey()
		{

		}

		public function get isLoaded():Boolean { return _keyData != null; }

		public override function toString():String
		{
			return "[HLSManifestEncryptionKey start=" + startSegmentId +", end=" + endSegmentId + ", iv=" + iv + ", url=" + url + ", loaded=" + isLoaded + "]";
		}

		public static function fromParams( params:String ):HLSManifestEncryptionKey
		{
			var result:HLSManifestEncryptionKey = new HLSManifestEncryptionKey();

			var tokens:Array = KeyParamParser.parseParams( params );
			var tokenCount:int = tokens.length;

			for ( var i:int = 0; i < tokenCount; i += 2 )
			{
				var name:String = tokens[ i ];
				var value:String = tokens[ i + 1 ];

				switch ( name )
				{
					case "URI" :
						result.url = value;
						break;

					case "IV" :
						result.iv = value;
						break;
				}

			}

			return result;
		}

		/**
		 * Creates an initialization vector from the passed in uint ID, usually
		 * a segment ID.
		 */
		public static function createIVFromID( id:uint ):ByteArray
		{
			var result:ByteArray = new ByteArray();
			result.writeUnsignedInt( 0 );
			result.writeUnsignedInt( 0 );
			result.writeUnsignedInt( 0 );
			result.writeUnsignedInt( id );
			return result;
		}

		public static function clearLoaderCache():void
		{
			for ( var key:String in LOADER_CACHE ) delete LOADER_CACHE[ key ];
		}

		/**
		 * Decrypts a video or audio stream using AES-128 with the provided initialization vector.
		 */

		public function decrypt( data:ByteArray, iv:ByteArray ):ByteArray
		{
			//logger.debug("got " + data.length + " bytes");
			if(data.length == 0)
				return data;

			var startTime:uint = getTimer();
			_key = new FastAESKey(_keyData);
			iv.position = 0;
			iv0 = iv.readUnsignedInt();
			iv1 = iv.readUnsignedInt();
			iv2 = iv.readUnsignedInt();
			iv3 = iv.readUnsignedInt();
			data.position = 0;
			data = _decryptCBC(data,data.length);
			if ( usePadding ){
				data = unpad( data );
			}
		//	logger.debug( "DECRYPTION OF " + data.length + " BYTES TOOK " + ( getTimer() - startTime ) + " MS" );
			return data;
		}

		/* Cypher Block Chaining Decryption, refer to
		* http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_
		* for algorithm description
		*/
		private function _decryptCBC(crypt : ByteArray, len : uint) : ByteArray {
			var src : Vector.<uint> = new Vector.<uint>(4);
			var dst : Vector.<uint> = new Vector.<uint>(4);
			var decrypt : ByteArray = new ByteArray();
			decrypt.length = len;

			for (var i : uint = 0; i < len / 16; i++) {
				// read src byte array
				src[0] = crypt.readUnsignedInt();
				src[1] = crypt.readUnsignedInt();
				src[2] = crypt.readUnsignedInt();
				src[3] = crypt.readUnsignedInt();

				// AES decrypt src vector into dst vector
				_key.decrypt128(src, dst);

				// CBC : write output = XOR(decrypted,IV)
				decrypt.writeUnsignedInt(dst[0] ^ iv0);
				decrypt.writeUnsignedInt(dst[1] ^ iv1);
				decrypt.writeUnsignedInt(dst[2] ^ iv2);
				decrypt.writeUnsignedInt(dst[3] ^ iv3);

				// CBC : next IV = (input)
				iv0 = src[0];
				iv1 = src[1];
				iv2 = src[2];
				iv3 = src[3];
			}
			return decrypt;
		}
		public function unpad(bytesToUnpad : ByteArray) : ByteArray {
			if ((bytesToUnpad.length % 16) != 0)
			{
				throw new Error("PKCS#5::unpad: ByteArray.length isn't a multiple of the blockSize");
				return a;
			}

			const paddingValue:int = bytesToUnpad[bytesToUnpad.length - 1];
			if (paddingValue > 15)
			{
				return bytesToUnpad;
			}
			var doUnpad:Boolean = true;
			for (var i:int = 0; i<paddingValue; i++) {
				var readValue:int = bytesToUnpad[bytesToUnpad.length - (1 + i)];
				if (paddingValue != readValue)
				{
					//throw new Error("PKCS#5:unpad: Invalid padding value. expected [" + paddingValue + "], found [" + readValue + "]");
					//break;
					doUnpad = false;
					//Break to make sure we don't underrun the byte array with a byte value bigger than 16
					break;
				}
			}

			if(doUnpad)
			{
				//subtract paddingValue + 1 since the value is one less than the number of padded bytes
				bytesToUnpad.length -= paddingValue + 1;
			}

			return bytesToUnpad;
		}

		public function retrieveStoredIV():ByteArray
		{
			CONFIG::LOGGING
			{
				logger.debug("IV of " + iv + " for " + url + ", key=" + Hex.fromArray(_keyData));
			}
			return Hex.toArray( iv );
		}

		private static function getLoader( url:String ):URLLoader
		{
			if ( LOADER_CACHE[ url ] != null ) return LOADER_CACHE[ url ] as URLLoader;
			var newLoader:URLLoader = new URLLoader();
			newLoader.dataFormat = URLLoaderDataFormat.BINARY;
			newLoader.load( new URLRequest( url ) );
			LOADER_CACHE[ url ] = newLoader;
			return newLoader;
		}

		public function load():void
		{
			isLoading = true;

			if ( isLoaded ) throw new Error( "Already loaded!" );
			var loader:URLLoader = getLoader( url );
			if ( loader.bytesTotal > 0 && loader.bytesLoaded == loader.bytesTotal ) onLoad();
			else loader.addEventListener( Event.COMPLETE, onLoad );
		}

		private function onLoad( e:Event = null ):void
		{
			isLoading = false;

			CONFIG::LOGGING
			{
				logger.debug("KEY LOADED! " + url);
			}

			var loader:URLLoader = getLoader( url );
			_keyData = loader.data as ByteArray;
			loader.removeEventListener( Event.COMPLETE, onLoad );
			dispatchEvent( new Event( Event.COMPLETE ) );
		}
	}
}

class KeyParamParser
{
	private static const STATE_PARSE_NAME:String = "ParseName";
	private static const STATE_BEGIN_PARSE_VALUE:String = "BeginParseValue";
	private static const STATE_PARSE_VALUE:String = "ParseValue";

	public static function parseParams( paramString:String ):Array
	{
		var result:Array = [];
		var cursor:int = 0;
		var state:String = STATE_PARSE_NAME;
		var accum:String = "";
		var usingQuotes:Boolean = false;

		while ( cursor < paramString.length )
		{
			var char:String = paramString.charAt( cursor );
			switch ( state )
			{
				case STATE_PARSE_NAME:

					if ( char == '=' )
					{
						result.push( accum );
						accum = "";
						state = STATE_BEGIN_PARSE_VALUE;
					}
					else accum += char;
					break;

				case STATE_BEGIN_PARSE_VALUE:

					if ( char == '"' ) usingQuotes = true;
					else accum += char;
					state = STATE_PARSE_VALUE;
					break;

				case STATE_PARSE_VALUE:

					if ( !usingQuotes && char == ',' )
					{
						result.push( accum );
						accum = "";
						state = STATE_PARSE_NAME;
						break;
					}

					if ( usingQuotes && char == '"' )
					{
						usingQuotes = false;
						break;
					}

					accum += char;
					break;
			}

			cursor++;

			if ( cursor == paramString.length ) result.push( accum );
		}

		return result;
	}
}

Update HLSManifestEncryptionKey.as

Update HLSManifestEncryptionKey.as

Adds optimized logic to early-out the unpadding algorithm of the end byte is 16 or larger, which would indicate there is no padding.