package aerys.minko.render.shader.part
{
	import aerys.minko.render.geometry.stream.format.VertexComponent;
	import aerys.minko.render.material.basic.BasicProperties;
	import aerys.minko.render.shader.SFloat;
	import aerys.minko.render.shader.Shader;
	import aerys.minko.type.enum.SamplerFiltering;
	import aerys.minko.type.enum.SamplerFormat;
	import aerys.minko.type.enum.SamplerMipMapping;
	import aerys.minko.type.enum.SamplerWrapping;

	public class DiffuseShaderPart extends ShaderPart
	{
		/**
		 * The shader part to use a diffuse map or fallback and use a solid color.
		 *
		 * @param main
		 *
		 */
		public function DiffuseShaderPart(main : Shader)
		{
			super(main);
		}

		public function getDiffuseColor(killOnAlphaThreshold : Boolean = true, uv : SFloat = null) : SFloat
		{
			var diffuseColor : SFloat	= null;
			var useVertexUv  : Boolean  = uv == null;

            uv ||= vertexUV.xy;

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

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

			if (useVertexUv)
				uv = interpolate(uv);

			if (meshBindings.propertyExists(BasicProperties.DIFFUSE_MAP) && meshBindings.propertyExists(VertexComponent.UV.toString()))
			{
				var diffuseMap	: SFloat	= meshBindings.getTextureParameter(
					BasicProperties.DIFFUSE_MAP,
					meshBindings.getProperty(BasicProperties.DIFFUSE_MAP_FILTERING, SamplerFiltering.LINEAR),
					meshBindings.getProperty(BasicProperties.DIFFUSE_MAP_MIPMAPPING, SamplerMipMapping.LINEAR),
					meshBindings.getProperty(BasicProperties.DIFFUSE_MAP_WRAPPING, SamplerWrapping.REPEAT),
					0,
                    meshBindings.getProperty(BasicProperties.DIFFUSE_MAP_FORMAT, SamplerFormat.RGBA)
				);

				diffuseColor = sampleTexture(diffuseMap, uv);
			}
			else if (meshBindings.propertyExists(BasicProperties.DIFFUSE_COLOR))
			{
				diffuseColor = meshBindings.getParameter(BasicProperties.DIFFUSE_COLOR, 4);
			}
			else
			{
				diffuseColor = float4(0., 0., 0., 1.);
			}

			if (meshBindings.propertyExists(BasicProperties.ALPHA_MAP))
			{
				var alphaMap 	: SFloat 	= meshBindings.getTextureParameter(
					BasicProperties.ALPHA_MAP,
					meshBindings.getProperty(BasicProperties.ALPHA_MAP_FILTERING, SamplerFiltering.LINEAR),
					meshBindings.getProperty(BasicProperties.ALPHA_MAP_MIPMAPPING, SamplerMipMapping.LINEAR),
					meshBindings.getProperty(BasicProperties.ALPHA_MAP_WRAPPING, SamplerWrapping.REPEAT),
					0,
					meshBindings.getProperty(BasicProperties.ALPHA_MAP_FORMAT, SamplerFormat.RGBA));
				var alphaSample	: SFloat	= sampleTexture(alphaMap, uv);

				diffuseColor = float4(diffuseColor.rgb, alphaSample.r);
			}

			if (meshBindings.propertyExists(BasicProperties.DIFFUSE_TRANSFORM))
			{
				diffuseColor = multiply4x4(
					diffuseColor,
					meshBindings.getParameter(BasicProperties.DIFFUSE_TRANSFORM, 16)
				);
			}

			if (killOnAlphaThreshold && meshBindings.propertyExists(BasicProperties.ALPHA_THRESHOLD))
			{
				var alphaThreshold : SFloat = meshBindings.getParameter(
					BasicProperties.ALPHA_THRESHOLD, 1
				);

				kill(subtract(0.5, lessThan(diffuseColor.w, alphaThreshold)));
			}

			return diffuseColor;
		}
	}
}

package aerys.minko.render.shader.part
{
	import aerys.minko.render.geometry.stream.format.VertexComponent;
	import aerys.minko.render.material.basic.BasicProperties;
	import aerys.minko.render.shader.SFloat;
	import aerys.minko.render.shader.Shader;
	import aerys.minko.type.enum.SamplerFiltering;
	import aerys.minko.type.enum.SamplerFormat;
	import aerys.minko.type.enum.SamplerMipMapping;
	import aerys.minko.type.enum.SamplerWrapping;

	public class DiffuseShaderPart extends ShaderPart
	{
		/**
		 * The shader part to use a diffuse map or fallback and use a solid color.
		 *
		 * @param main
		 *
		 */
		public function DiffuseShaderPart(main : Shader)
		{
			super(main);
		}

		public function getDiffuseColor(killOnAlphaThreshold : Boolean = true, uv : SFloat = null) : SFloat
		{
			var diffuseColor : SFloat	= null;
			var useVertexUv  : Boolean  = uv == null;

            uv ||= vertexUV.xy;

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

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

			if (useVertexUv)
				uv = interpolate(uv);

			if (meshBindings.propertyExists(BasicProperties.DIFFUSE_MAP) &&
				(meshBindings.propertyExists(VertexComponent.UV.toString()) || meshBindings.propertyExists(VertexComponent.XY.toString()))) // uv or sprite
			{
				var diffuseMap	: SFloat	= meshBindings.getTextureParameter(
					BasicProperties.DIFFUSE_MAP,
					meshBindings.getProperty(BasicProperties.DIFFUSE_MAP_FILTERING, SamplerFiltering.LINEAR),
					meshBindings.getProperty(BasicProperties.DIFFUSE_MAP_MIPMAPPING, SamplerMipMapping.LINEAR),
					meshBindings.getProperty(BasicProperties.DIFFUSE_MAP_WRAPPING, SamplerWrapping.REPEAT),
					0,
                    meshBindings.getProperty(BasicProperties.DIFFUSE_MAP_FORMAT, SamplerFormat.RGBA)
				);

				diffuseColor = sampleTexture(diffuseMap, uv);
			}
			else if (meshBindings.propertyExists(BasicProperties.DIFFUSE_COLOR))
			{
				diffuseColor = meshBindings.getParameter(BasicProperties.DIFFUSE_COLOR, 4);
			}
			else
			{
				diffuseColor = float4(0., 0., 0., 1.);
			}

			if (meshBindings.propertyExists(BasicProperties.ALPHA_MAP))
			{
				var alphaMap 	: SFloat 	= meshBindings.getTextureParameter(
					BasicProperties.ALPHA_MAP,
					meshBindings.getProperty(BasicProperties.ALPHA_MAP_FILTERING, SamplerFiltering.LINEAR),
					meshBindings.getProperty(BasicProperties.ALPHA_MAP_MIPMAPPING, SamplerMipMapping.LINEAR),
					meshBindings.getProperty(BasicProperties.ALPHA_MAP_WRAPPING, SamplerWrapping.REPEAT),
					0,
					meshBindings.getProperty(BasicProperties.ALPHA_MAP_FORMAT, SamplerFormat.RGBA));
				var alphaSample	: SFloat	= sampleTexture(alphaMap, uv);

				diffuseColor = float4(diffuseColor.rgb, alphaSample.r);
			}

			if (meshBindings.propertyExists(BasicProperties.DIFFUSE_TRANSFORM))
			{
				diffuseColor = multiply4x4(
					diffuseColor,
					meshBindings.getParameter(BasicProperties.DIFFUSE_TRANSFORM, 16)
				);
			}

			if (killOnAlphaThreshold && meshBindings.propertyExists(BasicProperties.ALPHA_THRESHOLD))
			{
				var alphaThreshold : SFloat = meshBindings.getParameter(
					BasicProperties.ALPHA_THRESHOLD, 1
				);

				kill(subtract(0.5, lessThan(diffuseColor.w, alphaThreshold)));
			}

			return diffuseColor;
		}
	}
}

Fix vertex component existence for sprites


/*
 *  Copyright: (c) 2015. Turtsevich Alexander
 *
 *  Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.html
 */

package com.kemsky.support
{
    import com.kemsky.Stream;

    import flash.utils.Dictionary;
    import flash.utils.getQualifiedClassName;

    /**
     * todo: register custom compare functions for custom types
     * @private
     */
    public class Compare
    {
        private static const classToFullName:Dictionary = new Dictionary(true);

        public static const NUMBER:String = "Number";
        public static const STRING:String = "String";
        public static const BOOLEAN:String = "Boolean";
        public static const DATE:String = "Date";
        public static const XML_TYPE:String = "XML";
        public static const XML_LIST:String = "XMLList";
        public static const CLASS:String = "Class";
        public static const ARRAY:String = "Array";
        public static const UNDEFINED:String = "void";

        /**
         * Allows to use generic compare functions(le, ge, lt and others) for the following types:
         * Number, Date, XML, String or Boolean
         * @param a first item
         * @param b second item
         * @param options combination of Stream.CASEINSENSITIVE | Stream.DESCENDING | Stream.NUMERIC
         * @param equals compare is used to check equality
         * @return -1 if a < b, 0 if a == b and 1 if a > b
         */
        public static function compare(a:Object, b:Object, options:uint = 0, equals:Boolean = false):int
        {
            var result:int = 0;
            if (a == null && b == null)
            {
                result = 0;
            }
            else if (a == null)
            {
                result = -1;
            }
            else if (b == null)
            {
                result = 1;
            }
            else
            {
                var numeric:Boolean = (options & Stream.NUMERIC) == Stream.NUMERIC;

                var caseInsensitive:Boolean = (options & Stream.CASEINSENSITIVE) == Stream.CASEINSENSITIVE;

                var typeOfA:String = getClassName(a);
                var typeOfB:String = getClassName(b);

                if (typeOfA == typeOfB)
                {
                    switch (typeOfA)
                    {
                        case BOOLEAN:
                            result = compareNumber(Number(a), Number(b));
                            break;
                        case NUMBER:
                            result = compareNumber(a as Number, b as Number);
                            break;
                        case STRING:
                            result = compareString(a as String, b as String, caseInsensitive);
                            break;
                        case DATE:
                            result = compareDate(a as Date, b as Date);
                            break;
                        case XML_TYPE:
                            result = compareXML(a as XML, b as XML, numeric, caseInsensitive);
                            break;
                        default:
                            if (equals)
                            {
                                result = a == b ? 0 : -1;
                            }
                            else
                            {
                                throw new StreamError("Sort is not supported: " + typeOfA);
                            }
                    }
                }
                else
                {
                    result = compareString(typeOfA, typeOfB, caseInsensitive);
                }
            }

            if ((options & Stream.DESCENDING) == Stream.DESCENDING)
            {
                result *= -1;
            }

            return result;
        }

        public static function getClassName(object:*):String
        {
            var cls:Class;
            if (object is XML)
            {
                return XML_TYPE;
            }
            else if (object is XMLList)
            {
                return XML_LIST;
            }
            else if (object is Class)
            {
                cls = object as Class;
            }
            else if (object === undefined)
            {
                return UNDEFINED;
            }
            else if (object != null)
            {
                cls = object.constructor;
            }

            var name:String = classToFullName[cls];
            if (name == null)
            {
                name = getQualifiedClassName(cls);
                classToFullName[cls] = name;
            }
            return name;
        }

        /**
         * @private
         */
        public static function compareXML(a:XML, b:XML, numeric:Boolean, caseInsensitive:Boolean):int
        {
            var result:int = 0;

            if (numeric)
            {
                result = compareNumber(parseFloat(a.toString()), parseFloat(b.toString()));
            }
            else
            {
                result = compareString(a.toString(), b.toString(), caseInsensitive);
            }

            return result;
        }

        /**
         * @private
         */
        public static function compareString(fa:String, fb:String, caseInsensitive:Boolean):int
        {
            // Convert to lowercase if we are case insensitive.
            if (caseInsensitive)
            {
                fa = fa.toLocaleLowerCase();
                fb = fb.toLocaleLowerCase();
            }

            var result:int = fa.localeCompare(fb);

            if (result < -1)
            {
                result = -1;
            }
            else if (result > 1)
            {
                result = 1;
            }

            return result;
        }

        /**
         * @private
         */
        public static function compareNumber(fa:Number, fb:Number):int
        {
            if ((fa != fa) && (fb != fb))
            {
                return 0;
            }

            if (fa != fa)
            {
                return -1;
            }

            if (fb != fb)
            {
                return 1;
            }

            if (fa < fb)
            {
                return -1;
            }

            if (fa > fb)
            {
                return 1;
            }

            return 0;
        }

        /**
         * @private
         */
        public static function compareDate(fa:Date, fb:Date):int
        {
            var na:Number = fa.getTime();
            var nb:Number = fb.getTime();

            if (na < nb)
            {
                return -1;
            }

            if (na > nb)
            {
                return 1;
            }

            return 0;
        }
    }
}

/*
 *  Copyright: (c) 2015. Turtsevich Alexander
 *
 *  Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.html
 */

package com.kemsky.support
{
    import com.kemsky.Stream;

    import flash.utils.Dictionary;
    import flash.utils.getQualifiedClassName;

    /**
     * todo: register custom compare functions for custom types
     * @private
     */
    public class Compare
    {
        private static const classToFullName:Dictionary = new Dictionary(true);

        public static const NUMBER:String = "Number";
        public static const STRING:String = "String";
        public static const BOOLEAN:String = "Boolean";
        public static const DATE:String = "Date";
        public static const XML_TYPE:String = "XML";
        public static const XML_LIST:String = "XMLList";
        public static const CLASS:String = "Class";
        public static const ARRAY:String = "Array";
        public static const UNDEFINED:String = "void";

        /**
         * Allows to use generic compare functions(le, ge, lt and others) for the following types:
         * Number, Date, XML, String or Boolean
         * @param a first item
         * @param b second item
         * @param options combination of Stream.CASEINSENSITIVE | Stream.DESCENDING | Stream.NUMERIC
         * @param equals compare is used to check equality
         * @return -1 if a < b, 0 if a == b and 1 if a > b
         */
        public static function compare(a:Object, b:Object, options:uint = 0, equals:Boolean = false):int
        {
            var result:int = 0;
            if (a == null && b == null)
            {
                result = 0;
            }
            else if (a == null)
            {
                result = -1;
            }
            else if (b == null)
            {
                result = 1;
            }
            else
            {
                var numeric:Boolean = (options & Stream.NUMERIC) == Stream.NUMERIC;

                var caseInsensitive:Boolean = (options & Stream.CASEINSENSITIVE) == Stream.CASEINSENSITIVE;

                var typeOfA:String = getClassName(a);
                var typeOfB:String = getClassName(b);

                if (typeOfA == typeOfB)
                {
                    switch (typeOfA)
                    {
                        case BOOLEAN:
                            result = compareNumber(Number(a), Number(b));
                            break;
                        case NUMBER:
                            result = compareNumber(a as Number, b as Number);
                            break;
                        case STRING:
                            result = compareString(a as String, b as String, caseInsensitive);
                            break;
                        case DATE:
                            result = compareDate(a as Date, b as Date);
                            break;
                        case XML_TYPE:
                            result = compareXML(a as XML, b as XML, numeric, caseInsensitive);
                            break;
                        default:
                            if (equals)
                            {
                                result = a == b ? 0 : -1;
                            }
                            else
                            {
                                throw new StreamError("Compare is not supported: " + typeOfA);
                            }
                    }
                }
                else
                {
                    result = compareString(typeOfA, typeOfB, caseInsensitive);
                }
            }

            if ((options & Stream.DESCENDING) == Stream.DESCENDING)
            {
                result *= -1;
            }

            return result;
        }

        public static function getClassName(object:*):String
        {
            var cls:Class;
            if (object is XML)
            {
                return XML_TYPE;
            }
            else if (object is XMLList)
            {
                return XML_LIST;
            }
            else if (object is Class)
            {
                cls = object as Class;
            }
            else if (object === undefined)
            {
                return UNDEFINED;
            }
            else if (object != null)
            {
                cls = object.constructor;
            }

            var name:String = classToFullName[cls];
            if (name == null)
            {
                name = getQualifiedClassName(cls);
                classToFullName[cls] = name;
            }
            return name;
        }

        /**
         * @private
         */
        public static function compareXML(a:XML, b:XML, numeric:Boolean, caseInsensitive:Boolean):int
        {
            var result:int = 0;

            if (numeric)
            {
                result = compareNumber(parseFloat(a.toString()), parseFloat(b.toString()));
            }
            else
            {
                result = compareString(a.toString(), b.toString(), caseInsensitive);
            }

            return result;
        }

        /**
         * @private
         */
        public static function compareString(fa:String, fb:String, caseInsensitive:Boolean):int
        {
            // Convert to lowercase if we are case insensitive.
            if (caseInsensitive)
            {
                fa = fa.toLocaleLowerCase();
                fb = fb.toLocaleLowerCase();
            }

            var result:int = fa.localeCompare(fb);

            if (result < -1)
            {
                result = -1;
            }
            else if (result > 1)
            {
                result = 1;
            }

            return result;
        }

        /**
         * @private
         */
        public static function compareNumber(fa:Number, fb:Number):int
        {
            if ((fa != fa) && (fb != fb))
            {
                return 0;
            }

            if (fa != fa)
            {
                return -1;
            }

            if (fb != fb)
            {
                return 1;
            }

            if (fa < fb)
            {
                return -1;
            }

            if (fa > fb)
            {
                return 1;
            }

            return 0;
        }

        /**
         * @private
         */
        public static function compareDate(fa:Date, fb:Date):int
        {
            var na:Number = fa.getTime();
            var nb:Number = fb.getTime();

            if (na < nb)
            {
                return -1;
            }

            if (na > nb)
            {
                return 1;
            }

            return 0;
        }
    }
}

clean up

clean up


package com.axis.mjpgplayer
{
  import com.axis.mjpgplayer.MJPGImage;
  import flash.display.Bitmap;
  import flash.display.LoaderInfo;
  import flash.display.Sprite;
  import flash.events.Event;
  import flash.events.IOErrorEvent;
  import flash.utils.ByteArray;
  import flash.external.ExternalInterface;

  public class MJPG extends Sprite
  {
    private var ipCam:IPCam;
    private var maxImages:uint = 2;
    private var firstImage:Boolean = true;
    private var imgBuf:Vector.<Object> = new Vector.<Object>();
    private var idleQue:Vector.<MJPGImage> = new Vector.<MJPGImage>();
    private var _playing:Boolean = false;

    // Statistics Variables
    private var sTime:Number = 0;
    private var decTime:uint = 0;
    private var _fRecCount:uint = 0;
    private var _fDecCount:uint = 0;
    private var _fps:Number = 0.0;

    public function MJPG(ipCam:IPCam)
    {
      this.ipCam = ipCam;
      addEventListener(Event.ADDED_TO_STAGE, onStageAdded);
    }

    private function onStageAdded(e:Event):void
    {
      ExternalInterface.addCallback("getFps", getFps);

      for (var i:uint = 0; i < maxImages; i++)
      {
        var loader:MJPGImage = new MJPGImage();
        loader.cacheAsBitmap = false;
        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete);
        loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onImageError);
        this.addChild(loader);
      }
      stage.addEventListener(Event.RESIZE, resizeListener);
    }

    private function resizeListener(e:Event):void {
      for each (var loader:MJPGImage in getChildren())
      {
        scaleAndPosition(loader);
      }
    }

    public function getChildren():Array
    {
       var children:Array = [];
       for (var i:uint = 0; i < this.numChildren; i++)
       {
        children.push(this.getChildAt(i));
       }
       return children;
    }

    [Bindable(event='framesDecChanged')]
    public function get framesDecoded():uint
    {
      return _fDecCount;
    }

    private function updateDecFrames(v:uint):void
    {
      _fDecCount = v;
      dispatchEvent(new Event("framesDecChanged"));
    }

    [Bindable(event='playingChanged')]
    public function get playing():Boolean
    {
      return _playing;
    }

    private function updatePlaying(v:Boolean):void
    {
      _playing = v;
      dispatchEvent(new Event("playingChanged"));
    }

    [Bindable(event='fpsChanged')]
    public function get fps():Number
    {
      return _fps;
    }

    public function getFps():Number
    {
      return _fps;
    }

    private function updateFps(v:Number):void
    {
      _fps = v;
      dispatchEvent(new Event("fpsChanged"));
    }

    private function loadImage(loader:MJPGImage, obj:Object):void
    {
      loader.data.loading = true;
      loader.data.inQue = false;
      loader.data.loadTime = new Date().getTime();
      loader.data.frame = obj.frame;
      loader.loadBytes(obj.data as ByteArray);
      obj = null;
    }

    public function load(image:ByteArray):void
    {
      if (imgBuf.length >= maxImages + 3)
      {
        var obj:Object = imgBuf.shift();
        obj = null;
      }
      _fRecCount++;
      imgBuf.push({frame: _fRecCount, data: image});

      if (!playing)
      {
        sTime = new Date().getTime();
        decTime = 0;
        _fRecCount = 1;
        updateDecFrames(0);
        updatePlaying(true);

        for each (var loader:MJPGImage in getChildren())
        {
          loader.data.inQue = true;
          idleQue.push(loader);
        }
      }

      if (idleQue.length > 0)
      {
        loadImage(idleQue.shift(), imgBuf.shift());
      }
    }

    private function scaleAndPosition(loader:MJPGImage):void
    {
      // Scale to fit stage
      var loaderAspectRatio:Number = loader.width / loader.height;
      var stageAspectRatio:Number = stage.stageWidth / stage.stageHeight;
      var scale:Number;
      if (loaderAspectRatio > stageAspectRatio)
      {
        scale = stage.stageWidth / loader.width;
      }
      else
      {
        scale = stage.stageHeight / loader.height;
      }
      loader.width *= scale;
      loader.height *= scale;

      // Center on stage
      loader.x = (stage.stageWidth - loader.width) / 2;
      loader.y = (stage.stageHeight - loader.height) / 2;
    }

    private function onLoadComplete(event:Event):void
    {
      if (!playing)
      {
        return;
      }

      var arr:Array = getChildren();
      var loader:MJPGImage = event.currentTarget.loader as MJPGImage;
      var bitmap:Bitmap = event.currentTarget.content;
      if (bitmap != null)
      {
        bitmap.smoothing = true;
      }
      loader.data.loading = false;

      scaleAndPosition(loader);

      var curTime:Number = new Date().getTime();
      decTime += curTime - loader.data.loadTime;
      if (arr[arr.length - 1].data.loadTime <= loader.data.loadTime)
      {
        if (maxImages > 2)
        {
          removeChild(loader);
          addChild(loader);
        }
        else if (maxImages == 2)
        {
          this.swapChildren(arr[0], arr[1]);
        }
        updateDecFrames(framesDecoded + 1);
        updateFps((framesDecoded * 1000) / (curTime - sTime));
      }

      arr = getChildren();
      for (var i:uint = 0; i < arr.length - 1; i++)
      {
        loader = arr[i] as MJPGImage;
        if (loader.data.inQue == true || loader.data.loading)
        {
          continue;
        }

        if (imgBuf.length == 0)
        {
          loader.data.inQue = true;
          idleQue.push(loader);
        }
        else
        {
          loadImage(loader, imgBuf.shift());
        }
      }

      if (firstImage) {
        ExternalInterface.call(ipCam.getJsEventCallbackName(), "started");
        firstImage = false;
      }
    }

    private function onImageError(event:IOErrorEvent):void
    {
      var loader:MJPGImage = event.currentTarget.loader as MJPGImage;
      loader.data.loading = false;
      if (imgBuf.length == 0)
      {
        loader.data.inQue = true;
        idleQue.push(loader);
      }
      else
        loadImage(loader, imgBuf.shift());
    }

    public function reset(clear:Boolean = false):void
    {
      firstImage = true;
      updatePlaying(false);
      idleQue.length = 0;

      while (imgBuf.length != 0)
      {
        _fRecCount--;
        var obj:Object = imgBuf.shift();
        obj = null;
      }

      var arr:Array = getChildren();
      for each (var loader:MJPGImage in arr)
      {
        if (loader.data.loading)
        {
          updateDecFrames(framesDecoded + 1);
        }
        loader.data.loading = false;
        loader.data.inQue = false;
        loader.data.loadTime = 0.0;

        if (clear)
        {
          loader.unload();
        }
      }

      updateFps((framesDecoded * 1000) / (new Date().getTime() - sTime));

      var recvFps:Number = (_fRecCount * 1000) / (new Date().getTime() - sTime);
    }
  }

}

package com.axis.mjpgplayer
{
  import com.axis.mjpgplayer.MJPGImage;
  import flash.display.Bitmap;
  import flash.display.LoaderInfo;
  import flash.display.Sprite;
  import flash.events.Event;
  import flash.events.IOErrorEvent;
  import flash.utils.ByteArray;
  import flash.external.ExternalInterface;

  public class MJPG extends Sprite
  {
    private var ipCam:IPCam;
    private var maxImages:uint = 2;
    private var firstImage:Boolean = true;
    private var imgBuf:Vector.<Object> = new Vector.<Object>();
    private var idleQue:Vector.<MJPGImage> = new Vector.<MJPGImage>();
    private var _playing:Boolean = false;

    // Statistics Variables
    private var sTime:Number = 0;
    private var decTime:uint = 0;
    private var _fRecCount:uint = 0;
    private var _fDecCount:uint = 0;
    private var _fps:Number = 0.0;

    public function MJPG(ipCam:IPCam)
    {
      this.ipCam = ipCam;
      addEventListener(Event.ADDED_TO_STAGE, onStageAdded);
    }

    private function onStageAdded(e:Event):void
    {
      ExternalInterface.addCallback("getFps", getFps);
      createLoaders();
      stage.addEventListener(Event.RESIZE, resizeListener);
    }

    private function createLoaders():void {
      for (var i:uint = 0; i < maxImages; i++)
      {
        var loader:MJPGImage = new MJPGImage();
        loader.cacheAsBitmap = false;
        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete);
        loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onImageError);
        this.addChild(loader);
      }
    }

    private function destroyLoaders():void {
      for each (var loader:MJPGImage in getChildren())
      {
        loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onLoadComplete);
        loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, onImageError);
      }
      removeChildren();
    }

    private function resizeListener(e:Event):void {
      for each (var loader:MJPGImage in getChildren())
      {
        scaleAndPosition(loader);
      }
    }

    public function getChildren():Array
    {
       var children:Array = [];
       for (var i:uint = 0; i < this.numChildren; i++)
       {
        children.push(this.getChildAt(i));
       }
       return children;
    }

    [Bindable(event='framesDecChanged')]
    public function get framesDecoded():uint
    {
      return _fDecCount;
    }

    private function updateDecFrames(v:uint):void
    {
      _fDecCount = v;
      dispatchEvent(new Event("framesDecChanged"));
    }

    [Bindable(event='playingChanged')]
    public function get playing():Boolean
    {
      return _playing;
    }

    private function updatePlaying(v:Boolean):void
    {
      _playing = v;
      dispatchEvent(new Event("playingChanged"));
    }

    [Bindable(event='fpsChanged')]
    public function get fps():Number
    {
      return _fps;
    }

    public function getFps():Number
    {
      return _fps;
    }

    private function updateFps(v:Number):void
    {
      _fps = v;
      dispatchEvent(new Event("fpsChanged"));
    }

    private function loadImage(loader:MJPGImage, obj:Object):void
    {
      loader.data.loading = true;
      loader.data.inQue = false;
      loader.data.loadTime = new Date().getTime();
      loader.data.frame = obj.frame;
      loader.loadBytes(obj.data as ByteArray);
      obj = null;
    }

    public function load(image:ByteArray):void
    {
      if (imgBuf.length >= maxImages + 3)
      {
        var obj:Object = imgBuf.shift();
        obj = null;
      }
      _fRecCount++;
      imgBuf.push({frame: _fRecCount, data: image});

      if (!playing)
      {
        sTime = new Date().getTime();
        decTime = 0;
        _fRecCount = 1;
        updateDecFrames(0);
        updatePlaying(true);

        for each (var loader:MJPGImage in getChildren())
        {
          loader.data.inQue = true;
          idleQue.push(loader);
        }
      }

      if (idleQue.length > 0)
      {
        loadImage(idleQue.shift(), imgBuf.shift());
      }
    }

    private function scaleAndPosition(loader:MJPGImage):void
    {
      // Scale to fit stage
      var loaderAspectRatio:Number = loader.width / loader.height;
      var stageAspectRatio:Number = stage.stageWidth / stage.stageHeight;
      var scale:Number;
      if (loaderAspectRatio > stageAspectRatio)
      {
        scale = stage.stageWidth / loader.width;
      }
      else
      {
        scale = stage.stageHeight / loader.height;
      }
      loader.width *= scale;
      loader.height *= scale;

      // Center on stage
      loader.x = (stage.stageWidth - loader.width) / 2;
      loader.y = (stage.stageHeight - loader.height) / 2;
    }

    private function onLoadComplete(event:Event):void
    {
      if (!playing)
      {
        return;
      }

      var arr:Array = getChildren();
      var loader:MJPGImage = event.currentTarget.loader as MJPGImage;
      var bitmap:Bitmap = event.currentTarget.content;
      if (bitmap != null)
      {
        bitmap.smoothing = true;
      }
      loader.data.loading = false;

      scaleAndPosition(loader);

      var curTime:Number = new Date().getTime();
      decTime += curTime - loader.data.loadTime;
      if (arr[arr.length - 1].data.loadTime <= loader.data.loadTime)
      {
        if (maxImages > 2)
        {
          removeChild(loader);
          addChild(loader);
        }
        else if (maxImages == 2)
        {
          this.swapChildren(arr[0], arr[1]);
        }
        updateDecFrames(framesDecoded + 1);
        updateFps((framesDecoded * 1000) / (curTime - sTime));
      }

      arr = getChildren();
      for (var i:uint = 0; i < arr.length - 1; i++)
      {
        loader = arr[i] as MJPGImage;
        if (loader.data.inQue == true || loader.data.loading)
        {
          continue;
        }

        if (imgBuf.length == 0)
        {
          loader.data.inQue = true;
          idleQue.push(loader);
        }
        else
        {
          loadImage(loader, imgBuf.shift());
        }
      }

      if (firstImage) {
        ExternalInterface.call(ipCam.getJsEventCallbackName(), "started");
        firstImage = false;
      }
    }

    private function onImageError(event:IOErrorEvent):void
    {
      var loader:MJPGImage = event.currentTarget.loader as MJPGImage;
      loader.data.loading = false;
      if (imgBuf.length == 0)
      {
        loader.data.inQue = true;
        idleQue.push(loader);
      }
      else
        loadImage(loader, imgBuf.shift());
    }

    public function reset(clear:Boolean = false):void
    {
      firstImage = true;
      updatePlaying(false);
      idleQue.length = 0;

      while (imgBuf.length != 0)
      {
        _fRecCount--;
        var obj:Object = imgBuf.shift();
        obj = null;
      }

      var arr:Array = getChildren();
      for each (var loader:MJPGImage in arr)
      {
        if (loader.data.loading)
        {
          updateDecFrames(framesDecoded + 1);
        }
        loader.data.loading = false;
        loader.data.inQue = false;
        loader.data.loadTime = 0.0;
      }

      if (clear)
      {
        destroyLoaders();
        createLoaders();
      }

      updateFps((framesDecoded * 1000) / (new Date().getTime() - sTime));

      var recvFps:Number = (_fRecCount * 1000) / (new Date().getTime() - sTime);
    }
  }

}

Make sure JPEG image is removed when player is stopped


//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.desktop.NativeApplication;
import flash.display.NativeWindow;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filesystem.File;
import flash.net.SharedObject;

import com.adobe.crypto.MD5;

import deng.fzip.FZip;
import deng.fzip.FZipFile;

import flump.bytesToXML;
import flump.display.Movie;
import flump.executor.Executor;
import flump.executor.Future;
import flump.export.Ternary;
import flump.xfl.ParseError;
import flump.xfl.XflLibrary;
import flump.xfl.XflMovie;

import mx.collections.ArrayCollection;

import spark.components.DataGrid;
import spark.components.DropDownList;
import spark.components.List;
import spark.components.Window;
import spark.events.GridSelectionEvent;

import starling.display.Sprite;

import com.threerings.util.F;
import com.threerings.util.Log;
import com.threerings.util.StringUtil;

public class Exporter
{
    public static const NA :NativeApplication = NativeApplication.nativeApplication;

    protected static const IMPORT_ROOT :String = "IMPORT_ROOT";
    protected static const AUTHORED_RESOLUTION :String = "AUTHORED_RESOLUTION";

    public function Exporter (win :ExporterWindow) {
        _win = win;
        _errors = _win.errors;
        _libraries = _win.libraries;

        _authoredResolution = _win.authoredResolutionPopup;
        _authoredResolution.dataProvider = new ArrayCollection(DeviceType.values().map(
            function (type :DeviceType, ..._) :Object {
                return new DeviceSelection(type);
            }));
        var initialSelection :DeviceType = null;
        if (_settings.data.hasOwnProperty(AUTHORED_RESOLUTION)) {
            try {
                initialSelection = DeviceType.valueOf(_settings.data[AUTHORED_RESOLUTION]);
            } catch (e :Error) {}
        }
        if (initialSelection == null) {
            initialSelection = DeviceType.IPHONE_RETINA;
        }
        _authoredResolution.selectedIndex = DeviceType.values().indexOf(initialSelection);
        _authoredResolution.addEventListener(Event.CHANGE, function (..._) :void {
            var selectedType :DeviceType = DeviceSelection(_authoredResolution.selectedItem).type;
            _settings.data[AUTHORED_RESOLUTION] = selectedType.name();
        });

        function updateExportEnabled (..._) :void {
            _win.export.enabled = _exportChooser.dir != null && _libraries.selectionLength > 0 &&
              _libraries.selectedItems.some(function (status :DocStatus, ..._) :Boolean {
                return status.isValid;
            });
        }
        _libraries.addEventListener(GridSelectionEvent.SELECTION_CHANGE, function (..._) :void {
            log.info("Changed", "selected", _libraries.selectedIndices);
            updateExportEnabled();
            _win.preview.enabled = _libraries.selectedItem.isValid;
        });
        _win.export.addEventListener(MouseEvent.CLICK, function (..._) :void {
            for each (var status :DocStatus in _libraries.selectedItems) {
                exportFlashDocument(status);
            }
        });
        _win.preview.addEventListener(MouseEvent.CLICK, function (..._) :void {
            showPreviewWindow(_libraries.selectedItem.lib);
        });
        _importChooser =
            new DirChooser(_settings, "IMPORT_ROOT", _win.importRoot, _win.browseImport);
        _importChooser.changed.add(setImport);
        setImport(_importChooser.dir);
        _exportChooser =
            new DirChooser(_settings, "EXPORT_ROOT", _win.exportRoot, _win.browseExport);
        _exportChooser.changed.add(updateExportEnabled);
        _win.addEventListener(Event.CLOSE, function (..._) :void { NA.exit(0); });

    }

    protected function setImport (root :File) :void {
        _libraries.dataProvider.removeAll();
        _errors.dataProvider.removeAll();
        if (root == null) return;
        _rootLen = root.nativePath.length + 1;
        if (_docFinder != null) _docFinder.shutdownNow();
        _docFinder = new Executor(2);
        findFlashDocuments(root, _docFinder);
    }

    protected function showPreviewWindow (lib :XflLibrary) :void {
        if (_previewController == null || _previewWindow.closed || _previewControls.closed) {
            _previewWindow = new PreviewWindow();
            _previewControls = new PreviewControlsWindow();
            _previewWindow.started = function (container :Sprite) :void {
                _previewController = new PreviewController(lib, container, _previewControls);
            }

            _previewWindow.open();
            _previewControls.open();

            preventWindowClose(_previewWindow.nativeWindow);
            preventWindowClose(_previewControls.nativeWindow);

        } else {
            _previewController.lib = lib;
            _previewWindow.nativeWindow.visible = true;
            _previewControls.nativeWindow.visible = true;
        }
    }

    // Causes a window to be hidden, rather than closed, when its close box is clicked
    protected static function preventWindowClose (window :NativeWindow) :void {
        window.addEventListener(Event.CLOSING, function (e :Event) :void {
            e.preventDefault();
            window.visible = false;
        });
    }

    protected var _previewController :PreviewController;
    protected var _previewWindow :PreviewWindow;
    protected var _previewControls :PreviewControlsWindow;

    protected function findFlashDocuments (base :File, exec :Executor) :void {
        Files.list(base, exec).succeeded.add(function (files :Array) :void {
            if (exec.isShutdown) return;
            for each (var file :File in files) {
                if (Files.hasExtension(file, "xfl")) {
                    addFlashDocument(file.parent);
                    return;
                }
            }
            for each (file in files) {
                if (file.isDirectory) findFlashDocuments(file, exec);
                else if (Files.hasExtension(file, "fla")) addFlashDocument(file);
            }
        });
    }

    protected function addFlashDocument (file :File) :void {
        const status :DocStatus = new DocStatus(file, _rootLen, Ternary.UNKNOWN, Ternary.UNKNOWN, null);
        _libraries.dataProvider.addItem(status);
        loadFlashDocument(status);
    }

    protected function exportFlashDocument (status :DocStatus) :void {
        BetwixtPublisher.publish(status.lib, status.file,
            DeviceSelection(_authoredResolution.selectedItem).type, _exportChooser.dir);
        status.updateModified(Ternary.FALSE);
    }

    protected function loadFlashDocument (status :DocStatus) :void {
        if (Files.hasExtension(status.file, "xfl")) status.file = status.file.parent;
        if (status.file.isDirectory) {
            const name :String = status.file.nativePath
                .substring(_rootLen).replace(File.separator, "/");
            const load :Future = new XflLoader().load(name, status.file);
            load.succeeded.add(function (lib :XflLibrary) :void {
                // Don't blow up if the export directory hasn't been chosen
                var isMod :Boolean = true;
                if (_exportChooser.dir != null) {
                    var metadata :File = _exportChooser.dir.resolvePath(
                        lib.location + "/resources.xml");
                    isMod = BetwixtPublisher.modified(lib, metadata);
                }
                status.lib = lib;
                status.updateModified(Ternary.of(isMod));
                for each (var err :ParseError in lib.getErrors()) {
                    _errors.dataProvider.addItem(err);
                    trace(err);
                }
                status.updateValid(Ternary.of(lib.valid));
            });
        } else loadFla(status.file);
    }

    protected function loadFla (file :File) :void {
        log.info("Loading fla", "path", file.nativePath);
        Files.load(file).succeeded.add(function (file :File) :void {
            const zip :FZip = new FZip();
            zip.loadBytes(file.data);
            const files :Array = [];
            for (var ii :int = 0; ii < zip.getFileCount(); ii++) files.push(zip.getFileAt(ii));
            const xmls :Array = F.filter(files, function (fz :FZipFile) :Boolean {
                return StringUtil.endsWith(fz.filename, ".xml");
            });
            const movies :Array = F.filter(xmls, function (fz :FZipFile) :Boolean {
                return StringUtil.startsWith(fz.filename, "LIBRARY/Animations/");
            });
            const textures :Array = F.filter(xmls, function (fz :FZipFile) :Boolean {
                return StringUtil.startsWith(fz.filename, "LIBRARY/Textures/");
            });
            function toFn (fz :FZipFile) :String { return fz.filename };
            log.info("Loaded", "bytes", file.data.length, "movies", F.map(movies, toFn),
                "textures", F.map(textures, toFn));
            for each (var fz :FZipFile in movies) {
                new XflMovie(fz.filename, bytesToXML(fz.content), MD5.hashBytes(fz.content));
            }
            NA.exit(0);
        });
    }

    protected var _rootLen :int;

    protected var _docFinder :Executor;
    protected var _win :ExporterWindow;
    protected var _libraries :DataGrid;
    protected var _errors :DataGrid;
    protected var _exportChooser :DirChooser;
    protected var _importChooser :DirChooser;
    protected var _authoredResolution :DropDownList;
    protected const _settings :SharedObject = SharedObject.getLocal("flump/Exporter");

    private static const log :Log = Log.getLog(Exporter);
}
}
import flash.events.EventDispatcher;
import flash.filesystem.File;

import flump.export.DeviceType;
import flump.export.Ternary;
import flump.xfl.XflLibrary;

import mx.core.IPropertyChangeNotifier;
import mx.events.PropertyChangeEvent;

class DeviceSelection {
    public var type :DeviceType;
    public function DeviceSelection (type :DeviceType) {
        this.type = type;
    }
    public function toString () :String {
        return type.displayName + " (" + type.resWidth + "x" + type.resHeight + ")";
    }
}

class DocStatus extends EventDispatcher implements IPropertyChangeNotifier {
    public var path :String;
    public var modified :String;
    public var valid :String = QUESTION;
    public var file :File;
    public var lib :XflLibrary;

    public function DocStatus (file :File, rootLen :int, modified :Ternary, valid :Ternary, lib :XflLibrary) {
        this.file = file;
        this.lib = lib;
        path = file.nativePath.substring(rootLen);
        _uid = path;

        updateModified(modified);
        updateValid(valid);
    }

    public function updateValid (newValid :Ternary) :void {
        changeField("valid", function (..._) :void {
            if (newValid == Ternary.TRUE) valid = CHECK;
            else if (newValid == Ternary.FALSE) valid = FROWN;
            else valid = QUESTION;
        });
    }

    public function get isValid () :Boolean { return valid == CHECK; }

    public function updateModified (newModified :Ternary) :void {
        changeField("modified", function (..._) :void {
            if (newModified == Ternary.TRUE) modified = CHECK;
            else if (newModified == Ternary.FALSE) modified = " ";
            else modified = QUESTION;
        });
    }

    protected function changeField(fieldName :String, modifier :Function) :void {
        const oldValue :Object = this[fieldName];
        modifier();
        const newValue :Object = this[fieldName];
        dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, fieldName, oldValue, newValue));
    }

    public function get uid () :String { return _uid; }
    public function set uid (uid :String) :void { _uid = uid; }

    protected var _uid :String;

    protected static const QUESTION :String = "?";
    protected static const FROWN :String = "☹";
    protected static const CHECK :String = "✓";
}

//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.desktop.NativeApplication;
import flash.display.NativeWindow;
import flash.display.Stage;
import flash.display.StageQuality;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filesystem.File;
import flash.net.SharedObject;

import com.adobe.crypto.MD5;

import deng.fzip.FZip;
import deng.fzip.FZipFile;

import flump.bytesToXML;
import flump.display.Movie;
import flump.executor.Executor;
import flump.executor.Future;
import flump.export.Ternary;
import flump.xfl.ParseError;
import flump.xfl.XflLibrary;
import flump.xfl.XflMovie;

import mx.collections.ArrayCollection;

import spark.components.DataGrid;
import spark.components.DropDownList;
import spark.components.List;
import spark.components.Window;
import spark.events.GridSelectionEvent;

import starling.display.Sprite;

import com.threerings.util.F;
import com.threerings.util.Log;
import com.threerings.util.StringUtil;

public class Exporter
{
    public static const NA :NativeApplication = NativeApplication.nativeApplication;

    protected static const IMPORT_ROOT :String = "IMPORT_ROOT";
    protected static const AUTHORED_RESOLUTION :String = "AUTHORED_RESOLUTION";

    public function Exporter (win :ExporterWindow) {
        _win = win;
        _errors = _win.errors;
        _libraries = _win.libraries;

        _authoredResolution = _win.authoredResolutionPopup;
        _authoredResolution.dataProvider = new ArrayCollection(DeviceType.values().map(
            function (type :DeviceType, ..._) :Object {
                return new DeviceSelection(type);
            }));
        var initialSelection :DeviceType = null;
        if (_settings.data.hasOwnProperty(AUTHORED_RESOLUTION)) {
            try {
                initialSelection = DeviceType.valueOf(_settings.data[AUTHORED_RESOLUTION]);
            } catch (e :Error) {}
        }
        if (initialSelection == null) {
            initialSelection = DeviceType.IPHONE_RETINA;
        }
        _authoredResolution.selectedIndex = DeviceType.values().indexOf(initialSelection);
        _authoredResolution.addEventListener(Event.CHANGE, function (..._) :void {
            var selectedType :DeviceType = DeviceSelection(_authoredResolution.selectedItem).type;
            _settings.data[AUTHORED_RESOLUTION] = selectedType.name();
        });

        function updateExportEnabled (..._) :void {
            _win.export.enabled = _exportChooser.dir != null && _libraries.selectionLength > 0 &&
              _libraries.selectedItems.some(function (status :DocStatus, ..._) :Boolean {
                return status.isValid;
            });
        }
        _libraries.addEventListener(GridSelectionEvent.SELECTION_CHANGE, function (..._) :void {
            log.info("Changed", "selected", _libraries.selectedIndices);
            updateExportEnabled();
            _win.preview.enabled = _libraries.selectedItem.isValid;
        });
        _win.export.addEventListener(MouseEvent.CLICK, function (..._) :void {
            for each (var status :DocStatus in _libraries.selectedItems) {
                exportFlashDocument(status);
            }
        });
        _win.preview.addEventListener(MouseEvent.CLICK, function (..._) :void {
            showPreviewWindow(_libraries.selectedItem.lib);
        });
        _importChooser =
            new DirChooser(_settings, "IMPORT_ROOT", _win.importRoot, _win.browseImport);
        _importChooser.changed.add(setImport);
        setImport(_importChooser.dir);
        _exportChooser =
            new DirChooser(_settings, "EXPORT_ROOT", _win.exportRoot, _win.browseExport);
        _exportChooser.changed.add(updateExportEnabled);
        _win.addEventListener(Event.CLOSE, function (..._) :void { NA.exit(0); });

    }

    protected function setImport (root :File) :void {
        _libraries.dataProvider.removeAll();
        _errors.dataProvider.removeAll();
        if (root == null) return;
        _rootLen = root.nativePath.length + 1;
        if (_docFinder != null) _docFinder.shutdownNow();
        _docFinder = new Executor(2);
        findFlashDocuments(root, _docFinder);
    }

    protected function showPreviewWindow (lib :XflLibrary) :void {
        if (_previewController == null || _previewWindow.closed || _previewControls.closed) {
            _previewWindow = new PreviewWindow();
            _previewControls = new PreviewControlsWindow();
            _previewWindow.started = function (container :Sprite) :void {
                _previewController = new PreviewController(lib, container, _previewControls);
            }

            _previewWindow.open();
            _previewControls.open();

            preventWindowClose(_previewWindow.nativeWindow);
            preventWindowClose(_previewControls.nativeWindow);

        } else {
            _previewController.lib = lib;
            _previewWindow.nativeWindow.visible = true;
            _previewControls.nativeWindow.visible = true;
        }
    }

    // Causes a window to be hidden, rather than closed, when its close box is clicked
    protected static function preventWindowClose (window :NativeWindow) :void {
        window.addEventListener(Event.CLOSING, function (e :Event) :void {
            e.preventDefault();
            window.visible = false;
        });
    }

    protected var _previewController :PreviewController;
    protected var _previewWindow :PreviewWindow;
    protected var _previewControls :PreviewControlsWindow;

    protected function findFlashDocuments (base :File, exec :Executor) :void {
        Files.list(base, exec).succeeded.add(function (files :Array) :void {
            if (exec.isShutdown) return;
            for each (var file :File in files) {
                if (Files.hasExtension(file, "xfl")) {
                    addFlashDocument(file.parent);
                    return;
                }
            }
            for each (file in files) {
                if (file.isDirectory) findFlashDocuments(file, exec);
                else if (Files.hasExtension(file, "fla")) addFlashDocument(file);
            }
        });
    }

    protected function addFlashDocument (file :File) :void {
        const status :DocStatus = new DocStatus(file, _rootLen, Ternary.UNKNOWN, Ternary.UNKNOWN, null);
        _libraries.dataProvider.addItem(status);
        loadFlashDocument(status);
    }

    protected function exportFlashDocument (status :DocStatus) :void {

        var stage :Stage = NA.activeWindow.stage;
        var prevQuality :String = stage.quality;

        stage.quality = StageQuality.BEST;
        BetwixtPublisher.publish(status.lib, status.file,
            DeviceSelection(_authoredResolution.selectedItem).type, _exportChooser.dir);

        stage.quality = prevQuality;
        status.updateModified(Ternary.FALSE);
    }

    protected function loadFlashDocument (status :DocStatus) :void {
        if (Files.hasExtension(status.file, "xfl")) status.file = status.file.parent;
        if (status.file.isDirectory) {
            const name :String = status.file.nativePath
                .substring(_rootLen).replace(File.separator, "/");
            const load :Future = new XflLoader().load(name, status.file);
            load.succeeded.add(function (lib :XflLibrary) :void {
                // Don't blow up if the export directory hasn't been chosen
                var isMod :Boolean = true;
                if (_exportChooser.dir != null) {
                    var metadata :File = _exportChooser.dir.resolvePath(
                        lib.location + "/resources.xml");
                    isMod = BetwixtPublisher.modified(lib, metadata);
                }
                status.lib = lib;
                status.updateModified(Ternary.of(isMod));
                for each (var err :ParseError in lib.getErrors()) {
                    _errors.dataProvider.addItem(err);
                    trace(err);
                }
                status.updateValid(Ternary.of(lib.valid));
            });
        } else loadFla(status.file);
    }

    protected function loadFla (file :File) :void {
        log.info("Loading fla", "path", file.nativePath);
        Files.load(file).succeeded.add(function (file :File) :void {
            const zip :FZip = new FZip();
            zip.loadBytes(file.data);
            const files :Array = [];
            for (var ii :int = 0; ii < zip.getFileCount(); ii++) files.push(zip.getFileAt(ii));
            const xmls :Array = F.filter(files, function (fz :FZipFile) :Boolean {
                return StringUtil.endsWith(fz.filename, ".xml");
            });
            const movies :Array = F.filter(xmls, function (fz :FZipFile) :Boolean {
                return StringUtil.startsWith(fz.filename, "LIBRARY/Animations/");
            });
            const textures :Array = F.filter(xmls, function (fz :FZipFile) :Boolean {
                return StringUtil.startsWith(fz.filename, "LIBRARY/Textures/");
            });
            function toFn (fz :FZipFile) :String { return fz.filename };
            log.info("Loaded", "bytes", file.data.length, "movies", F.map(movies, toFn),
                "textures", F.map(textures, toFn));
            for each (var fz :FZipFile in movies) {
                new XflMovie(fz.filename, bytesToXML(fz.content), MD5.hashBytes(fz.content));
            }
            NA.exit(0);
        });
    }

    protected var _rootLen :int;

    protected var _docFinder :Executor;
    protected var _win :ExporterWindow;
    protected var _libraries :DataGrid;
    protected var _errors :DataGrid;
    protected var _exportChooser :DirChooser;
    protected var _importChooser :DirChooser;
    protected var _authoredResolution :DropDownList;
    protected const _settings :SharedObject = SharedObject.getLocal("flump/Exporter");

    private static const log :Log = Log.getLog(Exporter);
}
}
import flash.events.EventDispatcher;
import flash.filesystem.File;

import flump.export.DeviceType;
import flump.export.Ternary;
import flump.xfl.XflLibrary;

import mx.core.IPropertyChangeNotifier;
import mx.events.PropertyChangeEvent;

class DeviceSelection {
    public var type :DeviceType;
    public function DeviceSelection (type :DeviceType) {
        this.type = type;
    }
    public function toString () :String {
        return type.displayName + " (" + type.resWidth + "x" + type.resHeight + ")";
    }
}

class DocStatus extends EventDispatcher implements IPropertyChangeNotifier {
    public var path :String;
    public var modified :String;
    public var valid :String = QUESTION;
    public var file :File;
    public var lib :XflLibrary;

    public function DocStatus (file :File, rootLen :int, modified :Ternary, valid :Ternary, lib :XflLibrary) {
        this.file = file;
        this.lib = lib;
        path = file.nativePath.substring(rootLen);
        _uid = path;

        updateModified(modified);
        updateValid(valid);
    }

    public function updateValid (newValid :Ternary) :void {
        changeField("valid", function (..._) :void {
            if (newValid == Ternary.TRUE) valid = CHECK;
            else if (newValid == Ternary.FALSE) valid = FROWN;
            else valid = QUESTION;
        });
    }

    public function get isValid () :Boolean { return valid == CHECK; }

    public function updateModified (newModified :Ternary) :void {
        changeField("modified", function (..._) :void {
            if (newModified == Ternary.TRUE) modified = CHECK;
            else if (newModified == Ternary.FALSE) modified = " ";
            else modified = QUESTION;
        });
    }

    protected function changeField(fieldName :String, modifier :Function) :void {
        const oldValue :Object = this[fieldName];
        modifier();
        const newValue :Object = this[fieldName];
        dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, fieldName, oldValue, newValue));
    }

    public function get uid () :String { return _uid; }
    public function set uid (uid :String) :void { _uid = uid; }

    protected var _uid :String;

    protected static const QUESTION :String = "?";
    protected static const FROWN :String = "☹";
    protected static const CHECK :String = "✓";
}

Use the best stage quality when publishing the atlases.

Once Flash 11.2 is out, we should use "16X16" as described at
http://blog.kaourantin.net/?p=152.


/*
 *  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);

			Steamworks.addEventListener(SteamEvent.STEAM_RESPONSE, onSteamResponse);
			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') );

				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("activateGameOverlay('Friends') == " + Steamworks.activateGameOverlay("Friends"));
		}

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

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

		private function onSteamResponse(e:SteamEvent):void{
			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);
					var file:String = Steamworks.publishWorkshopFileResult();
					log("File published as " + file);
					log("subscribePublishedFile(...) == " + Steamworks.subscribePublishedFile(file));
					break;
				case SteamConstants.RESPONSE_OnEnumerateUserSubscribedFiles:
					log("RESPONSE_OnEnumerateUserSubscribedFiles: " + e.response);
					var result:SubscribedFilesResult = Steamworks.enumerateUserSubscribedFilesResult();
					log("User subscribed files: " + result.resultsReturned + "/" + result.totalResults);
					for(var i:int = 0; i < result.resultsReturned; i++)
						log(i + ": " + result.publishedFileId[i] + " (" + result.timeSubscribed[i] + ")");
					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;

			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);

			Steamworks.addEventListener(SteamEvent.STEAM_RESPONSE, onSteamResponse);
			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') );

				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 onSteamResponse(e:SteamEvent):void{
			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);
					var file:String = Steamworks.publishWorkshopFileResult();
					log("File published as " + file);
					log("subscribePublishedFile(...) == " + Steamworks.subscribePublishedFile(file));
					break;
				case SteamConstants.RESPONSE_OnEnumerateUserSubscribedFiles:
					log("RESPONSE_OnEnumerateUserSubscribedFiles: " + e.response);
					var result:SubscribedFilesResult = Steamworks.enumerateUserSubscribedFilesResult();
					log("User subscribed files: " + result.resultsReturned + "/" + result.totalResults);
					for(var i:int = 0; i < result.resultsReturned; i++)
						log(i + ": " + result.publishedFileId[i] + " (" + result.timeSubscribed[i] + ")");
					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;

			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 isOverlayEnabled

Add test for isOverlayEnabled


/*
 PureMVC - Copyright(c) 2006-08 Futurescale, Inc., Some rights reserved.
 Your reuse is governed by the Creative Commons Attribution 3.0 United States License
*/
package org.puremvc.as3.patterns.observer
{
	import org.puremvc.as3.interfaces.*;

	/**
	 * A base IObserver implementation.
	 *
	 *

	 * An Observer is an object that encapsulates information
	 * about an interested object with a method that should
	 * be called when a particular INotification is broadcast.

	 *
	 *

	 * In PureMVC, the Observer class assumes these responsibilities:
	 *

	 *
Encapsulate the notification (callback) method of the interested object.

	 *
Encapsulate the notification context (this) of the interested object.

	 *
Provide methods for setting the notification method and context.

	 *
Provide a method for notifying the interested object.

	 *

	 *
	 * @see org.puremvc.as3.core.view.View View
	 * @see org.puremvc.as3.patterns.observer.Notification Notification
	 */
	public class Observer implements IObserver
	{
		private var notify:Function;
		private var context:Object;

		/**
		 * Constructor.
		 *
		 *

		 * The notification method on the interested object should take
		 * one parameter of type INotification

		 *
		 * @param notifyMethod the notification method of the interested object
		 * @param notifyContext the notification context of the interested object
		 */
		public function Observer( notifyMethod:Function, notifyContext:Object )
		{
			setNotifyMethod( notifyMethod );
			setNotifyContext( notifyContext );
		}

		/**
		 * Set the notification method.
		 *
		 *

		 * The notification method should take one parameter of type INotification.

		 *
		 * @param notifyMethod the notification (callback) method of the interested object.
		 */
		public function setNotifyMethod( notifyMethod:Function ):void
		{
			notify = notifyMethod;
		}

		/**
		 * Set the notification context.
		 *
		 * @param notifyContext the notification context (this) of the interested object.
		 */
		public function setNotifyContext( notifyContext:Object ):void
		{
			context = notifyContext;
		}

		/**
		 * Get the notification method.
		 *
		 * @return the notification (callback) method of the interested object.
		 */
		private function getNotifyMethod():Function
		{
			return notify;
		}

		/**
		 * Get the notification context.
		 *
		 * @return the notification context (this) of the interested object.
		 */
		private function getNotifyContext():Object
		{
			return context;
		}

		/**
		 * Notify the interested object.
		 *
		 * @param notification the INotification to pass to the interested object's notification method.
		 */
		public function notifyObserver( notification:INotification ):void
		{

			//If the handleNotification method fails internally, the notification needs to carry on being
			//delivered to other listeners.
			try
			{
				this.getNotifyMethod().apply(this.getNotifyContext(),[notification]);
			}
			catch(e : Error)
			{
				return;
			}
		}

		/**
		 * Compare an object to the notification context.
		 *
		 * @param object the object to compare
		 * @return boolean indicating if the object and the notification context are the same
		 */
		 public function compareNotifyContext( object:Object ):Boolean
		 {
		 	return object === this.context;
		 }
	}
}

/*
 PureMVC - Copyright(c) 2006-08 Futurescale, Inc., Some rights reserved.
 Your reuse is governed by the Creative Commons Attribution 3.0 United States License
*/
package org.puremvc.as3.patterns.observer
{
	import com.kaltura.kdpfl.view.controls.KTrace;

	import org.puremvc.as3.interfaces.*;

	/**
	 * A base IObserver implementation.
	 *
	 *

	 * An Observer is an object that encapsulates information
	 * about an interested object with a method that should
	 * be called when a particular INotification is broadcast.

	 *
	 *

	 * In PureMVC, the Observer class assumes these responsibilities:
	 *

	 *
Encapsulate the notification (callback) method of the interested object.

	 *
Encapsulate the notification context (this) of the interested object.

	 *
Provide methods for setting the notification method and context.

	 *
Provide a method for notifying the interested object.

	 *

	 *
	 * @see org.puremvc.as3.core.view.View View
	 * @see org.puremvc.as3.patterns.observer.Notification Notification
	 */
	public class Observer implements IObserver
	{
		private var notify:Function;
		private var context:Object;

		/**
		 * Constructor.
		 *
		 *

		 * The notification method on the interested object should take
		 * one parameter of type INotification

		 *
		 * @param notifyMethod the notification method of the interested object
		 * @param notifyContext the notification context of the interested object
		 */
		public function Observer( notifyMethod:Function, notifyContext:Object )
		{
			setNotifyMethod( notifyMethod );
			setNotifyContext( notifyContext );
		}

		/**
		 * Set the notification method.
		 *
		 *

		 * The notification method should take one parameter of type INotification.

		 *
		 * @param notifyMethod the notification (callback) method of the interested object.
		 */
		public function setNotifyMethod( notifyMethod:Function ):void
		{
			notify = notifyMethod;
		}

		/**
		 * Set the notification context.
		 *
		 * @param notifyContext the notification context (this) of the interested object.
		 */
		public function setNotifyContext( notifyContext:Object ):void
		{
			context = notifyContext;
		}

		/**
		 * Get the notification method.
		 *
		 * @return the notification (callback) method of the interested object.
		 */
		private function getNotifyMethod():Function
		{
			return notify;
		}

		/**
		 * Get the notification context.
		 *
		 * @return the notification context (this) of the interested object.
		 */
		private function getNotifyContext():Object
		{
			return context;
		}

		/**
		 * Notify the interested object.
		 *
		 * @param notification the INotification to pass to the interested object's notification method.
		 */
		public function notifyObserver( notification:INotification ):void
		{

			//If the handleNotification method fails internally, the notification needs to carry on being
			//delivered to other listeners.
			try
			{
				this.getNotifyMethod().apply(this.getNotifyContext(),[notification]);
			}
			catch(e : Error)
			{
				KTrace.getInstance().log("--Exception while notifying " + notification.getName() + ": " + e.message);
				return;
			}
		}

		/**
		 * Compare an object to the notification context.
		 *
		 * @param object the object to compare
		 * @return boolean indicating if the object and the notification context are the same
		 */
		 public function compareNotifyContext( object:Object ):Boolean
		 {
		 	return object === this.context;
		 }
	}
}

add informative trace when sendNotification fails


/* 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 org.mangui.hls.demux {

    import flash.utils.ByteArray;
    CONFIG::LOGGING {
    import org.mangui.hls.HLSSettings;
    import org.mangui.hls.utils.Log;
    }

    /** Constants and utilities for the H264 video format. **/
    public class Nalu {

        private static var _audNalu : ByteArray;
        // static initializer
        {
            _audNalu = new ByteArray();
            _audNalu.length = 2;
            _audNalu.writeByte(0x09);
            _audNalu.writeByte(0xF0);
        };

        /** Return an array with NAL delimiter indexes. **/
        public static function getNALU(nalu : ByteArray, position : uint) : Vector.<VideoFrame> {
            var units : Vector.<VideoFrame> = new Vector.<VideoFrame>();
            var unit_start : int;
            var unit_type : int;
            var unit_header : int;
            var aud_found : Boolean = false;
            // Loop through data to find NAL startcodes.
            var window : uint = 0;
            nalu.position = position;
            while (nalu.bytesAvailable > 4) {
                window = nalu.readUnsignedInt();
                // Match four-byte startcodes
                if ((window & 0xFFFFFFFF) == 0x01) {
                    // push previous NAL unit if new start delimiter found, dont push unit with type = 0
                    if (unit_start && unit_type) {
                        units.push(new VideoFrame(unit_header, nalu.position - 4 - unit_start, unit_start, unit_type));
                    }
                    unit_header = 4;
                    unit_start = nalu.position;
                    unit_type = nalu.readByte() & 0x1F;
                    if(unit_type ==9) {
                        aud_found = true;
                    }
                    /* if AUD already found and newly found unit is NDR or IDR,
                        stop parsing here and consider that this IDR/NDR is the last NAL unit
                        breaking the loop here is done for optimization purpose, as NAL parsing is time consuming ...
                     */
                    if (aud_found && (unit_type == 1 || unit_type == 5)) {
                        break;
                    }
                    // Match three-byte startcodes
                } else if ((window & 0xFFFFFF00) == 0x100) {
                    // push previous NAL unit if new start delimiter found, dont push unit with type = 0
                    if (unit_start && unit_type) {
                        units.push(new VideoFrame(unit_header, nalu.position - 4 - unit_start, unit_start, unit_type));
                    }
                    nalu.position--;
                    unit_header = 3;
                    unit_start = nalu.position;
                    unit_type = nalu.readByte() & 0x1F;
                    if(unit_type ==9) {
                        aud_found = true;
                    }
                    /* if AUD already found and newly found unit is NDR or IDR,
                        stop parsing here and consider that this IDR/NDR is the last NAL unit
                        breaking the loop here is done for optimization purpose, as NAL parsing is time consuming ...
                     */
                    if (aud_found && (unit_type == 1 || unit_type == 5)) {
                        break;
                    }
                } else {
                    nalu.position -= 3;
                }
            }
            // Append the last NAL to the array.
            if (unit_start) {
                units.push(new VideoFrame(unit_header, nalu.length - unit_start, unit_start, unit_type));
            }
            // Reset position and return results.
            CONFIG::LOGGING {
                if (HLSSettings.logDebug2) {
                    /** H264 NAL unit names. **/
                    const NAMES : Array = ['Unspecified',// 0
                    'NDR',                          // 1
                    'Partition A',                  // 2
                    'Partition B',                  // 3
                    'Partition C',                  // 4
                    'IDR',                          // 5
                    'SEI',                          // 6
                    'SPS',                          // 7
                    'PPS',                          // 8
                    'AUD',                          // 9
                    'End of Sequence',              // 10
                    'End of Stream',                // 11
                    'Filler Data'// 12
                    ];
                    if (units.length) {
                        var txt : String = "AVC: ";
                        for (var i : int = 0; i < units.length; i++) {
                            txt += NAMES[units[i].type] + ","; //+ ":" + units[i].length
                        }
                        Log.debug2(txt.substr(0, txt.length - 2) + " slices");
                    } else {
                        Log.debug2('AVC: no NALU slices found');
                    }
                }
            }
            nalu.position = position;
            return units;
        };

        public static function get AUD():ByteArray {
            return _audNalu;
        }
    }
}

/* 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 org.mangui.hls.demux {

    import flash.utils.ByteArray;
    CONFIG::LOGGING {
    import org.mangui.hls.HLSSettings;
    import org.mangui.hls.utils.Log;
    }

    /** Constants and utilities for the H264 video format. **/
    public class Nalu {

        private static var _audNalu : ByteArray;
        // static initializer
        {
            _audNalu = new ByteArray();
            _audNalu.length = 2;
            _audNalu.writeByte(0x09);
            _audNalu.writeByte(0xF0);
        };

        /** Return an array with NAL delimiter indexes. **/
        public static function getNALU(nalu : ByteArray, position : uint) : Vector.<VideoFrame> {
            var units : Vector.<VideoFrame> = new Vector.<VideoFrame>();
            var unit_start : int;
            var unit_type : int;
            var unit_header : int;
            var aud_found : Boolean = false;
            // Loop through data to find NAL startcodes.
            var window : uint = 0;
            nalu.position = position;
            while (nalu.bytesAvailable > 4) {
                window = nalu.readUnsignedInt();
                // Match four-byte startcodes
                if ((window & 0xFFFFFFFF) == 0x01) {
                    // push previous NAL unit if new start delimiter found, dont push unit with type = 0
                    if (unit_start && unit_type) {
                        units.push(new VideoFrame(unit_header, nalu.position - 4 - unit_start, unit_start, unit_type));
                    }
                    unit_header = 4;
                    unit_start = nalu.position;
                    unit_type = nalu.readByte() & 0x1F;
                    if(unit_type ==9) {
                        aud_found = true;
                    }
                    /* if AUD already found and newly found unit is NDR or IDR,
                        stop parsing here and consider that this IDR/NDR is the last NAL unit
                        breaking the loop here is done for optimization purpose, as NAL parsing is time consuming ...
                     */
                    if (aud_found && (unit_type == 1 || unit_type == 5)) {
                        break;
                    }
                    // Match three-byte startcodes
                } else if ((window & 0xFFFFFF00) == 0x100) {
                    // push previous NAL unit if new start delimiter found, dont push unit with type = 0
                    if (unit_start && unit_type) {
                        units.push(new VideoFrame(unit_header, nalu.position - 4 - unit_start, unit_start, unit_type));
                    }
                    nalu.position--;
                    unit_header = 3;
                    unit_start = nalu.position;
                    unit_type = nalu.readByte() & 0x1F;
                    if(unit_type ==9) {
                        aud_found = true;
                    }
                    /* if AUD already found and newly found unit is NDR or IDR,
                        stop parsing here and consider that this IDR/NDR is the last NAL unit
                        breaking the loop here is done for optimization purpose, as NAL parsing is time consuming ...
                     */
                    if (aud_found && (unit_type == 1 || unit_type == 5)) {
                        break;
                    }
                } else {
                    nalu.position -= 3;
                }
            }
            // Append the last NAL to the array.
            if (unit_start) {
                units.push(new VideoFrame(unit_header, nalu.length - unit_start, unit_start, unit_type));
            }
            // Reset position and return results.
            CONFIG::LOGGING {
                if (HLSSettings.logDebug2) {
                    /** H264 NAL unit names. **/
                    const NAMES : Array = ['Unspecified',// 0
                    'NDR',                          // 1
                    'Partition A',                  // 2
                    'Partition B',                  // 3
                    'Partition C',                  // 4
                    'IDR',                          // 5
                    'SEI',                          // 6
                    'SPS',                          // 7
                    'PPS',                          // 8
                    'AUD',                          // 9
                    'End of Sequence',              // 10
                    'End of Stream',                // 11
                    'Filler Data'// 12
                    ];
                    if (units.length) {
                        var txt : String = "AVC: ";
                        for (var i : int = 0; i < units.length; i++) {
                            txt += NAMES[units[i].type] + ","; //+ ":" + units[i].length
                        }
                        Log.debug2(txt.substr(0,txt.length-1) + " slices");
                    } else {
                        Log.debug2('AVC: no NALU slices found');
                    }
                }
            }
            nalu.position = position;
            return units;
        };

        public static function get AUD():ByteArray {
            return _audNalu;
        }
    }
}

fix truncated debug2 logs

fix truncated debug2 logs