package goplayer
{
  public class ConfigurationParser
  {
    public static const DEFAULT_API_URL : String
      = "http://staging.streamio.se/api"
    public static const DEFAULT_SKIN_URL : String = "goplayer-skin.swf"
    public static const DEFAULT_TRACKER_ID : String = "global"

    public static const VALID_PARAMETERS : Array = [
      "api", "tracker", "skin", "video", "bitrate",
      "enablertmp", "autoplay", "loop",
      "enablechrome", "enabletitle" ]

    private const result : Configuration = new Configuration

    private var parameters : Object
    private var originalParameterNames : Object

    public function ConfigurationParser
      (parameters : Object, originalParameterNames : Object)
    {
      this.parameters = parameters
      this.originalParameterNames = originalParameterNames
    }

    public function execute() : void
    {
      result.apiURL = getString("api", DEFAULT_API_URL)
      result.trackerID = getString("tracker", DEFAULT_TRACKER_ID)
      result.skinURL = getString("skin", DEFAULT_SKIN_URL)
      result.movieID = getString("video", null)
      result.bitratePolicy = getBitratePolicy("bitrate", BitratePolicy.BEST)
      result.enableRTMP = getBoolean("enablertmp", true)
      result.enableAutoplay = getBoolean("autoplay", false)
      result.enableLooping = getBoolean("loop", false)
      result.enableChrome = getBoolean("enablechrome", true)
      result.enableTitle = getBoolean("enabletitle", true)
    }

    public static function parse(parameters : Object) : Configuration
    {
      const normalizedParameters : Object = {}
      const originalParameterNames : Object = {}

      for (var name : String in parameters)
        if (VALID_PARAMETERS.indexOf(normalize(name)) == -1)
          reportUnknownParameter(name)
        else
          normalizedParameters[normalize(name)] = parameters[name],
            originalParameterNames[normalize(name)] = name

      const parser : ConfigurationParser = new ConfigurationParser
        (normalizedParameters, originalParameterNames)

      parser.execute()

      return parser.result
    }

    private static function normalize(name : String) : String
    { return name.toLowerCase().replace(/[^a-z]/g, "") }

    private static function reportUnknownParameter(name : String) : void
    { debug("Error: Unknown parameter: " + name) }

    // -----------------------------------------------------

    private function getString(name : String, fallback : String) : String
    { return name in parameters ? parameters[name] : fallback }

    private function getBoolean
      (name : String, fallback : Boolean) : Boolean
    {
      if (name in parameters)
        return $getBoolean(name, parameters[name], fallback)
      else
        return fallback
    }

    private function $getBoolean
      (name : String, value : String, fallback : Boolean) : Boolean
    {
      try
        { return $$getBoolean(value) }
      catch (error : Error)
        {
          reportInvalidParameter(name, value, ["true", "false"])

          return fallback
        }

      throw new Error
    }

    private function $$getBoolean(value : String) : Boolean
    {
      if (value == "true")
        return true
      else if (value == "false")
        return false
      else
        throw new Error
    }

    // -----------------------------------------------------

    private function getBitratePolicy
      (name : String, fallback : BitratePolicy) : BitratePolicy
    {
      if (name in parameters)
        return $getBitratePolicy(name, parameters[name], fallback)
      else
        return fallback
    }

    private function $getBitratePolicy
      (name : String, value : String,
       fallback : BitratePolicy) : BitratePolicy
    {
      try
        { return $$getBitratePolicy(value) }
      catch (error : Error)
        {
          reportInvalidParameter(name, value, BITRATE_POLICY_VALUES)

          return fallback
        }

      throw new Error
    }

    private const BITRATE_POLICY_VALUES : Array =
      ["<number>kbps", "min", "max", "best"]

    private function $$getBitratePolicy(value : String) : BitratePolicy
    {
      if (value == "max")
        return BitratePolicy.MAX
      else if (value == "min")
        return BitratePolicy.MIN
      else if (value == "best")
        return BitratePolicy.BEST
      else if (Bitrate.parse(value))
        return BitratePolicy.specific(Bitrate.parse(value))
      else
        throw new Error
    }

    // -----------------------------------------------------

    private function reportInvalidParameter
      (name : String, value : String, validValues : Array) : void
    {
      debug("Error: Invalid parameter: " +
            "“" + originalParameterNames[name] + "=" + value + "”; " +
            getInvalidParameterHint(validValues) + ".")
    }

    private function getInvalidParameterHint(values : Array) : String
    { return $getInvalidParameterHint(getQuotedValues(values)) }

    private function $getInvalidParameterHint(values : Array) : String
    {
      return "please use " +
        "either " + values.slice(0, -1).join(", ") + " " +
        "or " + values[values.length - 1]
    }

    private function getQuotedValues(values : Array) : Array
    {
      var result : Array = []

      for each (var value : String in values)
        result.push("“" + value + "”")

      return result
    }
  }
}

package goplayer
{
  public class ConfigurationParser
  {
    public static const DEFAULT_API_URL : String
      = "http://staging.streamio.se/api"
    public static const DEFAULT_SKIN_URL : String = "goplayer-skin.swf"
    public static const DEFAULT_TRACKER_ID : String = "global"

    public static const VALID_PARAMETERS : Array = [
      "api", "tracker", "skin", "video", "bitrate",
      "enablertmp", "autoplay", "loop",
      "skin:showchrome", "skin:showtitle" ]

    private const result : Configuration = new Configuration

    private var parameters : Object
    private var originalParameterNames : Object

    public function ConfigurationParser
      (parameters : Object, originalParameterNames : Object)
    {
      this.parameters = parameters
      this.originalParameterNames = originalParameterNames
    }

    public function execute() : void
    {
      result.apiURL = getString("api", DEFAULT_API_URL)
      result.trackerID = getString("tracker", DEFAULT_TRACKER_ID)
      result.skinURL = getString("skin", DEFAULT_SKIN_URL)
      result.movieID = getString("video", null)
      result.bitratePolicy = getBitratePolicy("bitrate", BitratePolicy.BEST)
      result.enableRTMP = getBoolean("enablertmp", true)
      result.enableAutoplay = getBoolean("autoplay", false)
      result.enableLooping = getBoolean("loop", false)
      result.enableChrome = getBoolean("skin:showchrome", true)
      result.enableTitle = getBoolean("skin:showtitle", true)
    }

    public static function parse(parameters : Object) : Configuration
    {
      const normalizedParameters : Object = {}
      const originalParameterNames : Object = {}

      for (var name : String in parameters)
        if (VALID_PARAMETERS.indexOf(normalize(name)) == -1)
          reportUnknownParameter(name)
        else
          normalizedParameters[normalize(name)] = parameters[name],
            originalParameterNames[normalize(name)] = name

      const parser : ConfigurationParser = new ConfigurationParser
        (normalizedParameters, originalParameterNames)

      parser.execute()

      return parser.result
    }

    private static function normalize(name : String) : String
    { return name.toLowerCase().replace(/[^a-z:]/g, "") }

    private static function reportUnknownParameter(name : String) : void
    { debug("Error: Unknown parameter: " + name) }

    // -----------------------------------------------------

    private function getString(name : String, fallback : String) : String
    { return name in parameters ? parameters[name] : fallback }

    private function getBoolean
      (name : String, fallback : Boolean) : Boolean
    {
      if (name in parameters)
        return $getBoolean(name, parameters[name], fallback)
      else
        return fallback
    }

    private function $getBoolean
      (name : String, value : String, fallback : Boolean) : Boolean
    {
      try
        { return $$getBoolean(value) }
      catch (error : Error)
        {
          reportInvalidParameter(name, value, ["true", "false"])

          return fallback
        }

      throw new Error
    }

    private function $$getBoolean(value : String) : Boolean
    {
      if (value == "true")
        return true
      else if (value == "false")
        return false
      else
        throw new Error
    }

    // -----------------------------------------------------

    private function getBitratePolicy
      (name : String, fallback : BitratePolicy) : BitratePolicy
    {
      if (name in parameters)
        return $getBitratePolicy(name, parameters[name], fallback)
      else
        return fallback
    }

    private function $getBitratePolicy
      (name : String, value : String,
       fallback : BitratePolicy) : BitratePolicy
    {
      try
        { return $$getBitratePolicy(value) }
      catch (error : Error)
        {
          reportInvalidParameter(name, value, BITRATE_POLICY_VALUES)

          return fallback
        }

      throw new Error
    }

    private const BITRATE_POLICY_VALUES : Array =
      ["<number>kbps", "min", "max", "best"]

    private function $$getBitratePolicy(value : String) : BitratePolicy
    {
      if (value == "max")
        return BitratePolicy.MAX
      else if (value == "min")
        return BitratePolicy.MIN
      else if (value == "best")
        return BitratePolicy.BEST
      else if (Bitrate.parse(value))
        return BitratePolicy.specific(Bitrate.parse(value))
      else
        throw new Error
    }

    // -----------------------------------------------------

    private function reportInvalidParameter
      (name : String, value : String, validValues : Array) : void
    {
      debug("Error: Invalid parameter: " +
            "“" + originalParameterNames[name] + "=" + value + "”; " +
            getInvalidParameterHint(validValues) + ".")
    }

    private function getInvalidParameterHint(values : Array) : String
    { return $getInvalidParameterHint(getQuotedValues(values)) }

    private function $getInvalidParameterHint(values : Array) : String
    {
      return "please use " +
        "either " + values.slice(0, -1).join(", ") + " " +
        "or " + values[values.length - 1]
    }

    private function getQuotedValues(values : Array) : Array
    {
      var result : Array = []

      for each (var value : String in values)
        result.push("“" + value + "”")

      return result
    }
  }
}

Rename `enable-chrome' => `skin:show-chrome' and `enable-title' => `skin:show-title'.


/*
 *  WorkshopConstants.as
 *  This file is part of FRESteamWorks.
 *
 *  Created by Ventero <http://github.com/Ventero> on 2013-04-24
 *  Copyright (c) 2013 Level Up Labs, LLC. All rights reserved.
 */

package com.amanitadesign.steam
{
	public class WorkshopConstants
	{
		public static const FILETYPE_Community:int = 0;
		public static const FILETYPE_Microtransaction:int = 1;
		public static const FILETYPE_Collection:int = 2;
		public static const FILETYPE_Art:int = 3;
		public static const FILETYPE_Video:int = 4;
		public static const FILETYPE_Screenshot:int = 5;
		public static const FILETYPE_Game:int = 6;
		public static const FILETYPE_Software:int = 7;
		public static const FILETYPE_Concept:int = 8;
		public static const FILETYPE_WebGuide:int = 9;
		public static const FILETYPE_IntegratedGuide:int = 10;

		public static const ENUMTYPE_RankedByVote:int = 0;
		public static const ENUMTYPE_Recent:int = 1;
		public static const ENUMTYPE_Trending:int = 2;
		public static const ENUMTYPE_FavoritesOfFriends:int = 3;
		public static const ENUMTYPE_VotedByFriends:int = 4;
		public static const ENUMTYPE_ContentByFriends:int = 5;
		public static const ENUMTYPE_RecentFromFollowedUsers:int = 6;

		public static const FILEACTION_Played:int = 0;
		public static const FILEACTION_Completed:int = 1;

		public static const VISIBILITY_Public:int = 0;
		public static const VISIBILITY_FriendsOnly:int = 1;
		public static const VISIBILITY_Private:int = 2;

		public static const FILEUPDATEHANDLE_Invalid:String = "18446744073709551615"; // 0xffffffffffffffffull
		public static const UGCHANDLE_Invalid:String = "18446744073709551615"; // 0xffffffffffffffffull
	}
}

/*
 *  WorkshopConstants.as
 *  This file is part of FRESteamWorks.
 *
 *  Created by Ventero <http://github.com/Ventero> on 2013-04-24
 *  Copyright (c) 2013 Level Up Labs, LLC. All rights reserved.
 */

package com.amanitadesign.steam
{
	public class WorkshopConstants
	{
		public static const FILETYPE_Community:int = 0;
		public static const FILETYPE_Microtransaction:int = 1;
		public static const FILETYPE_Collection:int = 2;
		public static const FILETYPE_Art:int = 3;
		public static const FILETYPE_Video:int = 4;
		public static const FILETYPE_Screenshot:int = 5;
		public static const FILETYPE_Game:int = 6;
		public static const FILETYPE_Software:int = 7;
		public static const FILETYPE_Concept:int = 8;
		public static const FILETYPE_WebGuide:int = 9;
		public static const FILETYPE_IntegratedGuide:int = 10;

		public static const ENUMTYPE_RankedByVote:int = 0;
		public static const ENUMTYPE_Recent:int = 1;
		public static const ENUMTYPE_Trending:int = 2;
		public static const ENUMTYPE_FavoritesOfFriends:int = 3;
		public static const ENUMTYPE_VotedByFriends:int = 4;
		public static const ENUMTYPE_ContentByFriends:int = 5;
		public static const ENUMTYPE_RecentFromFollowedUsers:int = 6;

		public static const FILEACTION_Played:int = 0;
		public static const FILEACTION_Completed:int = 1;

		public static const VISIBILITY_Public:int = 0;
		public static const VISIBILITY_FriendsOnly:int = 1;
		public static const VISIBILITY_Private:int = 2;

		public static const OVERLAYSTOREFLAG_None:int = 0;
		public static const OVERLAYSTOREFLAG_AddToCart:int = 1;
		public static const OVERLAYSTOREFLAG_AddToCartAndShow:int = 2;

		public static const FILEUPDATEHANDLE_Invalid:String = "18446744073709551615"; // 0xffffffffffffffffull
		public static const UGCHANDLE_Invalid:String = "18446744073709551615"; // 0xffffffffffffffffull
	}
}

Add EOverlayToStoreFlags

Add EOverlayToStoreFlags


/* Vivified
 * Copyright (C) 2007 Benjamin Otte <otte@gnome.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301  USA
 */

/*** general objects ***/

Wrap = function () {};
Wrap.prototype = {};
Wrap.prototype.toString = Native.wrap_toString;

Frame = function () extends Wrap {};
Frame.prototype = new Wrap ();
Frame.prototype.addProperty ("code", Native.frame_code_get, null);
Frame.prototype.addProperty ("name", Native.frame_name_get, null);
Frame.prototype.addProperty ("next", Native.frame_next_get, null);

/*** breakpoints ***/

Breakpoint = function () extends Native.Breakpoint {
  super ();
  Breakpoint.list.push (this);
};
Breakpoint.list = new Array ();
Breakpoint.prototype.addProperty ("active", Native.breakpoint_active_get, Native.breakpoint_active_set);

/*** information about the player ***/

Player = {};
Player.addProperty ("filename", Native.player_filename_get, Native.player_filename_set);
Player.addProperty ("frame", Native.player_frame_get, null);
Player.addProperty ("global", Native.player_global_get, null);
Player.addProperty ("variables", Native.player_variables_get, Native.player_variables_set);

/*** commands available for debugging ***/

Commands = new Object ();
Commands.print = Native.print;
Commands.error = Native.error;
Commands.r = Native.run;
Commands.run = Native.run;
Commands.halt = Native.stop;
Commands.stop = Native.stop;
Commands.s = Native.step;
Commands.step = Native.step;
Commands.reset = Native.reset;
Commands.restart = function () {
  Commands.reset ();
  Commands.run ();
};
Commands.quit = Native.quit;
/* can't use "break" as a function name, it's a keyword in JS */
Commands.add = function (name) {
  if (name == undefined) {
    Commands.error ("add command requires a function name");
    return undefined;
  }
  var ret = new Breakpoint ();
  ret.onStartFrame = function (frame) {
    if (frame.name != name)
      return false;

    Commands.print ("Breakpoint: function " + name + " called");
    Commands.print ("  " + frame);
    return true;
  };
  ret.toString = function () {
    return "function call " + name;
  };
  return ret;
};
Commands.list = function () {
  var a = Breakpoint.list;
  var i;
  for (i = 0; i < a.length; i++) {
    Commands.print (i + ": " + a[i]);
  }
};
Commands.del = function (id) {
  var a = Breakpoint.list;
  if (id == undefined) {
    while (a[0])
      Commands.del (0);
  }
  var b = a[id];
  a.splice (id, 1);
  b.active = false;
};
Commands.delete = Commands.del;
Commands.where = function () {
  var frame = Player.frame;
  if (frame == undefined) {
    Commands.print ("---");
    return;
  }
  var i = 0;
  while (frame) {
    Commands.print (i++ + ": " + frame);
    frame = frame.next;
  }
};
Commands.backtrace = Commands.where;
Commands.bt = Commands.where;
Commands.watch = function () {
  var object;
  var name;
  if (arguments.length == 1) {
    name = arguments[0];
  } else if (arguments.length == 2) {
    object = arguments[0];
    name = arguments[1];
  } else {
    Commands.error ("usage: watch [object] name");
    return;
  }
  var ret = new Breakpoint ();
  ret.onSetVariable = function (o, variable, value) {
    if (object && o != object)
      return false;
    if (variable != name)
      return;

    if (object) {
      Commands.print ("Breakpoint: variable " + name + " on " + object);
    } else {
      Commands.print ("Breakpoint: variable " + name);
    }
    Commands.print ("  " + Player.frame);
    return true;
  };
  ret.toString = function () {
    var s = "watch " + name;
    if (object)
      s += " on " + object;
    return s;
  };
  return ret;
};

implement watch command

implement watch command


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

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

import org.as3commons.reflect.Field;
import org.as3commons.reflect.Type;
import org.flexunit.asserts.assertEquals;
import org.flexunit.asserts.assertFalse;
import org.flexunit.asserts.assertNotNull;
import org.hamcrest.assertThat;
import org.hamcrest.collection.array;
import org.hamcrest.collection.arrayWithSize;
import org.hamcrest.collection.everyItem;
import org.hamcrest.core.isA;
import org.hamcrest.object.equalTo;

use namespace dolly_internal;

public class CloningOfCompositeCloneableClassTest {

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

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

		compositeCloneableClassType = Type.forInstance(compositeCloneableClass);
	}

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

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

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

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

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

		const arrayList:ArrayList = clone.arrayList;

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

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

		const targetArrayCollection:ArrayCollection = clone.arrayCollection;

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

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

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

import org.as3commons.reflect.Field;
import org.as3commons.reflect.Type;
import org.flexunit.asserts.assertEquals;
import org.flexunit.asserts.assertFalse;
import org.flexunit.asserts.assertNotNull;
import org.hamcrest.assertThat;
import org.hamcrest.collection.array;
import org.hamcrest.collection.arrayWithSize;
import org.hamcrest.collection.everyItem;
import org.hamcrest.core.isA;
import org.hamcrest.object.equalTo;

use namespace dolly_internal;

public class CloningOfCompositeCloneableClassTest {

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

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

		compositeCloneableClassType = Type.forInstance(compositeCloneableClass);
	}

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

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

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

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

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

		const arrayList:ArrayList = clone.arrayList;

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

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

		const arrayCollection:ArrayCollection = clone.arrayCollection;

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

Rename local method variable.

Rename local method variable.


package com.kaltura.kdpfl.view.controls
{
	import com.kaltura.kdpfl.controller.media.LiveStreamCommand;
	import com.kaltura.kdpfl.model.ConfigProxy;
	import com.kaltura.kdpfl.model.type.NotificationType;
	import com.kaltura.kdpfl.view.media.KMediaPlayerMediator;

	import flash.geom.Point;
	import flash.utils.getQualifiedClassName;

	import org.osmf.media.MediaPlayerState;
	import org.puremvc.as3.interfaces.INotification;
	import org.puremvc.as3.patterns.mediator.Mediator;

	/**
	 * Mediator for the buffer indicator animation. Controls the appearance and removal of the animation from the display list.
	 * @author Hila
	 *
	 */
	public class BufferAnimationMediator extends Mediator
	{
		public static const NAME:String = "spinnerMediator";
		public static const SPINNER_CLASS : String = "kspin";
		public var applicationLoadStyleName:String = '';
		public var bufferingStyleName:String = '';
		private var zeroPoint : Point = new Point( 0 , 0);

		/**
		 * flag indicating whether the active media has reached its end.
		 */
		private var _reachedEnd:Boolean=false;
		private var _currConfig : ConfigProxy;
		private var _notBuffering : Boolean = true;
		private var _prevStatePaused:Boolean = true;
		private var _lastPlayheadPos:Number;

		/**
		 * indicate if "bufferChange" event was sent, we started buffering
		 */
		private var _bufferChangeStart:Boolean = false;

		/**
		 * Constructor.
		 * @param viewComponent - the component controlled by the mediator.
		 *
		 */
		public function BufferAnimationMediator(viewComponent:Object=null)
		{
			super(NAME, viewComponent);
			_currConfig = facade.retrieveProxy(ConfigProxy.NAME) as ConfigProxy;
		}

		override public function handleNotification(note:INotification):void
		{
			var flashvars : Object = _currConfig.vo.flashvars;
			var noteName : String = note.getName();
			switch(noteName)
			{
				case NotificationType.SKIN_LOADED:
					//					spinner.swapLoadingWithAnimation( applicationLoadStyleName == '' ? SPINNER_CLASS : applicationLoadStyleName );
					spinner.visible = false;
					break;
				case NotificationType.LAYOUT_READY:
					if (flashvars.usePreloaderBufferAnimation && flashvars.usePreloaderBufferAnimation=='true' && flashvars.preloader)
					{
						spinner.setBufferingAnimation(getQualifiedClassName(flashvars.preloader));
					}
					else
					{
						spinner.setBufferingAnimation(applicationLoadStyleName == '' ? SPINNER_CLASS : applicationLoadStyleName );
					}
					break;
				case NotificationType.KDP_READY:
				case NotificationType.READY_TO_PLAY:
					spinner.visible = false;
					_reachedEnd = false;
					if (flashvars.usePreloaderBufferAnimation && flashvars.usePreloaderBufferAnimation=='true' && flashvars.preloader)
					{
						spinner.setBufferingAnimation(getQualifiedClassName(flashvars.preloader));
					}
					else
					{
						spinner.setBufferingAnimation(applicationLoadStyleName == '' ? SPINNER_CLASS : applicationLoadStyleName );
					}
					break;
				case NotificationType.PLAYER_STATE_CHANGE:
					if( note.getBody() == MediaPlayerState.BUFFERING)
					{
						_notBuffering = false;
						if(_reachedEnd)
							spinner.visible = false;
							//fix OSMF bug: sometimes "buffering" was sent after player paused, the spinner shouldn't be visible in this case
						else if (!_prevStatePaused)
							spinner.visible = true;

					}
					else
					{
						//only relevant if not rtmp
						/* if( note.getBody() == MediaPlayerState.READY ){
						spinner.visible = false;
						}
						if(_flashvars.streamerType != StreamerType.RTMP){
						spinner.visible = false;
						} */
						_notBuffering = true;
						if( note.getBody() == MediaPlayerState.PLAYING)
						{
							_reachedEnd = false;
							_prevStatePaused = false;
						//	spinner.visible = false;
						}
						if(note.getBody() == MediaPlayerState.PAUSED)
						{
							spinner.visible = false;
							_prevStatePaused = true;
						}
						if( note.getBody() == MediaPlayerState.READY)
						{
							spinner.visible = false;
						}
					}

					break;

				/**
				 * Until OSMF for seeking in rtmp is fixed (buffering-wise)
				 * add a new case for update playhead notification
				 * */
				case NotificationType.PLAYER_UPDATE_PLAYHEAD:
					//if _bufferChangeStart the next bufferChange event will make the spinner invisible
					if(_notBuffering && !_bufferChangeStart)
					{
						spinner.visible = false;
					}
					//fix another OSMF bug: we are buffering even though movie plays
					else if (spinner.visible)
					{
						var updateIntervalInSeconds:Number = (facade.retrieveMediator(KMediaPlayerMediator.NAME) as KMediaPlayerMediator).player.currentTimeUpdateInterval / 1000;
						var curPos:Number = parseFloat(Number(note.getBody()).toFixed(2));
						if ((curPos - _lastPlayheadPos)<=updateIntervalInSeconds)
						{
							spinner.visible = false;
						}
						_lastPlayheadPos = curPos;
					}

					break;
				case NotificationType.BUFFER_CHANGE:
					_bufferChangeStart = note.getBody();
					spinner.visible = _bufferChangeStart;
					break;
				case NotificationType.PLAYER_PLAY_END:
					_reachedEnd=true;
					spinner.visible = false;
					break;
				case NotificationType.KDP_EMPTY:
				case NotificationType.READY_TO_LOAD:
					spinner.visible = false;
					_reachedEnd=false;
					if (flashvars.usePreloaderBufferAnimation && flashvars.usePreloaderBufferAnimation=='true' && flashvars.preloader)
					{
						spinner.setBufferingAnimation(getQualifiedClassName(flashvars.preloader));
					}
					else
					{
						spinner.setBufferingAnimation(applicationLoadStyleName == '' ? SPINNER_CLASS : applicationLoadStyleName );
					}
					break;
				case NotificationType.CHANGE_MEDIA:
					//spinner.visible = true;

					break;

				//in case we are trying to connect to a live stream but it is not on air yet
				case NotificationType.LIVE_ENTRY:
					if (flashvars.hideSpinnerOnOffline=="true")
						spinner.visible = false;
					else
						spinner.visible = true;
					break;

				//in case the live stream we are trying to connect to was found to be on air
				case LiveStreamCommand.LIVE_STREAM_READY:
					spinner.visible = false;
					break;

				case NotificationType.PRELOADER_LOADED:
					var preObj:Object = note.getBody().preloader;
					if (flashvars.usePreloaderBufferAnimation && flashvars.usePreloaderBufferAnimation=='true' && preObj)
					{
						//save to flashvars, we might need it in the future
						_currConfig.vo.flashvars["preloader"] = preObj;
						spinner.setBufferingAnimation(getQualifiedClassName(preObj));
					}
					break;

			}
		}

		override public function listNotificationInterests():Array
		{
			return [
				NotificationType.SKIN_LOADED,
				NotificationType.PLAYER_STATE_CHANGE,
				NotificationType.PLAYER_PLAYED,
				NotificationType.PLAYER_UPDATE_PLAYHEAD, //TODO: REMOVE THIS WHEN I FIND A BETTER WORK AROUND TO THE BUG
				NotificationType.ENTRY_FAILED,
				NotificationType.CHANGE_MEDIA,
				NotificationType.PLAYER_PLAY_END,
				NotificationType.KDP_EMPTY,
				NotificationType.KDP_READY,
				NotificationType.LAYOUT_READY,
				NotificationType.LIVE_ENTRY,
				LiveStreamCommand.LIVE_STREAM_READY,
				NotificationType.READY_TO_PLAY,
				NotificationType.READY_TO_LOAD,
				NotificationType.ROOT_RESIZE,
				NotificationType.BUFFER_CHANGE,
				NotificationType.PRELOADER_LOADED
			];
		}
		/**
		 * the buffer indicator animation controlled by the mediator.
		 * @return
		 *
		 */
		public function get spinner():BufferAnimation
		{
			return viewComponent as BufferAnimation;
		}

	}
}

package com.kaltura.kdpfl.view.controls
{
	import com.kaltura.kdpfl.controller.media.LiveStreamCommand;
	import com.kaltura.kdpfl.model.ConfigProxy;
	import com.kaltura.kdpfl.model.type.NotificationType;
	import com.kaltura.kdpfl.view.media.KMediaPlayerMediator;

	import flash.geom.Point;
	import flash.utils.getQualifiedClassName;

	import org.osmf.media.MediaPlayerState;
	import org.puremvc.as3.interfaces.INotification;
	import org.puremvc.as3.patterns.mediator.Mediator;

	/**
	 * Mediator for the buffer indicator animation. Controls the appearance and removal of the animation from the display list.
	 * @author Hila
	 *
	 */
	public class BufferAnimationMediator extends Mediator
	{
		public static const NAME:String = "spinnerMediator";
		public static const SPINNER_CLASS : String = "kspin";
		public var applicationLoadStyleName:String = '';
		public var bufferingStyleName:String = '';
		private var zeroPoint : Point = new Point( 0 , 0);

		/**
		 * flag indicating whether the active media has reached its end.
		 */
		private var _reachedEnd:Boolean=false;
		private var _currConfig : ConfigProxy;
		private var _notBuffering : Boolean = true;
		private var _prevStatePaused:Boolean = true;
		private var _lastPlayheadPos:Number;

		/**
		 * indicate if "bufferChange" event was sent, we started buffering
		 */
		private var _bufferChangeStart:Boolean = false;

		/**
		 * Constructor.
		 * @param viewComponent - the component controlled by the mediator.
		 *
		 */
		public function BufferAnimationMediator(viewComponent:Object=null)
		{
			super(NAME, viewComponent);
			_currConfig = facade.retrieveProxy(ConfigProxy.NAME) as ConfigProxy;
		}

		override public function handleNotification(note:INotification):void
		{
			var flashvars : Object = _currConfig.vo.flashvars;
			var noteName : String = note.getName();
			switch(noteName)
			{
				case NotificationType.SKIN_LOADED:
					//					spinner.swapLoadingWithAnimation( applicationLoadStyleName == '' ? SPINNER_CLASS : applicationLoadStyleName );
					spinner.visible = false;
					break;
				case NotificationType.LAYOUT_READY:
					if (flashvars.usePreloaderBufferAnimation && flashvars.usePreloaderBufferAnimation=='true' && flashvars.preloader)
					{
						spinner.setBufferingAnimation(getQualifiedClassName(flashvars.preloader));
					}
					else
					{
						spinner.setBufferingAnimation(applicationLoadStyleName == '' ? SPINNER_CLASS : applicationLoadStyleName );
					}
					break;
				case NotificationType.KDP_READY:
				case NotificationType.READY_TO_PLAY:
					spinner.visible = false;
					_reachedEnd = false;
					if (flashvars.usePreloaderBufferAnimation && flashvars.usePreloaderBufferAnimation=='true' && flashvars.preloader)
					{
						spinner.setBufferingAnimation(getQualifiedClassName(flashvars.preloader));
					}
					else
					{
						spinner.setBufferingAnimation(applicationLoadStyleName == '' ? SPINNER_CLASS : applicationLoadStyleName );
					}
					break;
				case NotificationType.PLAYER_STATE_CHANGE:
					if( note.getBody() == MediaPlayerState.BUFFERING)
					{
						_notBuffering = false;
						if(_reachedEnd)
							spinner.visible = false;
							//fix OSMF bug: sometimes "buffering" was sent after player paused, the spinner shouldn't be visible in this case
						else if (!_prevStatePaused)
							spinner.visible = true;

					}
					else
					{
						//only relevant if not rtmp
						/* if( note.getBody() == MediaPlayerState.READY ){
						spinner.visible = false;
						}
						if(_flashvars.streamerType != StreamerType.RTMP){
						spinner.visible = false;
						} */
						_notBuffering = true;
						if( note.getBody() == MediaPlayerState.PLAYING)
						{
							_reachedEnd = false;
							_prevStatePaused = false;
						//	spinner.visible = false;
						}
						if(note.getBody() == MediaPlayerState.PAUSED)
						{
							spinner.visible = false;
							_prevStatePaused = true;
						}
						if( note.getBody() == MediaPlayerState.READY)
						{
							spinner.visible = false;
						}
					}

					break;

				/**
				 * Until OSMF for seeking in rtmp is fixed (buffering-wise)
				 * add a new case for update playhead notification
				 * */
				case NotificationType.PLAYER_UPDATE_PLAYHEAD:
					//if _bufferChangeStart the next bufferChange event will make the spinner invisible
					if(_notBuffering && !_bufferChangeStart)
					{
						spinner.visible = false;
					}
					//fix another OSMF bug: we are buffering even though movie plays
					else if (spinner.visible)
					{
						var updateIntervalInSeconds:Number = (facade.retrieveMediator(KMediaPlayerMediator.NAME) as KMediaPlayerMediator).player.currentTimeUpdateInterval / 1000;
						var curPos:Number = parseFloat(Number(note.getBody()).toFixed(2));
						if ((curPos - _lastPlayheadPos)<=updateIntervalInSeconds)
						{
							spinner.visible = false;
						}
						_lastPlayheadPos = curPos;
					}

					break;
				case NotificationType.BUFFER_CHANGE:
					_bufferChangeStart = note.getBody();
					//fix osmf bug: sometimes bufferChange was sent after playback complete
					spinner.visible = _bufferChangeStart && !_reachedEnd;
					break;
				case NotificationType.PLAYER_PLAY_END:
					_reachedEnd=true;
					spinner.visible = false;
					break;
				case NotificationType.KDP_EMPTY:
				case NotificationType.READY_TO_LOAD:
					spinner.visible = false;
					_reachedEnd=false;
					if (flashvars.usePreloaderBufferAnimation && flashvars.usePreloaderBufferAnimation=='true' && flashvars.preloader)
					{
						spinner.setBufferingAnimation(getQualifiedClassName(flashvars.preloader));
					}
					else
					{
						spinner.setBufferingAnimation(applicationLoadStyleName == '' ? SPINNER_CLASS : applicationLoadStyleName );
					}
					break;
				case NotificationType.CHANGE_MEDIA:
					//spinner.visible = true;

					break;

				//in case we are trying to connect to a live stream but it is not on air yet
				case NotificationType.LIVE_ENTRY:
					if (flashvars.hideSpinnerOnOffline=="true")
						spinner.visible = false;
					else
						spinner.visible = true;
					break;

				//in case the live stream we are trying to connect to was found to be on air
				case LiveStreamCommand.LIVE_STREAM_READY:
					spinner.visible = false;
					break;

				case NotificationType.PRELOADER_LOADED:
					var preObj:Object = note.getBody().preloader;
					if (flashvars.usePreloaderBufferAnimation && flashvars.usePreloaderBufferAnimation=='true' && preObj)
					{
						//save to flashvars, we might need it in the future
						_currConfig.vo.flashvars["preloader"] = preObj;
						spinner.setBufferingAnimation(getQualifiedClassName(preObj));
					}
					break;

			}
		}

		override public function listNotificationInterests():Array
		{
			return [
				NotificationType.SKIN_LOADED,
				NotificationType.PLAYER_STATE_CHANGE,
				NotificationType.PLAYER_PLAYED,
				NotificationType.PLAYER_UPDATE_PLAYHEAD, //TODO: REMOVE THIS WHEN I FIND A BETTER WORK AROUND TO THE BUG
				NotificationType.ENTRY_FAILED,
				NotificationType.CHANGE_MEDIA,
				NotificationType.PLAYER_PLAY_END,
				NotificationType.KDP_EMPTY,
				NotificationType.KDP_READY,
				NotificationType.LAYOUT_READY,
				NotificationType.LIVE_ENTRY,
				LiveStreamCommand.LIVE_STREAM_READY,
				NotificationType.READY_TO_PLAY,
				NotificationType.READY_TO_LOAD,
				NotificationType.ROOT_RESIZE,
				NotificationType.BUFFER_CHANGE,
				NotificationType.PRELOADER_LOADED
			];
		}
		/**
		 * the buffer indicator animation controlled by the mediator.
		 * @return
		 *
		 */
		public function get spinner():BufferAnimation
		{
			return viewComponent as BufferAnimation;
		}

	}
}

qnd: Fix OSMF bug: sometimes bufferChange events was sent after playback
has finished.


package stdio {
  import flash.display.*
  import flash.utils.getQualifiedClassName
  import flash.utils.setTimeout

  public class Sprite extends flash.display.Sprite {
    public function Sprite() {
      stage.scaleMode = StageScaleMode.NO_SCALE
      stage.align = StageAlign.TOP_LEFT

      // Let the subclass constructor run first.
      setTimeout(initialize, 0)
    }

    private function initialize(): void {
      setup(loaderInfo, this, start)
    }

    private function start(): void {
      if ("main" in this && this["main"].length === 0) {
        this["main"]()
      } else {
        warn("Please write your main method like this:")
        warn("public function main(): void {}")
        process.exit(1)
      }
    }

    private function warn(message: String): void {
      process.warn(getQualifiedClassName(this) + ": " + message)
    }
  }
}

package stdio {
  import flash.display.*
  import flash.utils.getQualifiedClassName
  import flash.utils.setTimeout

  public class Sprite extends flash.display.Sprite {
    public function Sprite() {
      if (stage) {
        stage.scaleMode = StageScaleMode.NO_SCALE
        stage.align = StageAlign.TOP_LEFT
      }

      // Let the subclass constructor run first.
      setTimeout(initialize, 0)
    }

    private function initialize(): void {
      setup(loaderInfo, this, start)
    }

    private function start(): void {
      if ("main" in this && this["main"].length === 0) {
        this["main"]()
      } else {
        warn("Please write your main method like this:")
        warn("public function main(): void {}")
        process.exit(1)
      }
    }

    private function warn(message: String): void {
      process.warn(getQualifiedClassName(this) + ": " + message)
    }
  }
}

Fix bug preventing running processes recursively.


package aerys.minko.scene.controller.mesh
{
	import aerys.minko.ns.minko_math;
	import aerys.minko.render.geometry.Geometry;
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.data.MeshVisibilityDataProvider;
	import aerys.minko.scene.node.Mesh;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.scene.node.camera.AbstractCamera;
	import aerys.minko.type.binding.DataBindings;
	import aerys.minko.type.enum.FrustumCulling;
	import aerys.minko.type.math.BoundingBox;
	import aerys.minko.type.math.BoundingSphere;
	import aerys.minko.type.math.Matrix4x4;
	import aerys.minko.type.math.Vector4;

	/**
	 * The MeshVisibilityController watches the Mesh and the active Camera of a Scene
	 * to determine whether the object is actually inside the view frustum or not.
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public final class VisibilityController extends AbstractController
	{
		use namespace minko_math;

		private static const TMP_VECTOR4		: Vector4	= new Vector4();

		private static const STATE_UNDEFINED	: uint		= 0;
		private static const STATE_INSIDE		: uint		= 1;
		private static const STATE_OUTSIDE		: uint		= 2;

		private var _mesh			: Mesh;
		private var _state			: uint;
		private var _lastTest		: int;
		private var _boundingBox	: BoundingBox;
		private var _boundingSphere	: BoundingSphere;

		private var _visibilityData	: MeshVisibilityDataProvider;

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

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

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

		public function VisibilityController()
		{
			super(Mesh);

			initialize();
		}

		private function initialize() : void
		{
			_boundingBox = new BoundingBox(Vector4.ZERO, Vector4.ONE);
			_boundingSphere = new BoundingSphere(Vector4.ZERO, 0.);

			_visibilityData = new MeshVisibilityDataProvider();

			targetAdded.add(targetAddedHandler);
			targetRemoved.add(targetRemovedHandler);
		}

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

			_mesh = target;

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

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

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

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

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

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

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

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

		private function meshLocalToWorldChangedHandler(transform : Matrix4x4) : void
		{
			var geom 	: Geometry 	= _mesh.geometry;
			var culling	: uint		= _visibilityData.frustumCulling;

			if (culling & FrustumCulling.BOX)
				transform.transformRawVectors(
					geom.boundingBox._vertices,
					_boundingBox._vertices
				);

			if (culling & FrustumCulling.SPHERE)
			{
				var center 	: Vector4 = transform.transformVector(geom.boundingSphere.center);
				var scale 	: Vector4 = transform.deltaTransformVector(Vector4.ONE, TMP_VECTOR4);

				_boundingSphere.update(
					center,
					geom.boundingSphere.radius * Math.max(scale.x, scale.y, scale.z)
				);
			}

			testCulling();
		}

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

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

				if (!camera)
					return ;

				_lastTest = camera.cameraData.frustum.testBoundingVolume(
					_boundingSphere,
					_boundingBox,
					null,
					culling,
					_lastTest
				);

				var inside : Boolean = _lastTest == -1;

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

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

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

			return clone;
		}
	}
}

package aerys.minko.scene.controller.mesh
{
	import aerys.minko.ns.minko_math;
	import aerys.minko.render.geometry.Geometry;
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.data.MeshVisibilityDataProvider;
	import aerys.minko.scene.node.Mesh;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.scene.node.camera.AbstractCamera;
	import aerys.minko.type.binding.DataBindings;
	import aerys.minko.type.enum.FrustumCulling;
	import aerys.minko.type.math.BoundingBox;
	import aerys.minko.type.math.BoundingSphere;
	import aerys.minko.type.math.Matrix4x4;
	import aerys.minko.type.math.Vector4;

	/**
	 * The MeshVisibilityController watches the Mesh and the active Camera of a Scene
	 * to determine whether the object is actually inside the view frustum or not.
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public final class VisibilityController extends AbstractController
	{
		use namespace minko_math;

		private static const TMP_VECTOR4		: Vector4	= new Vector4();

		private static const STATE_UNDEFINED	: uint		= 0;
		private static const STATE_INSIDE		: uint		= 1;
		private static const STATE_OUTSIDE		: uint		= 2;

		private var _mesh			: Mesh;
		private var _state			: uint;
		private var _lastTest		: int;
		private var _boundingBox	: BoundingBox;
		private var _boundingSphere	: BoundingSphere;

		private var _visibilityData	: MeshVisibilityDataProvider;

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

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

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

		public function VisibilityController()
		{
			super(Mesh);

			initialize();
		}

		private function initialize() : void
		{
			_boundingBox = new BoundingBox(Vector4.ZERO, Vector4.ONE);
			_boundingSphere = new BoundingSphere(Vector4.ZERO, 0.);

			_visibilityData = new MeshVisibilityDataProvider();

			targetAdded.add(targetAddedHandler);
			targetRemoved.add(targetRemovedHandler);
		}

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

			_mesh = target;

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

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

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

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

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

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

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

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

		private function meshLocalToWorldChangedHandler(transform : Matrix4x4) : void
		{
			var geom 	: Geometry 	= _mesh.geometry;
			var culling	: uint		= _visibilityData.frustumCulling;

			if (!geom.boundingBox || !geom.boundingSphere)
				return ;

			if (culling & FrustumCulling.BOX)
				transform.transformRawVectors(
					geom.boundingBox._vertices,
					_boundingBox._vertices
				);

			if (culling & FrustumCulling.SPHERE)
			{
				var center 	: Vector4 = transform.transformVector(geom.boundingSphere.center);
				var scale 	: Vector4 = transform.deltaTransformVector(Vector4.ONE, TMP_VECTOR4);

				_boundingSphere.update(
					center,
					geom.boundingSphere.radius * Math.max(scale.x, scale.y, scale.z)
				);
			}

			testCulling();
		}

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

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

				if (!camera)
					return ;

				_lastTest = camera.cameraData.frustum.testBoundingVolume(
					_boundingSphere,
					_boundingBox,
					null,
					culling,
					_lastTest
				);

				var inside : Boolean = _lastTest == -1;

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

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

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

			return clone;
		}
	}
}

fix VisibilityController null pointer exception when Geometry.boundingSphere or Geometry.boundingBox is null


package aerys.minko.render.material.environment
{
	public final class EnvironmentMappingProperties
	{
		public static const ENVIRONMENT_MAP				: String	= 'environmentMappingEnvironmentMap';
        public static const ENVIRONMENT_MAP_FILTERING	: String	= 'environmentMappingEnvironmentMapFiltering';
        public static const ENVIRONMENT_MAP_MIPMAPPING	: String	= 'environmentMappingEnvironmentMapMipMapping';
        public static const ENVIRONMENT_MAP_WRAPPING	: String	= 'environmentMappingEnvironmentMapWrapping';
        public static const ENVIRONMENT_MAP_FORMAT		: String	= 'environmentMappingEnvironmentMapFormat';

		public static const ENVIRONMENT_BLENDING		: String 	= 'environmentMappingBlending';
		public static const ENVIRONMENT_MAPPING_TYPE	: String	= 'environmentMappingType';

		public static const REFLECTIVITY				: String	= 'environmentMappingReflectivity';
	}
}

package aerys.minko.render.material.environment
{
	public final class EnvironmentMappingProperties
	{
		public static const ENVIRONMENT_MAP				: String	= 'environmentMap';
        public static const ENVIRONMENT_MAP_FILTERING	: String	= 'environmentMapFiltering';
        public static const ENVIRONMENT_MAP_MIPMAPPING	: String	= 'environmentMapMipMapping';
        public static const ENVIRONMENT_MAP_WRAPPING	: String	= 'environmentMapWrapping';
        public static const ENVIRONMENT_MAP_FORMAT		: String	= 'environmentMapFormat';

		public static const ENVIRONMENT_BLENDING		: String 	= 'environmentMappingBlending';
		public static const ENVIRONMENT_MAPPING_TYPE	: String	= 'environmentMappingType';

		public static const REFLECTIVITY				: String	= 'environmentMappingReflectivity';
	}
}

rename EnvironmentMappingProperties.environmentMappingEnvironmentMap to EnvironmentMappingProperties.environmentMap for consistency (and because it was really long to type...)


package stdio {
  import flash.display.*
  import flash.events.*
  import flash.utils.*
  import flash.net.*

  public class StandardProcess implements Process {
    private const buffered_stdin: BufferedStream = new BufferedStream
    private const stdin_socket: SocketStream = new SocketStream
    private const readline_socket: SocketStream = new SocketStream

    private const stdout_socket: SocketStream = new SocketStream
    private const stderr_socket: SocketStream = new SocketStream

    private var _env: Object
    private var _prompt: String = "> "

    public function StandardProcess(env: Object) {
      _env = env
    }

    public function initialize(callback: Function): void {
      if (available) {
        connect(callback)
      } else {
        callback()
      }
    }

    public function get available(): Boolean {
      return env["stdio.enabled"]
    }

    private function get http_url(): String {
      return env["stdio.http"]
    }

    private function get interactive(): Boolean {
      return env["stdio.interactive"] === "true"
    }

    private function connect(callback: Function): void {
      stdin_socket.onopen = onopen
      readline_socket.onopen = onopen
      stdout_socket.onopen = onopen
      stderr_socket.onopen = onopen

      var n: int = 0

      function onopen(): void {
        if (++n === 3) {
          callback()
        }
      }

      stdin_socket.ondata = buffered_stdin.write
      stdin_socket.onclose = buffered_stdin.close
      readline_socket.ondata = buffered_stdin.write
      readline_socket.onclose = buffered_stdin.close

      const stdin_port: int = get_int("stdio.in")
      const readline_port: int = get_int("stdio.readline")

      if (interactive) {
        readline_socket.connect("localhost", readline_port)
      } else {
        stdin_socket.connect("localhost", stdin_port)
      }

      const stdout_port: int = get_int("stdio.out")
      const stderr_port: int = get_int("stdio.err")

      stdout_socket.connect("localhost", stdout_port)
      stderr_socket.connect("localhost", stderr_port)

      function get_int(name: String): int {
        return parseInt(env[name])
      }
    }

    //----------------------------------------------------------------

    public function get env(): * {
      return _env
    }

    public function get argv(): Array {
      return env["stdio.argv"].split(" ").map(
        function (argument: String, ...rest: Array): String {
          return decodeURIComponent(argument)
        }
      )
    }

    public function puts(value: *): void {
      if (available) {
        if (interactive) {
          readline_socket.puts("!" + value)
        } else {
          stdout.puts(value)
        }
      } else {
        debug.show("puts: " + value)
      }
    }

    public function warn(value: *): void {
      if (available) {
        stderr.puts(value)
      } else {
        debug.show("warn: " + value)
      }
    }

    public function die(value: *): void {
      if (available) {
        warn(value); exit(-1)
      } else {
        throw new Error("fatal error: " + String(value))
      }
    }

    public function style(styles: String, string: String): String {
      const codes: Object = {
        none: 0, bold: 1, italic: 3, underline: 4, inverse: 7,
        black: 30, red: 31, green: 32, yellow: 33, blue: 34,
        magenta: 35, cyan: 36, white: 37, gray: 90, grey: 90
      }

      if (styles === "") {
        return string
      } else {
        return styles.split(/\s+/).map(
          function (style: String, ...rest: Array): String {
            if (style in codes) {
              return escape_sequence(codes[style])
            } else {
              throw new Error("style not supported: " + style)
            }
          }
        ).join("") + string + escape_sequence(0)
      }

      function escape_sequence(code: int): String {
        return "\x1b[" + code + "m"
      }
    }

    public function gets(callback: Function): void {
      if (available) {
        if (interactive) {
          readline_socket.puts("?" + _prompt)
        }

        stdin.gets(callback)
      } else {
        callback(null)
      }
    }

    public function set prompt(value: String): void {
      _prompt = value
    }

    public function get stdin(): InputStream {
      return buffered_stdin
    }

    public function get stdout(): OutputStream {
      return stdout_socket
    }

    public function get stderr(): OutputStream {
      return stderr_socket
    }

    public function handle(error: *): void {
      if (error is UncaughtErrorEvent) {
        UncaughtErrorEvent(error).preventDefault()
        handle(UncaughtErrorEvent(error).error)
        die("run-swf: uncaught error")
      } else if (error is Error) {
        // Important: Avoid the `Error(x)` casting syntax.
        http_post("/error", (error as Error).getStackTrace())
      } else if (error is ErrorEvent) {
        http_post("/error", (error as ErrorEvent).text)
      } else {
        http_post("/error", String(error))
      }
    }

    private function shell_quote(word: String): String {
      if (/^[-=.,\w]+$/.test(word)) {
        return word
      } else {
        return "'" + word.replace(/'/g, "'\\''") + "'"
      }
    }

    public function shell(
      command: *,
      callback: Function,
      errback: Function = null
    ): void {
      if (available) {
        if (command is Array) {
          command = command.map(
            function (word: String, ...rest: Array): String {
              return shell_quote(word)
            }
          ).join(" ")
        }

        http_post("/shell", command, function (data: String): void {
          const result: XML = new XML(data)
          const status: int = result.@status
          const stdout: String = result.stdout.text()
          const stderr: String = result.stderr.text()

          if (status === 0) {
            if (callback.length === 1) {
              callback(stdout)
            } else {
              callback(stdout, stderr)
            }
          } else if (errback === null) {
            warn(stderr)
          } else if (errback.length === 1) {
            errback(status)
          } else if (errback.length === 2) {
            errback(status, stderr)
          } else {
            errback(status, stderr, stdout)
          }
        })
      } else {
        throw new Error("cannot execute command: process not available")
      }
    }

    public function exit(status: int = 0): void {
      if (available) {
        when_ready(function (): void {
          http_post("/exit", String(status))
        })
      } else {
        throw new Error("cannot exit: process not available")
      }
    }

    //----------------------------------------------------------------

    private var n_pending_requests: int = 0
    private var ready_callbacks: Array = []

    private function when_ready(callback: Function): void {
      if (n_pending_requests === 0) {
        callback()
      } else {
        ready_callbacks.push(callback)
      }
    }

    private function handle_ready(): void {
      for each (var callback: Function in ready_callbacks) {
        callback()
      }

      ready_callbacks = []
    }

    private function http_post(
      path: String, content: String, callback: Function = null
    ): void {
      const request: URLRequest = new URLRequest(http_url + path)

      request.method = "POST"
      request.data = content

      const loader: URLLoader = new URLLoader

      ++n_pending_requests

      loader.addEventListener(
        Event.COMPLETE,
        function (event: Event): void {
          if (callback !== null) {
            callback(loader.data)
          }

          if (--n_pending_requests === 0) {
            handle_ready()
          }
        }
      )

      loader.load(request)
    }
  }
}

package stdio {
  import flash.display.*
  import flash.events.*
  import flash.utils.*
  import flash.net.*

  public class StandardProcess implements Process {
    private const buffered_stdin: BufferedStream = new BufferedStream
    private const stdin_socket: SocketStream = new SocketStream
    private const readline_socket: SocketStream = new SocketStream

    private const stdout_socket: SocketStream = new SocketStream
    private const stderr_socket: SocketStream = new SocketStream

    private var _env: Object
    private var _prompt: String = "> "

    public function StandardProcess(env: Object) {
      _env = env
    }

    public function initialize(callback: Function): void {
      if (available) {
        connect(callback)
      } else {
        callback()
      }
    }

    public function get available(): Boolean {
      return env["stdio.enabled"]
    }

    private function get http_url(): String {
      return env["stdio.http"]
    }

    private function get interactive(): Boolean {
      return env["stdio.interactive"] === "true"
    }

    private function connect(callback: Function): void {
      stdin_socket.onopen = onopen
      readline_socket.onopen = onopen
      stdout_socket.onopen = onopen
      stderr_socket.onopen = onopen

      var n: int = 0

      function onopen(): void {
        if (++n === 3) {
          callback()
        }
      }

      stdin_socket.ondata = buffered_stdin.write
      stdin_socket.onclose = buffered_stdin.close
      readline_socket.ondata = buffered_stdin.write
      readline_socket.onclose = buffered_stdin.close

      const stdin_port: int = get_int("stdio.in")
      const readline_port: int = get_int("stdio.readline")

      if (interactive) {
        readline_socket.connect("localhost", readline_port)
      } else {
        stdin_socket.connect("localhost", stdin_port)
      }

      const stdout_port: int = get_int("stdio.out")
      const stderr_port: int = get_int("stdio.err")

      stdout_socket.connect("localhost", stdout_port)
      stderr_socket.connect("localhost", stderr_port)

      function get_int(name: String): int {
        return parseInt(env[name])
      }
    }

    //----------------------------------------------------------------

    public function get env(): * {
      return _env
    }

    public function get argv(): Array {
      if (env["stdio.argv"] === "") {
        return []
      } else {
        return env["stdio.argv"].split(" ").map(
          function (argument: String, ...rest: Array): String {
            return decodeURIComponent(argument)
          }
        )
      }
    }

    public function puts(value: *): void {
      if (available) {
        if (interactive) {
          readline_socket.puts("!" + value)
        } else {
          stdout.puts(value)
        }
      } else {
        debug.show("puts: " + value)
      }
    }

    public function warn(value: *): void {
      if (available) {
        stderr.puts(value)
      } else {
        debug.show("warn: " + value)
      }
    }

    public function die(value: *): void {
      if (available) {
        warn(value); exit(-1)
      } else {
        throw new Error("fatal error: " + String(value))
      }
    }

    public function style(styles: String, string: String): String {
      const codes: Object = {
        none: 0, bold: 1, italic: 3, underline: 4, inverse: 7,
        black: 30, red: 31, green: 32, yellow: 33, blue: 34,
        magenta: 35, cyan: 36, white: 37, gray: 90, grey: 90
      }

      if (styles === "") {
        return string
      } else {
        return styles.split(/\s+/).map(
          function (style: String, ...rest: Array): String {
            if (style in codes) {
              return escape_sequence(codes[style])
            } else {
              throw new Error("style not supported: " + style)
            }
          }
        ).join("") + string + escape_sequence(0)
      }

      function escape_sequence(code: int): String {
        return "\x1b[" + code + "m"
      }
    }

    public function gets(callback: Function): void {
      if (available) {
        if (interactive) {
          readline_socket.puts("?" + _prompt)
        }

        stdin.gets(callback)
      } else {
        callback(null)
      }
    }

    public function set prompt(value: String): void {
      _prompt = value
    }

    public function get stdin(): InputStream {
      return buffered_stdin
    }

    public function get stdout(): OutputStream {
      return stdout_socket
    }

    public function get stderr(): OutputStream {
      return stderr_socket
    }

    public function handle(error: *): void {
      if (error is UncaughtErrorEvent) {
        UncaughtErrorEvent(error).preventDefault()
        handle(UncaughtErrorEvent(error).error)
        die("run-swf: uncaught error")
      } else if (error is Error) {
        // Important: Avoid the `Error(x)` casting syntax.
        http_post("/error", (error as Error).getStackTrace())
      } else if (error is ErrorEvent) {
        http_post("/error", (error as ErrorEvent).text)
      } else {
        http_post("/error", String(error))
      }
    }

    private function shell_quote(word: String): String {
      if (/^[-=.,\w]+$/.test(word)) {
        return word
      } else {
        return "'" + word.replace(/'/g, "'\\''") + "'"
      }
    }

    public function shell(
      command: *,
      callback: Function,
      errback: Function = null
    ): void {
      if (available) {
        if (command is Array) {
          command = command.map(
            function (word: String, ...rest: Array): String {
              return shell_quote(word)
            }
          ).join(" ")
        }

        http_post("/shell", command, function (data: String): void {
          const result: XML = new XML(data)
          const status: int = result.@status
          const stdout: String = result.stdout.text()
          const stderr: String = result.stderr.text()

          if (status === 0) {
            if (callback.length === 1) {
              callback(stdout)
            } else {
              callback(stdout, stderr)
            }
          } else if (errback === null) {
            warn(stderr)
          } else if (errback.length === 1) {
            errback(status)
          } else if (errback.length === 2) {
            errback(status, stderr)
          } else {
            errback(status, stderr, stdout)
          }
        })
      } else {
        throw new Error("cannot execute command: process not available")
      }
    }

    public function exit(status: int = 0): void {
      if (available) {
        when_ready(function (): void {
          http_post("/exit", String(status))
        })
      } else {
        throw new Error("cannot exit: process not available")
      }
    }

    //----------------------------------------------------------------

    private var n_pending_requests: int = 0
    private var ready_callbacks: Array = []

    private function when_ready(callback: Function): void {
      if (n_pending_requests === 0) {
        callback()
      } else {
        ready_callbacks.push(callback)
      }
    }

    private function handle_ready(): void {
      for each (var callback: Function in ready_callbacks) {
        callback()
      }

      ready_callbacks = []
    }

    private function http_post(
      path: String, content: String, callback: Function = null
    ): void {
      const request: URLRequest = new URLRequest(http_url + path)

      request.method = "POST"
      request.data = content

      const loader: URLLoader = new URLLoader

      ++n_pending_requests

      loader.addEventListener(
        Event.COMPLETE,
        function (event: Event): void {
          if (callback !== null) {
            callback(loader.data)
          }

          if (--n_pending_requests === 0) {
            handle_ready()
          }
        }
      )

      loader.load(request)
    }
  }
}

Make `process.argv` be [] when no arguments are given.


package aerys.minko.scene.node.camera
{
	import aerys.minko.ns.minko_scene;
	import aerys.minko.scene.controller.camera.CameraController;
	import aerys.minko.scene.data.CameraDataProvider;
	import aerys.minko.scene.node.AbstractSceneNode;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.type.Signal;
	import aerys.minko.type.binding.DataBindings;
	import aerys.minko.type.math.Matrix4x4;
	import aerys.minko.type.math.Ray;
	import aerys.minko.type.math.Vector4;

	import flash.geom.Point;

	use namespace minko_scene;

	public class Camera extends AbstractCamera
	{
		public static const DEFAULT_FOV		: Number	= Math.PI * .25;

        private static const TMP_VECTOR4    : Vector4   = new Vector4();

		public function get fieldOfView() : Number
		{
			return _cameraData.fieldOfView;
		}
		public function set fieldOfView(value : Number) : void
		{
			_cameraData.fieldOfView = value;
		}

		public function Camera(fieldOfView	: Number = DEFAULT_FOV,
							   zNear		: Number = AbstractCamera.DEFAULT_ZNEAR,
							   zFar			: Number = AbstractCamera.DEFAULT_ZFAR)
		{
			super(zNear, zFar);

			_cameraData.fieldOfView = fieldOfView;
		}

		override minko_scene function cloneNode() : AbstractSceneNode
		{
			var clone : Camera = new Camera(fieldOfView, zNear, zFar);

			clone.transform.copyFrom(this.transform);

			return clone as AbstractSceneNode;
		}

		override public function unproject(x : Number, y : Number, out : Ray = null) : Ray
		{
			if (!(root is Scene))
				throw new Error('Camera must be in the scene to unproject vectors.');

			out ||= new Ray();

			var sceneBindings	: DataBindings	= (root as Scene).bindings;
			var zNear			: Number		= _cameraData.zNear;
			var zFar			: Number		= _cameraData.zFar;
			var fovDiv2			: Number		= _cameraData.fieldOfView * 0.5;
			var width			: Number		= sceneBindings.getProperty('viewportWidth');
			var height			: Number		= sceneBindings.getProperty('viewportHeight');
			var xPercent		: Number		= 2.0 * (x / width - 0.5);
			var yPercent 		: Number		= 2.0 * (y / height - 0.5);
			var dx				: Number 		= Math.tan(fovDiv2) * xPercent * (width / height);
			var dy				: Number 		= -Math.tan(fovDiv2) * yPercent;

			out.origin.set(dx * zNear, dy * zNear, zNear);
			out.direction.set(dx * zNear, dy * zNear, zNear).normalize();

			localToWorld(out.origin, out.origin);
			localToWorld(out.direction, out.direction, true);

			return out;
		}

		override public function project(localToWorld : Matrix4x4, output : Point = null) : Point
		{
			output ||= new Point();

			var sceneBindings	: DataBindings	= (root as Scene).bindings;
			var width			: Number		= sceneBindings.getProperty('viewportWidth');
			var height			: Number		= sceneBindings.getProperty('viewportHeight');
			var translation		: Vector4		= localToWorld.getTranslation();
			var screenPosition	: Vector4		= _cameraData.worldToScreen.projectVector(
                translation, TMP_VECTOR4
            );

			output.x = width * ((screenPosition.x + 1.0) * .5);
			output.y = height * ((1.0 - ((screenPosition.y + 1.0) * .5)));

			return output;
		}
	}
}

package aerys.minko.scene.node.camera
{
	import aerys.minko.ns.minko_scene;
	import aerys.minko.scene.controller.camera.CameraController;
	import aerys.minko.scene.data.CameraDataProvider;
	import aerys.minko.scene.node.AbstractSceneNode;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.type.Signal;
	import aerys.minko.type.binding.DataBindings;
	import aerys.minko.type.math.Matrix4x4;
	import aerys.minko.type.math.Ray;
	import aerys.minko.type.math.Vector4;

	import flash.geom.Point;

	use namespace minko_scene;

	public class Camera extends AbstractCamera
	{
		public static const DEFAULT_FOV		: Number	= Math.PI * .25;

        private static const TMP_VECTOR4    : Vector4   = new Vector4();

		public function get fieldOfView() : Number
		{
			return _cameraData.fieldOfView;
		}
		public function set fieldOfView(value : Number) : void
		{
			_cameraData.fieldOfView = value;
		}

		public function Camera(fieldOfView	: Number = DEFAULT_FOV,
							   zNear		: Number = AbstractCamera.DEFAULT_ZNEAR,
							   zFar			: Number = AbstractCamera.DEFAULT_ZFAR)
		{
			super(zNear, zFar);

			_cameraData.fieldOfView = fieldOfView;
		}

		override minko_scene function cloneNode() : AbstractSceneNode
		{
			var clone : Camera = new Camera(fieldOfView, zNear, zFar);

			clone.transform.copyFrom(this.transform);

			return clone as AbstractSceneNode;
		}

		override public function unproject(x : Number, y : Number, out : Ray = null) : Ray
		{
			if (!(root is Scene))
				throw new Error('Camera must be in the scene to unproject vectors.');

			out ||= new Ray();

			var sceneBindings	: DataBindings	= (root as Scene).bindings;
			var zNear			: Number		= _cameraData.zNear;
			var zFar			: Number		= _cameraData.zFar;
			var fovDiv2			: Number		= _cameraData.fieldOfView * 0.5;
			var width			: Number		= sceneBindings.propertyExists('viewportWidth')
                ? sceneBindings.getProperty('viewportWidth')
                : 0.;
			var height			: Number		= sceneBindings.propertyExists('viewportHeight')
                ? sceneBindings.getProperty('viewportHeight')
                : 0.;
			var xPercent		: Number		= 2.0 * (x / width - 0.5);
			var yPercent 		: Number		= 2.0 * (y / height - 0.5);
			var dx				: Number 		= Math.tan(fovDiv2) * xPercent * (width / height);
			var dy				: Number 		= -Math.tan(fovDiv2) * yPercent;

			out.origin.set(dx * zNear, dy * zNear, zNear);
			out.direction.set(dx * zNear, dy * zNear, zNear).normalize();

			localToWorld(out.origin, out.origin);
			localToWorld(out.direction, out.direction, true);

			return out;
		}

		override public function project(localToWorld : Matrix4x4, output : Point = null) : Point
		{
			output ||= new Point();

			var sceneBindings	: DataBindings	= (root as Scene).bindings;
			var width			: Number		= sceneBindings.getProperty('viewportWidth');
			var height			: Number		= sceneBindings.getProperty('viewportHeight');
			var translation		: Vector4		= localToWorld.getTranslation();
			var screenPosition	: Vector4		= _cameraData.worldToScreen.projectVector(
                translation, TMP_VECTOR4
            );

			output.x = width * ((screenPosition.x + 1.0) * .5);
			output.y = height * ((1.0 - ((screenPosition.y + 1.0) * .5)));

			return output;
		}
	}
}

use 0 as default value when viewportWidth/viewportHeight is not defined in the scene bindings


package aerys.minko.render.shader
{
	import aerys.minko.ns.minko_render;
	import aerys.minko.ns.minko_shader;
	import aerys.minko.render.RenderTarget;
	import aerys.minko.render.resource.Context3DResource;
	import aerys.minko.render.resource.Program3DResource;
	import aerys.minko.render.shader.compiler.graph.ShaderGraph;
	import aerys.minko.render.shader.compiler.graph.nodes.AbstractNode;
	import aerys.minko.render.shader.part.ShaderPart;
	import aerys.minko.type.Signal;
	import aerys.minko.type.binding.DataBindings;

	import flash.utils.getQualifiedClassName;
	import aerys.minko.type.binding.Signature;
	import aerys.minko.type.binding.ShaderDataBindingsProxy;

	use namespace minko_shader;

	/**
	 * The base class to extend in order to create ActionScript shaders
	 * and program the GPU using AS3.
	 *
	 * @author Jean-Marc Le Roux
	 * @author Romain Gilliotte
	 *
	 * @see aerys.minko.render.shader.ShaderPart
	 * @see aerys.minko.render.shader.ShaderInstance
	 * @see aerys.minko.render.shader.ShaderSignature
	 * @see aerys.minko.render.shader.ShaderDataBindings
	 */
	public class Shader extends ShaderPart
	{
		use namespace minko_shader;
		use namespace minko_render;

		minko_shader var _meshBindings		: ShaderDataBindingsProxy		= null;
		minko_shader var _sceneBindings		: ShaderDataBindingsProxy		= null;
		minko_shader var _kills				: Vector.<AbstractNode>			= new <AbstractNode>[];

		private var _name					: String						= null;
		private var _enabled				: Boolean						= true;
		private var _defaultSettings		: ShaderSettings				= new ShaderSettings(null);

		private var _instances				: Vector.<ShaderInstance>		= new <ShaderInstance>[];
		private var _numActiveInstances		: uint							= 0;
		private var _numRenderedInstances	: uint							= 0;
		private var _settings				: Vector.<ShaderSettings>		= new <ShaderSettings>[];
		private var _programs				: Vector.<Program3DResource>	= new <Program3DResource>[];

		private var _begin					: Signal						= new Signal('Shader.begin');
		private var _end					: Signal						= new Signal('Shader.end');

		/**
		 * The name of the shader. Default value is the qualified name of the
		 * ActionScript shader class (example: "aerys.minko.render.effect.basic::BasicShader").
		 *
		 * @return
		 *
		 */
		public function get name() : String
		{
			return _name;
		}
		public function set name(value : String) : void
		{
			_name = value;
		}

		/**
		 * The signal executed when the shader (one of its forks) is used
		 * for rendering for the very first time during the current frame.
		 * Callbacks for this signal must accept the following arguments:
		 *

		 *
shader : Shader, the shader executing the signal

		 *
context : Context3D, the context used for rendering

		 *
backBuffer : RenderTarget, the render target used as the back-buffer

		 *

		 *
		 * @return
		 *
		 */
		public function get begin() : Signal
		{
			return _begin;
		}

		/**
		 * The signal executed when the shader (one of its forks) is used
		 * for rendering for the very last time during the current frame.
		 * Callbacks for this signal must accept the following arguments:
		 *

		 *
shader : Shader, the shader executing the signal

		 *
context : Context3D, the context used for rendering

		 *
backBuffer : RenderTarget, the render target used as the back-buffer

		 *

		 *
		 * @return
		 *
		 */
		public function get end() : Signal
		{
			return _end;
		}

		/**
		 * Whether the shader (and all its forks) are enabled for rendering
		 * or not.
		 *
		 * @return
		 *
		 */
		public function get enabled() : Boolean
		{
			return _enabled;
		}
		public function set enabled(value : Boolean) : void
		{
			_enabled = value;
		}

		/**
		 *
		 * @param priority Default value is 0.
		 * @param renderTarget Default value is null.
		 *
		 */
		public function Shader(renderTarget	: RenderTarget	= null,
							   priority		: Number		= 0.0)
		{
			super(this);

			_defaultSettings.renderTarget = renderTarget;
			_defaultSettings.priority = priority;

			_name = getQualifiedClassName(this);
		}

		public function fork(sceneBindings	: DataBindings,
							 meshBindings	: DataBindings) : ShaderInstance
		{
			var pass : ShaderInstance = findPass(sceneBindings, meshBindings);

			if (pass == null)
			{
				var signature	: Signature			= new Signature();
				var config		: ShaderSettings	= findOrCreateSettings(sceneBindings, meshBindings);

				signature.mergeWith(config.signature);

				var program		: Program3DResource	= null;

				if (config.enabled)
				{
					program = findOrCreateProgram(sceneBindings, meshBindings);
					signature.mergeWith(program.signature);
				}

				pass = new ShaderInstance(this, config, program, signature);
				pass.retained.add(shaderInstanceRetainedHandler);
				pass.released.add(shaderInstanceReleasedHandler);

				_instances.push(pass);
			}

			return pass;
		}

		public function disposeUnusedResources() : void
		{
			var numInstances	: uint = _instances.length;
			var currentId		: uint = 0;

			for (var instanceId : uint = 0; instanceId < numInstances; ++instanceId)
			{
				var passInstance : ShaderInstance = _instances[instanceId];

				if (!passInstance.isDisposable)
					_instances[currentId++] = passInstance;
			}

			_instances.length = currentId;
		}

		/**
		 * Override this method to initialize the settings
		 * - such as the blending operands or the triangle culling - of the shader.
		 * This values can be read from both the mesh and the scene bindings.
		 *
		 * @param settings
		 *
		 * @see aerys.minko.render.shader.ShaderSettings
		 *
		 */
		protected function initializeSettings(settings : ShaderSettings) : void
		{
			// nothing
		}

		/**
		 * The getVertexPosition() method is called to evaluate the vertex shader
		 * program that shall be executed on the GPU.
		 *
		 * @return The position of the vertex in clip space (normalized screen space).
		 *
		 */
		protected function getVertexPosition() : SFloat
		{
			throw new Error("The method 'getVertexPosition' must be implemented.");
		}

		/**
		 * The getPixelColor() method is called to evaluate the fragment shader
		 * program that shall be executed on the GPU.
		 *
		 * @return The color of the pixel on the screen.
		 *
		 */
		protected function getPixelColor() : SFloat
		{
			throw new Error("The method 'getPixelColor' must be implemented.");
		}

		private function findPass(sceneBindings	: DataBindings,
								  meshBindings	: DataBindings) : ShaderInstance
		{
			var numPasses : int = _instances.length;

			for (var passId : uint = 0; passId < numPasses; ++passId)
				if (_instances[passId].signature.isValid(sceneBindings, meshBindings))
					return _instances[passId];

			return null;
		}

		private function findOrCreateProgram(sceneBindings	: DataBindings,
											 meshBindings	: DataBindings) : Program3DResource
		{
			var numPrograms	: int = _programs.length;
			var program 	: Program3DResource;

			for (var programId : uint = 0; programId < numPrograms; ++programId)
				if (_programs[programId].signature.isValid(sceneBindings, meshBindings))
					return _programs[programId];

			var signature		: Signature		= new Signature();

			_meshBindings	= new ShaderDataBindingsProxy(meshBindings, signature, Signature.SOURCE_MESH);
			_sceneBindings	= new ShaderDataBindingsProxy(sceneBindings, signature, Signature.SOURCE_SCENE);

			var vertexPosition	: AbstractNode	= getVertexPosition()._node;
			var pixelColor		: AbstractNode	= getPixelColor()._node;
			var shaderGraph		: ShaderGraph	= new ShaderGraph(vertexPosition, pixelColor, _kills);

			program			= shaderGraph.generateProgram(_name, signature);
			_meshBindings	= null;
			_sceneBindings	= null;
			_kills.length	= 0;

			_programs.push(program);

			return program;
		}

		private function findOrCreateSettings(sceneBindings	: DataBindings,
											  meshBindings 	: DataBindings) : ShaderSettings
		{
			var numConfigs	: int 				= _settings.length;
			var config		: ShaderSettings	= null;

			for (var configId : int = 0; configId < numConfigs; ++configId)
				if (_settings[configId].signature.isValid(sceneBindings, meshBindings))
					return _settings[configId];

			var signature : Signature = new Signature();

			config			= _defaultSettings.clone(signature);
			_meshBindings	= new ShaderDataBindingsProxy(meshBindings, signature, Signature.SOURCE_MESH);
			_sceneBindings	= new ShaderDataBindingsProxy(sceneBindings, signature, Signature.SOURCE_SCENE);

			initializeSettings(config);

			_meshBindings	= null;
			_sceneBindings	= null;

			_settings.push(config);

			return config;
		}

		private function shaderInstanceRetainedHandler(instance : ShaderInstance,
													   numUses	: uint) : void
		{
			if (numUses == 1)
			{
				++_numActiveInstances;

				instance.begin.add(shaderInstanceBeginHandler);
				instance.end.add(shaderInstanceEndHandler);
			}
		}

		private function shaderInstanceReleasedHandler(instance : ShaderInstance,
													   numUses	: uint) : void
		{
			if (numUses == 0)
			{
				--_numActiveInstances;

				instance.begin.remove(shaderInstanceBeginHandler);
				instance.end.remove(shaderInstanceEndHandler);
			}
		}

		private function shaderInstanceBeginHandler(instance 	: ShaderInstance,
													context		: Context3DResource,
													backBuffer	: RenderTarget) : void
		{
			if (_numRenderedInstances == 0)
				_begin.execute(this, context, backBuffer);
		}

		private function shaderInstanceEndHandler(instance		: ShaderInstance,
												  context		: Context3DResource,
												  backBuffer	: RenderTarget) : void
		{
			_numRenderedInstances++;

			if (_numRenderedInstances == _numActiveInstances)
			{
				_numRenderedInstances = 0;
				_end.execute(this, context, backBuffer);
			}
		}
	}
}

package aerys.minko.render.shader
{
	import aerys.minko.ns.minko_render;
	import aerys.minko.ns.minko_shader;
	import aerys.minko.render.RenderTarget;
	import aerys.minko.render.resource.Context3DResource;
	import aerys.minko.render.resource.Program3DResource;
	import aerys.minko.render.shader.compiler.graph.ShaderGraph;
	import aerys.minko.render.shader.compiler.graph.nodes.AbstractNode;
	import aerys.minko.render.shader.part.ShaderPart;
	import aerys.minko.type.Signal;
	import aerys.minko.type.binding.DataBindings;

	import flash.utils.getQualifiedClassName;
	import aerys.minko.type.binding.Signature;
	import aerys.minko.type.binding.ShaderDataBindingsProxy;

	use namespace minko_shader;

	/**
	 * The base class to extend in order to create ActionScript shaders
	 * and program the GPU using AS3.
	 *
	 * @author Jean-Marc Le Roux
	 * @author Romain Gilliotte
	 *
	 * @see aerys.minko.render.shader.ShaderPart
	 * @see aerys.minko.render.shader.ShaderInstance
	 * @see aerys.minko.render.shader.ShaderSignature
	 * @see aerys.minko.render.shader.ShaderDataBindings
	 */
	public class Shader extends ShaderPart
	{
		use namespace minko_shader;
		use namespace minko_render;

		minko_shader var _meshBindings		: ShaderDataBindingsProxy		= null;
		minko_shader var _sceneBindings		: ShaderDataBindingsProxy		= null;
		minko_shader var _kills				: Vector.<AbstractNode>			= new <AbstractNode>[];

		private var _name					: String						= null;
		private var _enabled				: Boolean						= true;
		private var _defaultSettings		: ShaderSettings				= new ShaderSettings(null);

		private var _instances				: Vector.<ShaderInstance>		= new <ShaderInstance>[];
		private var _numActiveInstances		: uint							= 0;
		private var _numRenderedInstances	: uint							= 0;
		private var _settings				: Vector.<ShaderSettings>		= new <ShaderSettings>[];
		private var _programs				: Vector.<Program3DResource>	= new <Program3DResource>[];

		private var _begin					: Signal						= new Signal('Shader.begin');
		private var _end					: Signal						= new Signal('Shader.end');

		/**
		 * The name of the shader. Default value is the qualified name of the
		 * ActionScript shader class (example: "aerys.minko.render.effect.basic::BasicShader").
		 *
		 * @return
		 *
		 */
		public function get name() : String
		{
			return _name;
		}
		public function set name(value : String) : void
		{
			_name = value;
		}

		/**
		 * The signal executed when the shader (one of its forks) is used
		 * for rendering for the very first time during the current frame.
		 * Callbacks for this signal must accept the following arguments:
		 *

		 *
shader : Shader, the shader executing the signal

		 *
context : Context3D, the context used for rendering

		 *
backBuffer : RenderTarget, the render target used as the back-buffer

		 *

		 *
		 * @return
		 *
		 */
		public function get begin() : Signal
		{
			return _begin;
		}

		/**
		 * The signal executed when the shader (one of its forks) is used
		 * for rendering for the very last time during the current frame.
		 * Callbacks for this signal must accept the following arguments:
		 *

		 *
shader : Shader, the shader executing the signal

		 *
context : Context3D, the context used for rendering

		 *
backBuffer : RenderTarget, the render target used as the back-buffer

		 *

		 *
		 * @return
		 *
		 */
		public function get end() : Signal
		{
			return _end;
		}

		/**
		 * Whether the shader (and all its forks) are enabled for rendering
		 * or not.
		 *
		 * @return
		 *
		 */
		public function get enabled() : Boolean
		{
			return _enabled;
		}
		public function set enabled(value : Boolean) : void
		{
			_enabled = value;
		}

		/**
		 *
		 * @param priority Default value is 0.
		 * @param renderTarget Default value is null.
		 *
		 */
		public function Shader(renderTarget	: RenderTarget	= null,
							   priority		: Number		= 0.0)
		{
			super(this);

			_defaultSettings.renderTarget = renderTarget;
			_defaultSettings.priority = priority;

			_name = getQualifiedClassName(this);
		}

		public function fork(sceneBindings	: DataBindings,
							 meshBindings	: DataBindings) : ShaderInstance
		{
			var pass : ShaderInstance = findPass(sceneBindings, meshBindings);

			if (!pass)
			{
				var signature	: Signature			= new Signature();
				var config		: ShaderSettings	= findOrCreateSettings(
					sceneBindings, meshBindings
				);

				signature.mergeWith(config.signature);

				var program		: Program3DResource	= null;

				if (config.enabled)
				{
					program = findOrCreateProgram(sceneBindings, meshBindings);
					signature.mergeWith(program.signature);
				}

				pass = new ShaderInstance(this, config, program, signature);
				pass.retained.add(shaderInstanceRetainedHandler);
				pass.released.add(shaderInstanceReleasedHandler);

				_instances.push(pass);
			}

			return pass;
		}

		public function disposeUnusedResources() : void
		{
			var numInstances	: uint = _instances.length;
			var currentId		: uint = 0;

			for (var instanceId : uint = 0; instanceId < numInstances; ++instanceId)
			{
				var passInstance : ShaderInstance = _instances[instanceId];

				if (!passInstance.isDisposable)
					_instances[currentId++] = passInstance;
			}

			_instances.length = currentId;
		}

		/**
		 * Override this method to initialize the settings
		 * - such as the blending operands or the triangle culling - of the shader.
		 * This values can be read from both the mesh and the scene bindings.
		 *
		 * @param settings
		 *
		 * @see aerys.minko.render.shader.ShaderSettings
		 *
		 */
		protected function initializeSettings(settings : ShaderSettings) : void
		{
			// nothing
		}

		/**
		 * The getVertexPosition() method is called to evaluate the vertex shader
		 * program that shall be executed on the GPU.
		 *
		 * @return The position of the vertex in clip space (normalized screen space).
		 *
		 */
		protected function getVertexPosition() : SFloat
		{
			throw new Error("The method 'getVertexPosition' must be implemented.");
		}

		/**
		 * The getPixelColor() method is called to evaluate the fragment shader
		 * program that shall be executed on the GPU.
		 *
		 * @return The color of the pixel on the screen.
		 *
		 */
		protected function getPixelColor() : SFloat
		{
			throw new Error("The method 'getPixelColor' must be implemented.");
		}

		private function findPass(sceneBindings	: DataBindings,
								  meshBindings	: DataBindings) : ShaderInstance
		{
			var numPasses : int = _instances.length;

			for (var passId : uint = 0; passId < numPasses; ++passId)
				if (_instances[passId].signature.isValid(sceneBindings, meshBindings))
					return _instances[passId];

			return null;
		}

		private function findOrCreateProgram(sceneBindings	: DataBindings,
											 meshBindings	: DataBindings) : Program3DResource
		{
			var numPrograms	: int = _programs.length;
			var program 	: Program3DResource;

			for (var programId : uint = 0; programId < numPrograms; ++programId)
				if (_programs[programId].signature.isValid(sceneBindings, meshBindings))
					return _programs[programId];

			var signature		: Signature		= new Signature();

			_meshBindings	= new ShaderDataBindingsProxy(meshBindings, signature, Signature.SOURCE_MESH);
			_sceneBindings	= new ShaderDataBindingsProxy(sceneBindings, signature, Signature.SOURCE_SCENE);

			var vertexPosition	: AbstractNode	= getVertexPosition()._node;
			var pixelColor		: AbstractNode	= getPixelColor()._node;
			var shaderGraph		: ShaderGraph	= new ShaderGraph(vertexPosition, pixelColor, _kills);

			program			= shaderGraph.generateProgram(_name, signature);
			_meshBindings	= null;
			_sceneBindings	= null;
			_kills.length	= 0;

			_programs.push(program);

			return program;
		}

		private function findOrCreateSettings(sceneBindings	: DataBindings,
											  meshBindings 	: DataBindings) : ShaderSettings
		{
			var numConfigs	: int 				= _settings.length;
			var config		: ShaderSettings	= null;

			for (var configId : int = 0; configId < numConfigs; ++configId)
				if (_settings[configId].signature.isValid(sceneBindings, meshBindings))
					return _settings[configId];

			var signature : Signature = new Signature();

			config			= _defaultSettings.clone(signature);
			_meshBindings	= new ShaderDataBindingsProxy(meshBindings, signature, Signature.SOURCE_MESH);
			_sceneBindings	= new ShaderDataBindingsProxy(sceneBindings, signature, Signature.SOURCE_SCENE);

			initializeSettings(config);

			_meshBindings	= null;
			_sceneBindings	= null;

			_settings.push(config);

			return config;
		}

		private function shaderInstanceRetainedHandler(instance : ShaderInstance,
													   numUses	: uint) : void
		{
			if (numUses == 1)
			{
				++_numActiveInstances;

				instance.begin.add(shaderInstanceBeginHandler);
				instance.end.add(shaderInstanceEndHandler);
			}
		}

		private function shaderInstanceReleasedHandler(instance : ShaderInstance,
													   numUses	: uint) : void
		{
			if (numUses == 0)
			{
				--_numActiveInstances;

				instance.begin.remove(shaderInstanceBeginHandler);
				instance.end.remove(shaderInstanceEndHandler);
			}
		}

		private function shaderInstanceBeginHandler(instance 	: ShaderInstance,
													context		: Context3DResource,
													backBuffer	: RenderTarget) : void
		{
			if (_numRenderedInstances == 0)
				_begin.execute(this, context, backBuffer);
		}

		private function shaderInstanceEndHandler(instance		: ShaderInstance,
												  context		: Context3DResource,
												  backBuffer	: RenderTarget) : void
		{
			_numRenderedInstances++;

			if (_numRenderedInstances == _numActiveInstances)
			{
				_numRenderedInstances = 0;
				_end.execute(this, context, backBuffer);
			}
		}
	}
}

fix coding style

fix coding style