package aerys.minko.scene.visitor.data
{
	import aerys.minko.type.math.Frustum;
	import aerys.minko.type.math.Matrix4x4;
	import aerys.minko.type.math.Vector4;

	import flash.geom.Matrix;

	public class CameraData implements IWorldData
	{
		public static const POSITION		: String = 'position';
		public static const LOOK_AT			: String = 'lookAt';
		public static const UP				: String = 'up';

		public static const RATIO			: String = 'ratio';
		public static const FOV				: String = 'fov';
		public static const Z_NEAR			: String = 'zNear';

		public static const Z_FAR			: String = 'zFar';
		public static const Z_FAR_PARTS		: String = 'zFarParts';

		public static const VIEW			: String = 'view';
		public static const PROJECTION		: String = 'projection';
		public static const LOCAL_POSITION	: String = 'localPosition';
		public static const LOCAL_LOOK_AT	: String = 'localLookAt';

		public static const DIRECTION		: String = 'direction';
		public static const LOCAL_DIRECTION	: String = 'localDirection';

		public static const FRUSTUM			: String = 'frustum';

		// local data provider
		protected var _styleStack	: StyleStack;
		protected var _localData	: LocalData;

		// data available on initialisation
		protected var _position	: Vector4;
		protected var _lookAt	: Vector4;
		protected var _up		: Vector4;

		protected var _ratio	: Number;
		protected var _fov		: Number;
		protected var _zNear	: Number;
		protected var _zFar		: Number;

		// computed data
		protected var _zFarParts						: Vector4;
		protected var _zFarParts_invalidated			: Boolean;

		protected var _view								: Matrix4x4;
		protected var _view_positionVersion				: uint;
		protected var _view_lookAtVersion				: uint;
		protected var _view_upVersion					: uint;

		protected var _projection						: Matrix4x4;
		protected var _projection_invalidated			: Boolean;

		protected var _localPosition					: Vector4;
		protected var _localPosition_positionVersion	: uint;

		protected var _localLookAt						: Vector4;
		protected var _localLookAt_lookAtVersion		: uint;

		protected var _frustum							: Frustum;
		protected var _frustum_projectionVersion		: uint;

		public function get position() : Vector4
		{
			return _position;
		}

		public function get lookAt() : Vector4
		{
			return _lookAt;
		}

		public function get up() : Vector4
		{
			return _up;
		}

		public function get fieldOfView() : Number
		{
			return _fov;
		}

		public function get zNear() : Number
		{
			return _zNear;
		}

		public function get zFar() : Number
		{
			return _zFar;
		}

		public function get zFarParts() : Vector4
		{
			if (_zFarParts_invalidated)
			{
				_zFarParts = new Vector4(0, 0.25 * _zFar, 0.5 * _zFar, 0.75 * _zFar);
				_zFarParts_invalidated = false;
			}
			return _zFarParts;
		}

		public function get view() : Matrix4x4
		{
			if (_view_positionVersion != _position.version ||
				_view_lookAtVersion != _lookAt.version ||
				_view_upVersion != _up.version)
			{
				_view = Matrix4x4.lookAtLH(_position, _lookAt, _up, _view);

				_view_positionVersion	= _position.version;
				_view_lookAtVersion		= _lookAt.version;
				_view_upVersion			= _lookAt.version;
			}

			return _view;
		}

		public function get projection() : Matrix4x4
		{
			if (_projection_invalidated)
			{
				_projection = Matrix4x4.perspectiveFoVLH(_fov, _ratio, _zNear, _zFar, _projection);
				_projection_invalidated = false;
			}

			return _projection;
		}

		public function get frustrum() : Frustum
		{
			var projectionMatrix : Matrix4x4 = projection;

			if (_frustum_projectionVersion != projectionMatrix.version)
			{
				if (_frustum == null)
					_frustum = new Frustum();
				_frustum.update(projectionMatrix);
				_frustum_projectionVersion = projectionMatrix.version;
			}

			return _frustum;
		}

		public function get localPosition() : Vector4
		{
			if (_localPosition_positionVersion != _position.version)
			{
				_localPosition = _localData.world.multiplyVector(_position, _localPosition);
				_localPosition_positionVersion = _position.version;
			}

			return _localPosition;
		}

		public function get localLookAt() : Vector4
		{
			if (_localLookAt_lookAtVersion != _lookAt.version)
			{
				_localLookAt = _localData.world.deltaMultiplyVector(_lookAt, _localLookAt);
				_localLookAt_lookAtVersion = _lookAt.version;
			}

			return _localLookAt;
		}

		public function get localDirection() : Vector4
		{
			// FIXME: handle cache
			return Vector4.subtract(localPosition, localLookAt).normalize();
		}

		public function get direction() : Vector4
		{
			// FIXME: handle cache
			return Vector4.subtract(position, lookAt).normalize();
		}

		public function set ratio(v : Number) : void
		{
			_ratio = v;
			_projection_invalidated = true;
		}

		public function set position(v : Vector4) : void
		{
			_position = v;
		}

		public function set lookAt(v : Vector4) : void
		{
			_lookAt = v;
		}

		public function set up(v : Vector4) : void
		{
			_up = v;
		}

		public function set fov(v : Number) : void
		{
			_fov = v;
			_projection_invalidated = true;
		}

		public function set zNear(v : Number) : void
		{
			_zNear = v;
			_projection_invalidated = true;
		}

		public function set zFar(v : Number) : void
		{
			_zFar = v;
			_projection_invalidated = true;
		}

		public function CameraData()
		{
			reset()
		}

		public function setLocalDataProvider(styleStack	: StyleStack,
											 localData	: LocalData) : void
		{
			_styleStack	= styleStack;
			_localData	= localData;
		}

		public function invalidate() : void
		{
			// do nothing
		}

		public function reset() : void
		{
			_position	= null;
			_lookAt		= null;
			_up			= null;

			_ratio	= -1;
			_fov	= -1;
			_zNear	= -1;
			_zFar	= -1;

			_view_positionVersion			= uint.MAX_VALUE;
			_view_lookAtVersion				= uint.MAX_VALUE;
			_view_upVersion					= uint.MAX_VALUE;
			_localPosition_positionVersion	= uint.MAX_VALUE;
			_localLookAt_lookAtVersion		= uint.MAX_VALUE;
			_frustum_projectionVersion		= uint.MAX_VALUE;

			_zFarParts_invalidated	= true;
			_projection_invalidated = true;

			_localData && _localData.reset();
		}
	}
}

package aerys.minko.scene.visitor.data
{
	import aerys.minko.type.math.Frustum;
	import aerys.minko.type.math.Matrix4x4;
	import aerys.minko.type.math.Vector4;

	public class CameraData implements IWorldData
	{
		public static const POSITION		: String = 'position';
		public static const LOOK_AT			: String = 'lookAt';
		public static const UP				: String = 'up';

		public static const RATIO			: String = 'ratio';
		public static const FOV				: String = 'fov';
		public static const Z_NEAR			: String = 'zNear';

		public static const Z_FAR			: String = 'zFar';
		public static const Z_FAR_PARTS		: String = 'zFarParts';

		public static const VIEW			: String = 'view';
		public static const PROJECTION		: String = 'projection';
		public static const LOCAL_POSITION	: String = 'localPosition';
		public static const LOCAL_LOOK_AT	: String = 'localLookAt';

		public static const DIRECTION		: String = 'direction';
		public static const LOCAL_DIRECTION	: String = 'localDirection';

		public static const FRUSTUM			: String = 'frustum';

		// local data provider
		protected var _styleStack	: StyleStack;
		protected var _localData	: LocalData;

		// data available on initialisation
		protected var _position	: Vector4;
		protected var _lookAt	: Vector4;
		protected var _up		: Vector4;

		protected var _ratio	: Number;
		protected var _fov		: Number;
		protected var _zNear	: Number;
		protected var _zFar		: Number;

		// computed data
		protected var _zFarParts						: Vector4;
		protected var _zFarParts_invalidated			: Boolean;

		protected var _view								: Matrix4x4;
		protected var _view_positionVersion				: uint;
		protected var _view_lookAtVersion				: uint;
		protected var _view_upVersion					: uint;

		protected var _projection						: Matrix4x4;
		protected var _projection_invalidated			: Boolean;

		protected var _localPosition					: Vector4;
		protected var _localPosition_positionVersion	: uint;

		protected var _localLookAt						: Vector4;
		protected var _localLookAt_lookAtVersion		: uint;

		protected var _frustum							: Frustum;
		protected var _frustum_projectionVersion		: uint;

		public function get position() : Vector4
		{
			return _position;
		}

		public function get lookAt() : Vector4
		{
			return _lookAt;
		}

		public function get up() : Vector4
		{
			return _up;
		}

		public function get fieldOfView() : Number
		{
			return _fov;
		}

		public function get zNear() : Number
		{
			return _zNear;
		}

		public function get zFar() : Number
		{
			return _zFar;
		}

		public function get zFarParts() : Vector4
		{
			if (_zFarParts_invalidated)
			{
				_zFarParts = new Vector4(0, 0.25 * _zFar, 0.5 * _zFar, 0.75 * _zFar);
				_zFarParts_invalidated = false;
			}
			return _zFarParts;
		}

		public function get view() : Matrix4x4
		{
			if (_view_positionVersion != _position.version ||
				_view_lookAtVersion != _lookAt.version ||
				_view_upVersion != _up.version)
			{
				_view = Matrix4x4.lookAtLH(_position, _lookAt, _up, _view);

				_view_positionVersion	= _position.version;
				_view_lookAtVersion		= _lookAt.version;
				_view_upVersion			= _lookAt.version;
			}

			return _view;
		}

		public function get projection() : Matrix4x4
		{
			if (_projection_invalidated)
			{
				_projection = Matrix4x4.perspectiveFoVLH(_fov, _ratio, _zNear, _zFar, _projection);
				_projection_invalidated = false;
			}

			return _projection;
		}

		public function get frustrum() : Frustum
		{
			var projectionMatrix : Matrix4x4 = projection;

			if (_frustum_projectionVersion != projectionMatrix.version)
			{
				if (_frustum == null)
					_frustum = new Frustum();
				_frustum.update(projectionMatrix);
				_frustum_projectionVersion = projectionMatrix.version;
			}

			return _frustum;
		}

		public function get localPosition() : Vector4
		{
			if (_localPosition_positionVersion != _position.version)
			{
				_localPosition = _localData.world.multiplyVector(_position, _localPosition);
				_localPosition_positionVersion = _position.version;
			}

			return _localPosition;
		}

		public function get localLookAt() : Vector4
		{
			if (_localLookAt_lookAtVersion != _lookAt.version)
			{
				_localLookAt = _localData.world.deltaMultiplyVector(_lookAt, _localLookAt);
				_localLookAt_lookAtVersion = _lookAt.version;
			}

			return _localLookAt;
		}

		public function get localDirection() : Vector4
		{
			// FIXME: handle cache
			return Vector4.subtract(localPosition, localLookAt).normalize();
		}

		public function get direction() : Vector4
		{
			// FIXME: handle cache
			return Vector4.subtract(position, lookAt).normalize();
		}

		public function set ratio(v : Number) : void
		{
			_ratio = v;
			_projection_invalidated = true;
		}

		public function set position(v : Vector4) : void
		{
			_position = v;
		}

		public function set lookAt(v : Vector4) : void
		{
			_lookAt = v;
		}

		public function set up(v : Vector4) : void
		{
			_up = v;
		}

		public function set fov(v : Number) : void
		{
			_fov = v;
			_projection_invalidated = true;
		}

		public function set zNear(v : Number) : void
		{
			_zNear = v;
			_projection_invalidated = true;
		}

		public function set zFar(v : Number) : void
		{
			_zFar = v;
			_projection_invalidated = true;
		}

		public function CameraData()
		{
			reset()
		}

		public function setLocalDataProvider(styleStack	: StyleStack,
											 localData	: LocalData) : void
		{
			_styleStack	= styleStack;
			_localData	= localData;
		}

		public function invalidate() : void
		{
			// do nothing
		}

		public function reset() : void
		{
			_position	= null;
			_lookAt		= null;
			_up			= null;

			_ratio	= -1;
			_fov	= -1;
			_zNear	= -1;
			_zFar	= -1;

			_view_positionVersion			= uint.MAX_VALUE;
			_view_lookAtVersion				= uint.MAX_VALUE;
			_view_upVersion					= uint.MAX_VALUE;
			_localPosition_positionVersion	= uint.MAX_VALUE;
			_localLookAt_lookAtVersion		= uint.MAX_VALUE;
			_frustum_projectionVersion		= uint.MAX_VALUE;

			_zFarParts_invalidated	= true;
			_projection_invalidated = true;
		}
	}
}

Fix minor bug in CameraData (reset method is not called on the reference to localData anymore)


// Editor debug icons

BillboardSet@ debugIconsSetDirectionalLights;
BillboardSet@ debugIconsSetSpotLights;
BillboardSet@ debugIconsSetPointLights;
BillboardSet@ debugIconsSetCameras;
BillboardSet@ debugIconsSetSoundSources;
BillboardSet@ debugIconsSetSoundSources3D;
BillboardSet@ debugIconsSetSoundListeners;
BillboardSet@ debugIconsSetZones;

int stepDebugIconsUpdate = 30; //ms
int timeToNextDebugIconsUpdate = 0;
bool debugIconsShow = true;
Vector2 debugIconsSize = Vector2(0.025, 0.025);

void CreateDebugIcons()
{
    if (editorScene is null) return;

    debugIconsSetDirectionalLights = editorScene.CreateComponent("BillboardSet");
    debugIconsSetDirectionalLights.material = cache.GetResource("Material", "Materials/Editor/DebugIconLight.xml");
    debugIconsSetDirectionalLights.material.renderOrder = 255;
    debugIconsSetDirectionalLights.sorted = true;
    debugIconsSetDirectionalLights.temporary = true;
    debugIconsSetDirectionalLights.viewMask = 0x80000000;

    debugIconsSetSpotLights = editorScene.CreateComponent("BillboardSet");
    debugIconsSetSpotLights.material = cache.GetResource("Material", "Materials/Editor/DebugIconSpotLight.xml");
    debugIconsSetSpotLights.material.renderOrder = 255;
    debugIconsSetSpotLights.sorted = true;
    debugIconsSetSpotLights.temporary = true;
    debugIconsSetSpotLights.viewMask = 0x80000000;

    debugIconsSetPointLights = editorScene.CreateComponent("BillboardSet");
    debugIconsSetPointLights.material = cache.GetResource("Material", "Materials/Editor/DebugIconPointLight.xml");
    debugIconsSetPointLights.material.renderOrder = 255;
    debugIconsSetPointLights.sorted = true;
    debugIconsSetPointLights.temporary = true;
    debugIconsSetPointLights.viewMask = 0x80000000;

    debugIconsSetCameras = editorScene.CreateComponent("BillboardSet");
    debugIconsSetCameras.material = cache.GetResource("Material", "Materials/Editor/DebugIconCamera.xml");
    debugIconsSetCameras.material.renderOrder = 255;
    debugIconsSetCameras.sorted = true;
    debugIconsSetCameras.temporary = true;
    debugIconsSetCameras.viewMask = 0x80000000;

    debugIconsSetSoundSources = editorScene.CreateComponent("BillboardSet");
    debugIconsSetSoundSources.material = cache.GetResource("Material", "Materials/Editor/DebugIconSoundSource.xml");
    debugIconsSetSoundSources.material.renderOrder = 255;
    debugIconsSetSoundSources.sorted = true;
    debugIconsSetSoundSources.temporary = true;
    debugIconsSetSoundSources.viewMask = 0x80000000;

    debugIconsSetSoundSources3D = editorScene.CreateComponent("BillboardSet");
    debugIconsSetSoundSources3D.material = cache.GetResource("Material", "Materials/Editor/DebugIconSoundSource.xml");
    debugIconsSetSoundSources3D.material.renderOrder = 255;
    debugIconsSetSoundSources3D.sorted = true;
    debugIconsSetSoundSources3D.temporary = true;
    debugIconsSetSoundSources3D.viewMask = 0x80000000;

    debugIconsSetSoundListeners = editorScene.CreateComponent("BillboardSet");
    debugIconsSetSoundListeners.material = cache.GetResource("Material", "Materials/Editor/DebugIconSoundListener.xml");
    debugIconsSetSoundListeners.material.renderOrder = 255;
    debugIconsSetSoundListeners.sorted = true;
    debugIconsSetSoundListeners.temporary = true;
    debugIconsSetSoundListeners.viewMask = 0x80000000;

    debugIconsSetZones = editorScene.CreateComponent("BillboardSet");
    debugIconsSetZones.material = cache.GetResource("Material", "Materials/Editor/DebugIconZone.xml");
    debugIconsSetZones.material.renderOrder = 255;
    debugIconsSetZones.sorted = true;
    debugIconsSetZones.temporary = true;
    debugIconsSetZones.viewMask = 0x80000000;

}

void UpdateViewDebugIcons()
{
    if (timeToNextDebugIconsUpdate > time.systemTime) return;

    if (editorScene is null) return;
    // Checkout if scene do not have BBS component, add it once
    BillboardSet@ bbs = editorScene.GetComponent("BillboardSet");
    if (bbs is null)
    {
        CreateDebugIcons();
    }

    Vector3 camPos = cameraNode.worldPosition;

    if (debugIconsSetPointLights !is null)
    {
        debugIconsSetDirectionalLights.enabled = debugIconsShow;
        debugIconsSetSpotLights.enabled = debugIconsShow;
        debugIconsSetPointLights.enabled = debugIconsShow;

        Array<Node@> nodes = editorScene.GetChildrenWithComponent("Light", true);

        if (nodes.length > 0)
        {
            debugIconsSetDirectionalLights.numBillboards = 0;
            debugIconsSetSpotLights.numBillboards = 0;
            debugIconsSetPointLights.numBillboards = 0;

            debugIconsSetPointLights.Commit();
            debugIconsSetSpotLights.Commit();
            debugIconsSetDirectionalLights.Commit();

            debugIconsSetDirectionalLights.numBillboards = nodes.length;
            debugIconsSetSpotLights.numBillboards = nodes.length;
            debugIconsSetPointLights.numBillboards = nodes.length;

            for (int i=0;i<nodes.length; i++)
            {
                Light@ light = nodes[i].GetComponent("Light");

                if (light.lightType == LIGHT_POINT)
                {
                    Billboard@ bb = debugIconsSetPointLights.billboards[i];
                    bb.position = nodes[i].worldPosition;
                    bb.color = light.effectiveColor;
                    float distance = (camPos - nodes[i].worldPosition).length;
                    bb.size = debugIconsSize * distance;
                    bb.enabled = true;
                }
                else if (light.lightType == LIGHT_DIRECTIONAL)
                {
                    Billboard@ bb = debugIconsSetDirectionalLights.billboards[i];
                    bb.position = nodes[i].worldPosition;
                    bb.color = light.effectiveColor;
                    float distance = (camPos - nodes[i].worldPosition).length;
                    bb.size = debugIconsSize * distance;
                    bb.enabled = true;
                }
                else if (light.lightType == LIGHT_SPOT)
                {
                    Billboard@ bb = debugIconsSetSpotLights.billboards[i];
                    bb.position = nodes[i].worldPosition;
                    bb.color = light.effectiveColor;
                    float distance = (camPos - nodes[i].worldPosition).length;
                    bb.size = debugIconsSize * distance;
                    bb.enabled = true;
                }
            }

            debugIconsSetPointLights.Commit();
            debugIconsSetSpotLights.Commit();
            debugIconsSetDirectionalLights.Commit();

        }
    }

    if (debugIconsSetCameras !is null)
    {
        debugIconsSetCameras.enabled = debugIconsShow;
        Array<Node@> nodes = editorScene.GetChildrenWithComponent("Camera", true);

        if (nodes.length > 0)
        {
            debugIconsSetCameras.numBillboards = nodes.length;
            for (int i=0;i<nodes.length; i++)
            {
                Camera@ camera = nodes[i].GetComponent("Camera");
                Billboard@ bb = debugIconsSetCameras.billboards[i];
                bb.position = nodes[i].worldPosition;

                // if mainCamera enough closer to selected camera then make bb size relative to distance
                float distance = (camPos - nodes[i].worldPosition).length;
                bb.size = debugIconsSize * distance;

                bb.enabled = true;
            }

            debugIconsSetCameras.Commit();
        }
    }

    if (debugIconsSetSoundSources !is null)
    {
        debugIconsSetSoundSources.enabled = debugIconsShow;

        Array<Node@> nodes = editorScene.GetChildrenWithComponent("SoundSource", true);

        if (nodes.length > 0)
        {
            debugIconsSetSoundSources.numBillboards = nodes.length;
            for (int i=0;i<nodes.length; i++)
            {
                Component@ component = nodes[i].GetComponent("SoundSource");
                Billboard@ bb = debugIconsSetSoundSources.billboards[i];
                bb.position = nodes[i].worldPosition;
                float distance = (camPos - nodes[i].worldPosition).length;
                bb.size = debugIconsSize * distance;
                bb.enabled = component.enabled;
            }

            debugIconsSetSoundSources.Commit();
        }
    }

    if (debugIconsSetSoundSources3D !is null)
    {
        debugIconsSetSoundSources3D.enabled = debugIconsShow;

        Array<Node@> nodes = editorScene.GetChildrenWithComponent("SoundSource3D", true);

        if (nodes.length > 0)
        {
            debugIconsSetSoundSources3D.numBillboards = nodes.length;
            for (int i=0;i<nodes.length; i++)
            {
                Component@ component = nodes[i].GetComponent("SoundSource3D");
                Billboard@ bb = debugIconsSetSoundSources3D.billboards[i];
                bb.position = nodes[i].worldPosition;
                float distance = (camPos - nodes[i].worldPosition).length;
                bb.size = debugIconsSize * distance;
                bb.enabled = component.enabled;
            }

            debugIconsSetSoundSources3D.Commit();
        }
    }

    if (debugIconsSetSoundListeners !is null)
    {
        debugIconsSetSoundListeners.enabled = debugIconsShow;
        Array<Node@> nodes = editorScene.GetChildrenWithComponent("SoundListener" , true);

        if (nodes.length > 0)
        {
            debugIconsSetSoundListeners.numBillboards = nodes.length;
            for (int i=0;i<nodes.length; i++)
            {
                Component@ component = nodes[i].GetComponent("SoundListener");
                Billboard@ bb = debugIconsSetSoundListeners.billboards[i];
                bb.position = nodes[i].worldPosition;
                float distance = (camPos - nodes[i].worldPosition).length;
                bb.size = debugIconsSize * distance;
                bb.enabled = component.enabled;
            }

            debugIconsSetSoundListeners.Commit();
        }
    }

    if (debugIconsSetZones !is null)
    {
        debugIconsSetZones.enabled = debugIconsShow;

        // Collect all scene's Zones and add it
        Array<Node@> nodes = editorScene.GetChildrenWithComponent("Zone", true);

        Zone@ zone = editorScene.GetComponent("Zone");
        if (zone !is null)
        {
            debugIconsSetZones.numBillboards = 1;
            Billboard@ bb = debugIconsSetZones.billboards[0];
            bb.position = Vector3(0,0,0);
            float distance = (camPos - bb.position).length;
            bb.size = debugIconsSize * distance;
            //bb.color = zone.ambientColor;
            bb.enabled = zone.enabled;
        }

        if (nodes.length > 0)
        {
            debugIconsSetZones.numBillboards = 1 + nodes.length;
            for (int i=0;i<nodes.length; i++)
            {
                Zone@ zone = nodes[i].GetComponent("Zone");
                Billboard@ bb = debugIconsSetZones.billboards[i+1];
                bb.position = nodes[i].worldPosition;
                float distance = (camPos - nodes[i].worldPosition).length;
                bb.size = debugIconsSize * distance;
                //bb.color = zone.ambientColor;
                bb.enabled = zone.enabled;
            }

            debugIconsSetZones.Commit();
        }
    }

    timeToNextDebugIconsUpdate = time.systemTime + stepDebugIconsUpdate;
}

// Editor debug icons

BillboardSet@ debugIconsSetDirectionalLights;
BillboardSet@ debugIconsSetSpotLights;
BillboardSet@ debugIconsSetPointLights;
BillboardSet@ debugIconsSetCameras;
BillboardSet@ debugIconsSetSoundSources;
BillboardSet@ debugIconsSetSoundSources3D;
BillboardSet@ debugIconsSetSoundListeners;
BillboardSet@ debugIconsSetZones;

Node@ debugIconsNode = null;

int stepDebugIconsUpdate = 30; //ms
int timeToNextDebugIconsUpdate = 0;
bool debugIconsShow = true;
Vector2 debugIconsSize = Vector2(0.025, 0.025);

void CreateDebugIcons()
{
    if (editorScene is null) return;

    debugIconsSetDirectionalLights = debugIconsNode.CreateComponent("BillboardSet");
    debugIconsSetDirectionalLights.material = cache.GetResource("Material", "Materials/Editor/DebugIconLight.xml");
    debugIconsSetDirectionalLights.material.renderOrder = 255;
    debugIconsSetDirectionalLights.sorted = true;
    debugIconsSetDirectionalLights.temporary = true;
    debugIconsSetDirectionalLights.viewMask = 0x80000000;

    debugIconsSetSpotLights = debugIconsNode.CreateComponent("BillboardSet");
    debugIconsSetSpotLights.material = cache.GetResource("Material", "Materials/Editor/DebugIconSpotLight.xml");
    debugIconsSetSpotLights.material.renderOrder = 255;
    debugIconsSetSpotLights.sorted = true;
    debugIconsSetSpotLights.temporary = true;
    debugIconsSetSpotLights.viewMask = 0x80000000;

    debugIconsSetPointLights = debugIconsNode.CreateComponent("BillboardSet");
    debugIconsSetPointLights.material = cache.GetResource("Material", "Materials/Editor/DebugIconPointLight.xml");
    debugIconsSetPointLights.material.renderOrder = 255;
    debugIconsSetPointLights.sorted = true;
    debugIconsSetPointLights.temporary = true;
    debugIconsSetPointLights.viewMask = 0x80000000;

    debugIconsSetCameras = debugIconsNode.CreateComponent("BillboardSet");
    debugIconsSetCameras.material = cache.GetResource("Material", "Materials/Editor/DebugIconCamera.xml");
    debugIconsSetCameras.material.renderOrder = 255;
    debugIconsSetCameras.sorted = true;
    debugIconsSetCameras.temporary = true;
    debugIconsSetCameras.viewMask = 0x80000000;

    debugIconsSetSoundSources = debugIconsNode.CreateComponent("BillboardSet");
    debugIconsSetSoundSources.material = cache.GetResource("Material", "Materials/Editor/DebugIconSoundSource.xml");
    debugIconsSetSoundSources.material.renderOrder = 255;
    debugIconsSetSoundSources.sorted = true;
    debugIconsSetSoundSources.temporary = true;
    debugIconsSetSoundSources.viewMask = 0x80000000;

    debugIconsSetSoundSources3D = debugIconsNode.CreateComponent("BillboardSet");
    debugIconsSetSoundSources3D.material = cache.GetResource("Material", "Materials/Editor/DebugIconSoundSource.xml");
    debugIconsSetSoundSources3D.material.renderOrder = 255;
    debugIconsSetSoundSources3D.sorted = true;
    debugIconsSetSoundSources3D.temporary = true;
    debugIconsSetSoundSources3D.viewMask = 0x80000000;

    debugIconsSetSoundListeners = debugIconsNode.CreateComponent("BillboardSet");
    debugIconsSetSoundListeners.material = cache.GetResource("Material", "Materials/Editor/DebugIconSoundListener.xml");
    debugIconsSetSoundListeners.material.renderOrder = 255;
    debugIconsSetSoundListeners.sorted = true;
    debugIconsSetSoundListeners.temporary = true;
    debugIconsSetSoundListeners.viewMask = 0x80000000;

    debugIconsSetZones = debugIconsNode.CreateComponent("BillboardSet");
    debugIconsSetZones.material = cache.GetResource("Material", "Materials/Editor/DebugIconZone.xml");
    debugIconsSetZones.material.renderOrder = 255;
    debugIconsSetZones.sorted = true;
    debugIconsSetZones.temporary = true;
    debugIconsSetZones.viewMask = 0x80000000;
}

void UpdateViewDebugIcons()
{
    if (timeToNextDebugIconsUpdate > time.systemTime) return;

    if (editorScene is null) return;

    debugIconsNode = editorScene.GetChild("DebugIconsContainer", true);

    if (debugIconsNode is null)
    {
        debugIconsNode = editorScene.CreateChild("DebugIconsContainer", LOCAL);
        debugIconsNode.temporary = true;
    }

    // Checkout if debugIconsNode do not have any BBS component, add they at once
    BillboardSet@ bbs = debugIconsNode.GetComponent("BillboardSet");

    if (bbs is null)
    {
        CreateDebugIcons();
    }

    Vector3 camPos = cameraNode.worldPosition;

    if (debugIconsSetPointLights !is null)
    {
        debugIconsSetDirectionalLights.enabled = debugIconsShow;
        debugIconsSetSpotLights.enabled = debugIconsShow;
        debugIconsSetPointLights.enabled = debugIconsShow;

        Array<Node@> nodes = editorScene.GetChildrenWithComponent("Light", true);

        if (nodes.length > 0)
        {
            debugIconsSetDirectionalLights.numBillboards = 0;
            debugIconsSetSpotLights.numBillboards = 0;
            debugIconsSetPointLights.numBillboards = 0;

            debugIconsSetPointLights.Commit();
            debugIconsSetSpotLights.Commit();
            debugIconsSetDirectionalLights.Commit();

            debugIconsSetDirectionalLights.numBillboards = nodes.length;
            debugIconsSetSpotLights.numBillboards = nodes.length;
            debugIconsSetPointLights.numBillboards = nodes.length;

            for (int i=0;i<nodes.length; i++)
            {
                Light@ light = nodes[i].GetComponent("Light");

                if (light.lightType == LIGHT_POINT)
                {
                    Billboard@ bb = debugIconsSetPointLights.billboards[i];
                    bb.position = nodes[i].worldPosition;
                    bb.color = light.effectiveColor;
                    float distance = (camPos - nodes[i].worldPosition).length;
                    bb.size = debugIconsSize * distance;
                    bb.enabled = true;
                }
                else if (light.lightType == LIGHT_DIRECTIONAL)
                {
                    Billboard@ bb = debugIconsSetDirectionalLights.billboards[i];
                    bb.position = nodes[i].worldPosition;
                    bb.color = light.effectiveColor;
                    float distance = (camPos - nodes[i].worldPosition).length;
                    bb.size = debugIconsSize * distance;
                    bb.enabled = true;
                }
                else if (light.lightType == LIGHT_SPOT)
                {
                    Billboard@ bb = debugIconsSetSpotLights.billboards[i];
                    bb.position = nodes[i].worldPosition;
                    bb.color = light.effectiveColor;
                    float distance = (camPos - nodes[i].worldPosition).length;
                    bb.size = debugIconsSize * distance;
                    bb.enabled = true;
                }
            }

            debugIconsSetPointLights.Commit();
            debugIconsSetSpotLights.Commit();
            debugIconsSetDirectionalLights.Commit();

        }
    }

    if (debugIconsSetCameras !is null)
    {
        debugIconsSetCameras.enabled = debugIconsShow;
        Array<Node@> nodes = editorScene.GetChildrenWithComponent("Camera", true);

        if (nodes.length > 0)
        {
            debugIconsSetCameras.numBillboards = nodes.length;
            for (int i=0;i<nodes.length; i++)
            {
                Camera@ camera = nodes[i].GetComponent("Camera");
                Billboard@ bb = debugIconsSetCameras.billboards[i];
                bb.position = nodes[i].worldPosition;

                // if mainCamera enough closer to selected camera then make bb size relative to distance
                float distance = (camPos - nodes[i].worldPosition).length;
                bb.size = debugIconsSize * distance;

                bb.enabled = true;
            }

            debugIconsSetCameras.Commit();
        }
    }

    if (debugIconsSetSoundSources !is null)
    {
        debugIconsSetSoundSources.enabled = debugIconsShow;

        Array<Node@> nodes = editorScene.GetChildrenWithComponent("SoundSource", true);

        if (nodes.length > 0)
        {
            debugIconsSetSoundSources.numBillboards = nodes.length;
            for (int i=0;i<nodes.length; i++)
            {
                Component@ component = nodes[i].GetComponent("SoundSource");
                Billboard@ bb = debugIconsSetSoundSources.billboards[i];
                bb.position = nodes[i].worldPosition;
                float distance = (camPos - nodes[i].worldPosition).length;
                bb.size = debugIconsSize * distance;
                bb.enabled = component.enabled;
            }

            debugIconsSetSoundSources.Commit();
        }
    }

    if (debugIconsSetSoundSources3D !is null)
    {
        debugIconsSetSoundSources3D.enabled = debugIconsShow;

        Array<Node@> nodes = editorScene.GetChildrenWithComponent("SoundSource3D", true);

        if (nodes.length > 0)
        {
            debugIconsSetSoundSources3D.numBillboards = nodes.length;
            for (int i=0;i<nodes.length; i++)
            {
                Component@ component = nodes[i].GetComponent("SoundSource3D");
                Billboard@ bb = debugIconsSetSoundSources3D.billboards[i];
                bb.position = nodes[i].worldPosition;
                float distance = (camPos - nodes[i].worldPosition).length;
                bb.size = debugIconsSize * distance;
                bb.enabled = component.enabled;
            }

            debugIconsSetSoundSources3D.Commit();
        }
    }

    if (debugIconsSetSoundListeners !is null)
    {
        debugIconsSetSoundListeners.enabled = debugIconsShow;
        Array<Node@> nodes = editorScene.GetChildrenWithComponent("SoundListener" , true);

        if (nodes.length > 0)
        {
            debugIconsSetSoundListeners.numBillboards = nodes.length;
            for (int i=0;i<nodes.length; i++)
            {
                Component@ component = nodes[i].GetComponent("SoundListener");
                Billboard@ bb = debugIconsSetSoundListeners.billboards[i];
                bb.position = nodes[i].worldPosition;
                float distance = (camPos - nodes[i].worldPosition).length;
                bb.size = debugIconsSize * distance;
                bb.enabled = component.enabled;
            }

            debugIconsSetSoundListeners.Commit();
        }
    }

    if (debugIconsSetZones !is null)
    {
        debugIconsSetZones.enabled = debugIconsShow;

        // Collect all scene's Zones and add it
        Array<Node@> nodes = editorScene.GetChildrenWithComponent("Zone", true);

        Zone@ zone = editorScene.GetComponent("Zone");
        if (zone !is null)
        {
            debugIconsSetZones.numBillboards = 1;
            Billboard@ bb = debugIconsSetZones.billboards[0];
            bb.position = Vector3(0,0,0);
            float distance = (camPos - bb.position).length;
            bb.size = debugIconsSize * distance;
            //bb.color = zone.ambientColor;
            bb.enabled = zone.enabled;
        }

        if (nodes.length > 0)
        {
            debugIconsSetZones.numBillboards = 1 + nodes.length;
            for (int i=0;i<nodes.length; i++)
            {
                Zone@ zone = nodes[i].GetComponent("Zone");
                Billboard@ bb = debugIconsSetZones.billboards[i+1];
                bb.position = nodes[i].worldPosition;
                float distance = (camPos - nodes[i].worldPosition).length;
                bb.size = debugIconsSize * distance;
                //bb.color = zone.ambientColor;
                bb.enabled = zone.enabled;
            }

            debugIconsSetZones.Commit();
        }
    }

    timeToNextDebugIconsUpdate = time.systemTime + stepDebugIconsUpdate;
}

add debug temp container(node) and clear scene's scope


package com.nathancolgate {
	import com.elctech.S3UploadOptions;
	import com.adobe.net.MimeTypeMap;

	import flash.events.EventDispatcher;
	import flash.events.ProgressEvent;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.HTTPStatusEvent;
	import flash.events.DataEvent;
	import flash.external.ExternalInterface;

	import flash.net.FileReference;
	import flash.net.URLVariables;
	import flash.net.URLRequest;
	import flash.net.URLRequestMethod;
	import flash.net.URLRequestHeader;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;

	public class S3Signature extends EventDispatcher
	{
		[Event(name="complete", type="flash.event.COMPLETE")]

		public var upload_options:S3UploadOptions;

		private var signatureLoader:URLLoader;
		private var request:URLRequest;

		public function S3Signature(file:FileReference, signature:String, option_params:Object, file_params:Object)
		{
			upload_options					= new S3UploadOptions;
			upload_options.FileSize         = file.size.toString();
			upload_options.FileName         = getFileName(file);
			upload_options.ContentType      = getContentType(upload_options.FileName);
			upload_options.key              = upload_options.FileName;

			var variables:URLVariables			= new URLVariables();
			variables.key						= upload_options.key;
			variables.content_type				= upload_options.ContentType;

			var key:String;
			for(key in option_params)
			{
				if(option_params[key] is String)
					variables[key] = option_params[key];
			}
			for(key in file_params)
			{
				if(file_params[key] is String)
					variables[key] = file_params[key];
			}

			request			= new URLRequest(signature);
			request.method	= URLRequestMethod.GET;
			request.data	= variables;

			signatureLoader	= new URLLoader();
			signatureLoader.dataFormat = URLLoaderDataFormat.TEXT;
			signatureLoader.addEventListener(Event.COMPLETE, onComplete);
		}

		public function load():void
		{
			signatureLoader.load(request);
		}

		private function onComplete(event:Event):void
		{
			var loader:URLLoader = URLLoader(event.target);
			var xml:XML  = new XML(loader.data);

			upload_options.policy				= xml.policy;
			upload_options.signature			= xml.signature;
			upload_options.bucket				= xml.bucket;
			upload_options.AWSAccessKeyId		= xml.accesskeyid;
			upload_options.acl					= xml.acl;
			upload_options.Expires				= xml.expirationdate;
			upload_options.Secure				= xml.https;
			upload_options.key					= xml.key;
			upload_options.ContentDisposition	= xml.contentdisposition;

			dispatchEvent(event);
		}

		private function getContentType(fileName:String):String
		{
			var fileNameArray:Array		= fileName.split(/\./);
			var fileExtension:String	= fileNameArray[fileNameArray.length - 1];
			var mimeMap:MimeTypeMap		= new MimeTypeMap;
			var contentType:String		= mimeMap.getMimeType(fileExtension);
			return contentType;
		}

		private function getFileName(file:FileReference):String
		{
			var fileName:String = file.name.replace(/^.*(\\|\/)/gi, '').replace(/[^A-Za-z0-9\.\-]/gi, '_');
			return fileName;
		}
	}
}

package com.nathancolgate {
	import com.elctech.S3UploadOptions;
	import com.adobe.net.MimeTypeMap;

	import flash.events.EventDispatcher;
	import flash.events.ProgressEvent;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.HTTPStatusEvent;
	import flash.events.DataEvent;
	import flash.external.ExternalInterface;

	import flash.net.FileReference;
	import flash.net.URLVariables;
	import flash.net.URLRequest;
	import flash.net.URLRequestMethod;
	import flash.net.URLRequestHeader;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;

	public class S3Signature extends EventDispatcher
	{
		[Event(name="complete", type="flash.event.COMPLETE")]

		public var upload_options:S3UploadOptions;

		private var signatureLoader:URLLoader;
		private var request:URLRequest;

		public function S3Signature(file:FileReference, signature:String, option_params:Object, file_params:Object)
		{
			upload_options					= new S3UploadOptions;
			upload_options.FileSize         = file.size.toString();
			upload_options.FileName         = getFileName(file);
			upload_options.ContentType      = getContentType(upload_options.FileName);
			upload_options.key              = upload_options.FileName;

			var variables:URLVariables			= new URLVariables();
			variables.key						= upload_options.key;
			variables.content_type				= upload_options.ContentType;

			var key:String;
			for(key in option_params)
			{
				if(option_params[key] is String)
					variables[key] = option_params[key];
			}
			for(key in file_params)
			{
				if(file_params[key] is String)
					variables[key] = file_params[key];
			}

			request	= new URLRequest(signature);
			request.method = URLRequestMethod.POST;
			request.data = variables;
			request.contentType = 'application/x-www-form-urlencoded';

			signatureLoader	= new URLLoader();
			signatureLoader.dataFormat = URLLoaderDataFormat.TEXT;
			signatureLoader.addEventListener(Event.COMPLETE, onComplete);
		}

		public function load():void
		{
			signatureLoader.load(request);
		}

		private function onComplete(event:Event):void
		{
			var loader:URLLoader = URLLoader(event.target);
			var xml:XML  = new XML(loader.data);

			upload_options.policy				= xml.policy;
			upload_options.signature			= xml.signature;
			upload_options.bucket				= xml.bucket;
			upload_options.AWSAccessKeyId		= xml.accesskeyid;
			upload_options.acl					= xml.acl;
			upload_options.Expires				= xml.expirationdate;
			upload_options.Secure				= xml.https;
			upload_options.key					= xml.key;
			upload_options.ContentDisposition	= xml.contentdisposition;

			dispatchEvent(event);
		}

		private function getContentType(fileName:String):String
		{
			var fileNameArray:Array		= fileName.split(/\./);
			var fileExtension:String	= fileNameArray[fileNameArray.length - 1];
			var mimeMap:MimeTypeMap		= new MimeTypeMap;
			var contentType:String		= mimeMap.getMimeType(fileExtension);
			return contentType;
		}

		private function getFileName(file:FileReference):String
		{
			var fileName:String = file.name.replace(/^.*(\\|\/)/gi, '').replace(/[^A-Za-z0-9\.\-]/gi, '_');
			return fileName;
		}
	}
}

use POST when interactive with signature endpoint


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

package com.castlabs.dash.utils {
import com.castlabs.dash.DashContext;

import flash.events.EventDispatcher;
import flash.events.NetStatusEvent;

import org.osmf.net.NetStreamCodes;

public class SmoothMonitor {
    private static const ACCEPTED_BUFFERING_COUNT:uint = 1;

    private var _context:DashContext;

    private var _bufferingCount:Number = 0;

    public function SmoothMonitor(context:DashContext) {
        _context = context;
    }

    public function appendListeners(netStream:EventDispatcher):void {
        netStream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
    }

    private function onNetStatus(event:NetStatusEvent):void {
        if (event.info.code == NetStreamCodes.NETSTREAM_BUFFER_EMPTY) {
            _bufferingCount++;
            _context.console.warn("Registered buffering incident, bufferingCount='" + _bufferingCount + "'");
        }

        if (event.info.code == NetStreamCodes.NETSTREAM_SEEK_NOTIFY) {
            _bufferingCount = 0;
            _context.console.info("Reset buffering incidents counter");
        }
    }

    public function get fix():Number {
        var fix:Number = _bufferingCount - ACCEPTED_BUFFERING_COUNT;
        return fix > 0 ? fix : 0;
    }
}
}

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

package com.castlabs.dash.utils {
import com.castlabs.dash.DashContext;

import flash.events.EventDispatcher;
import flash.events.NetStatusEvent;

import com.castlabs.dash.utils.NetStreamCodes;

public class SmoothMonitor {
    private static const ACCEPTED_BUFFERING_COUNT:uint = 1;

    private var _context:DashContext;

    private var _bufferingCount:Number = 0;

    public function SmoothMonitor(context:DashContext) {
        _context = context;
    }

    public function appendListeners(netStream:EventDispatcher):void {
        netStream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
    }

    private function onNetStatus(event:NetStatusEvent):void {
        if (event.info.code == NetStreamCodes.NETSTREAM_BUFFER_EMPTY) {
            _bufferingCount++;
            _context.console.warn("Registered buffering incident, bufferingCount='" + _bufferingCount + "'");
        }

        if (event.info.code == NetStreamCodes.NETSTREAM_SEEK_NOTIFY) {
            _bufferingCount = 0;
            _context.console.info("Reset buffering incidents counter");
        }
    }

    public function get fix():Number {
        var fix:Number = _bufferingCount - ACCEPTED_BUFFERING_COUNT;
        return fix > 0 ? fix : 0;
    }
}
}

Change OSMF NetStreamCodes to utils package


package aerys.minko.render.shader
{
	import aerys.minko.ns.minko_shader;
	import aerys.minko.render.shader.compiler.graph.nodes.AbstractNode;
	import aerys.minko.render.shader.compiler.graph.nodes.leaf.Constant;
	import aerys.minko.render.shader.compiler.graph.nodes.vertex.Extract;
	import aerys.minko.render.shader.compiler.graph.nodes.vertex.Instruction;
	import aerys.minko.render.shader.compiler.graph.nodes.vertex.Overwriter;
	import aerys.minko.render.shader.compiler.register.Components;
	import aerys.minko.type.math.Matrix4x4;

	import flash.utils.Proxy;
	import flash.utils.flash_proxy;

	/**
	 * SFloat (Shader Float) objects are GPU-side computed value proxies
	 * declared, defined and used in ActionScript shaders.
	 *
	 *

	 * ActionScript shaders define what operations will be
	 * performed on the GPU. Those operations take arguments and return
	 * values that will be computed and accessible on the graphics hardware
	 * only. Those values are represented by SFloat objects.
	 *

	 *
	 *

	 * Because SFloat objects are just hardware memory proxies, it is not
	 * possible (and does not make sense to try) to read their actual value
	 * using CPU-side code. For the very same reason, most of the errors will
	 * be detected at runtime only. The only available property is the size
	 * (number of components) of the corresponding value (ie. 3D vector
	 * operations will return SFloat objects of size 3, dot-product will
	 * return a scalar SFloat object of size 1, ...).
	 *

	 *
	 *

	 * SFloat objects also provide OOP shader programming by encapsulating
	 * common operations (add, multiply, ...). They also allow the use of
	 * dynamic properties in order to read or write sub-components of
	 * non-scalar values. Example:
	 *

	 *
	 *

	 * public function getOutputColor() : void
	 * {
	 * 	var diffuse : SFloat = sampleTexture(BasicStyle.DIFFUSE_MAP);
	 *
	 * 	// use the RGB components of the diffuse map but use a
	 * 	// fixed alpha = 0.5
	 *  return combine(diffuse.rgb, 0.5);
	 * }
	 *

	 *
	 *

	 * Each SFloat object wraps a shader graph node that will be evaluated
	 * by the compiler in order to create the corresponding AGAL bytecode.
	 *

	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public dynamic final class SFloat extends Proxy
	{
		use namespace minko_shader;

		minko_shader var _node	: AbstractNode	= null;

		public final function get size() : uint
		{
			return _node.size;
		}

		public function SFloat(value : Object)
		{
			_node = getNode(value);
		}

		public final function scaleBy(arg : Object) : SFloat
		{
			_node = new Instruction(Instruction.MUL, _node, getNode(arg));

			return this;
		}

		public final function incrementBy(value : Object) : SFloat
		{
			_node = new Instruction(Instruction.ADD, _node, getNode(value));

			return this;
		}

		public final function decrementBy(value : Object) : SFloat
		{
			_node = new Instruction(Instruction.SUB, _node, getNode(value));

			return this;
		}

		public final function normalize() : SFloat
		{
			_node = new Instruction(Instruction.NRM, _node);

			return this;
		}

		public final function negate() : SFloat
		{
			_node = new Instruction(Instruction.NEG, _node);

			return this;
		}

		override flash_proxy function getProperty(name : *) : *
		{
			return new SFloat(new Extract(_node, Components.stringToComponent(name)));
		}

		override flash_proxy function setProperty(name : *, value : *) : void
		{
			var nodeComponent		: uint 			= Components.createContinuous(0, 0, _node.size, _node.size);
			var propertyComponent	: uint			= Components.stringToComponent(name);
			var propertyNode		: AbstractNode	= getNode(value);

			_node = new Overwriter(
				new <AbstractNode>[_node, propertyNode],
				new <uint>[nodeComponent, propertyComponent]
			);
		}

		private function getNode(value : Object) : AbstractNode
		{
			if (value is AbstractNode)
				return value as AbstractNode;

			if (value is SFloat)
				return (value as SFloat)._node;

			if (value is uint || value is int || value is Number)
				return new Constant(new <Number>[Number(value)]);

			if (value is Matrix4x4)
				return new Constant(Matrix4x4(value).getRawData(null, 0, false));

			throw new Error('This type cannot be casted to a shader value.');
		}
	}
}

package aerys.minko.render.shader
{
	import aerys.minko.ns.minko_shader;
	import aerys.minko.render.shader.compiler.graph.nodes.AbstractNode;
	import aerys.minko.render.shader.compiler.graph.nodes.leaf.Constant;
	import aerys.minko.render.shader.compiler.graph.nodes.vertex.Extract;
	import aerys.minko.render.shader.compiler.graph.nodes.vertex.Instruction;
	import aerys.minko.render.shader.compiler.graph.nodes.vertex.Overwriter;
	import aerys.minko.render.shader.compiler.register.Components;
	import aerys.minko.type.math.Matrix4x4;

	import flash.utils.Proxy;
	import flash.utils.flash_proxy;

	/**
	 * SFloat (Shader Float) objects are GPU-side computed value proxies
	 * declared, defined and used in ActionScript shaders.
	 *
	 *

	 * ActionScript shaders define what operations will be
	 * performed on the GPU. Those operations take arguments and return
	 * values that will be computed and accessible on the graphics hardware
	 * only. Those values are represented by SFloat objects.
	 *

	 *
	 *

	 * Because SFloat objects are just hardware memory proxies, it is not
	 * possible (and does not make sense to try) to read their actual value
	 * using CPU-side code. For the very same reason, most of the errors will
	 * be detected at runtime only. The only available property is the size
	 * (number of components) of the corresponding value (ie. 3D vector
	 * operations will return SFloat objects of size 3, dot-product will
	 * return a scalar SFloat object of size 1, ...).
	 *

	 *
	 *

	 * SFloat objects also provide OOP shader programming by encapsulating
	 * common operations (add, multiply, ...). They also allow the use of
	 * dynamic properties in order to read or write sub-components of
	 * non-scalar values. Example:
	 *

	 *
	 *

	 * public function getOutputColor() : void
	 * {
	 * 	var diffuse : SFloat = sampleTexture(BasicStyle.DIFFUSE_MAP);
	 *
	 * 	// use the RGB components of the diffuse map but use a
	 * 	// fixed alpha = 0.5
	 *  return combine(diffuse.rgb, 0.5);
	 * }
	 *

	 *
	 *

	 * Each SFloat object wraps a shader graph node that will be evaluated
	 * by the compiler in order to create the corresponding AGAL bytecode.
	 *

	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public dynamic final class SFloat extends Proxy
	{
		use namespace minko_shader;

		minko_shader var _node	: AbstractNode	= null;

		public final function get size() : uint
		{
			return _node.size;
		}

		public function SFloat(value : Object)
		{
			_node = getNode(value);
		}

		public final function scaleBy(arg : Object) : SFloat
		{
			_node = new Instruction(Instruction.MUL, _node, getNode(arg));

			return this;
		}

		public final function incrementBy(value : Object) : SFloat
		{
			_node = new Instruction(Instruction.ADD, _node, getNode(value));

			return this;
		}

		public final function decrementBy(value : Object) : SFloat
		{
			_node = new Instruction(Instruction.SUB, _node, getNode(value));

			return this;
		}

		public final function normalize() : SFloat
		{
			_node = new Instruction(Instruction.NRM, _node);

			return this;
		}

		public final function negate() : SFloat
		{
			_node = new Instruction(Instruction.NEG, _node);

			return this;
		}

		override flash_proxy function getProperty(name : *) : *
		{
			return new SFloat(new Extract(_node, Components.stringToComponent(name)));
		}

		override flash_proxy function setProperty(name : *, value : *) : void
		{
			var propertyName		: String		= String(name);
			var propertyComponent	: uint			= getPropertyWriteComponentMask(propertyName);
			var propertyNode		: AbstractNode	= getNode(value);
			var nodeComponent		: uint 			= Components.createContinuous(0, 0, _node.size, _node.size);

			propertyNode = new Overwriter(
				new <AbstractNode>[propertyNode],
				new <uint>[Components.createContinuous(0, 0, 4, propertyNode.size)]
			);

			_node = new Overwriter(
				new <AbstractNode>[_node, propertyNode],
				new <uint>[nodeComponent, propertyComponent]
			);
		}

		public static function getPropertyWriteComponentMask(string : String) : uint
		{
			var result : uint = 0x04040404;

			for (var i : uint = 0; i < 4; ++i)
				if (i < string.length)
					switch (string.charAt(i))
					{
						case 'x': case 'X': case 'r': case 'R':
							result = (0xffffff00 & result) | i;
							result |= i << (8 * 0);
							break;

						case 'y': case 'Y': case 'g': case 'G':
							result = (0xffff00ff & result) | i << 8;
							break;

						case 'z': case 'Z': case 'b': case 'B':
							result = (0xff00ffff & result) | i << 16;
							break;

						case 'w': case 'W': case 'a': case 'A':
							result = (0x00ffffff & result) | i << 24;
							break;

						default:
							throw new Error('Invalid string.');
					}

			return result;
		}

		private function getNode(value : Object) : AbstractNode
		{
			if (value is AbstractNode)
				return value as AbstractNode;

			if (value is SFloat)
				return (value as SFloat)._node;

			if (value is uint || value is int || value is Number)
				return new Constant(new <Number>[Number(value)]);

			if (value is Matrix4x4)
				return new Constant(Matrix4x4(value).getRawData(null, 0, false));

			throw new Error('This type cannot be casted to a shader value.');
		}
	}
}

fix SFloat.setProperty()

fix SFloat.setProperty()


/*
 *  FRESteamWorks.h
 *  This file is part of FRESteamWorks.
 *
 *  Created by David ´Oldes´ Oliva on 3/29/12.
 *  Contributors: Ventero <http://github.com/Ventero>
 *  Copyright (c) 2012 Amanita Design. All rights reserved.
 *  Copyright (c) 2012-2013 Level Up Labs, LLC. All rights reserved.
 */

package
{
	import com.amanitadesign.steam.FRESteamWorks;
	import com.amanitadesign.steam.SteamConstants;
	import com.amanitadesign.steam.SteamEvent;
	import com.amanitadesign.steam.WorkshopConstants;

	import flash.desktop.NativeApplication;
	import flash.display.SimpleButton;
	import flash.display.Sprite;
	import flash.display.StageDisplayState;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.utils.ByteArray;

	public class FRESteamWorksTest extends Sprite
	{
		public var Steamworks:FRESteamWorks = new FRESteamWorks();
		public var tf:TextField;

		private var _buttonPos:int = 5;
		private var _appId:uint;

		public function FRESteamWorksTest()
		{
			tf = new TextField();
			tf.x = 160;
			tf.width = stage.stageWidth - tf.x;
			tf.height = stage.stageHeight;
			addChild(tf);

			addButton("Check stats/achievements", checkAchievements);
			addButton("Toggle achievement", toggleAchievement);
			addButton("Toggle cloud enabled", toggleCloudEnabled);
			addButton("Toggle file", toggleFile);
			addButton("Publish file", publishFile);
			addButton("Toggle fullscreen", toggleFullscreen);
			addButton("Show Friends overlay", activateOverlay);
			addButton("List subscribed files", enumerateSubscribedFiles);
			addButton("List shared files", enumerateSharedFiles);
			addButton("List workshop files", enumerateWorkshopFiles);

			Steamworks.addEventListener(SteamEvent.STEAM_RESPONSE, onSteamResponse);
			Steamworks.addOverlayWorkaround(stage, true);
			NativeApplication.nativeApplication.addEventListener(Event.EXITING, onExit);
			try {
				//Steamworks.useCrashHandler(480, "1.0", "Feb 20 2013", "21:42:20");
				if(!Steamworks.init()){
					log("STEAMWORKS API is NOT available");
					return;
				}

				log("STEAMWORKS API is available\n");
				log("User ID: " + Steamworks.getUserID());
				_appId = Steamworks.getAppID();
				log("App ID: " + _appId);
				log("Persona name: " + Steamworks.getPersonaName());
				log("isCloudEnabledForApp() == "+Steamworks.isCloudEnabledForApp());
				log("getFileCount() == "+Steamworks.getFileCount());
				log("fileExists('test.txt') == "+Steamworks.fileExists('test.txt'));
				log("getDLCCount() == " + Steamworks.getDLCCount());

				Steamworks.resetAllStats(true);
			} catch(e:Error) {
				log("*** ERROR ***");
				log(e.message);
				log(e.getStackTrace());
			}

		}
		private function log(value:String):void{
			tf.appendText(value+"\n");
			tf.scrollV = tf.maxScrollV;
		}

		public function writeFileToCloud(fileName:String, data:String):Boolean {
			var dataOut:ByteArray = new ByteArray();
			dataOut.writeUTFBytes(data);
			return Steamworks.fileWrite(fileName, dataOut);
		}

		public function readFileFromCloud(fileName:String):String {
			var dataIn:ByteArray = new ByteArray();
			var result:String;
			dataIn.position = 0;
			dataIn.length = Steamworks.getFileSize(fileName);

			if(dataIn.length>0 && Steamworks.fileRead(fileName,dataIn)){
				result = dataIn.readUTFBytes(dataIn.length);
			}
			return result;
		}

		private function checkAchievements(e:Event = null):void {
			if(!Steamworks.isReady) return;

			// current stats and achievement ids are from steam example app
			log("isAchievement('ACH_WIN_ONE_GAME') == "+Steamworks.isAchievement("ACH_WIN_ONE_GAME"));
			log("isAchievement('ACH_TRAVEL_FAR_SINGLE') == "+Steamworks.isAchievement("ACH_TRAVEL_FAR_SINGLE"));
			log("setStatFloat('FeetTraveled') == "+Steamworks.setStatFloat('FeetTraveled', 21.3));
			log("setStatInt('NumGames', 2) == "+Steamworks.setStatInt('NumGames', 2));
			Steamworks.storeStats();
			log("getStatInt('NumGames') == "+Steamworks.getStatInt('NumGames'));
			log("getStatFloat('FeetTraveled') == "+Steamworks.getStatFloat('FeetTraveled'));
		}

		private function toggleAchievement(e:Event = null):void{
			if(!Steamworks.isReady) return;

			var result:Boolean = Steamworks.isAchievement("ACH_WIN_ONE_GAME");
			log("isAchievement('ACH_WIN_ONE_GAME') == " + result);
			if(!result) {
				log("setAchievement('ACH_WIN_ONE_GAME') == "+Steamworks.setAchievement("ACH_WIN_ONE_GAME"));
			} else {
				log("clearAchievement('ACH_WIN_ONE_GAME') == "+Steamworks.clearAchievement("ACH_WIN_ONE_GAME"));
			}
		}

		private function toggleCloudEnabled(e:Event = null):void {
			if(!Steamworks.isReady) return;

			var enabled:Boolean = Steamworks.isCloudEnabledForApp();
			log("isCloudEnabledForApp() == " + enabled);
			log("setCloudEnabledForApp(" + !enabled + ") == " + Steamworks.setCloudEnabledForApp(!enabled));
			log("isCloudEnabledForApp() == " + Steamworks.isCloudEnabledForApp());
		}

		private function toggleFile(e:Event = null):void {
			if(!Steamworks.isReady) return;

			var result:Boolean = Steamworks.fileExists('test.txt');
			log("fileExists('test.txt') == " + result);
			if(result){
				log("readFileFromCloud('test.txt') == "+readFileFromCloud('test.txt') );
				log("fileDelete('test.txt') == "+Steamworks.fileDelete('test.txt'));
			} else {
				log("writeFileToCloud('test.txt','click') == "+writeFileToCloud('test.txt','click'));
			}
		}

		private function publishFile(e:Event = null):void {
			if(!Steamworks.isReady) return;

			var res:Boolean = Steamworks.publishWorkshopFile("test.txt", "", _appId,
				"Test.txt", "Test.txt", WorkshopConstants.VISIBILITY_Private,
				["TestTag"], WorkshopConstants.FILETYPE_Community);
			log("publishWorkshopFile('test.txt' ...) == " + res);
		}

		private function toggleFullscreen(e:Event = null):void {
			if(stage.displayState == StageDisplayState.NORMAL)
				stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
			else
				stage.displayState = StageDisplayState.NORMAL;
		}

		private function activateOverlay(e:Event = null):void {
			if(!Steamworks.isReady) return;

			log("isOverlayEnabled() == " + Steamworks.isOverlayEnabled());
			log("activateGameOverlay('Friends') == " + Steamworks.activateGameOverlay("Friends"));
			log("isOverlayEnabled() == " + Steamworks.isOverlayEnabled());
		}

		private function enumerateSubscribedFiles(e:Event = null):void {
			if(!Steamworks.isReady) return;

			log("enumerateUserSubscribedFiles(0) == " + Steamworks.enumerateUserSubscribedFiles(0));
		}

		private function enumerateSharedFiles(e:Event = null):void {
			if(!Steamworks.isReady) return;

			var userID:String = Steamworks.getUserID();
			var res:Boolean = Steamworks.enumerateUserSharedWorkshopFiles(userID, 0, [], []);
			log("enumerateSharedFiles(" + userID + ", 0, [], []) == " + res);
		}

		private function enumerateWorkshopFiles(e:Event = null):void {
			if(!Steamworks.isReady) return;

			var res:Boolean = Steamworks.enumeratePublishedWorkshopFiles(
				WorkshopConstants.ENUMTYPE_RankedByVote, 0, 10, 0, [], []);
			log("enumerateSharedFiles(...) == " + res);
		}

		private var id:String;
		private var handle:String;
		private function onSteamResponse(e:SteamEvent):void{
			var apiCall:Boolean;
			var i:int;
			var file:String;
			switch(e.req_type){
				case SteamConstants.RESPONSE_OnUserStatsStored:
					log("RESPONSE_OnUserStatsStored: "+e.response);
					break;
				case SteamConstants.RESPONSE_OnUserStatsReceived:
					log("RESPONSE_OnUserStatsReceived: "+e.response);
					break;
				case SteamConstants.RESPONSE_OnAchievementStored:
					log("RESPONSE_OnAchievementStored: "+e.response);
					break;
				case SteamConstants.RESPONSE_OnPublishWorkshopFile:
					log("RESPONSE_OnPublishWorkshopFile: " + e.response);
					file = Steamworks.publishWorkshopFileResult();
					log("File published as " + file);
					log("subscribePublishedFile(...) == " + Steamworks.subscribePublishedFile(file));
					break;
				case SteamConstants.RESPONSE_OnEnumerateUserSubscribedFiles:
					log("RESPONSE_OnEnumerateUserSubscribedFiles: " + e.response);
					var subRes:SubscribedFilesResult = Steamworks.enumerateUserSubscribedFilesResult();
					log("User subscribed files: " + subRes.resultsReturned + "/" + subRes.totalResults);
					for(i = 0; i < subRes.resultsReturned; i++) {
						id = subRes.publishedFileId[i];
						apiCall = Steamworks.getPublishedFileDetails(subRes.publishedFileId[i]);
						log(i + ": " + subRes.publishedFileId[i] + " (" + subRes.timeSubscribed[i] + ") - " + apiCall);
					}
					break;
				case SteamConstants.RESPONSE_OnEnumerateUserSharedWorkshopFiles:
					log("RESPONSE_OnEnumerateUserSharedWorkshopFiles: " + e.response);
					var userRes:UserFilesResult = Steamworks.enumerateUserSharedWorkshopFilesResult();
					log("User shared files: " + userRes.resultsReturned + "/" + userRes.totalResults);
					for(i = 0; i < userRes.resultsReturned; i++) {
						log(i + ": " + userRes.publishedFileId[i]);
					}
					break;
				case SteamConstants.RESPONSE_OnEnumeratePublishedWorkshopFiles:
					log("RESPONSE_OnEnumeratePublishedWorkshopFiles: " + e.response);
					var fileRes:WorkshopFilesResult = Steamworks.enumeratePublishedWorkshopFilesResult();
					log("Workshop files: " + fileRes.resultsReturned + "/" + fileRes.totalResults);
					for(i = 0; i < fileRes.resultsReturned; i++) {
						log(i + ": " + fileRes.publishedFileId[i] + " - " + fileRes.score[i]);
					}
					if(fileRes.resultsReturned > 0) {
						file = fileRes.publishedFileId[0];
						log("updateUserPublishedItemVote(" + file + ", true)");
						apiCall = Steamworks.updateUserPublishedItemVote(file, true);
						log("updateUserPublishedItemVote(" + file + ", true) == " + apiCall);
					}
					break;
				case SteamConstants.RESPONSE_OnGetPublishedFileDetails:
					log("RESPONSE_OnGetPublishedFileDetails: " + e.response);
					var res:FileDetailsResult = Steamworks.getPublishedFileDetailsResult(id);
					log("Result for " + id + ": " + res);
					if(res) {
						log("File: " + res.fileName + ", handle: " + res.fileHandle);
						handle = res.fileHandle;
						apiCall = Steamworks.UGCDownload(res.fileHandle, 0);
						log("UGCDownload(...) == " + apiCall);
					}
					break;
				case SteamConstants.RESPONSE_OnUGCDownload:
					log("RESPONSE_OnUGCDownload: " + e.response);
					var ugcResult:DownloadUGCResult = Steamworks.getUGCDownloadResult(handle);
					log("Result for " + handle + ": " + ugcResult);
					if(ugcResult) {
						log("File: " + ugcResult.fileName + ", handle: " + ugcResult.fileHandle + ", size: " + ugcResult.size);
						var ba:ByteArray = new ByteArray();
						ba.length = ugcResult.size;
						apiCall = Steamworks.UGCRead(ugcResult.fileHandle, ugcResult.size, 0, ba);
						log("UGCRead(...) == " + apiCall);
						if(apiCall) {
							log("Result length: " + ba.position + "//" + ba.length);
							log("Result: " + ba.readUTFBytes(ugcResult.size));
						}
					}
					break;
				default:
					log("STEAMresponse type:"+e.req_type+" response:"+e.response);
			}
		}

		private function onExit(e:Event):void{
			log("Exiting application, cleaning up");
			Steamworks.dispose();
		}

		private function addButton(label:String, callback:Function):void {
			var button:Sprite = new Sprite();
			button.graphics.beginFill(0xaaaaaa);
			button.graphics.drawRoundRect(0, 0, 150, 30, 5, 5);
			button.graphics.endFill();
			button.buttonMode = true;
			button.useHandCursor = true;
			button.addEventListener(MouseEvent.CLICK, callback);
			button.x = 5;
			button.y = _buttonPos;
			_buttonPos += button.height + 5;

			button.addEventListener(MouseEvent.MOUSE_OVER, function(e:MouseEvent):void {
				button.graphics.clear();
				button.graphics.beginFill(0xccccccc);
				button.graphics.drawRoundRect(0, 0, 150, 30, 5, 5);
				button.graphics.endFill();
			});

			button.addEventListener(MouseEvent.MOUSE_OUT, function(e:MouseEvent):void {
				button.graphics.clear();
				button.graphics.beginFill(0xaaaaaa);
				button.graphics.drawRoundRect(0, 0, 150, 30, 5, 5);
				button.graphics.endFill();
			});

			var text:TextField = new TextField();
			text.text = label;
			text.width = 140;
			text.height = 25;
			text.x = 5;
			text.y = 5;
			text.mouseEnabled = false;

			button.addChild(text);
			addChild(button);
		}
	}
}

/*
 *  FRESteamWorks.h
 *  This file is part of FRESteamWorks.
 *
 *  Created by David ´Oldes´ Oliva on 3/29/12.
 *  Contributors: Ventero <http://github.com/Ventero>
 *  Copyright (c) 2012 Amanita Design. All rights reserved.
 *  Copyright (c) 2012-2013 Level Up Labs, LLC. All rights reserved.
 */

package
{
	import com.amanitadesign.steam.FRESteamWorks;
	import com.amanitadesign.steam.SteamConstants;
	import com.amanitadesign.steam.SteamEvent;
	import com.amanitadesign.steam.WorkshopConstants;

	import flash.desktop.NativeApplication;
	import flash.display.SimpleButton;
	import flash.display.Sprite;
	import flash.display.StageDisplayState;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.utils.ByteArray;

	public class FRESteamWorksTest extends Sprite
	{
		public var Steamworks:FRESteamWorks = new FRESteamWorks();
		public var tf:TextField;

		private var _buttonPos:int = 5;
		private var _appId:uint;

		public function FRESteamWorksTest()
		{
			tf = new TextField();
			tf.x = 160;
			tf.width = stage.stageWidth - tf.x;
			tf.height = stage.stageHeight;
			addChild(tf);

			addButton("Check stats/achievements", checkAchievements);
			addButton("Toggle achievement", toggleAchievement);
			addButton("Toggle cloud enabled", toggleCloudEnabled);
			addButton("Toggle file", toggleFile);
			addButton("Publish file", publishFile);
			addButton("Toggle fullscreen", toggleFullscreen);
			addButton("Show Friends overlay", activateOverlay);
			addButton("List subscribed files", enumerateSubscribedFiles);
			addButton("List shared files", enumerateSharedFiles);
			addButton("List workshop files", enumerateWorkshopFiles);
			addButton("Change file description", updateFile);

			Steamworks.addEventListener(SteamEvent.STEAM_RESPONSE, onSteamResponse);
			Steamworks.addOverlayWorkaround(stage, true);
			NativeApplication.nativeApplication.addEventListener(Event.EXITING, onExit);
			try {
				//Steamworks.useCrashHandler(480, "1.0", "Feb 20 2013", "21:42:20");
				if(!Steamworks.init()){
					log("STEAMWORKS API is NOT available");
					return;
				}

				log("STEAMWORKS API is available\n");
				log("User ID: " + Steamworks.getUserID());
				_appId = Steamworks.getAppID();
				log("App ID: " + _appId);
				log("Persona name: " + Steamworks.getPersonaName());
				log("isCloudEnabledForApp() == "+Steamworks.isCloudEnabledForApp());
				log("getFileCount() == "+Steamworks.getFileCount());
				log("fileExists('test.txt') == "+Steamworks.fileExists('test.txt'));
				log("getDLCCount() == " + Steamworks.getDLCCount());

				Steamworks.resetAllStats(true);
			} catch(e:Error) {
				log("*** ERROR ***");
				log(e.message);
				log(e.getStackTrace());
			}

		}
		private function log(value:String):void{
			tf.appendText(value+"\n");
			tf.scrollV = tf.maxScrollV;
		}

		public function writeFileToCloud(fileName:String, data:String):Boolean {
			var dataOut:ByteArray = new ByteArray();
			dataOut.writeUTFBytes(data);
			return Steamworks.fileWrite(fileName, dataOut);
		}

		public function readFileFromCloud(fileName:String):String {
			var dataIn:ByteArray = new ByteArray();
			var result:String;
			dataIn.position = 0;
			dataIn.length = Steamworks.getFileSize(fileName);

			if(dataIn.length>0 && Steamworks.fileRead(fileName,dataIn)){
				result = dataIn.readUTFBytes(dataIn.length);
			}
			return result;
		}

		private function checkAchievements(e:Event = null):void {
			if(!Steamworks.isReady) return;

			// current stats and achievement ids are from steam example app
			log("isAchievement('ACH_WIN_ONE_GAME') == "+Steamworks.isAchievement("ACH_WIN_ONE_GAME"));
			log("isAchievement('ACH_TRAVEL_FAR_SINGLE') == "+Steamworks.isAchievement("ACH_TRAVEL_FAR_SINGLE"));
			log("setStatFloat('FeetTraveled') == "+Steamworks.setStatFloat('FeetTraveled', 21.3));
			log("setStatInt('NumGames', 2) == "+Steamworks.setStatInt('NumGames', 2));
			Steamworks.storeStats();
			log("getStatInt('NumGames') == "+Steamworks.getStatInt('NumGames'));
			log("getStatFloat('FeetTraveled') == "+Steamworks.getStatFloat('FeetTraveled'));
		}

		private function toggleAchievement(e:Event = null):void{
			if(!Steamworks.isReady) return;

			var result:Boolean = Steamworks.isAchievement("ACH_WIN_ONE_GAME");
			log("isAchievement('ACH_WIN_ONE_GAME') == " + result);
			if(!result) {
				log("setAchievement('ACH_WIN_ONE_GAME') == "+Steamworks.setAchievement("ACH_WIN_ONE_GAME"));
			} else {
				log("clearAchievement('ACH_WIN_ONE_GAME') == "+Steamworks.clearAchievement("ACH_WIN_ONE_GAME"));
			}
		}

		private function toggleCloudEnabled(e:Event = null):void {
			if(!Steamworks.isReady) return;

			var enabled:Boolean = Steamworks.isCloudEnabledForApp();
			log("isCloudEnabledForApp() == " + enabled);
			log("setCloudEnabledForApp(" + !enabled + ") == " + Steamworks.setCloudEnabledForApp(!enabled));
			log("isCloudEnabledForApp() == " + Steamworks.isCloudEnabledForApp());
		}

		private function toggleFile(e:Event = null):void {
			if(!Steamworks.isReady) return;

			var result:Boolean = Steamworks.fileExists('test.txt');
			log("fileExists('test.txt') == " + result);
			if(result){
				log("readFileFromCloud('test.txt') == "+readFileFromCloud('test.txt') );
				log("fileDelete('test.txt') == "+Steamworks.fileDelete('test.txt'));
			} else {
				log("writeFileToCloud('test.txt','click') == "+writeFileToCloud('test.txt','click'));
			}
		}

		private function publishFile(e:Event = null):void {
			if(!Steamworks.isReady) return;

			var res:Boolean = Steamworks.publishWorkshopFile("test.txt", "", _appId,
				"Test.txt", "Test.txt", WorkshopConstants.VISIBILITY_Private,
				["TestTag"], WorkshopConstants.FILETYPE_Community);
			log("publishWorkshopFile('test.txt' ...) == " + res);
		}

		private function toggleFullscreen(e:Event = null):void {
			if(stage.displayState == StageDisplayState.NORMAL)
				stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
			else
				stage.displayState = StageDisplayState.NORMAL;
		}

		private function activateOverlay(e:Event = null):void {
			if(!Steamworks.isReady) return;

			log("isOverlayEnabled() == " + Steamworks.isOverlayEnabled());
			log("activateGameOverlay('Friends') == " + Steamworks.activateGameOverlay("Friends"));
			log("isOverlayEnabled() == " + Steamworks.isOverlayEnabled());
		}

		private function enumerateSubscribedFiles(e:Event = null):void {
			if(!Steamworks.isReady) return;

			log("enumerateUserSubscribedFiles(0) == " + Steamworks.enumerateUserSubscribedFiles(0));
		}

		private function enumerateSharedFiles(e:Event = null):void {
			if(!Steamworks.isReady) return;

			var userID:String = Steamworks.getUserID();
			var res:Boolean = Steamworks.enumerateUserSharedWorkshopFiles(userID, 0, [], []);
			log("enumerateSharedFiles(" + userID + ", 0, [], []) == " + res);
		}

		private function enumerateWorkshopFiles(e:Event = null):void {
			if(!Steamworks.isReady) return;

			var res:Boolean = Steamworks.enumeratePublishedWorkshopFiles(
				WorkshopConstants.ENUMTYPE_RankedByVote, 0, 10, 0, [], []);
			log("enumerateSharedFiles(...) == " + res);
		}

		private function updateFile(e:Event = null):void {
			if(!file) {
				log("No file handle set, publish or enumerate first");
				return;
			}

			var handle:String = Steamworks.createPublishedFileUpdateRequest(file);
			var res:Boolean = Steamworks.updatePublishedFileDescription(handle,
				"Test updated description");
			log("updatePublishedFileDescription(" + handle + ", ...) == " + res);
			if(!res) return;

			res = Steamworks.commitPublishedFileUpdate(handle);
			log("commitPublishedFileUpdate(...) == " + res);
		}

		private var id:String;
		private var handle:String;
		private var file:String;
		private function onSteamResponse(e:SteamEvent):void{
			var apiCall:Boolean;
			var i:int;
			switch(e.req_type){
				case SteamConstants.RESPONSE_OnUserStatsStored:
					log("RESPONSE_OnUserStatsStored: "+e.response);
					break;
				case SteamConstants.RESPONSE_OnUserStatsReceived:
					log("RESPONSE_OnUserStatsReceived: "+e.response);
					break;
				case SteamConstants.RESPONSE_OnAchievementStored:
					log("RESPONSE_OnAchievementStored: "+e.response);
					break;
				case SteamConstants.RESPONSE_OnPublishWorkshopFile:
					log("RESPONSE_OnPublishWorkshopFile: " + e.response);
					file = Steamworks.publishWorkshopFileResult();
					log("File published as " + file);
					log("subscribePublishedFile(...) == " + Steamworks.subscribePublishedFile(file));
					break;
				case SteamConstants.RESPONSE_OnEnumerateUserSubscribedFiles:
					log("RESPONSE_OnEnumerateUserSubscribedFiles: " + e.response);
					var subRes:SubscribedFilesResult = Steamworks.enumerateUserSubscribedFilesResult();
					log("User subscribed files: " + subRes.resultsReturned + "/" + subRes.totalResults);
					for(i = 0; i < subRes.resultsReturned; i++) {
						id = subRes.publishedFileId[i];
						apiCall = Steamworks.getPublishedFileDetails(subRes.publishedFileId[i]);
						log(i + ": " + subRes.publishedFileId[i] + " (" + subRes.timeSubscribed[i] + ") - " + apiCall);
					}
					break;
				case SteamConstants.RESPONSE_OnEnumerateUserSharedWorkshopFiles:
					log("RESPONSE_OnEnumerateUserSharedWorkshopFiles: " + e.response);
					var userRes:UserFilesResult = Steamworks.enumerateUserSharedWorkshopFilesResult();
					log("User shared files: " + userRes.resultsReturned + "/" + userRes.totalResults);
					for(i = 0; i < userRes.resultsReturned; i++) {
						log(i + ": " + userRes.publishedFileId[i]);
					}
					break;
				case SteamConstants.RESPONSE_OnEnumeratePublishedWorkshopFiles:
					log("RESPONSE_OnEnumeratePublishedWorkshopFiles: " + e.response);
					var fileRes:WorkshopFilesResult = Steamworks.enumeratePublishedWorkshopFilesResult();
					log("Workshop files: " + fileRes.resultsReturned + "/" + fileRes.totalResults);
					for(i = 0; i < fileRes.resultsReturned; i++) {
						log(i + ": " + fileRes.publishedFileId[i] + " - " + fileRes.score[i]);
					}
					if(fileRes.resultsReturned > 0) {
						file = fileRes.publishedFileId[0];
						log("updateUserPublishedItemVote(" + file + ", true)");
						apiCall = Steamworks.updateUserPublishedItemVote(file, true);
						log("updateUserPublishedItemVote(" + file + ", true) == " + apiCall);
					}
					break;
				case SteamConstants.RESPONSE_OnGetPublishedFileDetails:
					log("RESPONSE_OnGetPublishedFileDetails: " + e.response);
					var res:FileDetailsResult = Steamworks.getPublishedFileDetailsResult(id);
					log("Result for " + id + ": " + res);
					if(res) {
						log("File: " + res.fileName + ", handle: " + res.fileHandle);
						handle = res.fileHandle;
						apiCall = Steamworks.UGCDownload(res.fileHandle, 0);
						log("UGCDownload(...) == " + apiCall);
					}
					break;
				case SteamConstants.RESPONSE_OnUGCDownload:
					log("RESPONSE_OnUGCDownload: " + e.response);
					var ugcResult:DownloadUGCResult = Steamworks.getUGCDownloadResult(handle);
					log("Result for " + handle + ": " + ugcResult);
					if(ugcResult) {
						log("File: " + ugcResult.fileName + ", handle: " + ugcResult.fileHandle + ", size: " + ugcResult.size);
						var ba:ByteArray = new ByteArray();
						ba.length = ugcResult.size;
						apiCall = Steamworks.UGCRead(ugcResult.fileHandle, ugcResult.size, 0, ba);
						log("UGCRead(...) == " + apiCall);
						if(apiCall) {
							log("Result length: " + ba.position + "//" + ba.length);
							log("Result: " + ba.readUTFBytes(ugcResult.size));
						}
					}
					break;
				default:
					log("STEAMresponse type:"+e.req_type+" response:"+e.response);
			}
		}

		private function onExit(e:Event):void{
			log("Exiting application, cleaning up");
			Steamworks.dispose();
		}

		private function addButton(label:String, callback:Function):void {
			var button:Sprite = new Sprite();
			button.graphics.beginFill(0xaaaaaa);
			button.graphics.drawRoundRect(0, 0, 150, 25, 5, 5);
			button.graphics.endFill();
			button.buttonMode = true;
			button.useHandCursor = true;
			button.addEventListener(MouseEvent.CLICK, callback);
			button.x = 5;
			button.y = _buttonPos;
			_buttonPos += button.height + 5;

			button.addEventListener(MouseEvent.MOUSE_OVER, function(e:MouseEvent):void {
				button.graphics.clear();
				button.graphics.beginFill(0xccccccc);
				button.graphics.drawRoundRect(0, 0, 150, 25, 5, 5);
				button.graphics.endFill();
			});

			button.addEventListener(MouseEvent.MOUSE_OUT, function(e:MouseEvent):void {
				button.graphics.clear();
				button.graphics.beginFill(0xaaaaaa);
				button.graphics.drawRoundRect(0, 0, 150, 25, 5, 5);
				button.graphics.endFill();
			});

			var text:TextField = new TextField();
			text.text = label;
			text.width = 140;
			text.height = 25;
			text.x = 5;
			text.y = 5;
			text.mouseEnabled = false;

			button.addChild(text);
			addChild(button);
		}
	}
}

Add test for FileUpdate stuff (only description so far)


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

	[ExcludeClass]
	COMPILE::AS3
	public class Language {}

	COMPILE::JS
	public class Language
	{

		//--------------------------------------
		//   Static Property
		//--------------------------------------

		//--------------------------------------
		//   Static Function
		//--------------------------------------

		/**
		 * _as()
		 *
		 * @export
		 * @param {?} leftOperand The lefthand operand of the
		 * binary as operator in AS3.
		 * @param {?} rightOperand The righthand operand of the
		 * binary operator in AS3.
		 * @param {?=} coercion The cast is a coercion,
		 * throw expception if it fails.
		 * @return {?} Returns the lefthand operand if it is of the
		 * type of the righthand operand, otherwise null.
		 */
		static public function _as(leftOperand:Object, rightOperand:Object, coercion:* = null):Object
		{
			var error:Error, itIs:Boolean, message:String;

			coercion = (coercion !== undefined) ? coercion : false;

			itIs = _is(leftOperand, rightOperand);

			if (!itIs && coercion)
			{
				message = 'Type Coercion failed';

				if (TypeError)
				{
					error = new TypeError(message);
				}
				else
				{
					error = new Error(message);
				}
				throw error;
			}

			return (itIs) ? leftOperand : null;
		}

		/**
		 * int()
		 *
		 * @export
		 * @param {?} value The value to be cast.
		 * @return {number}
		 */
		static public function _int(value:Number):int
		{
			return value >> 0;
		}

		/**
		 * _is()
		 *
		 * @export
		 * @param {?} leftOperand The lefthand operand of the
		 * binary as operator in AS3.
		 * @param {?} rightOperand The righthand operand of the
		 * binary operator in AS3.
		 * @return {boolean}
		 */
		static public function _is(leftOperand:Object, rightOperand:Object):Boolean
		{
			var checkInterfaces:Function, superClass:Object;

			if (!leftOperand)
				return false;

			if (leftOperand && !rightOperand)
			{
				return false;
			}

			checkInterfaces = function(left:Object):Boolean {
				var i:uint, interfaces:Array;

				interfaces = left.FLEXJS_CLASS_INFO.interfaces;
				for (i = interfaces.length - 1; i > -1; i--) {
					if (interfaces[i] === rightOperand) {
						return true;
					}

					if (interfaces[i].prototype.FLEXJS_CLASS_INFO.interfaces) {
						var isit:Boolean = checkInterfaces(new interfaces[i]());
						if (isit) return true;
					}
				}

				return false;
			};

			if ((rightOperand === String && typeof leftOperand === 'string') ||
				(leftOperand instanceof /** @type {Object} */(rightOperand)))
			{
				return true;
			}

			if (typeof leftOperand === 'string')
				return false; // right was not String otherwise exit above

			if (typeof leftOperand === 'number')
				return rightOperand === Number;

			if (rightOperand === Array && Array.isArray(leftOperand))
				return true;

			if (leftOperand.FLEXJS_CLASS_INFO === undefined)
				return false; // could be a function but not an instance

			if (leftOperand.FLEXJS_CLASS_INFO.interfaces)
			{
				if (checkInterfaces(leftOperand))
				{
					return true;
				}
			}

			superClass = leftOperand.constructor.superClass_;

			if (superClass)
			{
				while (superClass && superClass.FLEXJS_CLASS_INFO)
				{
					if (superClass.FLEXJS_CLASS_INFO.interfaces)
					{
						if (checkInterfaces(superClass))
						{
							return true;
						}
					}
					superClass = superClass.constructor.superClass_;
				}
			}

			return false;
		}

		/**
		 * postdecrement handles foo++
		 *
		 * @export
		 * @param {Object} obj The object with the getter/setter.
		 * @param {string} prop The name of a property.
		 * @return {number}
		 */
		static public function postdecrement(obj:Object, prop:String):int
		{
			var value:int = obj[prop];
			obj[prop] = value - 1;
			return value;
		}

		/**
		 * postincrement handles foo++
		 *
		 * @export
		 * @param {Object} obj The object with the getter/setter.
		 * @param {string} prop The name of a property.
		 * @return {number}
		 */
		static public function postincrement(obj:Object, prop:String):int
		{
			var value:int = obj[prop];
			obj[prop] = value + 1;
			return value;
		}

		/**
		 * predecrement handles ++foo
		 *
		 * @export
		 * @param {Object} obj The object with the getter/setter.
		 * @param {string} prop The name of a property.
		 * @return {number}
		 */
		static public function predecrement(obj:Object, prop:String):int
		{
			var value:int = obj[prop] - 1;
			obj[prop] = value;
			return value;
		}

		/**
		 * preincrement handles --foo
		 *
		 * @export
		 * @param {Object} obj The object with the getter/setter.
		 * @param {string} prop The name of a property.
		 * @return {number}
		 */
		static public function preincrement(obj:Object, prop:String):int
		{
			var value:int = obj[prop] + 1;
			obj[prop] = value;
			return value;
		}

		/**
		 * superGetter calls the getter on the given class' superclass.
		 *
		 * @export
		 * @param {Object} clazz The class.
		 * @param {Object} pthis The this pointer.
		 * @param {string} prop The name of the getter.
		 * @return {Object}
		 */
		static public function superGetter(clazz:Object, pthis:Object, prop:String):Object
		{
			var superClass:Object = clazz.superClass_;
			var superdesc:Object = Object.getOwnPropertyDescriptor(superClass, prop);

			while (superdesc == null)
			{
				superClass = superClass.constructor.superClass_;
				superdesc = Object.getOwnPropertyDescriptor(superClass, prop);
			}
			return superdesc.get.call(pthis);
		}

		/**
		 * superSetter calls the setter on the given class' superclass.
		 *
		 * @export
		 * @param {Object} clazz The class.
		 * @param {Object} pthis The this pointer.
		 * @param {string} prop The name of the getter.
		 * @param {Object} value The value.
		 */
		static public function superSetter(clazz:Object, pthis:Object, prop:String, value:Object):void
		{
			var superClass:Object = clazz.superClass_;
			var superdesc:Object = Object.getOwnPropertyDescriptor(superClass, prop);

			while (superdesc == null)
			{
				superClass = superClass.constructor.superClass_;
				superdesc = Object.getOwnPropertyDescriptor(superClass, prop);
			}
			superdesc.set.apply(pthis, [value]);
		}

		static public function trace(...rest):void
		{
			var theConsole:*;

			var msg:String = '';

			for (var i:uint = 0; i < rest.length; i++)
			{
				if (i > 0)
					msg += ' ';
				msg += rest[i];
			}

			theConsole = ["goog"]["global"]["console"];

			if (theConsole === undefined && window.console !== undefined)
				theConsole = window.console;

			try
			{
				if (theConsole && theConsole.log)
				{
					theConsole.log(msg);
				}
			}
			catch (e:Error)
			{
				// ignore; at least we tried ;-)
			}
		}

		/**
		 * uint()
		 *
		 * @export
		 * @param {?} value The value to be cast.
		 * @return {number}
		 */
		static public function uint(value:Number):uint
		{
			return value >>> 0;
		}
	}
}

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

	[ExcludeClass]
	COMPILE::AS3
	public class Language {}

	COMPILE::JS
	public class Language
	{

		//--------------------------------------
		//   Static Property
		//--------------------------------------

		//--------------------------------------
		//   Static Function
		//--------------------------------------

		/**
		 * _as()
		 *
		 * @export
		 * @param {?} leftOperand The lefthand operand of the
		 * binary as operator in AS3.
		 * @param {?} rightOperand The righthand operand of the
		 * binary operator in AS3.
		 * @param {?=} coercion The cast is a coercion,
		 * throw expception if it fails.
		 * @return {?} Returns the lefthand operand if it is of the
		 * type of the righthand operand, otherwise null.
		 */
		static public function _as(leftOperand:Object, rightOperand:Object, coercion:* = null):Object
		{
			var error:Error, itIs:Boolean, message:String;

			coercion = (coercion !== undefined) ? coercion : false;

			itIs = _is(leftOperand, rightOperand);

			if (!itIs && coercion)
			{
				message = 'Type Coercion failed';

				if (TypeError)
				{
					error = new TypeError(message);
				}
				else
				{
					error = new Error(message);
				}
				throw error;
			}

			return (itIs) ? leftOperand : null;
		}

		/**
		 * int()
		 *
		 * @export
		 * @param {?} value The value to be cast.
		 * @return {number}
		 */
		static public function _int(value:Number):Number
		{
			return value >> 0;
		}

		/**
		 * _is()
		 *
		 * @export
		 * @param {?} leftOperand The lefthand operand of the
		 * binary as operator in AS3.
		 * @param {?} rightOperand The righthand operand of the
		 * binary operator in AS3.
		 * @return {boolean}
		 */
		static public function _is(leftOperand:Object, rightOperand:Object):Boolean
		{
			var checkInterfaces:Function, superClass:Object;

			if (!leftOperand)
				return false;

			if (leftOperand && !rightOperand)
			{
				return false;
			}

			checkInterfaces = function(left:Object):Boolean {
				var i:uint, interfaces:Array;

				interfaces = left.FLEXJS_CLASS_INFO.interfaces;
				for (i = interfaces.length - 1; i > -1; i--) {
					if (interfaces[i] === rightOperand) {
						return true;
					}

					if (interfaces[i].prototype.FLEXJS_CLASS_INFO.interfaces) {
						var isit:Boolean = checkInterfaces(new interfaces[i]());
						if (isit) return true;
					}
				}

				return false;
			};

			if ((rightOperand === String && typeof leftOperand === 'string') ||
				(leftOperand instanceof /** @type {Object} */(rightOperand)))
			{
				return true;
			}

			if (typeof leftOperand === 'string')
				return false; // right was not String otherwise exit above

			if (typeof leftOperand === 'number')
				return rightOperand === Number;

			if (rightOperand === Array && Array.isArray(leftOperand))
				return true;

			if (leftOperand.FLEXJS_CLASS_INFO === undefined)
				return false; // could be a function but not an instance

			if (leftOperand.FLEXJS_CLASS_INFO.interfaces)
			{
				if (checkInterfaces(leftOperand))
				{
					return true;
				}
			}

			superClass = leftOperand.constructor.superClass_;

			if (superClass)
			{
				while (superClass && superClass.FLEXJS_CLASS_INFO)
				{
					if (superClass.FLEXJS_CLASS_INFO.interfaces)
					{
						if (checkInterfaces(superClass))
						{
							return true;
						}
					}
					superClass = superClass.constructor.superClass_;
				}
			}

			return false;
		}

		/**
		 * postdecrement handles foo++
		 *
		 * @export
		 * @param {Object} obj The object with the getter/setter.
		 * @param {string} prop The name of a property.
		 * @return {number}
		 */
		static public function postdecrement(obj:Object, prop:String):int
		{
			var value:int = obj[prop];
			obj[prop] = value - 1;
			return value;
		}

		/**
		 * postincrement handles foo++
		 *
		 * @export
		 * @param {Object} obj The object with the getter/setter.
		 * @param {string} prop The name of a property.
		 * @return {number}
		 */
		static public function postincrement(obj:Object, prop:String):int
		{
			var value:int = obj[prop];
			obj[prop] = value + 1;
			return value;
		}

		/**
		 * predecrement handles ++foo
		 *
		 * @export
		 * @param {Object} obj The object with the getter/setter.
		 * @param {string} prop The name of a property.
		 * @return {number}
		 */
		static public function predecrement(obj:Object, prop:String):int
		{
			var value:int = obj[prop] - 1;
			obj[prop] = value;
			return value;
		}

		/**
		 * preincrement handles --foo
		 *
		 * @export
		 * @param {Object} obj The object with the getter/setter.
		 * @param {string} prop The name of a property.
		 * @return {number}
		 */
		static public function preincrement(obj:Object, prop:String):int
		{
			var value:int = obj[prop] + 1;
			obj[prop] = value;
			return value;
		}

		/**
		 * superGetter calls the getter on the given class' superclass.
		 *
		 * @export
		 * @param {Object} clazz The class.
		 * @param {Object} pthis The this pointer.
		 * @param {string} prop The name of the getter.
		 * @return {Object}
		 */
		static public function superGetter(clazz:Object, pthis:Object, prop:String):Object
		{
			var superClass:Object = clazz.superClass_;
			var superdesc:Object = Object.getOwnPropertyDescriptor(superClass, prop);

			while (superdesc == null)
			{
				superClass = superClass.constructor.superClass_;
				superdesc = Object.getOwnPropertyDescriptor(superClass, prop);
			}
			return superdesc.get.call(pthis);
		}

		/**
		 * superSetter calls the setter on the given class' superclass.
		 *
		 * @export
		 * @param {Object} clazz The class.
		 * @param {Object} pthis The this pointer.
		 * @param {string} prop The name of the getter.
		 * @param {Object} value The value.
		 */
		static public function superSetter(clazz:Object, pthis:Object, prop:String, value:Object):void
		{
			var superClass:Object = clazz.superClass_;
			var superdesc:Object = Object.getOwnPropertyDescriptor(superClass, prop);

			while (superdesc == null)
			{
				superClass = superClass.constructor.superClass_;
				superdesc = Object.getOwnPropertyDescriptor(superClass, prop);
			}
			superdesc.set.apply(pthis, [value]);
		}

		static public function trace(...rest):void
		{
			var theConsole:*;

			var msg:String = '';

			for (var i:uint = 0; i < rest.length; i++)
			{
				if (i > 0)
					msg += ' ';
				msg += rest[i];
			}

			theConsole = ["goog"]["global"]["console"];

			if (theConsole === undefined && window.console !== undefined)
				theConsole = window.console;

			try
			{
				if (theConsole && theConsole.log)
				{
					theConsole.log(msg);
				}
			}
			catch (e:Error)
			{
				// ignore; at least we tried ;-)
			}
		}

		/**
		 * uint()
		 *
		 * @export
		 * @param {?} value The value to be cast.
		 * @return {number}
		 */
		static public function uint(value:Number):Number
		{
			return value >>> 0;
		}
	}
}

fix return type

fix return type