//
// Flump - Copyright 2012 Three Rings Design

package flump.display {

import flump.mold.MovieMold;

import org.osflash.signals.Signal;

import starling.animation.IAnimatable;
import starling.display.DisplayObject;
import starling.display.Sprite;
import starling.events.Event;

/**
 * A movie created from flump-exported data. It has children corresponding to the layers in the
 * movie in Flash, in the same order and with the same names. It fills in those children
 * initially with the image or movie of the symbol on that exported layer. After the initial
 * population, it only applies the keyframe-based transformations to the child at the index
 * corresponding to the layer. This means it's safe to swap in other DisplayObjects at those
 * positions to have them animated in place of the initial child.
 *
 *
A Movie will not animate unless it's added to a Juggler (or its advanceTime() function
 * is otherwise called). When the movie is added to a juggler, it advances its playhead with the
 * frame ticks if isPlaying is true. It will automatically remove itself from its juggler when
 * removed from the stage.

 *
 * @see Library and LibraryLoader to create instances of Movie.
 */
public class Movie extends Sprite
    implements IAnimatable
{
    /** A label fired by all movies when entering their first frame. */
    public static const FIRST_FRAME :String = "flump.movie.FIRST_FRAME";

    /** A label fired by all movies when entering their last frame. */
    public static const LAST_FRAME :String = "flump.movie.LAST_FRAME";

    /** Fires the label string whenever it's passed in playing. */
    public const labelPassed :Signal = new Signal(String);

    /** @private */
    public function Movie (src :MovieMold, frameRate :Number, library :Library) {
        name = src.id;
        _labels = src.labels;
        _frameRate = frameRate;
        if (src.flipbook) {
            _layers = new Vector.<Layer>(1, true);
            _layers[0] = new Layer(this, src.layers[0], library, /*flipbook=*/true);
            _frames = src.layers[0].frames;
        } else {
            _layers = new Vector.<Layer>(src.layers.length, true);
            for (var ii :int = 0; ii < _layers.length; ii++) {
                _layers[ii] = new Layer(this, src.layers[ii], library, /*flipbook=*/false);
                _frames = Math.max(src.layers[ii].frames, _frames);
            }
        }
        _duration = _frames / _frameRate;
        updateFrame(0, /*fromSkip=*/true, /*overDuration=*/false);

        // When we're removed from the stage, remove ourselves from any juggler animating us.
        addEventListener(Event.REMOVED_FROM_STAGE, function (..._) :void {
            dispatchEventWith(Event.REMOVE_FROM_JUGGLER);
        });
    }

    /** @return the frame being displayed. */
    public function get frame () :int { return _frame; }

    /** @return the number of frames in the movie. */
    public function get frames () :int { return _frames; }

    /** @return true if the movie is currently playing. */
    public function get isPlaying () :Boolean { return _playing; }

    /** Starts playing if not already doing so, and continues to do so indefinitely.  */
    public function loop () :Movie {
        _playing = true;
        _stopFrame = NO_FRAME;
        return this;
    }

    /**
     * Moves to the given String label or int frame. Doesn't alter playing status or stop frame.
     * If there are labels at the given position, they're fired as part of the goto, even if the
     * current frame is equal to the destination. Labels between the current frame and the
     * destination frame are not fired.
     *
     * @param position the int frame or String label to goto.
     *
     * @return this movie for chaining
     *
     * @throws Error if position isn't an int or String, or if it is a String and that String isn't
     * a label on this movie
     */
    public function goto (position :Object) :Movie {
        const frame :int = extractFrame(position);
        updateFrame(frame, /*fromSkip=*/true, /*overDuration=*/false);
        return this;
    }

    /**
     * Starts playing if not already doing so, and continues to do so to the last frame in the
     * movie.
     */
    public function play () :Movie { return playTo(LAST_FRAME); }

   /**
    * Starts playing if not already doing so, and continues to do so to the given stop label or
    * frame.
    *
    * @param position to int frame or String label to stop at
    *
    * @return this movie for chaining
    *
    * @throws Error if position isn't an int or String, or if it is a String and that String isn't
    * a label on this movie.
    */
    public function playTo (position :Object) :Movie {
       _stopFrame = extractFrame(position);
       _playing = true;
       return this;
    }

    /** Stops playback if it's currently active. Doesn't alter the current frame or stop frame. */
    public function stop () :Movie {
        _playing = false;
        return this;
    }

    /** Advances the playhead by the give number of seconds. From IAnimatable. */
    public function advanceTime (dt :Number) :void {
        if (!_playing) return;

        _playTime += dt;
        var actualPlaytime :Number = _playTime;
        if (_playTime >= _duration) _playTime = _playTime % _duration;
        var newFrame :int = int(_playTime * _frameRate);
        const overDuration :Boolean = dt >= _duration;
        // If the update crosses or goes to the stopFrame, go to the stop frame, stop the movie and
        // clear it
        if (_stopFrame != NO_FRAME) {
            // how many frames remain to the stopframe?
            var framesRemaining :int =
                (_frame <= _stopFrame ? _stopFrame - _frame : _frames - _frame + _stopFrame);
            var framesElapsed :int = int(actualPlaytime * _frameRate) - _frame;
            if (framesElapsed >= framesRemaining) {
                _playing = false;
                newFrame = _stopFrame;
                _stopFrame = NO_FRAME;
            }
        }
        updateFrame(newFrame, false, overDuration);

        for (var ii :int = 0; ii < this.numChildren; ++ii) {
            var child :DisplayObject = getChildAt(ii);
            if (child is Movie) {
                Movie(child).advanceTime(dt);
            }
        }
    }

    /** @private */
    protected function extractFrame (position :Object) :int {
        if (position is int) return int(position);
        if (!(position is String)) throw new Error("Movie position must be an int frame or String label");
        const label :String = String(position);
        for (var ii :int = 0; ii < _labels.length; ii++) {
            if (_labels[ii] != null && _labels[ii].indexOf(label) != -1) return ii;
        }
        throw new Error("No such label '" + label + "'");
    }

    /** @private */
    protected function updateFrame (newFrame :int, fromSkip :Boolean, overDuration :Boolean) :void {
        if (newFrame >= _frames) {
            throw new Error("Asked to go to frame " + newFrame + " past the last frame, " +
                (_frames - 1));
        }
        if (_goingToFrame) {
            _pendingFrame = newFrame;
            return;
        }
        _goingToFrame = true;
        const differentFrame :Boolean = newFrame != _frame;
        const wrapped :Boolean = newFrame < _frame;
        if (differentFrame) {
            if (wrapped) {
                for each (var layer :Layer in _layers) {
                    layer.changedKeyframe = true;
                    layer.keyframeIdx = 0;
                }
            }
            for each (layer in _layers) layer.drawFrame(newFrame);
        }

        // Update the frame before firing, so if firing changes the frame, it sticks.
        const oldFrame :int = _frame;
        _frame = newFrame;
        if (fromSkip) {
            fireLabels(newFrame, newFrame);
            _playTime = newFrame/_frameRate;
        } else if (overDuration) {
            fireLabels(oldFrame + 1, _frames - 1);
            fireLabels(0, _frame);
        } else if (differentFrame) {
            if (wrapped) {
                fireLabels(oldFrame + 1, _frames - 1);
                fireLabels(0, _frame);
            } else fireLabels(oldFrame + 1, _frame);
        }
        _goingToFrame = false;
        if (_pendingFrame != NO_FRAME) {
            newFrame = _pendingFrame;
            _pendingFrame = NO_FRAME;
            updateFrame(newFrame, true, false);
        }

    }

    /** @private */
    protected function fireLabels (startFrame :int, endFrame :int) :void {
        for (var ii :int = startFrame; ii <= endFrame; ii++) {
            if (_labels[ii] == null) continue;
            for each (var label :String in _labels[ii]) labelPassed.dispatch(label);
        }
    }

    /** @private */
    protected var _goingToFrame :Boolean;
    /** @private */
    protected var _pendingFrame :int = NO_FRAME;
    /** @private */
    protected var _frame :int = NO_FRAME, _stopFrame :int = NO_FRAME;
    /** @private */
    protected var _playing :Boolean = true;
    /** @private */
    protected var _playTime :Number, _duration :Number;
    /** @private */
    protected var _layers :Vector.<Layer>;
    /** @private */
    protected var _frames :int;
    /** @private */
    protected var _frameRate :Number;
    /** @private */
    protected var _labels :Vector.<Vector.<String>>;

    private static const NO_FRAME :int = -1;
}
}

import flump.display.Library;
import flump.display.Movie;
import flump.mold.KeyframeMold;
import flump.mold.LayerMold;

import starling.display.DisplayObject;
import starling.display.Sprite;

class Layer {
    public var keyframeIdx :int ;// The index of the last keyframe drawn in drawFrame
    public var layerIdx :int;// This layer's index in the movie
    public var keyframes :Vector.<KeyframeMold>;
    // Only created if there are multiple items on this layer. If it does exist, the appropriate display is swapped in at keyframe changes. If it doesn't, the display is only added to the parent on layer creation
    public var displays :Vector.<DisplayObject>;// <SPDisplayObject*>
    public var movie :Movie; // The movie this layer belongs to
    // If the keyframe has changed since the last drawFrame
    public var changedKeyframe :Boolean;

    public function Layer (movie :Movie, src :LayerMold, library :Library, flipbook :Boolean) {
        keyframes = src.keyframes;
        this.movie = movie;
        var lastItem :String;
        for (var ii :int = 0; ii < keyframes.length && lastItem == null; ii++) {
            lastItem = keyframes[ii].ref;
        }
        if (!flipbook && lastItem == null) movie.addChild(new Sprite());// Label only layer
        else {
            var multipleItems :Boolean = flipbook;
            for (ii = 0; ii < keyframes.length && !multipleItems; ii++) {
                multipleItems = keyframes[ii].ref != lastItem;
            }
            if (!multipleItems) movie.addChild(library.createDisplayObject(lastItem));
            else {
                displays = new <DisplayObject>[];
                for each (var kf :KeyframeMold in keyframes) {
                    var display :DisplayObject =
                        (kf.ref == null ? new Sprite() : library.createDisplayObject(kf.ref));
                    displays.push(display);
                    display.name = src.name;
                }
                movie.addChild(displays[0]);
            }
        }
        layerIdx = movie.numChildren - 1;
        movie.getChildAt(layerIdx).name = src.name;
    }

    public function drawFrame (frame :int) :void {
        while (keyframeIdx < keyframes.length - 1 && keyframes[keyframeIdx + 1].index <= frame) {
            keyframeIdx++;
            changedKeyframe = true;
        }
        // We've got multiple items. Swap in the one for this kf
        if (changedKeyframe && displays != null) {
            movie.removeChildAt(layerIdx);
            movie.addChildAt(displays[keyframeIdx], layerIdx);
        }
        changedKeyframe = false;

        const kf :KeyframeMold = keyframes[keyframeIdx];
        const layer :DisplayObject = movie.getChildAt(layerIdx);
        if (keyframeIdx == keyframes.length - 1 || kf.index == frame) {
            layer.x = kf.x;
            layer.y = kf.y;
            layer.scaleX = kf.scaleX;
            layer.scaleY = kf.scaleY;
            layer.skewX = kf.skewX;
            layer.skewY = kf.skewY;
            layer.alpha = kf.alpha;
        } else {
            var interped :Number = (frame - kf.index)/kf.duration;
            var ease :Number = kf.ease;
            if (ease != 0) {
                var t :Number;
                if (ease < 0) {
                    // Ease in
                    var inv :Number = 1 - interped;
                    t = 1 - inv*inv;
                    ease = -ease;
                } else {
                    // Ease out
                    t = interped*interped;
                }
                interped = ease*t + (1 - ease)*interped;
            }

            const nextKf :KeyframeMold = keyframes[keyframeIdx + 1];
            layer.x = kf.x + (nextKf.x - kf.x) * interped;
            layer.y = kf.y + (nextKf.y - kf.y) * interped;
            layer.scaleX = kf.scaleX + (nextKf.scaleX - kf.scaleX) * interped;
            layer.scaleY = kf.scaleY + (nextKf.scaleY - kf.scaleY) * interped;
            layer.skewX = kf.skewX + (nextKf.skewX - kf.skewX) * interped;
            layer.skewY = kf.skewY + (nextKf.skewY - kf.skewY) * interped;
            layer.alpha = kf.alpha + (nextKf.alpha - kf.alpha) * interped;
        }

        layer.pivotX = kf.pivotX;
        layer.pivotY = kf.pivotY;
        layer.visible = kf.visible;
    }
}

//
// Flump - Copyright 2012 Three Rings Design

package flump.display {

import flump.mold.MovieMold;

import org.osflash.signals.Signal;

import starling.animation.IAnimatable;
import starling.display.DisplayObject;
import starling.display.Sprite;
import starling.events.Event;

/**
 * A movie created from flump-exported data. It has children corresponding to the layers in the
 * movie in Flash, in the same order and with the same names. It fills in those children
 * initially with the image or movie of the symbol on that exported layer. After the initial
 * population, it only applies the keyframe-based transformations to the child at the index
 * corresponding to the layer. This means it's safe to swap in other DisplayObjects at those
 * positions to have them animated in place of the initial child.
 *
 *
A Movie will not animate unless it's added to a Juggler (or its advanceTime() function
 * is otherwise called). When the movie is added to a juggler, it advances its playhead with the
 * frame ticks if isPlaying is true. It will automatically remove itself from its juggler when
 * removed from the stage.

 *
 * @see Library and LibraryLoader to create instances of Movie.
 */
public class Movie extends Sprite
    implements IAnimatable
{
    /** A label fired by all movies when entering their first frame. */
    public static const FIRST_FRAME :String = "flump.movie.FIRST_FRAME";

    /** A label fired by all movies when entering their last frame. */
    public static const LAST_FRAME :String = "flump.movie.LAST_FRAME";

    /** Fires the label string whenever it's passed in playing. */
    public const labelPassed :Signal = new Signal(String);

    /** @private */
    public function Movie (src :MovieMold, frameRate :Number, library :Library) {
        name = src.id;
        _labels = src.labels;
        _frameRate = frameRate;
        if (src.flipbook) {
            _layers = new Vector.<Layer>(1, true);
            _layers[0] = new Layer(this, src.layers[0], library, /*flipbook=*/true);
            _frames = src.layers[0].frames;
        } else {
            _layers = new Vector.<Layer>(src.layers.length, true);
            for (var ii :int = 0; ii < _layers.length; ii++) {
                _layers[ii] = new Layer(this, src.layers[ii], library, /*flipbook=*/false);
                _frames = Math.max(src.layers[ii].frames, _frames);
            }
        }
        _duration = _frames / _frameRate;
        updateFrame(0, /*fromSkip=*/true, /*overDuration=*/false);

        // When we're removed from the stage, remove ourselves from any juggler animating us.
        addEventListener(Event.REMOVED_FROM_STAGE, function (..._) :void {
            dispatchEventWith(Event.REMOVE_FROM_JUGGLER);
        });
    }

    /** @return the frame being displayed. */
    public function get frame () :int { return _frame; }

    /** @return the number of frames in the movie. */
    public function get frames () :int { return _frames; }

    /** @return true if the movie is currently playing. */
    public function get isPlaying () :Boolean { return _playing; }

    /** Starts playing if not already doing so, and continues to do so indefinitely.  */
    public function loop () :Movie {
        _playing = true;
        _stopFrame = NO_FRAME;
        return this;
    }

    /**
     * Moves to the given String label or int frame. Doesn't alter playing status or stop frame.
     * If there are labels at the given position, they're fired as part of the goto, even if the
     * current frame is equal to the destination. Labels between the current frame and the
     * destination frame are not fired.
     *
     * @param position the int frame or String label to goto.
     *
     * @return this movie for chaining
     *
     * @throws Error if position isn't an int or String, or if it is a String and that String isn't
     * a label on this movie
     */
    public function goto (position :Object) :Movie {
        const frame :int = extractFrame(position);
        updateFrame(frame, /*fromSkip=*/true, /*overDuration=*/false);
        return this;
    }

    /**
     * Starts playing if not already doing so, and continues to do so to the last frame in the
     * movie.
     */
    public function play () :Movie { return playTo(LAST_FRAME); }

   /**
    * Starts playing if not already doing so, and continues to do so to the given stop label or
    * frame.
    *
    * @param position to int frame or String label to stop at
    *
    * @return this movie for chaining
    *
    * @throws Error if position isn't an int or String, or if it is a String and that String isn't
    * a label on this movie.
    */
    public function playTo (position :Object) :Movie {
       _stopFrame = extractFrame(position);
       _playing = true;
       return this;
    }

    /** Stops playback if it's currently active. Doesn't alter the current frame or stop frame. */
    public function stop () :Movie {
        _playing = false;
        return this;
    }

    /** Advances the playhead by the give number of seconds. From IAnimatable. */
    public function advanceTime (dt :Number) :void {
        if (!_playing) return;

        _playTime += dt;
        var actualPlaytime :Number = _playTime;
        if (_playTime >= _duration) _playTime = _playTime % _duration;

        // If _playTime is very close to _duration, rounding error can cause us to
        // land on lastFrame + 1. Protect against that.
        var newFrame :int = Math.min(int(_playTime * _frameRate), _frames - 1);

        const overDuration :Boolean = dt >= _duration;

        // If the update crosses or goes to the stopFrame, go to the stop frame, stop the movie and
        // clear it
        if (_stopFrame != NO_FRAME) {
            // how many frames remain to the stopframe?
            var framesRemaining :int =
                (_frame <= _stopFrame ? _stopFrame - _frame : _frames - _frame + _stopFrame);
            var framesElapsed :int = int(actualPlaytime * _frameRate) - _frame;
            if (framesElapsed >= framesRemaining) {
                _playing = false;
                newFrame = _stopFrame;
                _stopFrame = NO_FRAME;
            }
        }
        updateFrame(newFrame, false, overDuration);

        for (var ii :int = 0; ii < this.numChildren; ++ii) {
            var child :DisplayObject = getChildAt(ii);
            if (child is Movie) {
                Movie(child).advanceTime(dt);
            }
        }
    }

    /** @private */
    protected function extractFrame (position :Object) :int {
        if (position is int) return int(position);
        if (!(position is String)) throw new Error("Movie position must be an int frame or String label");
        const label :String = String(position);
        for (var ii :int = 0; ii < _labels.length; ii++) {
            if (_labels[ii] != null && _labels[ii].indexOf(label) != -1) return ii;
        }
        throw new Error("No such label '" + label + "'");
    }

    /** @private */
    protected function updateFrame (newFrame :int, fromSkip :Boolean, overDuration :Boolean) :void {
        if (newFrame >= _frames) {
            throw new Error("Asked to go to frame " + newFrame + " past the last frame, " +
                (_frames - 1));
        }
        if (_goingToFrame) {
            _pendingFrame = newFrame;
            return;
        }
        _goingToFrame = true;
        const differentFrame :Boolean = newFrame != _frame;
        const wrapped :Boolean = newFrame < _frame;
        if (differentFrame) {
            if (wrapped) {
                for each (var layer :Layer in _layers) {
                    layer.changedKeyframe = true;
                    layer.keyframeIdx = 0;
                }
            }
            for each (layer in _layers) layer.drawFrame(newFrame);
        }

        // Update the frame before firing, so if firing changes the frame, it sticks.
        const oldFrame :int = _frame;
        _frame = newFrame;
        if (fromSkip) {
            fireLabels(newFrame, newFrame);
            _playTime = newFrame/_frameRate;
        } else if (overDuration) {
            fireLabels(oldFrame + 1, _frames - 1);
            fireLabels(0, _frame);
        } else if (differentFrame) {
            if (wrapped) {
                fireLabels(oldFrame + 1, _frames - 1);
                fireLabels(0, _frame);
            } else fireLabels(oldFrame + 1, _frame);
        }
        _goingToFrame = false;
        if (_pendingFrame != NO_FRAME) {
            newFrame = _pendingFrame;
            _pendingFrame = NO_FRAME;
            updateFrame(newFrame, true, false);
        }

    }

    /** @private */
    protected function fireLabels (startFrame :int, endFrame :int) :void {
        for (var ii :int = startFrame; ii <= endFrame; ii++) {
            if (_labels[ii] == null) continue;
            for each (var label :String in _labels[ii]) labelPassed.dispatch(label);
        }
    }

    /** @private */
    protected var _goingToFrame :Boolean;
    /** @private */
    protected var _pendingFrame :int = NO_FRAME;
    /** @private */
    protected var _frame :int = NO_FRAME, _stopFrame :int = NO_FRAME;
    /** @private */
    protected var _playing :Boolean = true;
    /** @private */
    protected var _playTime :Number, _duration :Number;
    /** @private */
    protected var _layers :Vector.<Layer>;
    /** @private */
    protected var _frames :int;
    /** @private */
    protected var _frameRate :Number;
    /** @private */
    protected var _labels :Vector.<Vector.<String>>;

    private static const NO_FRAME :int = -1;
}
}

import flump.display.Library;
import flump.display.Movie;
import flump.mold.KeyframeMold;
import flump.mold.LayerMold;

import starling.display.DisplayObject;
import starling.display.Sprite;

class Layer {
    public var keyframeIdx :int ;// The index of the last keyframe drawn in drawFrame
    public var layerIdx :int;// This layer's index in the movie
    public var keyframes :Vector.<KeyframeMold>;
    // Only created if there are multiple items on this layer. If it does exist, the appropriate display is swapped in at keyframe changes. If it doesn't, the display is only added to the parent on layer creation
    public var displays :Vector.<DisplayObject>;// <SPDisplayObject*>
    public var movie :Movie; // The movie this layer belongs to
    // If the keyframe has changed since the last drawFrame
    public var changedKeyframe :Boolean;

    public function Layer (movie :Movie, src :LayerMold, library :Library, flipbook :Boolean) {
        keyframes = src.keyframes;
        this.movie = movie;
        var lastItem :String;
        for (var ii :int = 0; ii < keyframes.length && lastItem == null; ii++) {
            lastItem = keyframes[ii].ref;
        }
        if (!flipbook && lastItem == null) movie.addChild(new Sprite());// Label only layer
        else {
            var multipleItems :Boolean = flipbook;
            for (ii = 0; ii < keyframes.length && !multipleItems; ii++) {
                multipleItems = keyframes[ii].ref != lastItem;
            }
            if (!multipleItems) movie.addChild(library.createDisplayObject(lastItem));
            else {
                displays = new <DisplayObject>[];
                for each (var kf :KeyframeMold in keyframes) {
                    var display :DisplayObject =
                        (kf.ref == null ? new Sprite() : library.createDisplayObject(kf.ref));
                    displays.push(display);
                    display.name = src.name;
                }
                movie.addChild(displays[0]);
            }
        }
        layerIdx = movie.numChildren - 1;
        movie.getChildAt(layerIdx).name = src.name;
    }

    public function drawFrame (frame :int) :void {
        while (keyframeIdx < keyframes.length - 1 && keyframes[keyframeIdx + 1].index <= frame) {
            keyframeIdx++;
            changedKeyframe = true;
        }
        // We've got multiple items. Swap in the one for this kf
        if (changedKeyframe && displays != null) {
            movie.removeChildAt(layerIdx);
            movie.addChildAt(displays[keyframeIdx], layerIdx);
        }
        changedKeyframe = false;

        const kf :KeyframeMold = keyframes[keyframeIdx];
        const layer :DisplayObject = movie.getChildAt(layerIdx);
        if (keyframeIdx == keyframes.length - 1 || kf.index == frame) {
            layer.x = kf.x;
            layer.y = kf.y;
            layer.scaleX = kf.scaleX;
            layer.scaleY = kf.scaleY;
            layer.skewX = kf.skewX;
            layer.skewY = kf.skewY;
            layer.alpha = kf.alpha;
        } else {
            var interped :Number = (frame - kf.index)/kf.duration;
            var ease :Number = kf.ease;
            if (ease != 0) {
                var t :Number;
                if (ease < 0) {
                    // Ease in
                    var inv :Number = 1 - interped;
                    t = 1 - inv*inv;
                    ease = -ease;
                } else {
                    // Ease out
                    t = interped*interped;
                }
                interped = ease*t + (1 - ease)*interped;
            }

            const nextKf :KeyframeMold = keyframes[keyframeIdx + 1];
            layer.x = kf.x + (nextKf.x - kf.x) * interped;
            layer.y = kf.y + (nextKf.y - kf.y) * interped;
            layer.scaleX = kf.scaleX + (nextKf.scaleX - kf.scaleX) * interped;
            layer.scaleY = kf.scaleY + (nextKf.scaleY - kf.scaleY) * interped;
            layer.skewX = kf.skewX + (nextKf.skewX - kf.skewX) * interped;
            layer.skewY = kf.skewY + (nextKf.skewY - kf.skewY) * interped;
            layer.alpha = kf.alpha + (nextKf.alpha - kf.alpha) * interped;
        }

        layer.pivotX = kf.pivotX;
        layer.pivotY = kf.pivotY;
        layer.visible = kf.visible;
    }
}

Fix movies occasionally landing on lastFrame + 1


//
// $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.utils.Dictionary;

/**
 * Base enum class for actionscript. Works pretty much like enums in Java, only you've got
 * to do one or two things.
 *
 * To use, you'll want to subclass and have something like the following:
 *
 * public final class Foo extends Enum
 * {
 *     public static const ONE = new Foo("ONE");
 *     public static const TWO = new Foo("TWO");
 *     finishedEnumerating(Foo);
 *
 *     // {at}private
 *     public function Foo (name :String)
 *     {
 *         super(name);
 *     }
 *
 *     public static function valueOf (name :String) :Foo
 *     {
 *         return Enum.valueOf(Foo, name);
 *     }
 *
 *     public static function values () :Array
 *     {
 *         return Enum.values(Foo);
 *     }
 * }
 *
 * Important notes:
 *  - make your class final
 *  - create a constructor that merely calls super
 *  - declare your enum constants const, and with the same String as their name.
 *  - call finishedEnumerating() at the end of your constants.
 *  - your enum objects should be immutable
 *  - implement a static valueOf() and values() methods for extra points, as above.
 */
public class Enum
    implements Hashable, Comparable
{
    /**
     * Call this constructor in your enum subclass constructor.
     */
    public function Enum (name :String)
    {
        const clazz :Class = ClassUtil.getClass(this);
        if (Boolean(_blocked[clazz])) {
            throw new Error("You may not just construct an enum!");

        } else if (name == null) {
            throw new ArgumentError("null is invalid.");
        }

        var list :Array = _enums[clazz] as Array;
        if (list == null) {
            list = [];
            _enums[clazz] = list;
        } else {
            for each (var enum :Enum in list) {
                if (enum.name() === name) {
                    throw new ArgumentError("Duplicate enum: " + name);
                }
            }
        }
        list.push(this);

        // now, actually construct
        _name = name;
    }

    /**
     * Get the name of this enum.
     */
    public function name () :String
    {
        return _name;
    }

    /**
     * Get the ordinal of this enum.
     * Note that you should not use the ordinal in normal cases, as it may change if a new
     * enum is defined. Ordinals should only be used if you are writing a data structure
     * that generically handles enums in an efficient manner, and you are never persisting
     * anything where the ordinal can change.
     */
    public function ordinal () :int
    {
        return (_enums[ClassUtil.getClass(this)] as Array).indexOf(this);
    }

    // from Hashable
    public function equals (other :Object) :Boolean
    {
        // enums are singleton
        return (other === this);
    }

    // from Hashable
    public function hashCode () :int
    {
        return ordinal();
    }

    /**
     * Return the String representation of this enum.
     */
    public function toString () :String
    {
        return _name;
    }

    // from Comparable
    public function compareTo (other :Object) :int
    {
        if (!ClassUtil.isSameClass(this, other)) {
            throw new ArgumentError("Not same class");
        }
        return Integer.compare(this.ordinal(), Enum(other).ordinal());
    }

    /**
     * Turn a String name into an Enum constant.
     */
    public static function valueOf (clazz :Class, name :String) :Enum
    {
        for each (var enum :Enum in values(clazz)) {
            if (enum.name() === name) {
                return enum;
            }
        }
        throw new ArgumentError("No such enum [class=" + clazz + ", name=" + name + "].");
    }

    /**
     * Get all the enums of the specified class, or null if it's not an enum.
     */
    public static function values (clazz :Class) :Array
    {
        var arr :Array = _enums[clazz] as Array;
        if (arr == null) {
            throw new ArgumentError("Not an enum [class=" + clazz + "].");
        }
        return arr.concat(); // return a copy, so that callers may not fuxor
    }

    /**
     * This should be called by your enum subclass after you've finished enumating the enum
     * constants. See the example in the class header documentation.
     */
    protected static function finishedEnumerating (clazz :Class) :void
    {
        _blocked[clazz] = true;
    }

    /** The String name of this enum value. */
    protected var _name :String;

    /** An array of enums for each enum class. */
    private static const _enums :Dictionary = new Dictionary(true);

    /** Is further instantiation of enum constants for a class allowed? */
    private static const _blocked :Dictionary = new Dictionary(true);

    finishedEnumerating(Enum); // do not allow any enums in this base class
}
}

//
// $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.utils.Dictionary;

/**
 * Base enum class for actionscript. Works pretty much like enums in Java, only you've got
 * to do one or two things.
 *
 * To use, you'll want to subclass and have something like the following:
 *
 * public final class Foo extends Enum
 * {
 *     public static const ONE = new Foo("ONE");
 *     public static const TWO = new Foo("TWO");
 *     finishedEnumerating(Foo);
 *
 *     // {at}private
 *     public function Foo (name :String)
 *     {
 *         super(name);
 *     }
 *
 *     public static function valueOf (name :String) :Foo
 *     {
 *         return Enum.valueOf(Foo, name);
 *     }
 *
 *     public static function values () :Array
 *     {
 *         return Enum.values(Foo);
 *     }
 * }
 *
 * Important notes:
 *  - make your class final
 *  - create a constructor that calls super(name)
 *  - declare your enum constants const, and with the same String as their name.
 *  - call finishedEnumerating() at the end of your constants.
 *  - your enum objects should be immutable
 *  - implement a static valueOf() and values() methods for extra points, as above.
 */
public class Enum
    implements Hashable, Comparable
{
    /**
     * Call this constructor in your enum subclass constructor.
     */
    public function Enum (name :String)
    {
        const clazz :Class = ClassUtil.getClass(this);
        if (Boolean(_blocked[clazz])) {
            throw new Error("You may not just construct an enum!");

        } else if (name == null) {
            throw new ArgumentError("null is invalid.");
        }

        var list :Array = _enums[clazz] as Array;
        if (list == null) {
            list = [];
            _enums[clazz] = list;
        } else {
            for each (var enum :Enum in list) {
                if (enum.name() === name) {
                    throw new ArgumentError("Duplicate enum: " + name);
                }
            }
        }
        list.push(this);

        // now, actually construct
        _name = name;
    }

    /**
     * Get the name of this enum.
     */
    public function name () :String
    {
        return _name;
    }

    /**
     * Get the ordinal of this enum.
     * Note that you should not use the ordinal in normal cases, as it may change if a new
     * enum is defined. Ordinals should only be used if you are writing a data structure
     * that generically handles enums in an efficient manner, and you are never persisting
     * anything where the ordinal can change.
     */
    public function ordinal () :int
    {
        return (_enums[ClassUtil.getClass(this)] as Array).indexOf(this);
    }

    // from Hashable
    public function equals (other :Object) :Boolean
    {
        // enums are singleton
        return (other === this);
    }

    // from Hashable
    public function hashCode () :int
    {
        return ordinal();
    }

    /**
     * Return the String representation of this enum.
     */
    public function toString () :String
    {
        return _name;
    }

    // from Comparable
    public function compareTo (other :Object) :int
    {
        if (!ClassUtil.isSameClass(this, other)) {
            throw new ArgumentError("Not same class");
        }
        return Integer.compare(this.ordinal(), Enum(other).ordinal());
    }

    /**
     * Turn a String name into an Enum constant.
     */
    public static function valueOf (clazz :Class, name :String) :Enum
    {
        for each (var enum :Enum in values(clazz)) {
            if (enum.name() === name) {
                return enum;
            }
        }
        throw new ArgumentError("No such enum [class=" + clazz + ", name=" + name + "].");
    }

    /**
     * Get all the enums of the specified class, or null if it's not an enum.
     */
    public static function values (clazz :Class) :Array
    {
        var arr :Array = _enums[clazz] as Array;
        if (arr == null) {
            throw new ArgumentError("Not an enum [class=" + clazz + "].");
        }
        return arr.concat(); // return a copy, so that callers may not fuxor
    }

    /**
     * This should be called by your enum subclass after you've finished enumating the enum
     * constants. See the example in the class header documentation.
     */
    protected static function finishedEnumerating (clazz :Class) :void
    {
        _blocked[clazz] = true;
    }

    /** The String name of this enum value. */
    protected var _name :String;

    /** An array of enums for each enum class. */
    private static const _enums :Dictionary = new Dictionary(true);

    /** Is further instantiation of enum constants for a class allowed? */
    private static const _blocked :Dictionary = new Dictionary(true);

    finishedEnumerating(Enum); // do not allow any enums in this base class
}
}

Comment tweak.

Comment tweak.

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


package org.mangui.osmf.plugins.utils {
    import org.mangui.hls.HLSError;
    import org.mangui.hls.HLSEvent;
    import org.osmf.events.MediaErrorCodes;

    public class ErrorManager {

        public static function getMediaErrorCode(event : HLSEvent) : int {
            var errorCode : int = MediaErrorCodes.NETSTREAM_PLAY_FAILED;
            if (event && event.error) {
                switch (event.error.code) {
                    case HLSError.FRAGMENT_LOADING_ERROR:
                    case HLSError.FRAGMENT_LOADING_CROSSDOMAIN_ERROR:
                    case HLSError.KEY_LOADING_ERROR:
                    case HLSError.KEY_LOADING_CROSSDOMAIN_ERROR:
                    case HLSError.MANIFEST_LOADING_CROSSDOMAIN_ERROR:
                    case HLSError.MANIFEST_LOADING_IO_ERROR:
                        errorCode = MediaErrorCodes.IO_ERROR;
                        break;
                    case org.mangui.hls.HLSError.FRAGMENT_PARSING_ERROR:
                    case org.mangui.hls.HLSError.KEY_PARSING_ERROR:
                    case org.mangui.hls.HLSError.MANIFEST_PARSING_ERROR:
                        errorCode = MediaErrorCodes.NETSTREAM_FILE_STRUCTURE_INVALID;
                        break;
                    case org.mangui.hls.HLSError.TAG_APPENDING_ERROR:
                        errorCode = MediaErrorCodes.ARGUMENT_ERROR;
                        break;
                }
            }
            return errorCode;
        };

        public static function getMediaErrorMessage(event : HLSEvent) : String {
            return (event && event.error) ? event.error.msg : "Unknown error";
        };
    };
}

Create ErrorManager util to get MediaErrorCode & MediaErrorMessage


/* -*- Mode: javascript; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is [Open Source Virtual Machine.].
 *
 * The Initial Developer of the Original Code is
 * Adobe System Incorporated.
 * Portions created by the Initial Developer are Copyright (C) 2010
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Adobe AS3 Team
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

var SECTION = "apply_001";
var VERSION = "";
startTest();

var TITLE = "Function.prototype.apply with very long argument lists";

writeHeaderToLog( SECTION + " "+ TITLE);

var testcases = getTestCases();
test();

function getTestCases()
{
    var array = new Array();
    var initial = 1000;
    var limit = 10000000;
    var multiplier = 10;

    function makeArray(n) {
        var A = new Array;
        for ( var i=0 ; i < n ; i++ )
            A[i] = i+1;
        return A;
    }

    function sum(...rest) {
        var n = 0;
        for ( var i=0 ; i < rest.length ; i++ )
            n += rest[i];
        return n;
    }

    for ( var i=initial ; i < limit ; i *= multiplier ) {
        status = 'Test apply(bigarray) #' + i;
        actual = sum.apply(null, makeArray(i));
        expect = (i*(i+1))/2;
        array.push(new TestCase(SECTION, status, expect, actual));
    }

    return array;
}

Fix 551959 - Need huge test case for Function.apply (r=treilly, r=brbaker)


package org.shypl.common.util {
	public class UintComparator extends SimpleComparator {
		private static var LOW_TO_HIGH:UintComparator;
		private static var HIGH_TO_LOW:UintComparator;

		public static function getInstance(reverse:Boolean = false):Comparator {
			if (reverse) {
				if (HIGH_TO_LOW === null) {
					HIGH_TO_LOW = new UintComparator(true);
				}
				return HIGH_TO_LOW;
			}

			if (LOW_TO_HIGH === null) {
				LOW_TO_HIGH = new UintComparator(false);
			}

			return LOW_TO_HIGH;
		}

		public function UintComparator(reverse:Boolean) {
			super(reverse);
		}

		override protected function isGreater(a:Object, b:Object):Boolean {
			return uint(a) > uint(b);
		}
	}
}

Add UintComparator

Add UintComparator


/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mangui.hls {
    import org.mangui.hls.constant.HLSSeekMode;
    import org.mangui.hls.constant.HLSMaxLevelCappingMode;

    public final class HLSSettings extends Object {
        /**
         * autoStartLoad
         *
         * if set to true,
         *      start level playlist and first fragments will be loaded automatically,
         *      after triggering of HlsEvent.MANIFEST_PARSED event
         * if set to false,
         *      an explicit API call (hls.startLoad()) will be needed
         *      to start quality level/fragment loading.
         *
         * Default is true
         */
        public static var autoStartLoad : Boolean = true;
        /**
         * capLevelToStage
         *
         * Limit levels usable in auto-quality by the stage dimensions (width and height).
         *      true - level width and height (defined in m3u8 playlist) will be compared with the player width and height (stage.stageWidth and stage.stageHeight).
         *             Max level will be set depending on the maxLevelCappingMode option.
         *      false - levels will not be limited. All available levels could be used in auto-quality mode taking only bandwidth into consideration.
         *
         * Note: this setting is ignored in manual mode so all the levels could be selected manually.
         *
         * Default is false
         */
        public static var capLevelToStage : Boolean = false;

        /**
         * maxLevelCappingMode
         *
         * Defines the max level capping mode to the one available in HLSMaxLevelCappingMode
         *      HLSMaxLevelCappingMode.DOWNSCALE - max capped level should be the one with the dimensions equal or greater than the stage dimensions (so the video will be downscaled)
         *      HLSMaxLevelCappingMode.UPSCALE - max capped level should be the one with the dimensions equal or lower than the stage dimensions (so the video will be upscaled)
         *
         * Default is HLSMaxLevelCappingMode.DOWNSCALE
         */
        public static var maxLevelCappingMode : String = HLSMaxLevelCappingMode.DOWNSCALE;

        // // // // // // /////////////////////////////////
        //
        // org.mangui.hls.stream.HLSNetStream
        //
        // // // // // // /////////////////////////////////
        /**
         * minBufferLength
         *
         * Defines minimum buffer length in seconds before playback can start, after seeking or buffer stalling.
         *
         * Default is -1 = auto
         */
        public static var minBufferLength : Number = -1;

        /**
         * minBufferLengthCapping
         *
         * Defines minimum buffer length capping value (max value) if minBufferLength is set to -1
         *
         * Default is -1 = no capping
         */
        public static var minBufferLengthCapping : Number = -1;

        /**
         * maxBufferLength
         *
         * Defines maximum buffer length in seconds.
         * (0 means infinite buffering)
         *
         * Default is 120
         */
        public static var maxBufferLength : Number = 120;

        /**
         * maxBackBufferLength
         *
         * Defines maximum back buffer length in seconds.
         * (0 means infinite back buffering)
         *
         * Default is 30
         */
        public static var maxBackBufferLength : Number = 30;

        /**
         * lowBufferLength
         *
         * Defines low buffer length in seconds.
         * When crossing down this threshold, HLS will switch to buffering state.
         *
         * Default is 3
         */
        public static var lowBufferLength : Number = 3;

        /**
         * mediaTimeUpdatePeriod
         *
         * time update period in ms
         * period at which HLSEvent.MEDIA_TIME will be triggered
         * Default is 100 ms
         */
        public static var mediaTimePeriod : int = 100;

        /**
         * fpsDroppedMonitoringPeriod
         *
         * dropped FPS Monitor Period in ms
         * period at which nb dropped FPS will be checked
         * Default is 5000 ms
         */
        public static var fpsDroppedMonitoringPeriod : int = 5000;

        /**
         * fpsDroppedMonitoringThreshold
         *
         * dropped FPS Threshold
         * every fpsDroppedMonitoringPeriod, dropped FPS will be compared to displayed FPS.
         * if during that period, ratio of (dropped FPS/displayed FPS) is greater or equal
         * than fpsDroppedMonitoringThreshold, HLSEvent.FPS_DROP event will be fired
         * Default is 0.2 (20%)
         */
        public static var fpsDroppedMonitoringThreshold : Number = 0.2;

        /**
         * capLevelonFPSDrop
         *
         * Limit levels usable in auto-quality when FPS drop is detected
         * i.e. if frame drop is detected on level 5, auto level will be capped to level 4 a
         *      true -  enabled
         *      false - disabled
         *
         * Note: this setting is ignored in manual mode so all the levels could be selected manually.
         *
         * Default is false
         */
        public static var capLevelonFPSDrop : Boolean = false;

        /**
         * smoothAutoSwitchonFPSDrop
         *
         * force a smooth level switch Limit when FPS drop is detected in auto-quality
         * i.e. if frame drop is detected on level 5, it will trigger an auto quality level switch
         * to level 4 for next fragment
         *      true -  enabled
         *      false - disabled
         *
         * Note: this setting is active only if capLevelonFPSDrop==true
         *
         * Default is true
         */
        public static var smoothAutoSwitchonFPSDrop : Boolean = true;

        /**
         * switchDownOnLevelError
         *
         * if level loading fails, and if in auto mode, and we are not on lowest level
         * don't report Level loading error straight-away, try to switch down first
         *      true -  enabled
         *      false - disabled
         *
         * Default is true
         */
        public static var switchDownOnLevelError : Boolean = true;

        /**
         * seekMode
         *
         * Defines seek mode to one form available in HLSSeekMode class:
         *      HLSSeekMode.ACCURATE_SEEK - accurate seeking to exact requested position
         *      HLSSeekMode.KEYFRAME_SEEK - key-frame based seeking (seek to nearest key frame before requested seek position)
         *
         * Default is HLSSeekMode.KEYFRAME_SEEK
         */
        public static var seekMode : String = HLSSeekMode.KEYFRAME_SEEK;

        /**
         * keyLoadMaxRetry
         *
         * Max nb of retries for Key Loading in case I/O errors are met,
         *      0, means no retry, error will be triggered automatically
         *     -1 means infinite retry
         *
         * Default is 3
         */
        public static var keyLoadMaxRetry : int = 3;

        /**
         * keyLoadMaxRetryTimeout
         *
         * Maximum key retry timeout (in milliseconds) in case I/O errors are met.
         * Every fail on key request, player will exponentially increase the timeout to try again.
         * It starts waiting 1 second (1000ms), than 2, 4, 8, 16, until keyLoadMaxRetryTimeout is reached.
         *
         * Default is 64000.
         */
        public static var keyLoadMaxRetryTimeout : Number = 64000;

        /**
         * fragmentLoadMaxRetry
         *
         * Max number of retries for Fragment Loading in case I/O errors are met,
         *      0, means no retry, error will be triggered automatically
         *     -1 means infinite retry
         *
         * Default is 3
         */
        public static var fragmentLoadMaxRetry : int = 3;

        /**
         * fragmentLoadMaxRetryTimeout
         *
         * Maximum Fragment retry timeout (in milliseconds) in case I/O errors are met.
         * Every fail on fragment request, player will exponentially increase the timeout to try again.
         * It starts waiting 1 second (1000ms), than 2, 4, 8, 16, until fragmentLoadMaxRetryTimeout is reached.
         *
         * Default is 4000
         */
        public static var fragmentLoadMaxRetryTimeout : Number = 4000;

        /**
         * fragmentLoadSkipAfterMaxRetry
         *
         * control behaviour in case fragment load still fails after max retry timeout
         * if set to true, fragment will be skipped and next one will be loaded.
         * If set to false, an I/O Error will be raised.
         *
         * Default is true.
         */
        public static var fragmentLoadSkipAfterMaxRetry : Boolean = true;

        /**
         * flushLiveURLCache
         *
         * If set to true, live playlist will be flushed from URL cache before reloading
         * (this is to workaround some cache issues with some combination of Flash Player / IE version)
         *
         * Default is false
         */
        public static var flushLiveURLCache : Boolean = false;

        /**
         * initialLiveManifestSize
         *
         * Number of segments needed to start playback of Live stream.
         *
         * Default is 1
         */
        public static var initialLiveManifestSize : uint = 1;

        /**
         * manifestLoadMaxRetry
         *
         * max nb of retries for Manifest Loading in case I/O errors are met,
         *      0, means no retry, error will be triggered automatically
         *     -1 means infinite retry
         */
        public static var manifestLoadMaxRetry : int = 3;

        /**
         * manifestLoadMaxRetryTimeout
         *
         * Maximum Manifest retry timeout (in milliseconds) in case I/O errors are met.
         * Every fail on fragment request, player will exponentially increase the timeout to try again.
         * It starts waiting 1 second (1000ms), than 2, 4, 8, 16, until manifestLoadMaxRetryTimeout is reached.
         *
         * Default is 64000
         */
        public static var manifestLoadMaxRetryTimeout : Number = 64000;

		/**
		 * manifestRedundantLoadmaxRetry
		 *
		 * max nb of looping over the redundant streams.
		 *   >0  means looping over the stream array 2 or more times
		 *    0  means looping exactly once (no retries) - default behaviour
		 *   -1  means infinite retry
		 */
         public static var manifestRedundantLoadmaxRetry : int = 3;
        /**
         * startFromBitrate
         *
         * If greater than 0, specifies the preferred bitrate.
         * If -1, and startFromLevel is not specified, automatic start level selection will be used.
         * This parameter, if set, will take priority over startFromLevel.
         *
         * Default is -1
         */
        public static var startFromBitrate : Number = -1;

        /**
         * startFromLevel
         *
         * start level :
         *  from 0 to 1 : indicates the "normalized" preferred level. As such, if it is 0.5, the closest to the middle bitrate will be selected and used first.
         * -1 : automatic start level selection, playback will start from level matching download bandwidth (determined from download of first segment)
         * -2 : playback will start from the first level appearing in Manifest (not sorted by bitrate)
         *
         * Default is -1
         */
        public static var startFromLevel : Number = -1;

        /**
         * autoStartMaxDuration
         *
         * max fragment loading duration in automatic start level selection mode (in ms)
         * -1 : max duration not capped
         * other : max duration is capped to avoid long playback starting time
         *
         * Default is -1
         */
        public static var autoStartMaxDuration : Number = -1;

        /**
         * seekFromLevel
         *
         * Seek level:
         *  from 0 to 1: indicates the "normalized" preferred bitrate. As such, if it is 0.5, the closest to the middle bitrate will be selected and used first.
         * -1 : automatic start level selection, keep previous level matching previous download bandwidth
         *
         * Default is -1
         */
        public static var seekFromLevel : Number = -1;

        /**
         * useHardwareVideoDecoder
         *
         * Use hardware video decoder:
         *  it will set NetStream.useHardwareDecoder
         *  refer to http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/NetStream.html#useHardwareDecoder
         *
         * Default is true
         */
        public static var useHardwareVideoDecoder : Boolean = true;

        /**
         * logInfo
         *
         * Defines whether INFO level log messages will will appear in the console
         *
         * Default is true
         */
        public static var logInfo : Boolean = true;

        /**
         * logDebug
         *
         * Defines whether DEBUG level log messages will will appear in the console
         *
         * Default is false
         */
        public static var logDebug : Boolean = false;

        /**
         * logDebug2
         *
         * Defines whether DEBUG2 level log messages will will appear in the console
         *
         * Default is false
         */
        public static var logDebug2 : Boolean = false;

        /**
         * logWarn
         *
         * Defines whether WARN level log messages will will appear in the console
         *
         * Default is true
         */
        public static var logWarn : Boolean = true;

        /**
         * logError
         *
         * Defines whether ERROR level log messages will will appear in the console
         *
         * Default is true
         */
        public static var logError : Boolean = true;
    }
}

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mangui.hls {
    import org.mangui.hls.constant.HLSSeekMode;
    import org.mangui.hls.constant.HLSMaxLevelCappingMode;

    public final class HLSSettings extends Object {
        /**
         * autoStartLoad
         *
         * if set to true,
         *      start level playlist and first fragments will be loaded automatically,
         *      after triggering of HlsEvent.MANIFEST_PARSED event
         * if set to false,
         *      an explicit API call (hls.startLoad()) will be needed
         *      to start quality level/fragment loading.
         *
         * Default is true
         */
        public static var autoStartLoad : Boolean = true;
        /**
         * capLevelToStage
         *
         * Limit levels usable in auto-quality by the stage dimensions (width and height).
         *      true - level width and height (defined in m3u8 playlist) will be compared with the player width and height (stage.stageWidth and stage.stageHeight).
         *             Max level will be set depending on the maxLevelCappingMode option.
         *      false - levels will not be limited. All available levels could be used in auto-quality mode taking only bandwidth into consideration.
         *
         * Note: this setting is ignored in manual mode so all the levels could be selected manually.
         *
         * Default is false
         */
        public static var capLevelToStage : Boolean = false;

        /**
         * maxLevelCappingMode
         *
         * Defines the max level capping mode to the one available in HLSMaxLevelCappingMode
         *      HLSMaxLevelCappingMode.DOWNSCALE - max capped level should be the one with the dimensions equal or greater than the stage dimensions (so the video will be downscaled)
         *      HLSMaxLevelCappingMode.UPSCALE - max capped level should be the one with the dimensions equal or lower than the stage dimensions (so the video will be upscaled)
         *
         * Default is HLSMaxLevelCappingMode.DOWNSCALE
         */
        public static var maxLevelCappingMode : String = HLSMaxLevelCappingMode.DOWNSCALE;

        // // // // // // /////////////////////////////////
        //
        // org.mangui.hls.stream.HLSNetStream
        //
        // // // // // // /////////////////////////////////
        /**
         * minBufferLength
         *
         * Defines minimum buffer length in seconds before playback can start, after seeking or buffer stalling.
         *
         * Default is -1 = auto
         */
        public static var minBufferLength : Number = -1;

        /**
         * minBufferLengthCapping
         *
         * Defines minimum buffer length capping value (max value) if minBufferLength is set to -1
         *
         * Default is -1 = no capping
         */
        public static var minBufferLengthCapping : Number = -1;

        /**
         * maxBufferLength
         *
         * Defines maximum buffer length in seconds.
         * (0 means infinite buffering)
         *
         * Default is 120
         */
        public static var maxBufferLength : Number = 120;

        /**
         * maxBackBufferLength
         *
         * Defines maximum back buffer length in seconds.
         * (0 means infinite back buffering)
         *
         * Default is 30
         */
        public static var maxBackBufferLength : Number = 30;

        /**
         * lowBufferLength
         *
         * Defines low buffer length in seconds.
         * When crossing down this threshold, HLS will switch to buffering state.
         *
         * Default is 3
         */
        public static var lowBufferLength : Number = 3;

        /**
         * mediaTimeUpdatePeriod
         *
         * time update period in ms
         * period at which HLSEvent.MEDIA_TIME will be triggered
         * Default is 100 ms
         */
        public static var mediaTimePeriod : int = 100;

        /**
         * fpsDroppedMonitoringPeriod
         *
         * dropped FPS Monitor Period in ms
         * period at which nb dropped FPS will be checked
         * Default is 5000 ms
         */
        public static var fpsDroppedMonitoringPeriod : int = 5000;

        /**
         * fpsDroppedMonitoringThreshold
         *
         * dropped FPS Threshold
         * every fpsDroppedMonitoringPeriod, dropped FPS will be compared to displayed FPS.
         * if during that period, ratio of (dropped FPS/displayed FPS) is greater or equal
         * than fpsDroppedMonitoringThreshold, HLSEvent.FPS_DROP event will be fired
         * Default is 0.2 (20%)
         */
        public static var fpsDroppedMonitoringThreshold : Number = 0.2;

        /**
         * capLevelonFPSDrop
         *
         * Limit levels usable in auto-quality when FPS drop is detected
         * i.e. if frame drop is detected on level 5, auto level will be capped to level 4 a
         *      true -  enabled
         *      false - disabled
         *
         * Note: this setting is ignored in manual mode so all the levels could be selected manually.
         *
         * Default is false
         */
        public static var capLevelonFPSDrop : Boolean = false;

        /**
         * smoothAutoSwitchonFPSDrop
         *
         * force a smooth level switch Limit when FPS drop is detected in auto-quality
         * i.e. if frame drop is detected on level 5, it will trigger an auto quality level switch
         * to level 4 for next fragment
         *      true -  enabled
         *      false - disabled
         *
         * Note: this setting is active only if capLevelonFPSDrop==true
         *
         * Default is true
         */
        public static var smoothAutoSwitchonFPSDrop : Boolean = true;

        /**
         * switchDownOnLevelError
         *
         * if level loading fails, and if in auto mode, and we are not on lowest level
         * don't report Level loading error straight-away, try to switch down first
         *      true -  enabled
         *      false - disabled
         *
         * Default is true
         */
        public static var switchDownOnLevelError : Boolean = true;

        /**
         * seekMode
         *
         * Defines seek mode to one form available in HLSSeekMode class:
         *      HLSSeekMode.ACCURATE_SEEK - accurate seeking to exact requested position
         *      HLSSeekMode.KEYFRAME_SEEK - key-frame based seeking (seek to nearest key frame before requested seek position)
         *
         * Default is HLSSeekMode.KEYFRAME_SEEK
         */
        public static var seekMode : String = HLSSeekMode.KEYFRAME_SEEK;

        /**
         * keyLoadMaxRetry
         *
         * Max nb of retries for Key Loading in case I/O errors are met,
         *      0, means no retry, error will be triggered automatically
         *     -1 means infinite retry
         *
         * Default is 3
         */
        public static var keyLoadMaxRetry : int = 3;

        /**
         * keyLoadMaxRetryTimeout
         *
         * Maximum key retry timeout (in milliseconds) in case I/O errors are met.
         * Every fail on key request, player will exponentially increase the timeout to try again.
         * It starts waiting 1 second (1000ms), than 2, 4, 8, 16, until keyLoadMaxRetryTimeout is reached.
         *
         * Default is 64000.
         */
        public static var keyLoadMaxRetryTimeout : Number = 64000;

        /**
         * fragmentLoadMaxRetry
         *
         * Max number of retries for Fragment Loading in case I/O errors are met,
         *      0, means no retry, error will be triggered automatically
         *     -1 means infinite retry
         *
         * Default is 3
         */
        public static var fragmentLoadMaxRetry : int = 3;

        /**
         * fragmentLoadMaxRetryTimeout
         *
         * Maximum Fragment retry timeout (in milliseconds) in case I/O errors are met.
         * Every fail on fragment request, player will exponentially increase the timeout to try again.
         * It starts waiting 1 second (1000ms), than 2, 4, 8, 16, until fragmentLoadMaxRetryTimeout is reached.
         *
         * Default is 4000
         */
        public static var fragmentLoadMaxRetryTimeout : Number = 4000;

        /**
         * fragmentLoadSkipAfterMaxRetry
         *
         * control behaviour in case fragment load still fails after max retry timeout
         * if set to true, fragment will be skipped and next one will be loaded.
         * If set to false, an I/O Error will be raised.
         *
         * Default is true.
         */
        public static var fragmentLoadSkipAfterMaxRetry : Boolean = true;

        /**
         * maxSkippedFragments
         *
         * Maximum count of skipped fragments in a row before an I/O Error will be raised.
         *      0 - no skip (same as fragmentLoadSkipAfterMaxRetry = false)
         *      -1 - no limit for skipping, skip till the end of the playlist
         *
         * Default is 5.
         */
        public static var maxSkippedFragments : int = 5;

        /**
         * flushLiveURLCache
         *
         * If set to true, live playlist will be flushed from URL cache before reloading
         * (this is to workaround some cache issues with some combination of Flash Player / IE version)
         *
         * Default is false
         */
        public static var flushLiveURLCache : Boolean = false;

        /**
         * initialLiveManifestSize
         *
         * Number of segments needed to start playback of Live stream.
         *
         * Default is 1
         */
        public static var initialLiveManifestSize : uint = 1;

        /**
         * manifestLoadMaxRetry
         *
         * max nb of retries for Manifest Loading in case I/O errors are met,
         *      0, means no retry, error will be triggered automatically
         *     -1 means infinite retry
         */
        public static var manifestLoadMaxRetry : int = 3;

        /**
         * manifestLoadMaxRetryTimeout
         *
         * Maximum Manifest retry timeout (in milliseconds) in case I/O errors are met.
         * Every fail on fragment request, player will exponentially increase the timeout to try again.
         * It starts waiting 1 second (1000ms), than 2, 4, 8, 16, until manifestLoadMaxRetryTimeout is reached.
         *
         * Default is 64000
         */
        public static var manifestLoadMaxRetryTimeout : Number = 64000;

		/**
		 * manifestRedundantLoadmaxRetry
		 *
		 * max nb of looping over the redundant streams.
		 *   >0  means looping over the stream array 2 or more times
		 *    0  means looping exactly once (no retries) - default behaviour
		 *   -1  means infinite retry
		 */
         public static var manifestRedundantLoadmaxRetry : int = 3;
        /**
         * startFromBitrate
         *
         * If greater than 0, specifies the preferred bitrate.
         * If -1, and startFromLevel is not specified, automatic start level selection will be used.
         * This parameter, if set, will take priority over startFromLevel.
         *
         * Default is -1
         */
        public static var startFromBitrate : Number = -1;

        /**
         * startFromLevel
         *
         * start level :
         *  from 0 to 1 : indicates the "normalized" preferred level. As such, if it is 0.5, the closest to the middle bitrate will be selected and used first.
         * -1 : automatic start level selection, playback will start from level matching download bandwidth (determined from download of first segment)
         * -2 : playback will start from the first level appearing in Manifest (not sorted by bitrate)
         *
         * Default is -1
         */
        public static var startFromLevel : Number = -1;

        /**
         * autoStartMaxDuration
         *
         * max fragment loading duration in automatic start level selection mode (in ms)
         * -1 : max duration not capped
         * other : max duration is capped to avoid long playback starting time
         *
         * Default is -1
         */
        public static var autoStartMaxDuration : Number = -1;

        /**
         * seekFromLevel
         *
         * Seek level:
         *  from 0 to 1: indicates the "normalized" preferred bitrate. As such, if it is 0.5, the closest to the middle bitrate will be selected and used first.
         * -1 : automatic start level selection, keep previous level matching previous download bandwidth
         *
         * Default is -1
         */
        public static var seekFromLevel : Number = -1;

        /**
         * useHardwareVideoDecoder
         *
         * Use hardware video decoder:
         *  it will set NetStream.useHardwareDecoder
         *  refer to http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/NetStream.html#useHardwareDecoder
         *
         * Default is true
         */
        public static var useHardwareVideoDecoder : Boolean = true;

        /**
         * logInfo
         *
         * Defines whether INFO level log messages will will appear in the console
         *
         * Default is true
         */
        public static var logInfo : Boolean = true;

        /**
         * logDebug
         *
         * Defines whether DEBUG level log messages will will appear in the console
         *
         * Default is false
         */
        public static var logDebug : Boolean = false;

        /**
         * logDebug2
         *
         * Defines whether DEBUG2 level log messages will will appear in the console
         *
         * Default is false
         */
        public static var logDebug2 : Boolean = false;

        /**
         * logWarn
         *
         * Defines whether WARN level log messages will will appear in the console
         *
         * Default is true
         */
        public static var logWarn : Boolean = true;

        /**
         * logError
         *
         * Defines whether ERROR level log messages will will appear in the console
         *
         * Default is true
         */
        public static var logError : Boolean = true;
    }
}

Introduce maxSkippedFragments setting

Introduce maxSkippedFragments setting


////////////////////////////////////////////////////////////////////////////////
//
//  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.core
{
    import flash.display.DisplayObject;
    import flash.events.Event;

    import org.apache.flex.core.IBead;
    import org.apache.flex.core.IStrand;

    /**
     *  The CallLater bead implements ways for
     *  a method to be called after other code has
     *  finished running.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
     */
	public class CallLaterBead implements IBead
	{
        /**
         *  Constructor.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function CallLaterBead()
		{
			super();
		}

        private var _strand:IStrand;

        /**
         *  @copy org.apache.flex.core.IBead#strand
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public function set strand(value:IStrand):void
        {
            _strand = value;
        }

        private var calls:Array;

        /**
         *  Calls a function after some amount of time.
         *
         *  CallLater works a bit differently than in
         *  the Flex SDK.  The Flex SDK version was
         *  could use the Flash Player's RENDER event
         *  to try to run code before the scren was
         *  updated.  Since there is no deferred rendering
         *  in HTML/JS/CSS, this version of callLater
         *  is almost always going to run after the
         *  screen is updated.
         *
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
        public function callLater(fn:Function, args:Array = null, thisArg:Object = null):void
        {
            DisplayObject(_strand).addEventListener(Event.ENTER_FRAME, enterFrameHandler);
            if (calls == null)
                calls = [ {thisArg: thisArg, fn: fn, args: args } ];
            else
                calls.push({thisArg: thisArg, fn: fn, args: args });
        }

        private function enterFrameHandler(event:Event):void
        {
            DisplayObject(_strand).removeEventListener(Event.ENTER_FRAME, enterFrameHandler);

            var list:Array = calls;
            var n:int = list.length;
            for (var i:int = 0; i < n; i++)
            {
                var call:Object = list.shift();
                var fn:Function = call.fn;
                fn.apply(call.thisArg, call.args);
            }

        }

    }
}

add a CallLaterBead

add a CallLaterBead


/*
 * Copyright 2008 Adobe Systems Inc., 2008 Google Inc.
 *
 * 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.
 *
 * Contributor(s):
 *   Zwetan Kjukov <zwetan@gmail.com>.
 */

package
{
    import flash.display.Sprite;

    /**
     * The basic framework Library to be included in the SWC.
     *

     * Note: This class is not a component, it is just
     * a shim that allow to declare the SWC manifest and associate an icon file.
     *

     */
    [ExcludeClass]
    [IconFile("gaforflash.png")]
    public class Library extends Sprite
    {
        public function Library()
        {
        }

    }
}

add Library file to build the SWC, this file replace ALL the classes defined in com.google.analytics.components.*


////////////////////////////////////////////////////////////////////////////////
//
//  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.html.staticControls.beads
{
	import flash.display.Graphics;
	import flash.events.Event;
	import flash.events.IEventDispatcher;

	import org.apache.flex.core.IBead;
	import org.apache.flex.core.IStrand;
	import org.apache.flex.core.UIBase;

	public class SolidBackgroundBead implements IBead
	{
		public function SolidBackgroundBead()
		{
		}

		private var _strand:IStrand;

		public function get strand():IStrand
		{
			return _strand;
		}
		public function set strand(value:IStrand):void
		{
			_strand = value;
            IEventDispatcher(value).addEventListener("heightChanged", changeHandler);
            IEventDispatcher(value).addEventListener("widthChanged", changeHandler);
		}

		private var _backgroundColor:uint;

		public function get backgroundColor():uint
		{
			return _backgroundColor;
		}
		public function set backgroundColor(value:uint):void
		{
			_backgroundColor = value;
			if (_strand)
				changeHandler(null);
		}

		private function changeHandler(event:Event):void
		{
            var host:UIBase = UIBase(_strand);
            var g:Graphics = host.graphics;
            var w:Number = host.width;
            var h:Number = host.height;
            g.clear();
            g.beginFill(backgroundColor);
            g.drawRect(0, 0, w, h);
            g.endFill();
		}
	}
}

Add bead to draw solid background

Add bead to draw solid background


package dolly.core.errors {

public class CloningError extends Error {

	public static const CLASS_IS_NOT_CLONEABLE_CODE:int = 1;
	public static const CLASS_IS_NOT_CLONEABLE_MESSAGE:String = "Class is not cloneable!";

	public function CloningError(message:* = "", id:* = 0) {
		super(message, id);
	}
}
}

Create new error class: CloningError.

Create new error class: CloningError.


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

package flash.utils {

[native(cls='ObjectInputClass')]
internal class ObjectInput implements IDataInput {
  public native function get bytesAvailable(): uint;
  public native function get objectEncoding(): uint;
  public native function set objectEncoding(version: uint): void;
  public native function get endian(): String;
  public native function set endian(type: String): void;
  public native function readBytes(bytes: ByteArray, offset: uint = 0, length: uint = 0): void;
  public native function readBoolean(): Boolean;
  public native function readByte(): int;
  public native function readUnsignedByte(): uint;
  public native function readShort(): int;
  public native function readUnsignedShort(): uint;
  public native function readInt(): int;
  public native function readUnsignedInt(): uint;
  public native function readFloat(): Number;
  public native function readDouble(): Number;
  public native function readMultiByte(length: uint, charSet: String): String;
  public native function readUTF(): String;
  public native function readUTFBytes(length: uint): String;
  public native function readObject(): *;
}
}

Add missing builtin flash.utils.ObjectInput


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

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

			private var playList:PlayList = new PlayList();

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

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

				songList.dataProvider = playList.songList;
			}

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

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

				playList.sortList(sortField);

				refreshList();
			}

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

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

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

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

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

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

				refreshList();

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

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

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

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

Add AS3 example.

Add AS3 example.

--HG--
branch : trunk


Add AS3 example.

Add AS3 example.


package org.shypl.common.net {
	public class InetSocketAddress {
		private var _host:String;
		private var _port:int;

		public function InetSocketAddress(host:String, port:int) {
			_host = host;
			_port = port;
		}

		public function get host():String {
			return _host;
		}

		public function get port():int {
			return _port;
		}

		public function toString():String {
			return _host + ":" + _port;
		}
	}
}

Add InetSocketAddress

Add InetSocketAddress


/*
    Weave (Web-based Analysis and Visualization Environment)
    Copyright (C) 2008-2011 University of Massachusetts Lowell

    This file is a part of Weave.

    Weave is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License, Version 3,
    as published by the Free Software Foundation.

    Weave 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Weave.  If not, see <http://www.gnu.org/licenses/>.
*/

package weave.data.DataSources
{
    import flash.net.URLRequest;

    import mx.charts.chartClasses.IColumn;
    import mx.rpc.events.FaultEvent;
    import mx.rpc.events.ResultEvent;

    import weave.api.data.ColumnMetadata;
    import weave.api.data.DataType;
    import weave.api.data.IAttributeColumn;
    import weave.api.data.IColumnReference;
    import weave.api.data.IDataSource;
    import weave.api.data.IWeaveTreeNode;
    import weave.api.newDisposableChild;
    import weave.api.newLinkableChild;
    import weave.api.registerDisposableChild;
    import weave.api.registerLinkableChild;
    import weave.api.reportError;
    import weave.compiler.Compiler;
    import weave.compiler.StandardLib;
    import weave.core.LinkablePromise;
    import weave.core.LinkableString;
    import weave.data.AttributeColumns.ProxyColumn;
    import weave.data.hierarchy.ColumnTreeNode;
    import weave.primitives.Dictionary2D;
    import weave.services.JsonCache;
    import weave.services.addAsyncResponder;

    public class FREDDataSource extends AbstractDataSource
    {
        WeaveAPI.ClassRegistry.registerImplementation(IDataSource, FREDDataSource, "Federal Reserve Economic Data");

        public function FREDDataSource()
        {
        }

        override protected function initialize():void
        {
            // recalculate all columns previously requested
            //refreshAllProxyColumns();

            super.initialize();
        }

		private const jsonCache:JsonCache = newLinkableChild(this, JsonCache);

		public const apiKey:LinkableString = registerLinkableChild(this, new LinkableString("fa99c080bdbd1d486a55e7cb6ab7acbb"));

		/**
		 * @param method Examples: "category", "category/series"
		 * @param params Example: {category_id: 125}
		 */
		private function getUrl(method:String, params:Object):String
		{
			params['api_key'] = apiKey.value;
			params['file_type'] = 'json';
			var paramsStr:String = '';
			for (var key:String in params)
				paramsStr += (paramsStr ? '&' : '?') + key + '=' + params[key];
			return "http://api.stlouisfed.org/fred/" + method + paramsStr;
		}
		/**
		 * @param method Examples: "category", "category/series"
		 * @param params Example: {category_id: 125}
		 */
		private function getJson(method:String, params:Object):Object
		{
			return jsonCache.getJsonObject(getUrl(method, params));
		}

		private var functionCache:Dictionary2D = new Dictionary2D();

		public function createCategoryNode(data:Object = null, ..._):ColumnTreeNode
		{
			if (!data)
			{
				var name:String = WeaveAPI.globalHashMap.getName(this);
				data = {id: 0, name: name};
			}
			var node:ColumnTreeNode = functionCache.get(createCategoryNode, data.id);
			if (!node)
			{
				node = new ColumnTreeNode({
					source: this,
					data: data,
					label: data.name,
					isBranch: true,
					hasChildBranches: true,
					children: function(node:ColumnTreeNode):Array {
						return [].concat(
							getCategoryChildren(node),
							getCategorySeries(node)
						);
					}
				});
				functionCache.set(createCategoryNode, data.id, node);
			}
			return node;
		}

		private function getCategoryChildren(node:ColumnTreeNode):Array
		{
			var result:Object = getJson('category/children', {category_id: node.data.id});

			if(!result.categories)
				return [];
			return result.categories.map(createCategoryNode);
		}

		private function getCategorySeries(node:ColumnTreeNode):Array
		{
			var result:Object = getJson('category/series', {category_id: node.data.id});

			if(!result.seriess)
				return [];

			return result.seriess.map(createSeriesNode);
		}

		public function getObservationsCSV(series_id:String):CSVDataSource
		{
			var csv:CSVDataSource = functionCache.get(getObservationsCSV, series_id);
			if (!csv)
			{
				csv = newLinkableChild(this, CSVDataSource);
				functionCache.set(getObservationsCSV, series_id, csv);

				var request1:URLRequest = new URLRequest(getUrl('series', {series_id: series_id}));
				addAsyncResponder(
					WeaveAPI.URLRequestUtils.getURL(csv, request1),
					function(event:ResultEvent, csv:CSVDataSource):void {
						var data:Object = JsonCache.parseJSON(event.result.toString());
						data = data.seriess[0];
						var request2:URLRequest = new URLRequest(getUrl('series/observations', {series_id: series_id}));
						addAsyncResponder(
							WeaveAPI.URLRequestUtils.getURL(csv, request2),
							function(event:ResultEvent, csv:CSVDataSource):void
							{
								var result:Object = JsonCache.parseJSON(event.result.toString());
								var columnOrder:Array = ['date', 'realtime_start', 'realtime_end', 'value'];
								var rows:Array = WeaveAPI.CSVParser.convertRecordsToRows(result.observations, columnOrder);
								csv.csvData.setSessionState(rows);
								var valueTitle:String = lang("{0} ({1})", data.title, data.units);
								var metadataArray:Array = [
									{title: 'date', dataType: DataType.DATE, dateFormat: 'YYYY-MM-DD'},
									{title: 'realtime_start', dataType: DataType.DATE, dateFormat: 'YYYY-MM-DD'},
									{title: 'realtime_end', dataType: DataType.DATE, dateFormat: 'YYYY-MM-DD'},
									{title: valueTitle, dataType: DataType.NUMBER},
								];
								csv.metadata.setSessionState(metadataArray);
							},
							handleFault,
							csv
						);
					},
					handleFault,
					csv
				);
			}
			return csv;
		}
		private function handleFault(event:FaultEvent, token:Object = null):void
		{
			reportError(event);
		}

		public function createSeriesNode(data:Object, ..._):IWeaveTreeNode
		{
			var node:IWeaveTreeNode = functionCache.get(createSeriesNode, data.id);
			if (!node)
			{
				node = new ColumnTreeNode({
					label: data.title,
					source: this,
					data: data,
					isBranch: true,
					hasChildBranches: false,
					children: function(node:ColumnTreeNode):Array {
						var csv:CSVDataSource = getObservationsCSV(data.id);
						var csvRoot:IWeaveTreeNode = csv.getHierarchyRoot();
						node.source = csv;
						return csvRoot.getChildren().map(function(csvNode:IColumnReference, ..._):IWeaveTreeNode {
							var meta:Object = csvNode.getColumnMetadata();
							meta[META_SERIES_ID] = data.id;
							meta[META_COLUMN_NAME] = meta[CSVDataSource.METADATA_COLUMN_NAME];
							return generateHierarchyNode(meta);
						});
					}
				});
				functionCache.set(createSeriesNode, data.id, node);
			}
			return node;
		}

        override public function getHierarchyRoot():IWeaveTreeNode
        {

            if (!_rootNode)
            {
                var source:FREDDataSource = this;
                _rootNode = createCategoryNode();
            }
            return _rootNode;
        }

		public static const META_SERIES_ID:String = 'FRED_series_id';
		public static const META_COLUMN_NAME:String = 'FRED_column_name';

		public static const META_ID_FIELDS:Array = [META_SERIES_ID, META_COLUMN_NAME];

		override public function findHierarchyNode(metadata:Object):IWeaveTreeNode
		{
			return null;
		}

		override protected function generateHierarchyNode(metadata:Object):IWeaveTreeNode
		{
			if (!metadata)
				return null;

			return new ColumnTreeNode({
				source: this,
				idFields: META_ID_FIELDS,
				columnMetadata: metadata
			});
		}

        override protected function requestColumnFromSource(proxyColumn:ProxyColumn):void
        {
            var series:String = proxyColumn.getMetadata(META_SERIES_ID);
			//var columnName:String = proxyColumn.getMetadata(META_COLUMN_NAME);
			var csv:CSVDataSource = getObservationsCSV(series);
			var csvColumn:IAttributeColumn = csv.getAttributeColumn(ColumnMetadata.getAllMetadata(proxyColumn));
			proxyColumn.setInternalColumn(csvColumn);
        }
    }
}

add FRED data source

add FRED data source


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

package flash.utils {
public interface IExternalizable {
  function writeExternal(output: IDataOutput): void;
  function readExternal(input: IDataInput): void;
}
}

Add missing builtin flash.utils.IExternalizable