package im.siver.logger.controllers {

    import flash.display.BitmapData;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.MouseEvent;
    import flash.geom.Rectangle;

    import im.siver.logger.models.Constants;
    import im.siver.logger.utils.LoggerUtils;
    import im.siver.logger.views.components.Filter;
    import im.siver.logger.views.components.panels.TracePanel;
    import im.siver.logger.views.components.windows.SnapshotWindow;
    import im.siver.logger.views.components.windows.TraceWindow;

    import mx.collections.ArrayCollection;
    import mx.events.CollectionEvent;
    import mx.events.FlexEvent;
    import mx.events.ListEvent;
    import mx.utils.StringUtil;

    public final class TraceController extends EventDispatcher {

        [Bindable]
        private var _dataFilterd:ArrayCollection = new ArrayCollection();

        private var _data:ArrayCollection = new ArrayCollection();
        private var _panel:TracePanel;
        private var _send:Function;

        /**
         * Save panel
         */
        public function TraceController(panel:TracePanel, send:Function) {
            _panel = panel;
            _send = send;
            _panel.addEventListener(FlexEvent.CREATION_COMPLETE, creationComplete, false, 0, true);
        }

        private function collectionDidChange(e:CollectionEvent):void {
            if (_panel.autoScrollButton.selected) {
                _panel.datagrid.validateNow();
                _panel.datagrid.verticalScrollPosition = _panel.datagrid.maxVerticalScrollPosition;
            }
        }

        /**
         * Panel is ready to link data providers
         */
        private function creationComplete(e:FlexEvent):void {
            _panel.removeEventListener(FlexEvent.CREATION_COMPLETE, creationComplete);
            _panel.datagrid.dataProvider = _dataFilterd;
            _panel.datagrid.addEventListener(ListEvent.ITEM_DOUBLE_CLICK, showTrace, false, 0, true);
            _panel.filter.addEventListener(Filter.CHANGED, filterChanged, false, 0, true);
            _panel.clearButton.addEventListener(MouseEvent.CLICK, clear, false, 0, true);
            _dataFilterd.addEventListener(CollectionEvent.COLLECTION_CHANGE, collectionDidChange, false, 0, true);
        }

        /**
         * Show a trace in an output window
         */
        private function filterChanged(event:Event):void {
            // Check if a filter term is given
            if (_panel.filter.words.length == 0) {
                _dataFilterd.filterFunction = null;
                _dataFilterd.refresh();
            } else {
                _dataFilterd.filterFunction = checkFilter;
                _dataFilterd.refresh();
            }
        }

        private function addItem(item:Object):void {
            _dataFilterd.addItem(item);
        }

        private function simpleFilter(item:Object):Boolean {
            return false;
        }

        /**
         * Loop through the search terms and compare strings
         */
        private function checkFilter(item:Object):Boolean {
            var message:String = item.message;
            var target:String = item.target;
            var label:String = item.label;
            var person:String = item.person;
            if (message == null) message = "";
            if (target == null) target = "";
            if (label == null) label = "";
            if (person == null) person = "";
            message = StringUtil.trim(message).toLowerCase();
            target = StringUtil.trim(target).toLowerCase();
            label = StringUtil.trim(label).toLowerCase();
            person = StringUtil.trim(person).toLowerCase();
            var i:int;

            // Clone words
            var words:Array = [];
            for (i = 0; i < _panel.filter.words.length; i++) {
                words[i] = _panel.filter.words[i];
            }

            if (message != "") {
                for (i = 0; i < words.length; i++) {
                    if (message.indexOf(words[i]) != -1) {
                        words.splice(i, 1);
                        i--;
                    }
                }
            }
            if (words.length == 0) return true;
            if (target != "") {
                for (i = 0; i < words.length; i++) {
                    if (target.indexOf(words[i]) != -1) {
                        words.splice(i, 1);
                        i--;
                    }
                }
            }
            if (words.length == 0) return true;
            if (label != "") {
                for (i = 0; i < words.length; i++) {
                    if (label.indexOf(words[i]) != -1) {
                        words.splice(i, 1);
                        i--;
                    }
                }
            }
            if (words.length == 0) return true;
            if (person != "") {
                for (i = 0; i < words.length; i++) {
                    if (person.indexOf(words[i]) != -1) {
                        words.splice(i, 1);
                        i--;
                    }
                }
            }
            if (words.length == 0) return true;
            return false;
        }

        /**
         * Show a trace in an output window
         */
        private function showTrace(event:ListEvent):void {
            // Check if the selected item is still available
            if (event.currentTarget.selectedItem != null) {

                // Get the data
                var item:Object = _dataFilterd.getItemAt(event.currentTarget.selectedIndex);

                // Check the window to open
                if (item.message == "Snapshot" && item.xml == null) {
                    var snapshotWindow:SnapshotWindow = new SnapshotWindow();
                    snapshotWindow.setData(item);
                    snapshotWindow.open();
                } else {
                    var traceWindow:TraceWindow = new TraceWindow();
                    traceWindow.setData(item);
                    traceWindow.open();
                }
            }
        }

        /**
         * Clear traces
         */
        public function clear(event:MouseEvent = null):void {
            _data.removeAll();
            _dataFilterd.removeAll();
            _panel.datagrid.horizontalScrollPosition = 0;
        }

        /**
         * Data handler from client
         */
        public function setData(data:Object):void {
            // Vars for loop
            var date:Date;
            var hours:String;
            var minutes:String;
            var seconds:String;
            var miliseconds:String;
            var time:String;
            var memory:String;
            var traceItem:Object;

            switch (data["command"]) {

                case Constants.COMMAND_CLEAR_TRACES:
                    clear();
                    break;

                case Constants.COMMAND_TRACE:

                    // Format the properties
                    date = data["date"];
                    time = zeroPad(date.getHours(), 2) + ":" + zeroPad(date.getMinutes(), 2) + ":" + zeroPad(date.getSeconds(), 2) + "." + zeroPad(date.getMilliseconds(), 3);
                    memory = Math.round(data["memory"] / 1024) + " Kb";

                    // Create the trace object
                    traceItem = {};

                    // Check the label
                    if (data["xml"]..node.length() > 1 && data["xml"]..node.length() <= 3) {
                        if (data["xml"].node[0].@type == Constants.TYPE_STRING || data["xml"].node[0].@type == Constants.TYPE_BOOLEAN || data["xml"].node[0].@type == Constants.TYPE_NUMBER || data["xml"].node[0].@type == Constants.TYPE_INT || data["xml"].node[0].@type == Constants.TYPE_UINT) {
                            traceItem.message = LoggerUtils.stripBreaks(LoggerUtils.htmlUnescape(data["xml"].node.children()[0].@label));
                        } else {
                            traceItem.message = LoggerUtils.stripBreaks(LoggerUtils.htmlUnescape(data["xml"].node.@label)) + " ...";
                        }
                    } else {
                        traceItem.message = LoggerUtils.stripBreaks(LoggerUtils.htmlUnescape(data["xml"].node.@label)) + " ...";
                    }

                    // Clean target
                    if (data['target'].indexOf('object') != -1) {
                        traceItem.target = String(data['target']).replace('object ', '');
                    } else {
                        traceItem.target = data["target"];
                    }

                    // Add extra info
                    traceItem.line = _data.length + 1;
                    traceItem.time = time;
                    traceItem.memory = memory;
                    traceItem.reference = data["reference"];
                    traceItem.label = data["label"];
                    traceItem.person = data["person"];
                    traceItem.color = data["color"];
                    traceItem.xml = data["xml"];

                    // Add to list
                    _data.addItem(traceItem);
                    addItem(traceItem);
                    break;

                case Constants.COMMAND_SNAPSHOT:

                    // Format the properties
                    date = data["date"];
                    hours = (date.getHours() < 10) ? "0" + date.getHours().toString() : date.getHours().toString();
                    minutes = (date.getMinutes() < 10) ? "0" + date.getMinutes().toString() : date.getMinutes().toString();
                    seconds = (date.getSeconds() < 10) ? "0" + date.getSeconds().toString() : date.getSeconds().toString();
                    miliseconds = date.getMilliseconds().toString();
                    time = hours + ":" + minutes + ":" + seconds + "." + miliseconds;
                    memory = Math.round(data["memory"] / 1024) + " Kb";

                    // Read the bitmap
                    try {
                        var bitmapData:BitmapData = new BitmapData(data["width"], data["height"]);
                        bitmapData.setPixels(new Rectangle(0, 0, data["width"], data["height"]), data["bytes"]);
                    } catch (e:Error) {
                        return;
                    }

                    // Create the trace object
                    traceItem = {};
                    traceItem.line = _data.length + 1;
                    traceItem.time = time;
                    traceItem.memory = memory;
                    traceItem.width = data["width"];
                    traceItem.height = data["height"];
                    traceItem.bitmapData = bitmapData;
                    traceItem.message = "Snapshot";
                    traceItem.target = data["target"];
                    traceItem.label = data["label"];
                    traceItem.person = data["person"];
                    traceItem.color = data["color"];
                    traceItem.xml = null;

                    // Add to list
                    _data.addItem(traceItem);
                    addItem(traceItem);
                    break;
            }
        }

        private function zeroPad(value:int, length:int, pad:String = '0'):String {
            var result:String = String(value);
            while (result.length < length) {
                result = pad + result;
            }
            return result;
        }
    }
}

package im.siver.logger.controllers {

    import flash.display.BitmapData;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.MouseEvent;
    import flash.geom.Rectangle;

    import im.siver.logger.models.Constants;
    import im.siver.logger.utils.LoggerUtils;
    import im.siver.logger.views.components.Filter;
    import im.siver.logger.views.components.panels.TracePanel;
    import im.siver.logger.views.components.windows.SnapshotWindow;
    import im.siver.logger.views.components.windows.TraceWindow;

    import mx.collections.ArrayCollection;
    import mx.events.CollectionEvent;
    import mx.events.FlexEvent;
    import mx.events.ListEvent;
    import mx.utils.StringUtil;

    public final class TraceController extends EventDispatcher {

        [Bindable]
        private var _dataFiltered:ArrayCollection = new ArrayCollection();

        private var _data:ArrayCollection = new ArrayCollection();
        private var _panel:TracePanel;
        private var _send:Function;

        /**
         * Save panel
         */
        public function TraceController(panel:TracePanel, send:Function) {
            _panel = panel;
            _send = send;
            _panel.addEventListener(FlexEvent.CREATION_COMPLETE, creationComplete, false, 0, true);
        }

        private function collectionDidChange(e:CollectionEvent):void {
            if (_panel.autoScrollButton.selected) {
                _panel.datagrid.validateNow();
                _panel.datagrid.verticalScrollPosition = _panel.datagrid.maxVerticalScrollPosition;
            }
        }

        /**
         * Panel is ready to link data providers
         */
        private function creationComplete(e:FlexEvent):void {
            _panel.removeEventListener(FlexEvent.CREATION_COMPLETE, creationComplete);
            _panel.datagrid.dataProvider = _dataFiltered;
            _panel.datagrid.addEventListener(ListEvent.ITEM_DOUBLE_CLICK, showTrace, false, 0, true);
            _panel.filter.addEventListener(Filter.CHANGED, filterChanged, false, 0, true);
            _panel.clearButton.addEventListener(MouseEvent.CLICK, clear, false, 0, true);
            _dataFiltered.addEventListener(CollectionEvent.COLLECTION_CHANGE, collectionDidChange, false, 0, true);
        }

        /**
         * Show a trace in an output window
         */
        private function filterChanged(event:Event):void {
            // Check if a filter term is given
            if (_panel.filter.words.length == 0) {
                _dataFiltered.filterFunction = null;
                _dataFiltered.refresh();
            } else {
                _dataFiltered.filterFunction = fullFilter;
                _dataFiltered.refresh();
            }
        }

        /**
         * Look through targets and messages
         * @param item data-provider item
         * @return true if item has been found
         */
        private function fullFilter(item:Object):Boolean {
            var message:String = item.message;
            var target:String = item.target;
            var i:int, words:Array = _panel.filter.words, len:int = words.length;

            if (target != null) {
                target = target.toLowerCase();
                for (i = 0; i < len; ++i) {
                    if (target.indexOf(words[i]) != -1) {
                        return true;
                    }
                }
            }

            if (message != null) {
                message = message.toLowerCase();
                for (i = 0; i < len; ++i) {
                    if (message.indexOf(words[i]) != -1) {
                        return true;
                    }
                }
            }
            return false;
        }

        /**
         * Show a trace in an output window
         */
        private function showTrace(event:ListEvent):void {
            // Check if the selected item is still available
            if (event.currentTarget.selectedItem != null) {

                // Get the data
                var item:Object = _dataFiltered.getItemAt(event.currentTarget.selectedIndex);

                // Check the window to open
                if (item.message == "Snapshot" && item.xml == null) {
                    var snapshotWindow:SnapshotWindow = new SnapshotWindow();
                    snapshotWindow.setData(item);
                    snapshotWindow.open();
                } else {
                    var traceWindow:TraceWindow = new TraceWindow();
                    traceWindow.setData(item);
                    traceWindow.open();
                }
            }
        }

        /**
         * Clear traces
         */
        public function clear(event:MouseEvent = null):void {
            _data.removeAll();
            _dataFiltered.removeAll();
            _panel.datagrid.horizontalScrollPosition = 0;
        }

        /**
         * Data handler from client
         */
        public function setData(data:Object):void {
            // Vars for loop
            var date:Date;
            var hours:String;
            var minutes:String;
            var seconds:String;
            var miliseconds:String;
            var time:String;
            var memory:String;
            var traceItem:Object;

            switch (data["command"]) {

                case Constants.COMMAND_CLEAR_TRACES:
                    clear();
                    break;

                case Constants.COMMAND_TRACE:

                    // Format the properties
                    date = data["date"];
                    time = zeroPad(date.getHours(), 2) + ":" + zeroPad(date.getMinutes(), 2) + ":" + zeroPad(date.getSeconds(), 2) + "." + zeroPad(date.getMilliseconds(), 3);
                    memory = Math.round(data["memory"] / 1024) + " Kb";

                    // Create the trace object
                    traceItem = {};

                    // Check the label
                    if (data["xml"]..node.length() > 1 && data["xml"]..node.length() <= 3) {
                        if (data["xml"].node[0].@type == Constants.TYPE_STRING || data["xml"].node[0].@type == Constants.TYPE_BOOLEAN || data["xml"].node[0].@type == Constants.TYPE_NUMBER || data["xml"].node[0].@type == Constants.TYPE_INT || data["xml"].node[0].@type == Constants.TYPE_UINT) {
                            traceItem.message = LoggerUtils.stripBreaks(LoggerUtils.htmlUnescape(data["xml"].node.children()[0].@label));
                        } else {
                            traceItem.message = LoggerUtils.stripBreaks(LoggerUtils.htmlUnescape(data["xml"].node.@label)) + " ...";
                        }
                    } else {
                        traceItem.message = LoggerUtils.stripBreaks(LoggerUtils.htmlUnescape(data["xml"].node.@label)) + " ...";
                    }

                    // Clean target
                    if (data['target'].indexOf('object') != -1) {
                        traceItem.target = String(data['target']).replace('object ', '');
                    } else {
                        traceItem.target = data["target"];
                    }

                    // Add extra info
                    traceItem.line = _data.length + 1;
                    traceItem.time = time;
                    traceItem.memory = memory;
                    traceItem.reference = data["reference"];
                    traceItem.label = data["label"];
                    traceItem.person = data["person"];
                    traceItem.color = data["color"];
                    traceItem.xml = data["xml"];

                    // Add to list
                    _data.addItem(traceItem);
                    _dataFiltered.addItem(traceItem);
                    break;

                case Constants.COMMAND_SNAPSHOT:

                    // Format the properties
                    date = data["date"];
                    hours = (date.getHours() < 10) ? "0" + date.getHours().toString() : date.getHours().toString();
                    minutes = (date.getMinutes() < 10) ? "0" + date.getMinutes().toString() : date.getMinutes().toString();
                    seconds = (date.getSeconds() < 10) ? "0" + date.getSeconds().toString() : date.getSeconds().toString();
                    miliseconds = date.getMilliseconds().toString();
                    time = hours + ":" + minutes + ":" + seconds + "." + miliseconds;
                    memory = Math.round(data["memory"] / 1024) + " Kb";

                    // Read the bitmap
                    try {
                        var bitmapData:BitmapData = new BitmapData(data["width"], data["height"]);
                        bitmapData.setPixels(new Rectangle(0, 0, data["width"], data["height"]), data["bytes"]);
                    } catch (e:Error) {
                        return;
                    }

                    // Create the trace object
                    traceItem = {};
                    traceItem.line = _data.length + 1;
                    traceItem.time = time;
                    traceItem.memory = memory;
                    traceItem.width = data["width"];
                    traceItem.height = data["height"];
                    traceItem.bitmapData = bitmapData;
                    traceItem.message = "Snapshot";
                    traceItem.target = data["target"];
                    traceItem.label = data["label"];
                    traceItem.person = data["person"];
                    traceItem.color = data["color"];
                    traceItem.xml = null;

                    // Add to list
                    _data.addItem(traceItem);
                    _dataFiltered.addItem(traceItem);
                    break;
            }
        }

        private function zeroPad(value:int, length:int, pad:String = '0'):String {
            var result:String = String(value);
            while (result.length < length) {
                result = pad + result;
            }
            return result;
        }
    }
}

Improve filtering

Improve filtering


// Editor debug icons

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

Node@ debugIconsNode = null;

int stepDebugIconsUpdate = 40; //ms
int timeToNextDebugIconsUpdate = 0;
const int splinePathResolution = 16;
bool debugIconsShow = true;
Vector2 debugIconsSize = Vector2(0.025, 0.025);
Vector2 debugIconsSizeSmall = debugIconsSize / 2.0;

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

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

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

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

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

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

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

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

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

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

}

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

    if (editorScene is null) return;

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

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

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

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

    Vector3 camPos = cameraNode.worldPosition;

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

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

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

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

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

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

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

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

        }
    }

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

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

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

                bb.enabled = true;
            }

            debugIconsSetCameras.Commit();
        }
    }

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

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

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

            debugIconsSetSoundSources.Commit();
        }
    }

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

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

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

            debugIconsSetSoundSources3D.Commit();
        }
    }

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

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

            debugIconsSetSoundListeners.Commit();
        }
    }

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

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

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

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

            debugIconsSetZones.Commit();
        }
    }

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

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

        if (nodes.length > 0)
        {
            debugIconsSetSplinesPoints.numBillboards = nodes.length * splinePathResolution;

            float splineStep = 1.0f / splinePathResolution;

            for(int i=0; i < nodes.length; i++)
            {

                SplinePath@ sp = nodes[i].GetComponent("SplinePath");
                if(sp !is null)
                {
                    Vector3 splinePoint;
                    // Create path
                    for(int step=0; step < splinePathResolution; step++)
                    {
                        splinePoint = sp.GetPoint(splineStep * step);

                        float distance = (camPos - splinePoint).length;
                        int index = (i * splinePathResolution) + step;
                        Billboard@ bb = debugIconsSetSplinesPoints.billboards[index];
                        bb.position = splinePoint;
                        bb.size = debugIconsSizeSmall * distance;

                        if (step == 0)
                        {
                            bb.color = Color(1,1,0);
                            bb.size = debugIconsSize * distance;
                        }
                        else if ((step+1) >= (splinePathResolution - splineStep))
                        {
                            bb.color = Color(0,1,0);
                            bb.size = debugIconsSize * distance;
                        }
                        else
                        {
                            bb.color = Color(1,1,1);
                            bb.size = debugIconsSizeSmall * distance;
                        }
                        bb.enabled = sp.enabled;
                    }
                }
            }

            debugIconsSetSplinesPoints.Commit();
        }
    }

    timeToNextDebugIconsUpdate = time.systemTime + stepDebugIconsUpdate;
}

// Editor debug icons

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

Node@ debugIconsNode = null;

int stepDebugIconsUpdate = 60; //ms
int timeToNextDebugIconsUpdate = 0;

int stepDebugIconsUpdateSplinePath = 500; //ms
int timeToNextDebugIconsUpdateSplinePath = 0;

const int splinePathResolution = 16;
bool debugIconsShow = true;
Vector2 debugIconsSize = Vector2(0.025, 0.025);
Vector2 debugIconsSizeSmall = debugIconsSize / 2.0;

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

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

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

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

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

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

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

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

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

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

}

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

    if (editorScene is null) return;

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

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

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

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

    Vector3 camPos = cameraNode.worldPosition;

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

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

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

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

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

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

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

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

        }
    }

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

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

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

                bb.enabled = true;
            }

            debugIconsSetCameras.Commit();
        }
    }

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

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

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

            debugIconsSetSoundSources.Commit();
        }
    }

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

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

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

            debugIconsSetSoundSources3D.Commit();
        }
    }

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

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

            debugIconsSetSoundListeners.Commit();
        }
    }

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

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

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

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

            debugIconsSetZones.Commit();
        }
    }

    if (timeToNextDebugIconsUpdateSplinePath < time.systemTime)
    {
        if (debugIconsSetSplinesPoints !is null)
        {
            debugIconsSetSplinesPoints.enabled = debugIconsShow;

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

            if (nodes.length > 0)
            {
                debugIconsSetSplinesPoints.numBillboards = nodes.length * splinePathResolution;

                float splineStep = 1.0f / splinePathResolution;

                for(int i=0; i < nodes.length; i++)
                {

                    SplinePath@ sp = nodes[i].GetComponent("SplinePath");
                    if(sp !is null)
                    {
                        Vector3 splinePoint;
                        // Create path
                        for(int step=0; step < splinePathResolution; step++)
                        {
                            splinePoint = sp.GetPoint(splineStep * step);

                            float distance = (camPos - splinePoint).length;
                            int index = (i * splinePathResolution) + step;
                            Billboard@ bb = debugIconsSetSplinesPoints.billboards[index];
                            bb.position = splinePoint;
                            bb.size = debugIconsSizeSmall * distance;

                            if (step == 0)
                            {
                                bb.color = Color(1,1,0);
                                bb.size = debugIconsSize * distance;
                            }
                            else if ((step+1) >= (splinePathResolution - splineStep))
                            {
                                bb.color = Color(0,1,0);
                                bb.size = debugIconsSize * distance;
                            }
                            else
                            {
                                bb.color = Color(1,1,1);
                                bb.size = debugIconsSizeSmall * distance;
                            }
                            bb.enabled = sp.enabled;
                        }
                    }
                }

                debugIconsSetSplinesPoints.Commit();
            }
        }

        timeToNextDebugIconsUpdateSplinePath = time.systemTime + stepDebugIconsUpdateSplinePath;
    }

    timeToNextDebugIconsUpdate = time.systemTime + stepDebugIconsUpdate;
}

increase update time for splinepath

increase update time for splinepath


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

package com.freshplanet.ane.AirDeviceId {

import com.freshplanet.ane.AirDeviceId.events.AirDeviceIdEvent;

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

	public class AirDeviceId extends EventDispatcher {

		// --------------------------------------------------------------------------------------//
		//																						 //
		// 									   PUBLIC API										 //
		// 																						 //
		// --------------------------------------------------------------------------------------//

		/** AirAlert is supported on iOS and Android devices. */
		public static function get isSupported() : Boolean {
			return isAndroid || isIOS;
		}

		/**
		 * AirDeviceId instance
		 * @return AirDeviceId instance
		 */
		public static function get instance() : AirDeviceId {
			return _instance ? _instance : new AirDeviceId();
		}

		/**
		 * Get device id
		 * @param salt a developer specific salt
		 */
		public function getID( salt:String ) : String {

			if (isSupported)
				return _context.call( 'getID', salt ) as String;

			return null;
		}

		/**
		 * Get vendor identifier
		 * @return
		 */
		public function getIDFV():String {

			if (isSupported)
				return _context.call( 'getIDFV' ) as String;

			return null;
		}

		/**
		 * Get advertising identifier
		 * @return
		 */
		public function getIDFA() : void {

			if ( isSupported )
				_context.call( 'getIDFA' );

		}

		// --------------------------------------------------------------------------------------//
		//																						 //
		// 									 	PRIVATE API										 //
		// 																						 //
		// --------------------------------------------------------------------------------------//

		private static const EXTENSION_ID : String = "com.freshplanet.ane.AirDeviceId";
		private static var _instance : AirDeviceId = null;
		private var _context : ExtensionContext = null;

		/**
		 * "private" singleton constructor
		 */
		public function AirDeviceId() {

			if ( !_instance ) {

				_context = ExtensionContext.createExtensionContext( EXTENSION_ID, null );

				if  (_context != null ) {
					_context.addEventListener( StatusEvent.STATUS, _onStatus );
				}
				else {
					trace('[AirDeviceId] Error - Extension Context is null.');
				}

				_instance = this;
			}
			else {
				throw Error( 'This is a singleton, use getInstance(), do not call the constructor directly.' );
			}
		}

		/**
		 * Status events allow the native part of the ANE to communicate with the ActionScript part.
		 * We use event.code to represent the type of event, and event.level to carry the data.
		 */
		private function _onStatus( event:StatusEvent ) : void {

			if ( event.code == AirDeviceIdEvent.RECEIVED_IDFA ) {
				this.dispatchEvent(new AirDeviceIdEvent(AirDeviceIdEvent.RECEIVED_IDFA, event.level));
			}
			else if ( event.code == "log" ) {
				trace( '[AirDeviceId] ' + event.level );
			}
		}

		private static function get isIOS():Boolean {
			return Capabilities.manufacturer.indexOf("iOS") > -1 && Capabilities.os.indexOf("x86_64") < 0 && Capabilities.os.indexOf("i386") < 0;
		}

		private static function get isAndroid():Boolean {
			return Capabilities.manufacturer.indexOf("Android") > -1;
		}
	}
}

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

package com.freshplanet.ane.AirDeviceId {

import com.freshplanet.ane.AirDeviceId.events.AirDeviceIdEvent;

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

	public class AirDeviceId extends EventDispatcher {

		// --------------------------------------------------------------------------------------//
		//																						 //
		// 									   PUBLIC API										 //
		// 																						 //
		// --------------------------------------------------------------------------------------//

		/** AirAlert is supported on iOS and Android devices. */
		public static function get isSupported() : Boolean {
			return isAndroid || isIOS;
		}

		/**
		 * AirDeviceId instance
		 * @return AirDeviceId instance
		 */
		public static function get instance() : AirDeviceId {
			return _instance ? _instance : new AirDeviceId();
		}

		/**
		 * Get vendor identifier
		 * @return
		 */
		public function getIDFV():String {

			if (isSupported)
				return _context.call( 'getIDFV' ) as String;

			return null;
		}

		/**
		 * Get advertising identifier
		 * @return
		 */
		public function getIDFA() : void {

			if ( isSupported )
				_context.call( 'getIDFA' );

		}

		// --------------------------------------------------------------------------------------//
		//																						 //
		// 									 	PRIVATE API										 //
		// 																						 //
		// --------------------------------------------------------------------------------------//

		private static const EXTENSION_ID : String = "com.freshplanet.ane.AirDeviceId";
		private static var _instance : AirDeviceId = null;
		private var _context : ExtensionContext = null;

		/**
		 * "private" singleton constructor
		 */
		public function AirDeviceId() {

			if ( !_instance ) {

				_context = ExtensionContext.createExtensionContext( EXTENSION_ID, null );

				if  (_context != null ) {
					_context.addEventListener( StatusEvent.STATUS, _onStatus );
				}
				else {
					trace('[AirDeviceId] Error - Extension Context is null.');
				}

				_instance = this;
			}
			else {
				throw Error( 'This is a singleton, use getInstance(), do not call the constructor directly.' );
			}
		}

		/**
		 * Status events allow the native part of the ANE to communicate with the ActionScript part.
		 * We use event.code to represent the type of event, and event.level to carry the data.
		 */
		private function _onStatus( event:StatusEvent ) : void {

			if ( event.code == AirDeviceIdEvent.RECEIVED_IDFA ) {
				this.dispatchEvent(new AirDeviceIdEvent(AirDeviceIdEvent.RECEIVED_IDFA, event.level));
			}
			else if ( event.code == "log" ) {
				trace( '[AirDeviceId] ' + event.level );
			}
		}

		private static function get isIOS():Boolean {
			return Capabilities.manufacturer.indexOf("iOS") > -1 && Capabilities.os.indexOf("x86_64") < 0 && Capabilities.os.indexOf("i386") < 0;
		}

		private static function get isAndroid():Boolean {
			return Capabilities.manufacturer.indexOf("Android") > -1;
		}
	}
}

remove getID() from AS3 side

remove getID() from AS3 side


package org.shypl.biser.csi.client {
	import flash.events.EventDispatcher;

	import org.shypl.biser.csi.Address;
	import org.shypl.biser.csi.ConnectionCloseReason;
	import org.shypl.common.lang.IllegalStateException;
	import org.shypl.common.logging.LogManager;
	import org.shypl.common.logging.Logger;
	import org.shypl.common.logging.PrefixedLoggerProxy;

	[Event(type="org.shypl.biser.csi.client.ClientEvent", name="clientConnected")]
	[Event(type="org.shypl.biser.csi.client.ClientEvent", name="clientConnectionInterrupted")]
	[Event(type="org.shypl.biser.csi.client.ClientEvent", name="clientConnectionEstablished")]
	[Event(type="org.shypl.biser.csi.client.ClientConnectFailEvent", name="clientConnectFail")]
	[Event(type="org.shypl.biser.csi.client.ClientDisconnectedEvent", name="clientDisconnected")]
	[Event(type="org.shypl.biser.csi.client.ClientDisconnectWarningEvent", name="clientDisconnectWarning")]
	public class Client extends EventDispatcher {
		private static const LOGGER:Logger = LogManager.getLogger(Client);

		private var _channelProvider:ChannelProvider;
		private var _api:Api;
		private var _logger:PrefixedLoggerProxy;

		private var _connecting:Boolean;
		private var _connected:Boolean;
		private var _connection:Connection;

		public function Client(channelProvider:ChannelProvider, api:Api) {
			_channelProvider = channelProvider;
			_api = api;

			_logger = new PrefixedLoggerProxy(LOGGER, "[" + _api.name + "] ");
		}

		internal function get channelProvider():ChannelProvider {
			return _channelProvider;
		}

		internal function get api():Api {
			return _api;
		}

		public function isConnecting():Boolean {
			return _connecting;
		}

		public function isConnected():Boolean {
			return _connected;
		}

		public function connect(address:Address, authorizationKey:String):void {
			if (isConnecting() || isConnected()) {
				throw new IllegalStateException();
			}

			_logger.info("Connecting to {}", address);
			_connecting = true;
			_connection = new Connection(this, address, authorizationKey);
			_api.setConnection(_connection);
		}

		public function disconnect():void {
			if (!isConnecting() && !isConnecting()) {
				throw new IllegalStateException();
			}
			_connecting = false;

			_logger.info("Disconnecting");
			_connection.close(ConnectionCloseReason.NONE);
		}

		internal function processConnected():void {
			_logger.info("Connected");
			_connecting = false;
			_connected = true;
			dispatchEvent(new ClientEvent(ClientEvent.CLIENT_CONNECTED));
		}

		internal function processDisconnected(reason:ConnectionCloseReason):void {
			_logger.info("Disconnected by reason {}", reason);

			_connecting = false;
			_connected = false;
			_connection = null;
			_api.setConnection(null);
			dispatchEvent(new ClientDisconnectedEvent(reason));
		}

		internal function processConnectFail(reason:Error):void {
			_logger.info("Connect failed by reason {}", reason);
			_connecting = false;
			_connected = false;
			dispatchEvent(new ClientConnectFailEvent(reason));
		}

		internal function processConnectionInterrupted():void {
			_logger.info("Connection is interrupted");
			dispatchEvent(new ClientEvent(ClientEvent.CLIENT_CONNECTION_INTERRUPTED));
		}

		internal function processConnectionEstablished():void {
			_logger.info("Connection is established");
			dispatchEvent(new ClientEvent(ClientEvent.CLIENT_CONNECTION_ESTABLISHED));
		}

		internal function processDisconnectWarning(timeout:int):void {
			_logger.info("warning to disconnect after {} seconds", timeout);
			dispatchEvent(new ClientDisconnectWarningEvent(timeout));
		}
	}
}

package org.shypl.biser.csi.client {
	import flash.events.EventDispatcher;

	import org.shypl.biser.csi.Address;
	import org.shypl.biser.csi.ConnectionCloseReason;
	import org.shypl.common.lang.IllegalStateException;
	import org.shypl.common.logging.LogManager;
	import org.shypl.common.logging.Logger;
	import org.shypl.common.logging.PrefixedLoggerProxy;

	[Event(type="org.shypl.biser.csi.client.ClientEvent", name="clientConnected")]
	[Event(type="org.shypl.biser.csi.client.ClientEvent", name="clientConnectionInterrupted")]
	[Event(type="org.shypl.biser.csi.client.ClientEvent", name="clientConnectionEstablished")]
	[Event(type="org.shypl.biser.csi.client.ClientConnectFailEvent", name="clientConnectFail")]
	[Event(type="org.shypl.biser.csi.client.ClientDisconnectedEvent", name="clientDisconnected")]
	[Event(type="org.shypl.biser.csi.client.ClientDisconnectWarningEvent", name="clientDisconnectWarning")]
	public class Client extends EventDispatcher {
		private static const LOGGER:Logger = LogManager.getLogger(Client);

		private var _channelProvider:ChannelProvider;
		private var _api:Api;
		private var _logger:PrefixedLoggerProxy;

		private var _connecting:Boolean;
		private var _connected:Boolean;
		private var _connection:Connection;

		public function Client(channelProvider:ChannelProvider, api:Api) {
			_channelProvider = channelProvider;
			_api = api;

			_logger = new PrefixedLoggerProxy(LOGGER, "[" + _api.name + "] ");
		}

		internal function get channelProvider():ChannelProvider {
			return _channelProvider;
		}

		internal function get api():Api {
			return _api;
		}

		public function isConnecting():Boolean {
			return _connecting;
		}

		public function isConnected():Boolean {
			return _connected;
		}

		public function connect(address:Address, authorizationKey:String):void {
			if (isConnecting() || isConnected()) {
				throw new IllegalStateException();
			}

			_logger.info("Connecting to {}", address);
			_connecting = true;
			_connection = new Connection(this, address, authorizationKey);
			_api.setConnection(_connection);
		}

		public function disconnect():void {
			if (!_connecting && !_connected) {
				throw new IllegalStateException();
			}
			_connecting = false;

			_logger.info("Disconnecting");
			_connection.close(ConnectionCloseReason.NONE);
		}

		internal function processConnected():void {
			_logger.info("Connected");
			_connecting = false;
			_connected = true;
			dispatchEvent(new ClientEvent(ClientEvent.CLIENT_CONNECTED));
		}

		internal function processDisconnected(reason:ConnectionCloseReason):void {
			_logger.info("Disconnected by reason {}", reason);

			_connecting = false;
			_connected = false;
			_connection = null;
			_api.setConnection(null);
			dispatchEvent(new ClientDisconnectedEvent(reason));
		}

		internal function processConnectFail(reason:Error):void {
			_logger.info("Connect failed by reason {}", reason);
			_connecting = false;
			_connected = false;
			dispatchEvent(new ClientConnectFailEvent(reason));
		}

		internal function processConnectionInterrupted():void {
			_logger.info("Connection is interrupted");
			dispatchEvent(new ClientEvent(ClientEvent.CLIENT_CONNECTION_INTERRUPTED));
		}

		internal function processConnectionEstablished():void {
			_logger.info("Connection is established");
			dispatchEvent(new ClientEvent(ClientEvent.CLIENT_CONNECTION_ESTABLISHED));
		}

		internal function processDisconnectWarning(timeout:int):void {
			_logger.info("warning to disconnect after {} seconds", timeout);
			dispatchEvent(new ClientDisconnectWarningEvent(timeout));
		}
	}
}

Fix client disconnect

Fix client disconnect


//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

package com.threerings.util {

import flash.display.DisplayObject;
import flash.display.Loader;
import flash.display.LoaderInfo;

import flash.errors.IllegalOperationError;

import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;

import flash.utils.ByteArray;

import flash.system.ApplicationDomain;
import flash.system.LoaderContext;

/**
 * Allows you to load an embeded SWF stored as a Byte Array then access any stored classes
 * within the SWF.
 * Embed your swf like:
 * [Embed(source="foo.swf", mimeType="application/octet-stream"]
 * Then, instantiate that class and pass it to load() as a ByteArray.
 *
 * An Event.COMPLETE will be dispatched upon the successful completion of a call to
 * {@link load}.  IOErrorEvent.IO_ERROR will be dispatched if there's a problem reading the
 * ByteArray.
 *
 * @deprecated Content packs are coming, and symbols can be embedded directly
 * by using [Embed(source="foo.swf#somesymbol")]
 */
public class EmbeddedSwfLoader extends EventDispatcher
{
    public function EmbeddedSwfLoader (useSubDomain :Boolean = false)
    {
        _useSubDomain = useSubDomain;
        _loader = new Loader();
        _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, dispatchEvent);
        _loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, dispatchEvent);
    }

// This doesn't work. We cannot write parameters to the contentLoaderInfo.
// So: there is no way to pass parameters to content loaded using loadBytes,
// and there's no way to pass parameters to any other content without
// destroying caching (because you must append them to the url). Stupid flash.
//    /**
//     * Set a parameter accessible to the loaded content.
//     */
//    public function setParameter (name :String, val :String) :void
//    {
//        _loader.contentLoaderInfo.parameters[name] = val;
//    }

    /**
     * Load the SWF from a Byte Array.  A CLASS_LOADED event will be dispatched on successful
     * completion of the load.  If any errors occur, a LOAD_ERROR event will be dispatched.
     */
    public function load (byteArray :ByteArray) :void
    {
        var context :LoaderContext = new LoaderContext();
        context.applicationDomain = _useSubDomain ?
            new ApplicationDomain(ApplicationDomain.currentDomain) :
            ApplicationDomain.currentDomain;
        _loader.loadBytes(byteArray, context);
    }

    /**
     * Get the top-level display object defined in the loaded SWF.
     */
    public function getContent () :DisplayObject
    {
        checkLoaded();
        return _loader.content;
    }

    /**
     * Retrieves a class definition from the loaded swf.
     *
     * @throws IllegalOperationError when the swf has not completed loading or the class does
     * not exist
     */
    public function getClass (className :String) :Class
    {
        return getSymbol(className) as Class;
    }

    /**
     * Retrieves a Function definition from the loaded swf.
     *
     * @throws IllegalOperationError when the swf has not completed loading or the class does
     * not exist
     */
    public function getFunction (functionName :String) :Function
    {
        return getSymbol(functionName) as Function;
    }

    /**
     * Retrieves a symbol definition from the loaded swf.
     *
     * @throws IllegalOperationError when the swf has not completed loading or the class does
     * not exist
     */
    public function getSymbol (symbolName :String) :Object
    {
        checkLoaded();
        try {
            return _loader.contentLoaderInfo.applicationDomain.getDefinition(symbolName);
        } catch (e: Error) {
            throw new IllegalOperationError(symbolName + " definition not found");
        }
        return null;
    }

    /**
     * Checks if a symbol exists in the library.
     *
     * @throws IllegalOperationError when the swf has not completed loading.
     */
    public function isSymbol (className :String) :Boolean
    {
        checkLoaded();
        return _loader.contentLoaderInfo.applicationDomain.hasDefinition(className);
    }

    /**
     * Validate that the load operation is complete.
     */
    protected function checkLoaded () :void
    {
        var loaderInfo :LoaderInfo = _loader.contentLoaderInfo;
        if (loaderInfo.bytesTotal == 0 || loaderInfo.bytesLoaded != loaderInfo.bytesTotal) {

            throw new IllegalOperationError("SWF has not completed loading");
        }
    }

    protected var _loader :Loader;
    protected var _useSubDomain :Boolean;
}
}

//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

package com.threerings.util {

import flash.display.DisplayObject;
import flash.display.Loader;
import flash.display.LoaderInfo;

import flash.errors.IllegalOperationError;

import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;

import flash.utils.ByteArray;

import flash.system.ApplicationDomain;
import flash.system.LoaderContext;

/**
 * Allows you to load an embeded SWF stored as a Byte Array then access any stored classes
 * within the SWF.
 * Embed your swf like:
 * [Embed(source="foo.swf", mimeType="application/octet-stream")]
 * Then, instantiate that class and pass it to load() as a ByteArray.
 *
 * An Event.COMPLETE will be dispatched upon the successful completion of a call to
 * {@link load}.  IOErrorEvent.IO_ERROR will be dispatched if there's a problem reading the
 * ByteArray.
 *
 * @deprecated Content packs are coming, and symbols can be embedded directly
 * by using [Embed(source="foo.swf#somesymbol")]
 */
public class EmbeddedSwfLoader extends EventDispatcher
{
    public function EmbeddedSwfLoader (useSubDomain :Boolean = false)
    {
        _useSubDomain = useSubDomain;
        _loader = new Loader();
        _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, dispatchEvent);
        _loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, dispatchEvent);
    }

// This doesn't work. We cannot write parameters to the contentLoaderInfo.
// So: there is no way to pass parameters to content loaded using loadBytes,
// and there's no way to pass parameters to any other content without
// destroying caching (because you must append them to the url). Stupid flash.
//    /**
//     * Set a parameter accessible to the loaded content.
//     */
//    public function setParameter (name :String, val :String) :void
//    {
//        _loader.contentLoaderInfo.parameters[name] = val;
//    }

    /**
     * Load the SWF from a Byte Array.  A CLASS_LOADED event will be dispatched on successful
     * completion of the load.  If any errors occur, a LOAD_ERROR event will be dispatched.
     */
    public function load (byteArray :ByteArray) :void
    {
        var context :LoaderContext = new LoaderContext();
        context.applicationDomain = _useSubDomain ?
            new ApplicationDomain(ApplicationDomain.currentDomain) :
            ApplicationDomain.currentDomain;
        _loader.loadBytes(byteArray, context);
    }

    /**
     * Get the top-level display object defined in the loaded SWF.
     */
    public function getContent () :DisplayObject
    {
        checkLoaded();
        return _loader.content;
    }

    /**
     * Retrieves a class definition from the loaded swf.
     *
     * @throws IllegalOperationError when the swf has not completed loading or the class does
     * not exist
     */
    public function getClass (className :String) :Class
    {
        return getSymbol(className) as Class;
    }

    /**
     * Retrieves a Function definition from the loaded swf.
     *
     * @throws IllegalOperationError when the swf has not completed loading or the class does
     * not exist
     */
    public function getFunction (functionName :String) :Function
    {
        return getSymbol(functionName) as Function;
    }

    /**
     * Retrieves a symbol definition from the loaded swf.
     *
     * @throws IllegalOperationError when the swf has not completed loading or the class does
     * not exist
     */
    public function getSymbol (symbolName :String) :Object
    {
        checkLoaded();
        try {
            return _loader.contentLoaderInfo.applicationDomain.getDefinition(symbolName);
        } catch (e: Error) {
            throw new IllegalOperationError(symbolName + " definition not found");
        }
        return null;
    }

    /**
     * Checks if a symbol exists in the library.
     *
     * @throws IllegalOperationError when the swf has not completed loading.
     */
    public function isSymbol (className :String) :Boolean
    {
        checkLoaded();
        return _loader.contentLoaderInfo.applicationDomain.hasDefinition(className);
    }

    /**
     * Validate that the load operation is complete.
     */
    protected function checkLoaded () :void
    {
        var loaderInfo :LoaderInfo = _loader.contentLoaderInfo;
        if (loaderInfo.bytesTotal == 0 || loaderInfo.bytesLoaded != loaderInfo.bytesTotal) {

            throw new IllegalOperationError("SWF has not completed loading");
        }
    }

    protected var _loader :Loader;
    protected var _useSubDomain :Boolean;
}
}

Comment fix.

Comment fix.

git-svn-id: a1a4b28b82a3276cc491891159dd9963a0a72fae@4716 542714f4-19e9-0310-aa3c-eee0fc999fb1


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

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

    COMPILE::JS
    {
        import goog.bind;
    }

    /**
     * @flexjsignoreimport goog.bind
     */
    COMPILE::JS
	public class Language
	{

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

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

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

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

			itIs = Language.is(leftOperand, rightOperand);

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

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

			return (itIs) ? leftOperand : null;
		}

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

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

			if (leftOperand == null)
				return false;

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

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

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

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

				return false;
			};

			if ((rightOperand === String && typeof(leftOperand) === 'string') ||
				(leftOperand instanceof (rightOperand)))
			{
				return true;
			}

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

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

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

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

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

			superClass = leftOperand.constructor;
            superClass = superClass.superClass_;

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

			return false;
		}

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

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

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

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

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

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

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

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

		static public function trace(...rest):void
		{
			var theConsole:*;
            var windowConsole:* = window.console;

			var msg:String = '';

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

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

			if (theConsole === undefined && windowConsole !== undefined)
				theConsole = windowConsole;

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

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

        /**
         * caches closures and returns the one closure
         *
         * @param fn The method on the instance.
         * @param object The instance.
         * @param boundMethodName The name to use to cache the closure.
         * @return The closure.
         */
        static public function closure(fn:Function, object:Object, boundMethodName:String):Function {
            if (object.hasOwnProperty(boundMethodName)) {
                return object[boundMethodName];
            }
            var boundMethod:Function = goog.bind(fn, object);
            Object.defineProperty(object, boundMethodName, {
                value: boundMethod
            });
            return boundMethod;
        };

	}
}

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

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

    COMPILE::JS
    {
        import goog.bind;
        import goog.global;
    }

    /**
     * @flexjsignoreimport goog.bind
     * @flexjsignoreimport goog.global
     */
    COMPILE::JS
	public class Language
	{

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

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

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

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

			itIs = Language.is(leftOperand, rightOperand);

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

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

			return (itIs) ? leftOperand : null;
		}

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

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

			if (leftOperand == null)
				return false;

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

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

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

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

				return false;
			};

			if ((rightOperand === String && typeof(leftOperand) === 'string') ||
				(leftOperand instanceof (rightOperand)))
			{
				return true;
			}

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

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

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

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

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

			superClass = leftOperand.constructor;
            superClass = superClass.superClass_;

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

			return false;
		}

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

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

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

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

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

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

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

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

		static public function trace(...rest):void
		{
			var theConsole:*;
            var windowConsole:* = window.console;

			var msg:String = '';

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

			theConsole = goog.global.console;

			if (theConsole === undefined && windowConsole !== undefined)
				theConsole = windowConsole;

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

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

        /**
         * caches closures and returns the one closure
         *
         * @param fn The method on the instance.
         * @param object The instance.
         * @param boundMethodName The name to use to cache the closure.
         * @return The closure.
         */
        static public function closure(fn:Function, object:Object, boundMethodName:String):Function {
            if (object.hasOwnProperty(boundMethodName)) {
                return object[boundMethodName];
            }
            var boundMethod:Function = goog.bind(fn, object);
            Object.defineProperty(object, boundMethodName, {
                value: boundMethod
            });
            return boundMethod;
        };

	}
}

fix trace

fix trace


package {

  class ClassA
  {
    public function ClassA()
    {
      trace('A');
    }
    protected function foo() : void
    {
      trace('a');
    }
    protected function bar() : void
    {
      trace('b');
    }
  }

  class ClassC extends ClassA
  {
    public function ClassC()
    {
      trace('> C');
      super();

      foo();
      bar();
      trace('< C');
    }

    override protected function bar() : void {
      super.bar();
      trace('override b');
    }
  }

  class ClassE extends ClassC
  {
    public function ClassE()
    {
      trace('> E');
      super();
      foo();
      bar();
      trace('< E');
    }

    override protected function bar() : void {
      super.bar();
      trace('override b again');
    }
  }

  // var c = new ClassC();
  // var e = new ClassE();

  class X {
    protected var
  }
  trace("--");
}

package {

  class ClassA
  {
    public function ClassA()
    {
      trace('A');
    }
    protected function foo() : void
    {
      trace('a');
    }
    protected function bar() : void
    {
      trace('b');
    }
  }

  class ClassC extends ClassA
  {
    public function ClassC()
    {
      trace('> C');
      super();

      foo();
      bar();
      trace('< C');
    }

    override protected function bar() : void {
      super.bar();
      trace('override b');
    }
  }

  class ClassE extends ClassC
  {
    public function ClassE()
    {
      trace('> E');
      super();
      foo();
      bar();
      trace('< E');
    }

    override protected function bar() : void {
      super.bar();
      trace('override b again');
    }
  }

  trace("--");
}

Fix call super test case.

Fix call super test case.


package
{
    import flash.media.Sound;
    import flash.media.SoundChannel;
    import flash.net.URLRequest;

    public class ImpetusSound
    {
        private var url:String;
        private var sound:Sound;

        private var channel:SoundChannel;

        public function ImpetusSound(url:String):void
        {
            this.url = url;
            this.sound = new Sound();

            this.sound.load(new URLRequest(url));

            this.channel = null;
        }

        public function getUrl():String
        {
            return this.url
        }

        public function play():void
        {
        }

        public function stop():void
        {
            this.channel.stop();

            this.channel = null;
        }

        public function setPos(pos:int):void
        {
        }

        public function getPos():int
        {
        }
    }
}

package
{
    import flash.media.Sound;
    import flash.media.SoundChannel;
    import flash.net.URLRequest;

    public class ImpetusSound
    {
        private var url:String;
        private var sound:Sound;

        private var channel:SoundChannel;

        public function ImpetusSound(url:String):void
        {
            this.url = url;
            this.sound = new Sound();

            this.sound.load(new URLRequest(url));

            this.channel = null;
        }

        public function getUrl():String
        {
            return this.url
        }

        public function play():void
        {
            if(this.channel != null)
            {
                this.channel.stop();
            }

            this.channel = sound.play(0);
        }

        public function stop():void
        {
            this.channel.stop();

            this.channel = null;
        }

        public function setPos(pos:int):void
        {
        }

        public function getPos():int
        {
        }
    }
}

Implement ImpetusSound::play()

Implement ImpetusSound::play()