/*
#
# Copyright (c) 2008-2010 rPath, Inc.
#
# This program is distributed under the terms of the MIT License as found
# in a file called LICENSE. If it is not present, the license
# is always available at http://www.opensource.org/licenses/mit-license.php.
#
# This program is distributed in the hope that it will be useful, but
# without any warranty; without even the implied warranty of merchantability
# or fitness for a particular purpose. See the MIT License for full details.
*/

package com.rpath.raf.util
{
    import flash.utils.Dictionary;

    import mx.collections.ArrayCollection;
    import spark.components.Application;
    import mx.core.FlexGlobals;
    import mx.core.IFlexDisplayObject;
    import mx.formatters.NumberBaseRoundType;
    import mx.formatters.NumberFormatter;
    import mx.managers.PopUpManager;
    import mx.managers.PopUpManagerChildList;

    public class UIHelper
    {

        public static function checkBooleans(...args):Boolean
        {
            for each (var b:* in args)
            {
                if (b is Array || b is ArrayCollection)
                {
                    for each (var c:* in b)
                    {
                        // allow for nested arrays
                        checkBooleans(c);
                    }
                }
                else
                {
                    if (!b)
                        return false;
                }
            }
            return true;
        }

        public static function checkOneOf(...args):Boolean
        {
            for each (var b:* in args)
            {
                if (b)
                    return true;
            }
            return false;
        }

        public static function formattedDate(unixTimestamp:Number):String
        {
            if (isNaN(unixTimestamp))
                return "";

            var date:Date = new Date(unixTimestamp * 1000);
            /*
             * Note that we add 1 to month b/c January is 0 in Flex
             */
            return padLeft(date.getMonth() +1) + "/" + padLeft(date.getDate()) +
                "/" + padLeft(date.getFullYear()) + " " + padLeft(date.getHours()) +
                ":" + padLeft(date.getMinutes()) + ":" + padLeft(date.getSeconds());
        }

        public static function padLeft(number:Number):String
        {
            var strNum:String = number.toString();
            if (number.toString().length == 1)
                strNum = "0" + strNum;

            return strNum;
        }

        /**
         * Replace \r\n with \n, replace \r with \n
         */
        public static function processCarriageReturns(value:String):String
        {
            if (!value)
                return value;

            var cr:String = String.fromCharCode(13);
            var crRegex:RegExp = new RegExp(cr, "gm");

            var crnl:String = String.fromCharCode(13, 10);
            var crnlRegex:RegExp = new RegExp(crnl, "gm");

            // process CRNL first
            value = value.replace(crnlRegex, '\n');

            // process CR
            value = value.replace(crRegex, '\n');

            return value;
        }

        private static var popupModelMap:Dictionary = new Dictionary(true);
        private static var popupOwnerMap:Dictionary = new Dictionary(true);

        public static function createPopup(clazz:Class):*
        {
            var popup:Object = PopUpManager.createPopUp(FlexGlobals.topLevelApplication as Application,
                clazz, false, PopUpManagerChildList.APPLICATION) as clazz;
            return popup as IFlexDisplayObject;
        }

        public static function createSingletonPopupForModel(clazz:Class, model:Object, owner:Object=null):*
        {
            var popup:Object;

            popup = popupForModel(model);
            if (popup == null)
            {
                popup = PopUpManager.createPopUp(FlexGlobals.topLevelApplication as Application,
                    clazz, false, PopUpManagerChildList.APPLICATION) as clazz;

                popupModelMap[model] = popup;

                if (owner)
                {
                    popupOwnerMap[popup] = owner;
                }
            }

            return popup as IFlexDisplayObject;
        }

        public static function popupForModel(model:Object):*
        {
            return popupModelMap[model];
        }

        public static function removePopupForModel(model:Object):void
        {
            var popup:IFlexDisplayObject = popupModelMap[model];
            if (popup)
            {
                delete popupModelMap[model];
                delete popupOwnerMap[popup];
            }

        }

        public static function removePopupsForOwner(owner:Object):void
        {
            for (var popup:* in popupOwnerMap)
            {
                if (popupOwnerMap[popup] === owner)
                {
                    delete popupOwnerMap[popup];
                    // scan the model map too
                    for (var model:* in popupModelMap)
                    {
                        if (popupModelMap[model] === popup)
                        {
                            delete popupModelMap[model];
                        }
                    }
                }
            }
        }

        public static function popupsForOwner(owner:Object):Array
        {
            var result:Array = [];
            for (var popup:* in popupOwnerMap)
            {
                if (popupOwnerMap[popup] === owner)
                {
                    result.push(popup);
                }
            }

            return result;
        }

        public static function closePopupsForOwner(owner:Object):void
        {
            for each (var popup:* in UIHelper.popupsForOwner(owner))
            {
                PopUpManager.removePopUp(popup);
            }

            removePopupsForOwner(owner);
        }

        // make bytes human readable
        public static function humanReadableSize(bytes:Number, precision:int=1):String
        {
            var s:String = bytes + ' bytes';

            var nf:NumberFormatter = new NumberFormatter();
            nf.precision = precision;
            nf.useThousandsSeparator = true;
            nf.useNegativeSign = true;
            nf.rounding = NumberBaseRoundType.NEAREST;

            if (bytes > 1073741824)
            {
                s = nf.format((bytes / 1073741824.0)) + ' GB' + ' (' + (s) + ')';
            }
            else if (bytes > 1048576)
            {
                s = nf.format((bytes / 1048576.0)) + ' MB' + ' (' + (s) + ')';
            }
            else if (bytes > 1024)
            {
                s = nf.format((bytes / 1024.0)) + ' KB' + ' (' + (s) + ')';
            }

            return s;
        }
    }
}

/*
#
# Copyright (c) 2008-2010 rPath, Inc.
#
# This program is distributed under the terms of the MIT License as found
# in a file called LICENSE. If it is not present, the license
# is always available at http://www.opensource.org/licenses/mit-license.php.
#
# This program is distributed in the hope that it will be useful, but
# without any warranty; without even the implied warranty of merchantability
# or fitness for a particular purpose. See the MIT License for full details.
*/

package com.rpath.raf.util
{
    import flash.utils.Dictionary;

    import mx.collections.ArrayCollection;
    import spark.components.Application;
    import mx.core.FlexGlobals;
    import mx.core.IFlexDisplayObject;
    import mx.formatters.NumberBaseRoundType;
    import mx.formatters.NumberFormatter;
    import mx.managers.PopUpManager;
    import mx.managers.PopUpManagerChildList;

    public class UIHelper
    {

        public static function checkBooleans(...args):Boolean
        {
            for each (var b:* in args)
            {
                if (b is Array || b is ArrayCollection)
                {
                    for each (var c:* in b)
                    {
                        // allow for nested arrays
                        checkBooleans(c);
                    }
                }
                else
                {
                    if (!b)
                        return false;
                }
            }
            return true;
        }

        public static function checkOneOf(...args):Boolean
        {
            for each (var b:* in args)
            {
                if (b is Array || b is ArrayCollection)
                {
                    for each (var c:* in b)
                    {
                        // allow for nested arrays
                        if (checkOneOf(c))
                            return true;
                    }
                }
                else if (b)
                {
                    return true;
                }
            }
            return false;
        }

        public static function formattedDate(unixTimestamp:Number):String
        {
            if (isNaN(unixTimestamp))
                return "";

            var date:Date = new Date(unixTimestamp * 1000);
            /*
             * Note that we add 1 to month b/c January is 0 in Flex
             */
            return padLeft(date.getMonth() +1) + "/" + padLeft(date.getDate()) +
                "/" + padLeft(date.getFullYear()) + " " + padLeft(date.getHours()) +
                ":" + padLeft(date.getMinutes()) + ":" + padLeft(date.getSeconds());
        }

        public static function padLeft(number:Number):String
        {
            var strNum:String = number.toString();
            if (number.toString().length == 1)
                strNum = "0" + strNum;

            return strNum;
        }

        /**
         * Replace \r\n with \n, replace \r with \n
         */
        public static function processCarriageReturns(value:String):String
        {
            if (!value)
                return value;

            var cr:String = String.fromCharCode(13);
            var crRegex:RegExp = new RegExp(cr, "gm");

            var crnl:String = String.fromCharCode(13, 10);
            var crnlRegex:RegExp = new RegExp(crnl, "gm");

            // process CRNL first
            value = value.replace(crnlRegex, '\n');

            // process CR
            value = value.replace(crRegex, '\n');

            return value;
        }

        private static var popupModelMap:Dictionary = new Dictionary(true);
        private static var popupOwnerMap:Dictionary = new Dictionary(true);

        public static function createPopup(clazz:Class):*
        {
            var popup:Object = PopUpManager.createPopUp(FlexGlobals.topLevelApplication as Application,
                clazz, false, PopUpManagerChildList.APPLICATION) as clazz;
            return popup as IFlexDisplayObject;
        }

        public static function createSingletonPopupForModel(clazz:Class, model:Object, owner:Object=null):*
        {
            var popup:Object;

            popup = popupForModel(model);
            if (popup == null)
            {
                popup = PopUpManager.createPopUp(FlexGlobals.topLevelApplication as Application,
                    clazz, false, PopUpManagerChildList.APPLICATION) as clazz;

                popupModelMap[model] = popup;

                if (owner)
                {
                    popupOwnerMap[popup] = owner;
                }
            }

            return popup as IFlexDisplayObject;
        }

        public static function popupForModel(model:Object):*
        {
            return popupModelMap[model];
        }

        public static function removePopupForModel(model:Object):void
        {
            var popup:IFlexDisplayObject = popupModelMap[model];
            if (popup)
            {
                delete popupModelMap[model];
                delete popupOwnerMap[popup];
            }

        }

        public static function removePopupsForOwner(owner:Object):void
        {
            for (var popup:* in popupOwnerMap)
            {
                if (popupOwnerMap[popup] === owner)
                {
                    delete popupOwnerMap[popup];
                    // scan the model map too
                    for (var model:* in popupModelMap)
                    {
                        if (popupModelMap[model] === popup)
                        {
                            delete popupModelMap[model];
                        }
                    }
                }
            }
        }

        public static function popupsForOwner(owner:Object):Array
        {
            var result:Array = [];
            for (var popup:* in popupOwnerMap)
            {
                if (popupOwnerMap[popup] === owner)
                {
                    result.push(popup);
                }
            }

            return result;
        }

        public static function closePopupsForOwner(owner:Object):void
        {
            for each (var popup:* in UIHelper.popupsForOwner(owner))
            {
                PopUpManager.removePopUp(popup);
            }

            removePopupsForOwner(owner);
        }

        // make bytes human readable
        public static function humanReadableSize(bytes:Number, precision:int=1):String
        {
            var s:String = bytes + ' bytes';

            var nf:NumberFormatter = new NumberFormatter();
            nf.precision = precision;
            nf.useThousandsSeparator = true;
            nf.useNegativeSign = true;
            nf.rounding = NumberBaseRoundType.NEAREST;

            if (bytes > 1073741824)
            {
                s = nf.format((bytes / 1073741824.0)) + ' GB' + ' (' + (s) + ')';
            }
            else if (bytes > 1048576)
            {
                s = nf.format((bytes / 1048576.0)) + ' MB' + ' (' + (s) + ')';
            }
            else if (bytes > 1024)
            {
                s = nf.format((bytes / 1024.0)) + ' KB' + ' (' + (s) + ')';
            }

            return s;
        }
    }
}

Allow UIHelper.checkOneOf to recurse arrays


//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.geom.Point;
import flash.geom.Rectangle;

import flump.xfl.XflTexture;

public class PackedTexture
{
    public const holder :Sprite = new Sprite();
    public var tex :XflTexture;
    public var offset :Point;
    public var w :int, h :int, a :int;
    public var atlasX :int, atlasY :int;
    public var atlasRotated :Boolean;

    public function PackedTexture (tex :XflTexture, image :DisplayObject) {
        this.tex = tex;
        holder.addChild(image);
        const bounds :Rectangle = image.getBounds(holder);
        offset = new Point(bounds.x, bounds.y);
        w = Math.ceil(bounds.width);
        h = Math.ceil(bounds.height);
        a = w * h;
    }

    public function toString () :String {
        return "a " + a + " w " + w + " h " + h + " atlas " + atlasX + ", " + atlasY;
    }
}
}

//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.geom.Point;
import flash.geom.Rectangle;

import flump.xfl.XflTexture;

public class PackedTexture
{
    public const holder :Sprite = new Sprite();
    public var tex :XflTexture;
    public var offset :Point;
    public var w :int, h :int, a :int;
    public var atlasX :int, atlasY :int;
    public var atlasRotated :Boolean;

    public function PackedTexture (tex :XflTexture, image :DisplayObject) {
        this.tex = tex;
        holder.addChild(image);
        const bounds :Rectangle = image.getBounds(holder);
        image.x = -bounds.x;
        image.y = -bounds.y;
        offset = new Point(bounds.x, bounds.y);
        w = Math.ceil(bounds.width);
        h = Math.ceil(bounds.height);
        a = w * h;
    }

    public function toString () :String {
        return "a " + a + " w " + w + " h " + h + " atlas " + atlasX + ", " + atlasY;
    }
}
}

Move the images by their offset

Move the images by their offset


//
// Flump - Copyright 2013 Flump Authors

package flump.export {

import aspire.util.Map;
import aspire.util.maps.ValueComputingMap;

import flash.utils.Dictionary;

import flump.display.ImageCreator;

import flump.display.Library;
import flump.display.Movie;
import flump.display.MovieCreator;
import flump.display.SymbolCreator;
import flump.export.texturepacker.TexturePacker;
import flump.mold.AtlasMold;
import flump.mold.AtlasTextureMold;
import flump.mold.KeyframeMold;
import flump.mold.LayerMold;
import flump.mold.MovieMold;
import flump.xfl.XflLibrary;
import flump.xfl.XflTexture;

import starling.display.DisplayObject;
import starling.display.Image;
import starling.textures.Texture;

public class DisplayCreator
    implements Library
{
    public function DisplayCreator (lib :XflLibrary) {
        _lib = lib;

        const atlases :Vector.<Atlas> = TexturePacker.withLib(lib).createAtlases();
        for each (var atlas :Atlas in atlases) {
            var atlastMold :AtlasMold = atlas.toMold();
            var baseTexture :Texture = AtlasUtil.toTexture(atlas);
            _baseTextures.push(baseTexture);
            for each (var atlasTexture :AtlasTextureMold in atlastMold.textures) {
                var tex :Texture = Texture.fromTexture(baseTexture, atlasTexture.bounds);
                _creators[atlasTexture.symbol] = new ImageCreator(tex, atlasTexture.origin, atlasTexture.symbol);
            }
        }

        for each (var movieMold :MovieMold in lib.movies) {
            _creators[movieMold.id] = new MovieCreator(movieMold, lib.frameRate);
        }
    }

    public function getSymbolCreator (symbol :String) :SymbolCreator {
        return _creators[symbol];
    }

    public function get imageSymbols () :Vector.<String> {
        // Vector.map can't be used to create a Vector of a new type
        const symbols :Vector.<String> = new <String>[];
        for each (var tex :XflTexture in _lib.textures) {
            symbols.push(tex.symbol);
        }
        return symbols;
    }

    public function get movieSymbols () :Vector.<String> {
        // Vector.map can't be used to create a Vector of a new type
        const symbols :Vector.<String> = new <String>[];
        for each (var movie :MovieMold in _lib.movies) {
            symbols.push(movie.id);
        }
        return symbols;
    }

    public function get isNamespaced () :Boolean {
        return false;
    }

    public function createDisplayObject (id :String) :DisplayObject {
        var creator :SymbolCreator = _creators[id];
        return creator.create(this);
    }

    public function createImage (id :String) :Image {
        return Image(createDisplayObject(id));
    }

    public function getImageTexture (id :String) :Texture {
        return ImageCreator(_creators[id]).texture;
    }

    public function createMovie (name :String) :Movie {
        return new Movie(_lib.getItem(name, MovieMold), _lib.frameRate, this);
    }

    public function getMemoryUsage (id :String, subtex :Dictionary = null) :int {
        if (id == null) return 0;

        const tex :Texture = getStarlingTexture(id);
        if (tex != null) {
            const usage :int = 4 * tex.width * tex.height;
            if (subtex != null && !subtex.hasOwnProperty(id)) subtex[id] = usage;
            return usage;
        }

        const mold :MovieMold = _lib.getItem(id, MovieMold);
        if (subtex == null) subtex = new Dictionary();
        for each (var layer :LayerMold in mold.layers) {
            for each (var kf :KeyframeMold in layer.keyframes) getMemoryUsage(kf.ref, subtex);
        }
        var subtexUsage :int = 0;
        for (var texName :String in subtex) subtexUsage += subtex[texName];
        return subtexUsage;
    }

    public function dispose () :void {
        if (_baseTextures != null) {
            for each (var tex :Texture in _baseTextures) {
                tex.dispose();
            }
            _baseTextures = null;
            _creators = null;
        }
    }

    /**
     * Gets the maximum number of pixels drawn in a single frame by the given id. If it's
     * a texture, that's just the number of pixels in the texture. For a movie, it's the frame with
     * the largest set of textures present in its keyframe. For movies inside movies, the frame
     * drawn usage is the maximum that movie can draw. We're trying to get the worst case here.
     */
    public function getMaxDrawn (id :String) :int { return _maxDrawn.get(id); }

    protected function loadTexture (symbol :String) :DisplayObject {
        return ImageCreator(_creators[symbol]).create(this);
    }

    protected function calcMaxDrawn (id :String) :int {
        if (id == null) return 0;

        const tex :Texture = getStarlingTexture(id);
        if (tex != null) return tex.width * tex.height;

        const mold :MovieMold = _lib.getItem(id, MovieMold);
        var maxDrawn :int = 0;
        for (var ii :int = 0; ii < mold.frames; ii++) {
            var drawn :int = 0;
            for each (var layer :LayerMold in mold.layers) {
                var kf :KeyframeMold = layer.keyframeForFrame(ii);
                drawn += kf.visible ? getMaxDrawn(kf.ref) : 0;
            }
            maxDrawn = Math.max(maxDrawn, drawn);
        }
        return maxDrawn;
    }

    private function getStarlingTexture (symbol :String) :Texture {
        var imageCreator :ImageCreator = _creators[symbol] as ImageCreator;
        return (imageCreator != null ? imageCreator.texture : null);
    }

    protected const _maxDrawn :Map = ValueComputingMap.newMapOf(String, calcMaxDrawn);
    protected var _baseTextures :Vector.<Texture> = new <Texture>[];
    protected var _creators :Dictionary = new Dictionary(); // <name, ImageCreator|MovieCreator>
    protected var _lib :XflLibrary;
}
}

//
// Flump - Copyright 2013 Flump Authors

package flump.export {

import aspire.util.Map;
import aspire.util.maps.ValueComputingMap;

import flash.utils.Dictionary;

import flump.display.ImageCreator;

import flump.display.Library;
import flump.display.Movie;
import flump.display.MovieCreator;
import flump.display.SymbolCreator;
import flump.export.texturepacker.TexturePacker;
import flump.mold.AtlasMold;
import flump.mold.AtlasTextureMold;
import flump.mold.KeyframeMold;
import flump.mold.LayerMold;
import flump.mold.MovieMold;
import flump.xfl.XflLibrary;
import flump.xfl.XflTexture;

import starling.display.DisplayObject;
import starling.display.Image;
import starling.textures.Texture;

public class DisplayCreator
    implements Library
{
    public function DisplayCreator (lib :XflLibrary) {
        _lib = lib;

        const atlases :Vector.<Atlas> = TexturePacker.withLib(lib).createAtlases();
        for each (var atlas :Atlas in atlases) {
            var atlastMold :AtlasMold = atlas.toMold();
            var baseTexture :Texture = AtlasUtil.toTexture(atlas);
            _baseTextures.push(baseTexture);
            for each (var atlasTexture :AtlasTextureMold in atlastMold.textures) {
                var tex :Texture = Texture.fromTexture(baseTexture, atlasTexture.bounds);
                _creators[atlasTexture.symbol] = new ImageCreator(tex, atlasTexture.origin, atlasTexture.symbol);
            }
        }

        for each (var movieMold :MovieMold in lib.movies) {
            _creators[movieMold.id] = new MovieCreator(movieMold, lib.frameRate);
        }
    }

    public function getSymbolCreator (symbol :String) :SymbolCreator {
        return _creators[symbol];
    }

    public function get imageSymbols () :Vector.<String> {
        // Vector.map can't be used to create a Vector of a new type
        const symbols :Vector.<String> = new <String>[];
        for each (var tex :XflTexture in _lib.textures) {
            symbols.push(tex.symbol);
        }
        return symbols;
    }

    public function get movieSymbols () :Vector.<String> {
        // Vector.map can't be used to create a Vector of a new type
        const symbols :Vector.<String> = new <String>[];
        for each (var movie :MovieMold in _lib.movies) {
            symbols.push(movie.id);
        }
        return symbols;
    }

    public function get isNamespaced () :Boolean {
        return false;
    }

    public function get baseTextures () :Vector.<Texture> {
        return _baseTextures;
    }

    public function createDisplayObject (id :String) :DisplayObject {
        var creator :SymbolCreator = _creators[id];
        return creator.create(this);
    }

    public function createImage (id :String) :Image {
        return Image(createDisplayObject(id));
    }

    public function getImageTexture (id :String) :Texture {
        return ImageCreator(_creators[id]).texture;
    }

    public function createMovie (name :String) :Movie {
        return new Movie(_lib.getItem(name, MovieMold), _lib.frameRate, this);
    }

    public function getMemoryUsage (id :String, subtex :Dictionary = null) :int {
        if (id == null) return 0;

        const tex :Texture = getStarlingTexture(id);
        if (tex != null) {
            const usage :int = 4 * tex.width * tex.height;
            if (subtex != null && !subtex.hasOwnProperty(id)) subtex[id] = usage;
            return usage;
        }

        const mold :MovieMold = _lib.getItem(id, MovieMold);
        if (subtex == null) subtex = new Dictionary();
        for each (var layer :LayerMold in mold.layers) {
            for each (var kf :KeyframeMold in layer.keyframes) getMemoryUsage(kf.ref, subtex);
        }
        var subtexUsage :int = 0;
        for (var texName :String in subtex) subtexUsage += subtex[texName];
        return subtexUsage;
    }

    public function dispose () :void {
        if (_baseTextures != null) {
            for each (var tex :Texture in _baseTextures) {
                tex.dispose();
            }
            _baseTextures = null;
            _creators = null;
        }
    }

    /**
     * Gets the maximum number of pixels drawn in a single frame by the given id. If it's
     * a texture, that's just the number of pixels in the texture. For a movie, it's the frame with
     * the largest set of textures present in its keyframe. For movies inside movies, the frame
     * drawn usage is the maximum that movie can draw. We're trying to get the worst case here.
     */
    public function getMaxDrawn (id :String) :int { return _maxDrawn.get(id); }

    protected function loadTexture (symbol :String) :DisplayObject {
        return ImageCreator(_creators[symbol]).create(this);
    }

    protected function calcMaxDrawn (id :String) :int {
        if (id == null) return 0;

        const tex :Texture = getStarlingTexture(id);
        if (tex != null) return tex.width * tex.height;

        const mold :MovieMold = _lib.getItem(id, MovieMold);
        var maxDrawn :int = 0;
        for (var ii :int = 0; ii < mold.frames; ii++) {
            var drawn :int = 0;
            for each (var layer :LayerMold in mold.layers) {
                var kf :KeyframeMold = layer.keyframeForFrame(ii);
                drawn += kf.visible ? getMaxDrawn(kf.ref) : 0;
            }
            maxDrawn = Math.max(maxDrawn, drawn);
        }
        return maxDrawn;
    }

    private function getStarlingTexture (symbol :String) :Texture {
        var imageCreator :ImageCreator = _creators[symbol] as ImageCreator;
        return (imageCreator != null ? imageCreator.texture : null);
    }

    protected const _maxDrawn :Map = ValueComputingMap.newMapOf(String, calcMaxDrawn);
    protected var _baseTextures :Vector.<Texture> = new <Texture>[];
    protected var _creators :Dictionary = new Dictionary(); // <name, ImageCreator|MovieCreator>
    protected var _lib :XflLibrary;
}
}

Add missing DisplayCreator.baseTextures

exporter: Add missing DisplayCreator.baseTextures


package com.amanitadesign.steam {
	import flash.desktop.NativeProcess;
	import flash.desktop.NativeProcessStartupInfo;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.StatusEvent;
	import flash.filesystem.File;
	import flash.utils.ByteArray;
	import flash.utils.IDataInput;
	import flash.utils.IDataOutput;
	import flash.utils.clearInterval;
	import flash.utils.setInterval;

	public class FRESteamWorks extends EventDispatcher {
		[Event(name="steam_response", type="com.amanitadesign.steam.SteamEvent")]

		private static const PATH:String = "NativeApps/Linux/APIWrapper";

		private var _file:File;
		private var _process:NativeProcess;
		private var _tm:int;

		public var isReady:Boolean = false;

		private static const AIRSteam_Init:int = 0;
		private static const AIRSteam_RunCallbacks:int = 1;
		private static const AIRSteam_RequestStats:int = 2;
		private static const AIRSteam_SetAchievement:int = 3;
		private static const AIRSteam_ClearAchievement:int = 4;
		private static const AIRSteam_IsAchievement:int = 5;
		private static const AIRSteam_GetStatInt:int = 6;
		private static const AIRSteam_GetStatFloat:int = 7;
		private static const AIRSteam_SetStatInt:int = 8;
		private static const AIRSteam_SetStatFloat:int = 9;
		private static const AIRSteam_StoreStats:int = 10;
		private static const AIRSteam_ResetAllStats:int = 11;
		private static const AIRSteam_GetFileCount:int = 12;
		private static const AIRSteam_GetFileSize:int = 13;
		private static const AIRSteam_FileExists:int = 14;
		private static const AIRSteam_FileWrite:int = 15;
		private static const AIRSteam_FileRead:int = 16;
		private static const AIRSteam_FileDelete:int = 17;
		private static const AIRSteam_IsCloudEnabledForApp:int = 18;
		private static const AIRSteam_SetCloudEnabledForApp:int = 19;

		public function FRESteamWorks (target:IEventDispatcher = null) {
			_file = File.applicationDirectory.resolvePath(PATH);
			_process = new NativeProcess();
			super(target);
		}

		public function dispose():void {
			if(_process.running) {
				_process.closeInput();
				_process.exit();
			}
			clearInterval(_tm);
			isReady = false;
		}

		private function startProcess():void {
			var startupInfo:NativeProcessStartupInfo = new NativeProcessStartupInfo();
			startupInfo.executable = _file;

			_process.start(startupInfo);
			_process.addEventListener(ProgressEvent.STANDARD_ERROR_DATA, eventDispatched);
			_process.addEventListener(IOErrorEvent.STANDARD_OUTPUT_IO_ERROR, errorCallback);
		}

		public function init():Boolean {
			trace("Init called");
			if(!_file.exists) return false;
			startProcess();
			if(!_process.running) return false;

			callWrapper(AIRSteam_Init);
			isReady = readBoolResponse();
			if(isReady) _tm = setInterval(runCallbacks, 100);
			return isReady;
		}

		private function callWrapper(funcName:int, params:Array = null):void{
			if(!_process.running) startProcess();

			trace("Calling: " + funcName + "//" + params);
			var stdin:IDataOutput = _process.standardInput;
			stdin.writeUTFBytes(funcName + "\n");

			if(!params) return;

			for(var i:int = 0; i < params.length; ++i) {
				if(params[i] is ByteArray) {
					var length:uint = params[i].length;
					// length + 1 for the added newline
					stdin.writeUTFBytes(String(length + 1) + "\n");
					stdin.writeBytes(params[i]);
					stdin.writeUTFBytes("\n");
				} else {
					stdin.writeUTFBytes(String(params[i]) + "\n");
				}
			}
		}

		private function waitForData(output:IDataInput):uint {
			while(!output.bytesAvailable) {
				// wait
			}

			return output.bytesAvailable;
		}

		private function readBoolResponse():Boolean {
			if(!_process.running) return false;
			var stdout:IDataInput = _process.standardOutput;
			var avail:uint = waitForData(stdout);

			var response:String = stdout.readUTFBytes(1);
			trace(response + "//" + (response == "t"));
			return (response == "t");
		}

		private function readIntResponse():int {
			if(!_process.running) return 0;
			var stdout:IDataInput = _process.standardOutput;
			var avail:uint = waitForData(stdout);

			var response:String = stdout.readUTFBytes(avail);
			trace(response);
			return parseInt(response, 10);
		}

		private function readFloatResponse():Number {
			if(!_process.running) return 0.0;
			var stdout:IDataInput = _process.standardOutput;
			var avail:uint = waitForData(stdout);

			var response:String = stdout.readUTFBytes(avail)
			trace(response);
			return parseFloat(response);
		}

		private function readStringResponse():String {
			if(!_process.running) return "";
			var stdout:IDataInput = _process.standardOutput;
			var avail:uint = waitForData(stdout);

			var response:String = stdout.readUTFBytes(avail)
			trace(response);
			return response;
		}

		private function eventDispatched(e:ProgressEvent):void {
			var stderr:IDataInput = _process.standardError;
			var avail:uint = stderr.bytesAvailable;
			var data:String = stderr.readUTFBytes(avail);
			trace("Got progress event, data available: " + avail);
			trace("Content: " + data);

			var pattern:RegExp = /__event__<(\d+),(\d+)>/g;
			var result:Object;
			while((result = pattern.exec(data))) {
				var req_type:int = new int(result[1]);
				var response:int = new int(result[2]);
				trace("Got event: " + req_type + "//" + response);
				var steamEvent:SteamEvent = new SteamEvent(SteamEvent.STEAM_RESPONSE, req_type, response);
				dispatchEvent(steamEvent);
			}
		}

		private function errorCallback(e:IOErrorEvent):void {
			// the process doesn't accept our input anymore, try to restart it
			if(_process.running) {
				_process.closeInput();
				_process.exit();
			}

			startProcess();
		}

		public function requestStats():Boolean {
			trace("requestStats called");
			callWrapper(AIRSteam_RequestStats);
			return readBoolResponse();
		}

		public function runCallbacks():Boolean {
			trace("runCallbacks called");
			callWrapper(AIRSteam_RunCallbacks);
			return true;
		}

		public function setAchievement(id:String):Boolean {
			trace("setAchievement called");
			callWrapper(AIRSteam_SetAchievement, [id]);
			return readBoolResponse();
		}

		public function clearAchievement(id:String):Boolean {
			trace("clearAchievement called");
			callWrapper(AIRSteam_ClearAchievement, [id]);
			return readBoolResponse();
		}

		public function isAchievement(id:String):Boolean {
			trace("isAchievement called");
			callWrapper(AIRSteam_IsAchievement, [id]);
			return readBoolResponse();
		}

		public function getStatInt(id:String):int {
			trace("getStatInt called");
			callWrapper(AIRSteam_GetStatInt, [id]);
			return readIntResponse();
		}

		public function getStatFloat(id:String):Number {
			trace("getStatFloat called");
			callWrapper(AIRSteam_GetStatFloat, [id]);
			return readFloatResponse();
		}

		public function setStatInt(id:String, value:int):Boolean {
			trace("setStatInt called");
			callWrapper(AIRSteam_SetStatInt, [id, value]);
			return readBoolResponse();
		}

		public function setStatFloat(id:String, value:Number):Boolean {
			trace("setStatFloat called");
			callWrapper(AIRSteam_SetStatFloat, [id, value]);
			return readBoolResponse();
		}

		public function storeStats():Boolean {
			trace("storeStats called");
			callWrapper(AIRSteam_StoreStats);
			return readBoolResponse();
		}

		public function resetAllStats(bAchievementsToo:Boolean):Boolean {
			trace("resetAllStats called");
			callWrapper(AIRSteam_ResetAllStats, [bAchievementsToo]);
			return readBoolResponse();
		}

		public function getFileCount():int {
			trace("getFileCount called");
			callWrapper(AIRSteam_GetFileCount);
			return readIntResponse();
		}

		public function getFileSize(fileName:String):int {
			trace("getFileSize called");
			callWrapper(AIRSteam_GetFileSize, [fileName]);
			return readIntResponse();
		}

		public function fileExists(fileName:String):Boolean {
			trace("fileExists called");
			callWrapper(AIRSteam_FileExists, [fileName]);
			return readBoolResponse();
		}

		public function fileWrite(fileName:String, data:ByteArray):Boolean {
			trace("fileWrite called");
			callWrapper(AIRSteam_FileWrite, [fileName, data]);
			return readBoolResponse();
		}

		public function fileRead(fileName:String, data:ByteArray):Boolean {
			trace("fileRead called");
			callWrapper(AIRSteam_FileRead, [fileName]);

			var success:Boolean = readBoolResponse();
			if(success) {
				var content:String = readStringResponse();
				data.writeUTFBytes(content);
				data.position = 0;
			}

			return success;
		}

		public function fileDelete(fileName:String):Boolean {
			trace("fileDelete called");
			callWrapper(AIRSteam_FileDelete, [fileName]);
			return readBoolResponse();
		}

		public function isCloudEnabledForApp():Boolean {
			trace("isCloudEnabledForApp called");
			callWrapper(AIRSteam_IsCloudEnabledForApp);
			return readBoolResponse();
		}

		public function setCloudEnabledForApp(enabled:Boolean):Boolean {
			trace("setCloudEnabledForApp called");
			callWrapper(AIRSteam_SetCloudEnabledForApp, [enabled]);
			return readBoolResponse();
		}
	}
}

package com.amanitadesign.steam {
	import flash.desktop.NativeProcess;
	import flash.desktop.NativeProcessStartupInfo;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.StatusEvent;
	import flash.filesystem.File;
	import flash.utils.ByteArray;
	import flash.utils.IDataInput;
	import flash.utils.IDataOutput;
	import flash.utils.clearInterval;
	import flash.utils.setInterval;

	public class FRESteamWorks extends EventDispatcher {
		[Event(name="steam_response", type="com.amanitadesign.steam.SteamEvent")]

		private static const PATH:String = "NativeApps/Linux/APIWrapper";

		private var _file:File;
		private var _process:NativeProcess;
		private var _tm:int;

		public var isReady:Boolean = false;

		private static const AIRSteam_Init:int = 0;
		private static const AIRSteam_RunCallbacks:int = 1;
		private static const AIRSteam_RequestStats:int = 2;
		private static const AIRSteam_SetAchievement:int = 3;
		private static const AIRSteam_ClearAchievement:int = 4;
		private static const AIRSteam_IsAchievement:int = 5;
		private static const AIRSteam_GetStatInt:int = 6;
		private static const AIRSteam_GetStatFloat:int = 7;
		private static const AIRSteam_SetStatInt:int = 8;
		private static const AIRSteam_SetStatFloat:int = 9;
		private static const AIRSteam_StoreStats:int = 10;
		private static const AIRSteam_ResetAllStats:int = 11;
		private static const AIRSteam_GetFileCount:int = 12;
		private static const AIRSteam_GetFileSize:int = 13;
		private static const AIRSteam_FileExists:int = 14;
		private static const AIRSteam_FileWrite:int = 15;
		private static const AIRSteam_FileRead:int = 16;
		private static const AIRSteam_FileDelete:int = 17;
		private static const AIRSteam_IsCloudEnabledForApp:int = 18;
		private static const AIRSteam_SetCloudEnabledForApp:int = 19;

		public function FRESteamWorks (target:IEventDispatcher = null) {
			_file = File.applicationDirectory.resolvePath(PATH);
			_process = new NativeProcess();
			super(target);
		}

		public function dispose():void {
			if(_process.running) {
				_process.closeInput();
				_process.exit();
			}
			clearInterval(_tm);
			isReady = false;
		}

		private function startProcess():void {
			var startupInfo:NativeProcessStartupInfo = new NativeProcessStartupInfo();
			startupInfo.executable = _file;

			_process.start(startupInfo);
			_process.addEventListener(ProgressEvent.STANDARD_ERROR_DATA, eventDispatched);
			_process.addEventListener(IOErrorEvent.STANDARD_OUTPUT_IO_ERROR, errorCallback);
		}

		public function init():Boolean {
			if(!_file.exists) return false;
			startProcess();
			if(!_process.running) return false;

			callWrapper(AIRSteam_Init);
			isReady = readBoolResponse();
			if(isReady) _tm = setInterval(runCallbacks, 100);
			return isReady;
		}

		private function callWrapper(funcName:int, params:Array = null):void{
			if(!_process.running) startProcess();

			var stdin:IDataOutput = _process.standardInput;
			stdin.writeUTFBytes(funcName + "\n");

			if(!params) return;

			for(var i:int = 0; i < params.length; ++i) {
				if(params[i] is ByteArray) {
					var length:uint = params[i].length;
					// length + 1 for the added newline
					stdin.writeUTFBytes(String(length + 1) + "\n");
					stdin.writeBytes(params[i]);
					stdin.writeUTFBytes("\n");
				} else {
					stdin.writeUTFBytes(String(params[i]) + "\n");
				}
			}
		}

		private function waitForData(output:IDataInput):uint {
			while(!output.bytesAvailable) {
				// wait
			}

			return output.bytesAvailable;
		}

		private function readBoolResponse():Boolean {
			if(!_process.running) return false;
			var stdout:IDataInput = _process.standardOutput;
			var avail:uint = waitForData(stdout);

			var response:String = stdout.readUTFBytes(1);
			return (response == "t");
		}

		private function readIntResponse():int {
			if(!_process.running) return 0;
			var stdout:IDataInput = _process.standardOutput;
			var avail:uint = waitForData(stdout);

			var response:String = stdout.readUTFBytes(avail);
			return parseInt(response, 10);
		}

		private function readFloatResponse():Number {
			if(!_process.running) return 0.0;
			var stdout:IDataInput = _process.standardOutput;
			var avail:uint = waitForData(stdout);

			var response:String = stdout.readUTFBytes(avail)
			return parseFloat(response);
		}

		private function readStringResponse():String {
			if(!_process.running) return "";
			var stdout:IDataInput = _process.standardOutput;
			var avail:uint = waitForData(stdout);

			var response:String = stdout.readUTFBytes(avail)
			return response;
		}

		private function eventDispatched(e:ProgressEvent):void {
			var stderr:IDataInput = _process.standardError;
			var avail:uint = stderr.bytesAvailable;
			var data:String = stderr.readUTFBytes(avail);

			var pattern:RegExp = /__event__<(\d+),(\d+)>/g;
			var result:Object;
			while((result = pattern.exec(data))) {
				var req_type:int = new int(result[1]);
				var response:int = new int(result[2]);
				var steamEvent:SteamEvent = new SteamEvent(SteamEvent.STEAM_RESPONSE, req_type, response);
				dispatchEvent(steamEvent);
			}
		}

		private function errorCallback(e:IOErrorEvent):void {
			// the process doesn't accept our input anymore, try to restart it
			if(_process.running) {
				_process.closeInput();
				_process.exit();
			}

			startProcess();
		}

		public function requestStats():Boolean {
			callWrapper(AIRSteam_RequestStats);
			return readBoolResponse();
		}

		public function runCallbacks():Boolean {
			callWrapper(AIRSteam_RunCallbacks);
			return true;
		}

		public function setAchievement(id:String):Boolean {
			callWrapper(AIRSteam_SetAchievement, [id]);
			return readBoolResponse();
		}

		public function clearAchievement(id:String):Boolean {
			callWrapper(AIRSteam_ClearAchievement, [id]);
			return readBoolResponse();
		}

		public function isAchievement(id:String):Boolean {
			callWrapper(AIRSteam_IsAchievement, [id]);
			return readBoolResponse();
		}

		public function getStatInt(id:String):int {
			callWrapper(AIRSteam_GetStatInt, [id]);
			return readIntResponse();
		}

		public function getStatFloat(id:String):Number {
			callWrapper(AIRSteam_GetStatFloat, [id]);
			return readFloatResponse();
		}

		public function setStatInt(id:String, value:int):Boolean {
			callWrapper(AIRSteam_SetStatInt, [id, value]);
			return readBoolResponse();
		}

		public function setStatFloat(id:String, value:Number):Boolean {
			callWrapper(AIRSteam_SetStatFloat, [id, value]);
			return readBoolResponse();
		}

		public function storeStats():Boolean {
			callWrapper(AIRSteam_StoreStats);
			return readBoolResponse();
		}

		public function resetAllStats(bAchievementsToo:Boolean):Boolean {
			callWrapper(AIRSteam_ResetAllStats, [bAchievementsToo]);
			return readBoolResponse();
		}

		public function getFileCount():int {
			callWrapper(AIRSteam_GetFileCount);
			return readIntResponse();
		}

		public function getFileSize(fileName:String):int {
			callWrapper(AIRSteam_GetFileSize, [fileName]);
			return readIntResponse();
		}

		public function fileExists(fileName:String):Boolean {
			callWrapper(AIRSteam_FileExists, [fileName]);
			return readBoolResponse();
		}

		public function fileWrite(fileName:String, data:ByteArray):Boolean {
			callWrapper(AIRSteam_FileWrite, [fileName, data]);
			return readBoolResponse();
		}

		public function fileRead(fileName:String, data:ByteArray):Boolean {
			callWrapper(AIRSteam_FileRead, [fileName]);

			var success:Boolean = readBoolResponse();
			if(success) {
				var content:String = readStringResponse();
				data.writeUTFBytes(content);
				data.position = 0;
			}

			return success;
		}

		public function fileDelete(fileName:String):Boolean {
			callWrapper(AIRSteam_FileDelete, [fileName]);
			return readBoolResponse();
		}

		public function isCloudEnabledForApp():Boolean {
			callWrapper(AIRSteam_IsCloudEnabledForApp);
			return readBoolResponse();
		}

		public function setCloudEnabledForApp(enabled:Boolean):Boolean {
			callWrapper(AIRSteam_SetCloudEnabledForApp, [enabled]);
			return readBoolResponse();
		}
	}
}

Remove debug traces

Remove debug traces


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

package avm1lib {
  public class AVM1Broadcaster {
    public static function initialize(obj: Object): void {
      obj._listeners = [];
      obj.broadcastMessage = _broadcastMessage;
      obj.addListener = _addListener;
      obj.removeListener = _removeListener;
    }
  }
}

function _broadcastMessage(eventName: String): void {
  var args: Array = Array.prototype.slice.call(arguments, 1);
  var listeners: Array = this._listeners;
  for (var i: int = 0; i < listeners.length; i++) {
    var listener: Object = listeners[i];
    if (!(eventName in listener)) {
      continue;
    }
    listener[eventName].apply(listener, args);
  }
}
function _addListener(listener: Object): void {
  if (this._broadcastEventsRegistrationNeeded) {
    this._broadcastEventsRegistrationNeeded = false;
    for (var i: int = 0; i < this._broadcastEvents.length; i++) {
      (function (subject: Object, eventName: String): void {
        subject[eventName] = function handler(): void {
          _broadcastMessage.apply(subject, [eventName].concat(arguments));
        };
      })(this, this._broadcastEvents[i]);
    }
  }
  this._listeners.push(listener);
}
function _removeListener(listener: Object): Boolean {
  var i: int = this._listeners.indexOf(listener);
  if (i < 0) {
    return false;
  }
  this._listeners.splice(i, 1);
  return true;
}

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

package avm1lib {
  public class AVM1Broadcaster {
    public static function initialize(obj: Object): void {
      obj._listeners = [];
      obj.broadcastMessage = _broadcastMessage;
      obj.addListener = _addListener;
      obj.removeListener = _removeListener;
    }
  }
}

function _broadcastMessage(eventName: String, ...args): void {
  var listeners: Array = this._listeners;
  for (var i: int = 0; i < listeners.length; i++) {
    var listener: Object = listeners[i];
    if (!(eventName in listener)) {
      continue;
    }
    listener[eventName].apply(listener, args);
  }
}
function _addListener(listener: Object): void {
  if (this._broadcastEventsRegistrationNeeded) {
    this._broadcastEventsRegistrationNeeded = false;
    for (var i: int = 0; i < this._broadcastEvents.length; i++) {
      (function (subject: Object, eventName: String): void {
        subject[eventName] = function handler(): void {
          _broadcastMessage.apply(subject, [eventName].concat(arguments));
        };
      })(this, this._broadcastEvents[i]);
    }
  }
  this._listeners.push(listener);
}
function _removeListener(listener: Object): Boolean {
  var i: int = this._listeners.indexOf(listener);
  if (i < 0) {
    return false;
  }
  this._listeners.splice(i, 1);
  return true;
}

Fix AVM1 event broadcaster to correctly pass on arguments to listeners

Using `Array.prototype.slice.call(arguments, 1)` didn't work at all, but `...args` does.


package aerys.minko.type
{
	import flash.events.IEventDispatcher;
	import flash.events.KeyboardEvent;

	public final class KeyboardManager
	{
		private var _keys	: Array	= [];

		public function KeyboardManager()
		{
		}

		public function bind(dispatcher : IEventDispatcher) : void
		{
			dispatcher.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
			dispatcher.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
		}

		public function unbind(dispatcher : IEventDispatcher) : void
		{
			dispatcher.removeEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
			dispatcher.removeEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
		}

		private function keyDownHandler(event : KeyboardEvent) : void
		{
			_keys[event.keyCode] = true;
		}

		private function keyUpHandler(event : KeyboardEvent) : void
		{
			_keys[event.keyCode] = false;
		}

		public function keyIsDown(keyCode : uint) : Boolean
		{
			return !!_keys[keyCode];
		}
	}
}

package aerys.minko.type
{
	import flash.events.IEventDispatcher;
	import flash.events.KeyboardEvent;

	public final class KeyboardManager
	{
		public static const NO_KEY	: uint		= uint(-1);

		private var _keys			: Array		= [];

		private var _downSignals	: Array		= [];
		private var _upSignals		: Array		= [];
		private var _keyDown		: Signal	= new Signal('KeyboardManager.keyDown');
		private var _keyUp			: Signal	= new Signal('KeyboardManager.keyDown');

		public function KeyboardManager()
		{
		}

		public function bind(dispatcher : IEventDispatcher) : void
		{
			dispatcher.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
			dispatcher.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
		}

		public function unbind(dispatcher : IEventDispatcher) : void
		{
			dispatcher.removeEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
			dispatcher.removeEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
		}

		public function keyDown(keyCode : uint = 0xffffffff) : Signal
		{
			if (keyCode == NO_KEY)
				return _keyDown;
			else
				return _downSignals[keyCode] || (_downSignals[keyCode] = new Signal('KeyDown[' + keyCode + ']'));
		}

		public function keyUp(keyCode : uint = 0xffffffff) : Signal
		{
			if (keyCode == NO_KEY)
				return _keyUp;
			else
				return _upSignals[keyCode] || (_upSignals[keyCode] = new Signal('KeyUp[' + keyCode + ']'));
		}

		private function keyDownHandler(event : KeyboardEvent) : void
		{
			var keyCode : uint		= event.keyCode;
			var signal 	: Signal 	= _downSignals[keyCode] as Signal;

			_keys[keyCode] = true;

			if (signal != null)
				signal.execute(this, keyCode);
		}

		private function keyUpHandler(event : KeyboardEvent) : void
		{
			var keyCode : uint		= event.keyCode;
			var signal 	: Signal 	= _upSignals[keyCode] as Signal;

			_keys[keyCode] = false;

			if (signal != null)
				signal.execute(this, keyCode);
		}

		public function keyIsDown(keyCode : uint) : Boolean
		{
			return !!_keys[keyCode];
		}
	}
}

add (per key) up/down signals to KeyboardManager


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

import mx.core.FlexGlobals;

import spark.utils.LabelUtil;

public final class LabelUtil
{
    public static function findLongestLabelItem(items:Array,
                                                labelField:String = null,
                                                labelFunction:Function = null):Object
    {
        var longestItem:Object;

        var currentItemWidth:Number;
        var longestItemLabelWidth:Number = 0;
        var currentItemLabel:String;

        for each (var item:Object in items)
        {
            currentItemLabel = itemToLabel(item, labelField, labelFunction);

            currentItemWidth =
                FlexGlobals.topLevelApplication.measureText(currentItemLabel).width;

            if (currentItemWidth > longestItemLabelWidth)
            {
                longestItemLabelWidth = currentItemWidth;
                longestItem = item;
            }
        }

        return longestItem;
    }

    private static function itemToLabel(item:Object,
                                        labelField:String = null,
                                        labelFunction:Function = null):String
    {
        return spark.utils.LabelUtil.itemToLabel(item, labelField, labelFunction);
    }
}
}

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

import mx.core.FlexGlobals;
import mx.utils.StringUtil;

import spark.utils.LabelUtil;

public final class LabelUtil
{
    public static function findLongestLabelItem(items:Array,
                                                labelField:String = null,
                                                labelFunction:Function = null):Object
    {
        var longestItem:Object;

        var currentItemWidth:Number;
        var longestItemLabelWidth:Number = 0;
        var currentItemLabel:String;

        for each (var item:Object in items)
        {
            currentItemLabel = itemToLabel(item, labelField, labelFunction);

            currentItemWidth =
                FlexGlobals.topLevelApplication.measureText(currentItemLabel).width;

            if (currentItemWidth > longestItemLabelWidth)
            {
                longestItemLabelWidth = currentItemWidth;
                longestItem = item;
            }
        }

        return longestItem;
    }

    private static function itemToLabel(item:Object,
                                        labelField:String = null,
                                        labelFunction:Function = null):String
    {
        return spark.utils.LabelUtil.itemToLabel(item, labelField, labelFunction);
    }

    public static function generateUniqueLabel(fileNameTemplate:String, usedNames:Array, isUniqueFunction:Function = null):String
    {
        var currentID:int = 1;
        var uniqueLabel:String;

        var uniquenessFunction:Function =
            isUniqueFunction != null ? isUniqueFunction : isNameUnique;

        do
        {
            uniqueLabel = StringUtil.substitute(fileNameTemplate, currentID++);
        } while (!uniquenessFunction(uniqueLabel, usedNames));

        return uniqueLabel;
    }

    private static function isNameUnique(name:String, usedNames:Array):Boolean
    {
        return usedNames.indexOf(name) == -1;
    }
}
}

Add utility to generate unique label.

Add utility to generate unique label.


			import flash.events.MouseEvent;
			import com.example.programmingas3.playlist.PlayList;
			import com.example.programmingas3.playlist.Song;
			import com.example.programmingas3.playlist.SortProperty;

			// constants for the different "states" of the song form
			private static const ADD_SONG:uint = 1;
			private static const SONG_DETAIL:uint = 2;

			private var playList:PlayList = new PlayList();

			private function initApp():void
			{
				// set the initial state of the song form, for adding a new song
				setFormState(ADD_SONG);

				// prepopulate the list with a few songs
				playList.addSong(new Song("Nessun Dorma", "Luciano Pavarotti", 1990, "nessundorma.mp3", ["90's", "Opera"]));
				playList.addSong(new Song("Come Undone", "Duran Duran", 1993, "comeundone.mp3", ["90's", "Pop"]));
				playList.addSong(new Song("Think of Me", "Sarah Brightman", 1987, "thinkofme.mp3", ["Showtunes"]));
				playList.addSong(new Song("Unbelievable", "EMF", 1991, "unbelievable.mp3", ["90's", "Pop"]));

				songList.dataProvider = playList.songList;
			}

			private function sortList(sortField:SortProperty):void
			{
				// Make all the sort type buttons enabled.
				// The active one will be grayed-out below
				sortByTitle.selected = false;
				sortByArtist.selected = false;
				sortByYear.selected = false;

				switch (sortField)
				{
					case SortProperty.TITLE:
						sortByTitle.selected = true;
						break;
					case SortProperty.ARTIST:
						sortByArtist.selected = true;
						break;
					case SortProperty.YEAR:
						sortByYear.selected = true;
						break;
				}

				playList.sortList(sortField);

				refreshList();
			}

			private function refreshList():void
			{
				// remember which song was selected
				var selectedSong:Song = Song(songList.selectedItem);

				// re-assign the song list as the dataprovider to get the newly sorted list
				// and force the List control to refresh itself
				songList.dataProvider = playList.songList;

				// reset the song selection
				if (selectedSong != null)
				{
					songList.selectedItem = selectedSong;
				}
			}

			private function songSelectionChange():void
			{
				if (songList.selectedIndex != -1)
				{
					setFormState(SONG_DETAIL);
				}
				else
				{
					setFormState(ADD_SONG);
				}
			}

			private function addNewSong():void
			{
				// gather the values from the form and add the new song
				var title:String = newSongTitle.text;
				var artist:String = newSongArtist.text;
				var year:uint = newSongYear.value;
				var filename:String = newSongFilename.text;
				var genres:Array = newSongGenres.selectedItems;

				playList.addSong(new Song(title, artist, year, filename, genres));

				refreshList();

				// clear out the "add song" form fields
				setFormState(ADD_SONG);
			}

			private function songListLabel(item:Object):String
			{
				return item.toString();
			}

			private function setFormState(state:uint):void
			{
				// set the form title and control state
				switch (state)
				{
					case ADD_SONG:
						formTitle.text = "Add New Song";
						// show the submit button
						submitSongData.visible = true;
						showAddControlsBtn.visible = false;
						// clear the form fields
						newSongTitle.text = "";
						newSongArtist.text = "";
						newSongYear.value = (new Date()).fullYear;
						newSongFilename.text = "";
						newSongGenres.selectedIndex = -1;
						// deselect the currently selected song (if any)
						songList.selectedIndex = -1;
						break;

					case SONG_DETAIL:
						formTitle.text = "Song Details";
						// populate the form with the selected item's data
						var selectedSong:Song = Song(songList.selectedItem);
						newSongTitle.text = selectedSong.title;
						newSongArtist.text = selectedSong.artist;
						newSongYear.value = selectedSong.year;
						newSongFilename.text = selectedSong.filename;
						newSongGenres.selectedItems = selectedSong.genres;
						// hide the submit button
						submitSongData.visible = false;
						showAddControlsBtn.visible = true;
						break;
				}
			}

			import flash.events.MouseEvent;
			import com.example.programmingas3.playlist.PlayList;
			import com.example.programmingas3.playlist.Song;
			import com.example.programmingas3.playlist.SortProperty;

			// constants for the different "states" of the song form
			private static const ADD_SONG:uint = 1;
			private static const SONG_DETAIL:uint = 2;

			private var playList:PlayList = new PlayList.<T>();

			private function initApp():void
			{
				// set the initial state of the song form, for adding a new song
				setFormState(ADD_SONG);

				// prepopulate the list with a few songs
				playList.addSong(new Song("Nessun Dorma", "Luciano Pavarotti", 1990, "nessundorma.mp3", ["90's", "Opera"]));
				playList.addSong(new Song("Come Undone", "Duran Duran", 1993, "comeundone.mp3", ["90's", "Pop"]));
				playList.addSong(new Song("Think of Me", "Sarah Brightman", 1987, "thinkofme.mp3", ["Showtunes"]));
				playList.addSong(new Song("Unbelievable", "EMF", 1991, "unbelievable.mp3", ["90's", "Pop"]));

				songList.dataProvider = playList.songList;
			}

			private function sortList(sortField:SortProperty.<T>):void
			{
				// Make all the sort type buttons enabled.
				// The active one will be grayed-out below
				sortByTitle.selected = false;
				sortByArtist.selected = false;
				sortByYear.selected = false;

				switch (sortField)
				{
					case SortProperty.TITLE:
						sortByTitle.selected = true;
						break;
					case SortProperty.ARTIST:
						sortByArtist.selected = true;
						break;
					case SortProperty.YEAR:
						sortByYear.selected = true;
						break;
				}

				playList.sortList(sortField);

				refreshList();
			}

			private function refreshList():void
			{
				// remember which song was selected
				var selectedSong:Song = Song(songList.selectedItem);

				// re-assign the song list as the dataprovider to get the newly sorted list
				// and force the List control to refresh itself
				songList.dataProvider = playList.songList;

				// reset the song selection
				if (selectedSong != null)
				{
					songList.selectedItem = selectedSong;
				}
			}

			private function songSelectionChange():void
			{
				if (songList.selectedIndex != -1)
				{
					setFormState(SONG_DETAIL);
				}
				else
				{
					setFormState(ADD_SONG);
				}
			}

			private function addNewSong():void
			{
				// gather the values from the form and add the new song
				var title:String = newSongTitle.text;
				var artist:String = newSongArtist.text;
				var year:uint = newSongYear.value;
				var filename:String = newSongFilename.text;
				var genres:Array = newSongGenres.selectedItems;

				playList.addSong(new Song(title, artist, year, filename, genres));

				refreshList();

				// clear out the "add song" form fields
				setFormState(ADD_SONG);
			}

			private function songListLabel(item:Object):String
			{
				return item.toString();
			}

			private function setFormState(state:uint):void
			{
				// set the form title and control state
				switch (state)
				{
					case ADD_SONG:
						formTitle.text = "Add New Song";
						// show the submit button
						submitSongData.visible = true;
						showAddControlsBtn.visible = false;
						// clear the form fields
						newSongTitle.text = "";
						newSongArtist.text = "";
						newSongYear.value = (new Date()).fullYear;
						newSongFilename.text = "";
						newSongGenres.selectedIndex = -1;
						// deselect the currently selected song (if any)
						songList.selectedIndex = -1;
						break;

					case SONG_DETAIL:
						formTitle.text = "Song Details";
						// populate the form with the selected item's data
						var selectedSong:Song = Song(songList.selectedItem);
						newSongTitle.text = selectedSong.title;
						newSongArtist.text = selectedSong.artist;
						newSongYear.value = selectedSong.year;
						newSongFilename.text = selectedSong.filename;
						newSongGenres.selectedItems = selectedSong.genres;
						// hide the submit button
						submitSongData.visible = false;
						showAddControlsBtn.visible = true;
						break;
				}
			}

Add type generics to AS3 test file.

Add type generics to AS3 test file.


/**
  * LFCApplication.as
  *
  * @copyright Copyright 2007, 2008, 2009 Laszlo Systems, Inc.  All Rights Reserved.
  *            Use is subject to license terms.
  *
  * @topic Kernel
  * @subtopic swf9
  * @author Henry Minsky <hminsky@laszlosystems.com>
  */

public class LFCApplication {

    // This serves as the superclass of DefaultApplication, currently that is where
    // the compiler puts top level code to run.

    #passthrough (toplevel:true) {
    import flash.display.DisplayObject;
    import flash.display.Sprite;
    import flash.display.Stage;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.events.FocusEvent;
    import flash.system.Capabilities;
    }#

    // The application sprite
    static public var _sprite:Sprite;

    public static function addChild(child:DisplayObject):DisplayObject {
       return _sprite.addChild(child);
    }

    public static function removeChild(child:DisplayObject):DisplayObject {
       return _sprite.removeChild(child);
    }

    public static function setChildIndex(child:DisplayObject, index:int):void {
        _sprite.setChildIndex(child, index);
    }

    // Allow anyone access to the stage object (see ctor below)
    public static var stage:Stage = null;

    // global tabEnabled flag for TextField
    public static var textfieldTabEnabled:Boolean = false;

    public function LFCApplication (sprite:Sprite) {
        LFCApplication._sprite = sprite;
        // wait for the ADDED_TO_STAGE event before continuing to init
        LFCApplication._sprite.addEventListener(Event.ADDED_TO_STAGE, initLFC);
    }

    private function initLFC(event:Event = null) :void {
        LFCApplication._sprite.removeEventListener(Event.ADDED_TO_STAGE, initLFC);
        // Allow anyone to access the stage object
        LFCApplication.stage = LFCApplication._sprite.stage;
        runToplevelDefinitions()

        if (Capabilities.playerType == "ActiveX") {
            // Workaround for ActiveX control swallowing browser focus events
            stage.addEventListener(Event.ACTIVATE, allKeysUp);

            // workaround for flash player bug FP-1355
            LFCApplication.textfieldTabEnabled = true;
            stage.addEventListener(FocusEvent.KEY_FOCUS_CHANGE, preventFocusChange);
        }

        // necessary for consistent behavior - in netscape browsers HTML is ignored
        stage.align = StageAlign.TOP_LEFT;
        stage.scaleMode = StageScaleMode.NO_SCALE;
        //Stage.align = ('canvassalign' in global && global.canvassalign != null) ? global.canvassalign : "LT";
        //Stage.scaleMode = ('canvasscale' in global && global.canvasscale != null) ? global.canvasscale : "noScale";

        // Register for callbacks from the kernel
        LzMouseKernel.setCallback(lz.ModeManager, 'rawMouseEvent');
        LzMouseKernel.initCursor();

        LzKeyboardKernel.setCallback(lz.Keys, '__keyEvent');
    }

    private function allKeysUp(event:Event):void {
        lz.Keys.__allKeysUp('flash activate');
    }

    private function preventFocusChange(event:FocusEvent):void {
        if (event.keyCode == 9) {
            event.preventDefault();
        }
    }

    public function runToplevelDefinitions() {
        // overridden by swf9 script compiler
    }

}

// Resource library
// contains {ptype, class, frames, width, height}
// ptype is one of "ar" (app relative) or "sr" (system relative)
var LzResourceLibrary :Object = {};

/**
  * LFCApplication.as
  *
  * @copyright Copyright 2007, 2008, 2009 Laszlo Systems, Inc.  All Rights Reserved.
  *            Use is subject to license terms.
  *
  * @topic Kernel
  * @subtopic swf9
  * @author Henry Minsky <hminsky@laszlosystems.com>
  */

public class LFCApplication {

    // This serves as the superclass of DefaultApplication, currently that is where
    // the compiler puts top level code to run.

    #passthrough (toplevel:true) {
    import flash.display.DisplayObject;
    import flash.display.Sprite;
    import flash.display.Stage;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.events.FocusEvent;
    import flash.system.Capabilities;
    }#

    // The application sprite
    static public var _sprite:Sprite;

    public static function addChild(child:DisplayObject):DisplayObject {
       return _sprite.addChild(child);
    }

    public static function removeChild(child:DisplayObject):DisplayObject {
       return _sprite.removeChild(child);
    }

    public static function setChildIndex(child:DisplayObject, index:int):void {
        _sprite.setChildIndex(child, index);
    }

    // Allow anyone access to the stage object (see ctor below)
    public static var stage:Stage = null;

    // global tabEnabled flag for TextField
    public static var textfieldTabEnabled:Boolean = false;

    public function LFCApplication (sprite:Sprite) {
        LFCApplication._sprite = sprite;
        // wait for the ADDED_TO_STAGE event before continuing to init
        LFCApplication._sprite.addEventListener(Event.ADDED_TO_STAGE, initLFC);
    }

    private function initLFC(event:Event = null) :void {
        LFCApplication._sprite.removeEventListener(Event.ADDED_TO_STAGE, initLFC);
        // Allow anyone to access the stage object
        LFCApplication.stage = LFCApplication._sprite.stage;
        runToplevelDefinitions()

        if (Capabilities.playerType == "ActiveX") {
            // Workaround for ActiveX control swallowing browser focus events
            stage.addEventListener(Event.ACTIVATE, allKeysUp);

            // workaround for flash player bug FP-1355
            LFCApplication.textfieldTabEnabled = true;
            stage.addEventListener(FocusEvent.KEY_FOCUS_CHANGE, preventFocusChange);
        }

        // necessary for consistent behavior - in netscape browsers HTML is ignored
        stage.align = StageAlign.TOP_LEFT;
        stage.scaleMode = StageScaleMode.NO_SCALE;
        //Stage.align = ('canvassalign' in global && global.canvassalign != null) ? global.canvassalign : "LT";
        //Stage.scaleMode = ('canvasscale' in global && global.canvasscale != null) ? global.canvasscale : "noScale";

        // Register for callbacks from the kernel
        LzMouseKernel.setCallback(lz.ModeManager, 'rawMouseEvent');
        LzMouseKernel.initCursor();

        LzKeyboardKernel.setCallback(lz.Keys, '__keyEvent');
    }

    private function allKeysUp(event:Event):void {
        lz.Keys.__allKeysUp();
    }

    private function preventFocusChange(event:FocusEvent):void {
        if (event.keyCode == 9) {
            event.preventDefault();
        }
    }

    public function runToplevelDefinitions() {
        // overridden by swf9 script compiler
    }

}

// Resource library
// contains {ptype, class, frames, width, height}
// ptype is one of "ar" (app relative) or "sr" (system relative)
var LzResourceLibrary :Object = {};

Change 20090901-hqm-5 by hqm@badtzmaru.home on 2009-09-01 11:49:48 EDT
    in /Users/hqm/openlaszlo/trunk-clean
    for http://svn.openlaszlo.org/openlaszlo/trunk

Summary:  fix for swf10 error when using context menu

New Features:

Bugs Fixed: LPP-8438

Technical Reviewer: max
QA Reviewer: andre
Doc Reviewer: (pending)

Documentation:

Release Notes:

Details:

+ remove extra arg from call to LzKeysService.__allKeysUp

Tests:

In Windows IE7, no longer get runtime error when showing context menu in app

git-svn-id: d62bde4b5aa582fdf07c8d403e53e0399a7ed285@14640 fa20e4f9-1d0a-0410-b5f3-dc9c16b8b17c


package
{
  import flash.external.ExternalInterface;
  import flash.display.*;
  import flash.events.*;
  import flash.geom.Rectangle;
  import flash.media.StageVideoAvailability;
  import flash.media.StageVideo;
  import flash.media.SoundTransform;
  import flash.media.Video;
  import flash.net.NetConnection;
  import flash.net.NetStream;
  import flash.system.Security;
  import flash.utils.Timer;
  import flash.utils.setTimeout;

  public class Player extends MovieClip {
    private var _video:Video;
    private var _stageVideo:StageVideo;
    private var _ns:NetStream;
    private var _nc:NetConnection;
    private var totalTime:Number;
    private var playbackId:String;
    private var playbackState:String;
    private var videoVolumeTransform:SoundTransform;
    private var isOnStageVideo:Boolean = false;
    private var heartbeat:Timer = new Timer(500);
    private var source:String;

    public function Player() {
      Security.allowDomain('*');
      Security.allowInsecureDomain('*');
      playbackId = LoaderInfo(this.root.loaderInfo).parameters.playbackId;
      playbackState = "IDLE";
      _video = new Video();
      setupCallbacks();
      setTimeout(flashReady, 50);
    }
    private function flashReady(): void {
      _triggerEvent('flashready');
      setupStage();
    }
    private function onConnectionStatus(e:NetStatusEvent):void {
      if (e.info.code == "NetConnection.Connect.Success"){
        setupNetStream();
      }
    }
    private function setupNetStream():void {
      videoVolumeTransform = new SoundTransform();
      videoVolumeTransform.volume = 1;
      createNetStream();
      _stageVideo.attachNetStream(_ns);
      _ns.play(source);
    }
    private function createNetStream():void {
      _ns = new NetStream(_nc);
      _ns.client = this;
      _ns.soundTransform = videoVolumeTransform;
      _ns.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
      _ns.bufferTime = 10;
      _ns.inBufferSeek = true;
      _ns.maxPauseBufferTime = 3600;
      _ns.backBufferTime = 3600;
    }
    private function setupStage():void {
      stage.scaleMode = StageScaleMode.NO_SCALE;
      stage.align = StageAlign.TOP_LEFT;
      stage.fullScreenSourceRect = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
      stage.displayState = StageDisplayState.NORMAL;
      stage.addEventListener(StageVideoAvailabilityEvent.STAGE_VIDEO_AVAILABILITY, _onStageVideoAvailability);
      stage.addEventListener(Event.RESIZE, _onResize);
    }
    private function setupNetConnection():void {
      _nc = new NetConnection();
      _nc.client = this;
      _nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
      _nc.addEventListener(NetStatusEvent.NET_STATUS, onConnectionStatus);
      _nc.connect(null);
    }
    private function setupCallbacks():void {
      ExternalInterface.addCallback("setVideoSize", setVideoSize);
      ExternalInterface.addCallback("playerPlay", playerPlay);
      ExternalInterface.addCallback("playerPause", playerPause);
      ExternalInterface.addCallback("playerStop", playerStop);
      ExternalInterface.addCallback("playerSeek", playerSeek);
      ExternalInterface.addCallback("playerVolume", playerVolume);
      ExternalInterface.addCallback("playerResume", playerResume);
      ExternalInterface.addCallback("getState", getState);
      ExternalInterface.addCallback("getPosition", getPosition);
      ExternalInterface.addCallback("getDuration", getDuration);
      ExternalInterface.addCallback("getBytesLoaded", getBytesLoaded);
      ExternalInterface.addCallback("getBytesTotal", getBytesTotal);
    }
    private function getBytesTotal():Number {
      return _ns.bytesTotal;
    }
    private function getBytesLoaded():Number {
      return _ns.bytesLoaded;
    }
    private function netStatusHandler(event:NetStatusEvent):void {
      if (event.info.code === "NetStream.Buffer.Full") {
        playbackState = "PLAYING";
        _ns.bufferTime = 15;
      } else if (isBuffering(event.info.code)) {
        playbackState = "PLAYING_BUFFERING";
      } else if (event.info.code == "NetStream.Video.DimensionChange") {
        setVideoSize(stage.stageWidth, stage.stageHeight);
      } else if (event.info.code == "NetStream.Play.Stop") {
        playbackState = "ENDED";
        heartbeat.stop();
      } else if (event.info.code == "NetStream.Buffer.Empty") {
        _ns.bufferTime = 5;
      }
      _triggerEvent('statechanged');
    }
    private function isBuffering(code:String):Boolean {
      return Boolean(code == "NetStream.Buffer.Empty" && playbackState != "ENDED" ||
                     code == "NetStream.SeekStart.Notify" ||
                     code == "NetStream.Play.Start");
    }
    private function _onResize(event:Event):void {
      setVideoSize(stage.stageWidth, stage.stageHeight);
    }
    private function onHeartbeat( event:TimerEvent ):void {
      _triggerEvent('progress');
      _triggerEvent('timeupdate');
    }
    private function playerPlay(url:String):void {
      source = url;
      setupNetConnection();
      heartbeat.addEventListener( TimerEvent.TIMER, onHeartbeat );
      heartbeat.start();
    }
    private function playerPause():void {
      _ns.pause();
      if (_ns.bytesLoaded == _ns.bytesTotal) {
        heartbeat.stop();
      }
      playbackState = "PAUSED";
    }
    private function playerStop():void {
      _ns.pause();
      _ns.seek(0);
      heartbeat.stop();
      playbackState = "IDLE";
    }
    private function playerSeek(position:Number):void {
      _ns.seek(position);
    }
    private function playerResume():void {
      playbackState = "PLAYING";
      _ns.resume();
      heartbeat.start();
    }
    private function playerVolume(level:Number):void {
      videoVolumeTransform.volume = level/100;
      _ns.soundTransform = videoVolumeTransform;
    }
    private function getState():String {
      return playbackState;
    }
    private function getPosition():Number {
      return _ns.time;
    }
    private function getDuration():Number {
      return totalTime;
    }
    private function setVideoSize(width:Number, height:Number):void {
      stage.fullScreenSourceRect = new Rectangle(0, 0, width, height);
      var rect:Rectangle = new Rectangle(0,0, width, height);// resizeRectangle(stage.stageWidth, stage.stageHeight, width, height);
      _video.width = rect.width;
      _video.height = rect.height;
      _video.x = rect.x;
      _video.y = rect.y;
      if (isOnStageVideo) {
        _stageVideo.viewPort = rect;
      }
    }
    public static function resizeRectangle(videoWidth : Number, videoHeight : Number, containerWidth : Number, containerHeight : Number) : Rectangle {
      var rect : Rectangle = new Rectangle();
      var xscale : Number = containerWidth / videoWidth;
      var yscale : Number = containerHeight / videoHeight;
      if (xscale >= yscale) {
          rect.width = Math.min(videoWidth * yscale, containerWidth);
          rect.height = videoHeight * yscale;
      } else {
          rect.width = Math.min(videoWidth * xscale, containerWidth);
          rect.height = videoHeight * xscale;
      }
      rect.width = Math.ceil(rect.width);
      rect.height = Math.ceil(rect.height);
      rect.x = Math.round((containerWidth - rect.width) / 2);
      rect.y = Math.round((containerHeight - rect.height) / 2);
      return rect;
    }
    private function _triggerEvent(name: String):void {
      ExternalInterface.call('Clappr.Mediator.trigger("' + playbackId + ':' + name +'")');
    }
    private function _enableStageVideo():void {
      if (_stageVideo == null) {
        _stageVideo = stage.stageVideos[0];
        _stageVideo.viewPort = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
      }
      if (_video.parent) {
          removeChild(_video);
      }
      _stageVideo.attachNetStream(_ns);
    }
    private function _disableStageVideo():void {
      _video.attachNetStream(_ns);
      _video.smoothing = true;
      addChild(_video);
    }
    private function _onStageVideoAvailability(evt:StageVideoAvailabilityEvent):void {
      if (evt.availability && stage.stageVideos.length > 0) {
        _enableStageVideo();
        isOnStageVideo = true;
      } else {
        _disableStageVideo();
      }
    }
    public function onMetaData(info:Object):void {
      totalTime = info.duration;
      _triggerEvent('timeupdate');
      receivedMeta(info);
    }
    public function receivedMeta(data:Object):void {
        setVideoSize(stage.stageWidth, stage.stageHeight);
    }
    public function onBWDone(...rest):void {
        setVideoSize(stage.stageWidth, stage.stageHeight);
    }
    public function asyncErrorHandler(event:AsyncErrorEvent):void {
    }
    public function onFCSubscribe(info:Object):void {
    }
    public function cuePointHandler(infoObject:Object):void {
    }
    public function onFI(infoObject:Object):void {
    }
	public function onPlayStatus(infoObject:Object):void {
	}
  }
}

package
{
  import flash.external.ExternalInterface;
  import flash.display.*;
  import flash.events.*;
  import flash.geom.Rectangle;
  import flash.media.StageVideoAvailability;
  import flash.media.StageVideo;
  import flash.media.SoundTransform;
  import flash.media.Video;
  import flash.net.NetConnection;
  import flash.net.NetStream;
  import flash.system.Security;
  import flash.utils.Timer;
  import flash.utils.setTimeout;

  public class Player extends MovieClip {
    private var _video:Video;
    private var _stageVideo:StageVideo;
    private var _ns:NetStream;
    private var _nc:NetConnection;
    private var totalTime:Number;
    private var playbackId:String;
    private var playbackState:String;
    private var videoVolumeTransform:SoundTransform;
    private var isOnStageVideo:Boolean = false;
    private var heartbeat:Timer = new Timer(500);
    private var source:String;

    public function Player() {
      Security.allowDomain('*');
      Security.allowInsecureDomain('*');
      playbackId = LoaderInfo(this.root.loaderInfo).parameters.playbackId;
      playbackState = "IDLE";
      _video = new Video();
      setupCallbacks();
      setupStage();
    }
    private function flashReady(): void {
      _triggerEvent('flashready');
    }
    private function onConnectionStatus(e:NetStatusEvent):void {
      if (e.info.code == "NetConnection.Connect.Success"){
        setupNetStream();
      }
    }
    private function setupNetStream():void {
      videoVolumeTransform = new SoundTransform();
      videoVolumeTransform.volume = 1;
      createNetStream();
      _stageVideo.attachNetStream(_ns);
      _ns.play(source);
    }
    private function createNetStream():void {
      _ns = new NetStream(_nc);
      _ns.client = this;
      _ns.soundTransform = videoVolumeTransform;
      _ns.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
      _ns.bufferTime = 10;
      _ns.inBufferSeek = true;
      _ns.maxPauseBufferTime = 3600;
      _ns.backBufferTime = 3600;
    }
    private function setupStage():void {
      stage.scaleMode = StageScaleMode.NO_SCALE;
      stage.align = StageAlign.TOP_LEFT;
      stage.fullScreenSourceRect = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
      stage.displayState = StageDisplayState.NORMAL;
      stage.addEventListener(StageVideoAvailabilityEvent.STAGE_VIDEO_AVAILABILITY, _onStageVideoAvailability);
      stage.addEventListener(Event.RESIZE, _onResize);
    }
    private function setupNetConnection():void {
      _nc = new NetConnection();
      _nc.client = this;
      _nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
      _nc.addEventListener(NetStatusEvent.NET_STATUS, onConnectionStatus);
      _nc.connect(null);
    }
    private function setupCallbacks():void {
      ExternalInterface.addCallback("setVideoSize", setVideoSize);
      ExternalInterface.addCallback("playerPlay", playerPlay);
      ExternalInterface.addCallback("playerPause", playerPause);
      ExternalInterface.addCallback("playerStop", playerStop);
      ExternalInterface.addCallback("playerSeek", playerSeek);
      ExternalInterface.addCallback("playerVolume", playerVolume);
      ExternalInterface.addCallback("playerResume", playerResume);
      ExternalInterface.addCallback("getState", getState);
      ExternalInterface.addCallback("getPosition", getPosition);
      ExternalInterface.addCallback("getDuration", getDuration);
      ExternalInterface.addCallback("getBytesLoaded", getBytesLoaded);
      ExternalInterface.addCallback("getBytesTotal", getBytesTotal);
    }
    private function getBytesTotal():Number {
      return _ns.bytesTotal;
    }
    private function getBytesLoaded():Number {
      return _ns.bytesLoaded;
    }
    private function netStatusHandler(event:NetStatusEvent):void {
      if (event.info.code === "NetStream.Buffer.Full") {
        playbackState = "PLAYING";
        _ns.bufferTime = 15;
      } else if (isBuffering(event.info.code)) {
        playbackState = "PLAYING_BUFFERING";
      } else if (event.info.code == "NetStream.Video.DimensionChange") {
        setVideoSize(stage.stageWidth, stage.stageHeight);
      } else if (event.info.code == "NetStream.Play.Stop") {
        playbackState = "ENDED";
        heartbeat.stop();
      } else if (event.info.code == "NetStream.Buffer.Empty") {
        _ns.bufferTime = 5;
      }
      _triggerEvent('statechanged');
    }
    private function isBuffering(code:String):Boolean {
      return Boolean(code == "NetStream.Buffer.Empty" && playbackState != "ENDED" ||
                     code == "NetStream.SeekStart.Notify" ||
                     code == "NetStream.Play.Start");
    }
    private function _onResize(event:Event):void {
      setVideoSize(stage.stageWidth, stage.stageHeight);
    }
    private function onHeartbeat( event:TimerEvent ):void {
      _triggerEvent('progress');
      _triggerEvent('timeupdate');
    }
    private function playerPlay(url:String):void {
      source = url;
      setupNetConnection();
      heartbeat.addEventListener( TimerEvent.TIMER, onHeartbeat );
      heartbeat.start();
    }
    private function playerPause():void {
      _ns.pause();
      if (_ns.bytesLoaded == _ns.bytesTotal) {
        heartbeat.stop();
      }
      playbackState = "PAUSED";
    }
    private function playerStop():void {
      _ns.pause();
      _ns.seek(0);
      heartbeat.stop();
      playbackState = "IDLE";
    }
    private function playerSeek(position:Number):void {
      _ns.seek(position);
    }
    private function playerResume():void {
      playbackState = "PLAYING";
      _ns.resume();
      heartbeat.start();
    }
    private function playerVolume(level:Number):void {
      videoVolumeTransform.volume = level/100;
      _ns.soundTransform = videoVolumeTransform;
    }
    private function getState():String {
      return playbackState;
    }
    private function getPosition():Number {
      return _ns.time;
    }
    private function getDuration():Number {
      return totalTime;
    }
    private function setVideoSize(width:Number, height:Number):void {
      stage.fullScreenSourceRect = new Rectangle(0, 0, width, height);
      var rect:Rectangle = new Rectangle(0,0, width, height);// resizeRectangle(stage.stageWidth, stage.stageHeight, width, height);
      _video.width = rect.width;
      _video.height = rect.height;
      _video.x = rect.x;
      _video.y = rect.y;
      if (isOnStageVideo) {
        _stageVideo.viewPort = rect;
      }
    }
    public static function resizeRectangle(videoWidth : Number, videoHeight : Number, containerWidth : Number, containerHeight : Number) : Rectangle {
      var rect : Rectangle = new Rectangle();
      var xscale : Number = containerWidth / videoWidth;
      var yscale : Number = containerHeight / videoHeight;
      if (xscale >= yscale) {
          rect.width = Math.min(videoWidth * yscale, containerWidth);
          rect.height = videoHeight * yscale;
      } else {
          rect.width = Math.min(videoWidth * xscale, containerWidth);
          rect.height = videoHeight * xscale;
      }
      rect.width = Math.ceil(rect.width);
      rect.height = Math.ceil(rect.height);
      rect.x = Math.round((containerWidth - rect.width) / 2);
      rect.y = Math.round((containerHeight - rect.height) / 2);
      return rect;
    }
    private function _triggerEvent(name: String):void {
      ExternalInterface.call('Clappr.Mediator.trigger("' + playbackId + ':' + name +'")');
    }
    private function _enableStageVideo():void {
      if (_stageVideo == null) {
        _stageVideo = stage.stageVideos[0];
        _stageVideo.viewPort = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
      }
      if (_video.parent) {
          removeChild(_video);
      }
      _stageVideo.attachNetStream(_ns);
    }
    private function _disableStageVideo():void {
      _video.attachNetStream(_ns);
      _video.smoothing = true;
      addChild(_video);
    }
    private function _onStageVideoAvailability(evt:StageVideoAvailabilityEvent):void {
      if (evt.availability && stage.stageVideos.length > 0) {
        _enableStageVideo();
        isOnStageVideo = true;
      } else {
        _disableStageVideo();
      }
      flashReady();
    }
    public function onMetaData(info:Object):void {
      totalTime = info.duration;
      _triggerEvent('timeupdate');
      receivedMeta(info);
    }
    public function receivedMeta(data:Object):void {
        setVideoSize(stage.stageWidth, stage.stageHeight);
    }
    public function onBWDone(...rest):void {
        setVideoSize(stage.stageWidth, stage.stageHeight);
    }
    public function asyncErrorHandler(event:AsyncErrorEvent):void {
    }
    public function onFCSubscribe(info:Object):void {
    }
    public function cuePointHandler(infoObject:Object):void {
    }
    public function onFI(infoObject:Object):void {
    }
	public function onPlayStatus(infoObject:Object):void {
	}
  }
}

flash: call setupStage() before flashReady() (fixes #320)


package flash.media {
  import Object;
  import flash.utils.ByteArray;
  import flash.media.SoundTransform;
  public final class SoundMixer {
    public function SoundMixer() {}
    public static native function stopAll():void;
    public static native function computeSpectrum(outputArray:ByteArray, FFTMode:Boolean = false, stretchFactor:int = 0):void;
    public static native function get bufferTime():int;
    public static native function set bufferTime(bufferTime:int):void;
    public static native function get soundTransform():SoundTransform;
    public static native function set soundTransform(sndTransform:SoundTransform):void;
    public static native function areSoundsInaccessible():Boolean;
    public static native function get audioPlaybackMode():String;
    public static native function set audioPlaybackMode(value:String):void;
    public static native function get useSpeakerphoneForVoice():Boolean;
    public static native function set useSpeakerphoneForVoice(value:Boolean):void;
  }
}

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

package flash.media {
import flash.utils.ByteArray;

[native(cls='SoundMixerClass')]
public final class SoundMixer {
  public static native function get bufferTime():int;

  public static native function set bufferTime(bufferTime:int):void;

  public static native function get soundTransform():SoundTransform;

  public static native function set soundTransform(sndTransform:SoundTransform):void;

  public static native function get audioPlaybackMode():String;

  public static native function set audioPlaybackMode(value:String):void;

  public static native function get useSpeakerphoneForVoice():Boolean;

  public static native function set useSpeakerphoneForVoice(value:Boolean):void;

  public static native function stopAll():void;

  public static native function computeSpectrum(outputArray:ByteArray, FFTMode:Boolean = false, stretchFactor:int = 0):void;

  public static native function areSoundsInaccessible():Boolean;

  public function SoundMixer() {}
}
}

Implement as3 part of SoundMixer

Implement as3 part of SoundMixer


package dolly {

import dolly.core.dolly_internal;
import dolly.core.errors.CloningError;
import dolly.core.metadata.MetadataName;

import org.as3commons.reflect.Accessor;
import org.as3commons.reflect.AccessorAccess;
import org.as3commons.reflect.Field;
import org.as3commons.reflect.Type;

use namespace dolly_internal;

public class Cloner {

	private static function isTypeCloneable(type:Type):Boolean {
		return type.hasMetadata(MetadataName.CLONEABLE);
	}

	dolly_internal static function findAllWritableFieldsForType(type:Type):Vector.<Field> {
		const result:Vector.<Field> = new Vector.<Field>();

		for each(var field:Field in type.properties) {
			if (!(field is Accessor) || (field as Accessor).access == AccessorAccess.READ_WRITE) {
				result.push(field);
			}
		}

		return result;
	}

	public static function clone(source:*):* {
		const type:Type = Type.forInstance(source);

		if (!isTypeCloneable(type)) {
			throw new CloningError(
					CloningError.CLASS_IS_NOT_CLONEABLE_MESSAGE,
					CloningError.CLASS_IS_NOT_CLONEABLE_CODE
			);
		}

		const clone:* = new (type.clazz)();

		// Find all public writable fields in a hierarchy of a source object
		// and assign their values to a clone object.
		const fieldsToClone:Vector.<Field> = findAllWritableFieldsForType(type);
		var name:String;
		for each(var field:Field in fieldsToClone) {
			name = field.name;
			clone[name] = source[name];
		}

		return clone;
	}
}
}

package dolly {

import dolly.core.dolly_internal;
import dolly.core.errors.CloningError;
import dolly.core.metadata.MetadataName;

import org.as3commons.reflect.Accessor;
import org.as3commons.reflect.AccessorAccess;
import org.as3commons.reflect.Field;
import org.as3commons.reflect.Type;

use namespace dolly_internal;

public class Cloner {

	private static function isTypeCloneable(type:Type):Boolean {
		return type.hasMetadata(MetadataName.CLONEABLE);
	}

	dolly_internal static function findAllWritableFieldsForType(type:Type):Vector.<Field> {
		const result:Vector.<Field> = new Vector.<Field>();

		for each(var field:Field in type.properties) {
			if (!(field is Accessor) || (field as Accessor).access == AccessorAccess.READ_WRITE) {
				result.push(field);
			}
		}

		return result;
	}

	public static function clone(source:*):* {
		const type:Type = Type.forInstance(source);

		if (!isTypeCloneable(type)) {
			throw new CloningError(
					CloningError.CLASS_IS_NOT_CLONEABLE_MESSAGE,
					CloningError.CLASS_IS_NOT_CLONEABLE_CODE
			);
		}

		const clonedInstance:* = new (type.clazz)();

		// Find all public writable fields in a hierarchy of a source object
		// and assign their values to a clone object.
		const fieldsToClone:Vector.<Field> = findAllWritableFieldsForType(type);
		var name:String;
		for each(var field:Field in fieldsToClone) {
			name = field.name;
			clonedInstance[name] = source[name];
		}

		return clonedInstance;
	}
}
}

Rename local variable in method Cloner.clone().