package utils
{
	import flash.geom.Rectangle;

	/**
	 * For place texture
	 */
	public final class TextureUtil
	{
		private static const HIGHEST:uint = 0xFFFFFFFF;

		/**
		 * Place textures by textureAtlasXML data
		 */
		public static function packTextures(widthDefault:uint, padding:uint, rectMap:Object, verticalSide:Boolean = false):Rectangle
		{
			for each(var rect:Rectangle in rectMap)
			{
				break;
			}
			if(!rect)
			{
				return null;
			}

			var dimensions:uint = 0;
			var rectList:Vector.<Rectangle> = new Vector.<Rectangle>;
			for each(rect in rectMap)
			{
				dimensions += rect.width * rect.height;
				rectList.push(rect);
			}
			//sort texture by size
			rectList.sort(sortRectList);

			if(widthDefault == 0)
			{
				//calculate width for Auto size
				widthDefault = Math.sqrt(dimensions);
			}

			widthDefault = getNearest2N(Math.max(int(rectList[0].width) + padding, widthDefault));

			var heightMax:uint = HIGHEST;
			var remainAreaList:Vector.<Rectangle> = new Vector.<Rectangle>;
			remainAreaList.push(new Rectangle(0, 0, widthDefault, heightMax));

			var isFit:Boolean;
			var width:int;
			var height:int;

			var area:Rectangle;
			var areaPrev:Rectangle;
			var areaNext:Rectangle;
			var areaID:int;
			var rectID:int;
			do
			{
				//Find highest blank area
				area = getHighestArea(remainAreaList);
				areaID = remainAreaList.indexOf(area);
				isFit = false;
				rectID = 0;
				for each(rect in rectList)
				{
					//check if the area is fit
					width = int(rect.width) + padding;
					height = int(rect.height) + padding;
					if (area.width >= width && area.height >= height)
					{
						//place portrait texture
						if(
							verticalSide?
							(
								height > width * 4?
								(
									areaID > 0?
									(area.height - height >= remainAreaList[areaID - 1].height):
									true
								):
								true
							):
							true
						)
						{
							isFit = true;
							break;
						}
					}
					rectID ++;
				}

				if(isFit)
				{
					//place texture if size is fit
					rect.x = area.x;
					rect.y = area.y;
					rectList.splice(rectID, 1);
					remainAreaList.splice(
						areaID + 1,
						0,
						new Rectangle(area.x + width, area.y, area.width - width, area.height)
					);
					area.y += height;
					area.width = width;
					area.height -= height;
				}
				else
				{
					//not fit, don't place it, merge blank area to others toghther
					if(areaID == 0)
					{
						areaNext = remainAreaList[areaID + 1];
					}
					else if(areaID == remainAreaList.length - 1)
					{
						areaNext = remainAreaList[areaID - 1];
					}
					else
					{
						areaPrev = remainAreaList[areaID - 1];
						areaNext = remainAreaList[areaID + 1];
						areaNext = areaPrev.height <= areaNext.height?areaNext:areaPrev;
					}
					if(area.x < areaNext.x)
					{
						areaNext.x = area.x;
					}
					areaNext.width = area.width + areaNext.width;
					remainAreaList.splice(areaID, 1);
				}
			}
			while (rectList.length > 0);

			heightMax = getNearest2N(heightMax - getLowestArea(remainAreaList).height);

			return new Rectangle(0, 0, widthDefault, heightMax);
		}

		private static function sortRectList(rect1:Rectangle, rect2:Rectangle):int
		{
			var v1:uint = rect1.width + rect1.height;
			var v2:uint = rect2.width + rect2.height;
			if (v1 == v2)
			{
				return rect1.width > rect2.width?-1:1;
			}
			return v1 > v2?-1:1;
		}

		private static function getNearest2N(_n:uint):uint
		{
			return _n & _n - 1?1 << _n.toString(2).length:_n;
		}

		private static function getHighestArea(areaList:Vector.<Rectangle>):Rectangle
		{
			var height:uint = 0;
			var areaHighest:Rectangle;
			for each(var area:Rectangle in areaList)
			{
				if (area.height > height)
				{
					height = area.height;
					areaHighest = area;
				}
			}
			return areaHighest;
		}

		private static function getLowestArea(areaList:Vector.<Rectangle>):Rectangle
		{
			var height:uint = HIGHEST;
			var areaLowest:Rectangle;
			for each(var area:Rectangle in areaList)
			{
				if (area.height < height)
				{
					height = area.height;
					areaLowest = area;
				}
			}
			return areaLowest;
		}
	}
}

package utils
{
	import flash.geom.Rectangle;

	/**
	 * For place texture
	 */
	public final class TextureUtil
	{
		private static const HIGHEST:uint = 0xFFFFFFFF;

		/**
		 * Place textures by textureAtlasXML data
		 */
		public static function packTextures(widthDefault:uint, padding:uint, rectMap:Object, verticalSide:Boolean = false):Rectangle
		{
			for each(var rect:Rectangle in rectMap)
			{
				break;
			}
			if(!rect)
			{
				return null;
			}

			var dimensions:uint = 0;
			var maxWidth:Number = 0;
			var rectList:Vector.<Rectangle> = new Vector.<Rectangle>;
			for each(rect in rectMap)
			{
				dimensions += rect.width * rect.height;
				rectList.push(rect);

				maxWidth = Math.max(rect.width, maxWidth);
			}
			//sort texture by size
			rectList.sort(sortRectList);

			if(widthDefault == 0)
			{
				//calculate width for Auto size
				widthDefault = Math.sqrt(dimensions);
			}

			widthDefault = getNearest2N(Math.max(maxWidth + padding, widthDefault));

			var heightMax:uint = HIGHEST;
			var remainAreaList:Vector.<Rectangle> = new Vector.<Rectangle>;
			remainAreaList.push(new Rectangle(0, 0, widthDefault, heightMax));

			var isFit:Boolean;
			var width:int;
			var height:int;

			var area:Rectangle;
			var areaPrev:Rectangle;
			var areaNext:Rectangle;
			var areaID:int;
			var rectID:int;
			do
			{
				//Find highest blank area
				area = getHighestArea(remainAreaList);
				areaID = remainAreaList.indexOf(area);
				isFit = false;
				rectID = 0;
				for each(rect in rectList)
				{
					//check if the area is fit
					width = int(rect.width) + padding;
					height = int(rect.height) + padding;
					if (area.width >= width && area.height >= height)
					{
						//place portrait texture
						if(
							verticalSide?
							(
								height > width * 4?
								(
									areaID > 0?
									(area.height - height >= remainAreaList[areaID - 1].height):
									true
								):
								true
							):
							true
						)
						{
							isFit = true;
							break;
						}
					}
					rectID ++;
				}

				if(isFit)
				{
					//place texture if size is fit
					rect.x = area.x;
					rect.y = area.y;
					rectList.splice(rectID, 1);
					remainAreaList.splice(
						areaID + 1,
						0,
						new Rectangle(area.x + width, area.y, area.width - width, area.height)
					);
					area.y += height;
					area.width = width;
					area.height -= height;
				}
				else
				{
					//not fit, don't place it, merge blank area to others toghther
					if(areaID == 0)
					{
						areaNext = remainAreaList[areaID + 1];
					}
					else if(areaID == remainAreaList.length - 1)
					{
						areaNext = remainAreaList[areaID - 1];
					}
					else
					{
						areaPrev = remainAreaList[areaID - 1];
						areaNext = remainAreaList[areaID + 1];
						areaNext = areaPrev.height <= areaNext.height?areaNext:areaPrev;
					}
					if(area.x < areaNext.x)
					{
						areaNext.x = area.x;
					}
					areaNext.width = area.width + areaNext.width;
					remainAreaList.splice(areaID, 1);
				}
			}
			while (rectList.length > 0);

			heightMax = getNearest2N(heightMax - getLowestArea(remainAreaList).height);

			return new Rectangle(0, 0, widthDefault, heightMax);
		}

		private static function sortRectList(rect1:Rectangle, rect2:Rectangle):int
		{
			var v1:uint = rect1.width + rect1.height;
			var v2:uint = rect2.width + rect2.height;
			if (v1 == v2)
			{
				return rect1.width > rect2.width?-1:1;
			}
			return v1 > v2?-1:1;
		}

		private static function getNearest2N(_n:uint):uint
		{
			return _n & _n - 1?1 << _n.toString(2).length:_n;
		}

		private static function getHighestArea(areaList:Vector.<Rectangle>):Rectangle
		{
			var height:uint = 0;
			var areaHighest:Rectangle;
			for each(var area:Rectangle in areaList)
			{
				if (area.height > height)
				{
					height = area.height;
					areaHighest = area;
				}
			}
			return areaHighest;
		}

		private static function getLowestArea(areaList:Vector.<Rectangle>):Rectangle
		{
			var height:uint = HIGHEST;
			var areaLowest:Rectangle;
			for each(var area:Rectangle in areaList)
			{
				if (area.height < height)
				{
					height = area.height;
					areaLowest = area;
				}
			}
			return areaLowest;
		}
	}
}

fix get TextureAtlas width bug

fix get TextureAtlas width bug


m4_pattern_allow([^URBI_SERVER$])		         -*- shell-script -*-

AS_INIT()dnl
URBI_PREPARE()

set -e

case $VERBOSE in
  x) set -x;;
esac

# Avoid zombies and preserve debugging information.
cleanup ()
{
  exit_status=$?

  # In case we were caught by set -e, kill the children.
  children_kill
  children_harvest
  children_report

  children_sta=$(children_status remote)
  # Don't clean before calling children_status...
  test x$VERBOSE != x || children_clean

  case $exit_status:$children_sta in
    0:0) ;;
    0:*) # Maybe a children exited for SKIP etc.
	 exit $children_sta;;
    *:*) # If liburbi-check failed, there is a big problem.
	 error SOFTWARE "liburbi-check itself failed with $exit_status";;
  esac
  # rst_expect sets exit=false if it saw a failure.
  $exit
}
for signal in 1 2 13 15; do
  trap 'error $((128 + $signal)) \
	      "received signal $signal ($(kill -l $signal))"' $signal
done
trap cleanup 0

# Overriden to include the test name.
stderr ()
{
  echo >&2 "$(basename $0): $me: $@"
  echo >&2
}

# Sleep some time, but taking into account the fact that
# instrumentation slows down a lot.
my_sleep ()
{
  if $INSTRUMENT; then
    sleep $(($1 * 5))
  else
    sleep $1
  fi
}

## -------------- ##
## Main program.  ##
## -------------- ##

exec 3>&2

: ${abs_builddir='@abs_builddir@'}
check_dir abs_builddir liburbi-check
: ${abs_top_builddir='@abs_top_builddir@'}
check_dir abs_top_builddir config.status

# Make it absolute.
chk=$(absolute "$1")
if test ! -f "$chk.cc"; then
  fatal "no such file: $chk.cc"
fi

period=32
# ./../../../tests/2.x/andexp-pipeexp.chk -> 2.x
medir=$(basename $(dirname "$chk"))
# ./../../../tests/2.x/andexp-pipeexp.chk -> 2.x/andexp-pipeexp
me=$medir/$(basename "$chk" ".cc")
# ./../../../tests/2.x/andexp-pipeexp.chk -> andexp-pipeexp
meraw=$(basename $me)    # MERAW!

srcdir=$(absolute $srcdir)
export srcdir
# Move to a private dir.
rm -rf $me.dir
mkdir -p $me.dir
cd $me.dir

# Help debugging
set | rst_pre "$me variables"

# $URBI_SERVER.
#
# If this SDK-Remote is part of the Kernel package, then we should not
# use an installed urbi-console, but rather the one which is part of
# this package.
if test -x ${abs_top_builddir}/../src/urbi-console; then
  URBI_SERVER=${abs_top_builddir}/../src/urbi-console
else
  # Leaves trailing files, so run it in subdir.
  find_urbi_server
fi

# compute expected output
sed -n -e 's@//= @@p' $chk.cc >output.exp
touch error.exp
echo 0 >status.exp

#start it
valgrind=$(instrument "server.val")
cmd="$valgrind $URBI_SERVER --port 0 -w server.port --period $period"
echo "$cmd" >server.cmd
$cmd >server.out 2>server.err &
children_register server

my_sleep 2

#start the test
valgrind=$(instrument "remote.val")
cmd="$valgrind ../../tests localhost $(cat server.port) $meraw"
echo "$cmd" >remote.cmd
$cmd >remote.out.raw 2>remote.err &
children_register remote

# Let some time to run the tests.
children_wait 10

# Ignore the "client errors".
sed -e '/^E client error/d' remote.out.raw >remote.out.eff
# Compare expected output with actual output.
rst_expect output remote.out
rst_pre "Error output" remote.err

# Display Valgrind report.
rst_pre "Valgrind" remote.val

# Exit with success: liburbi-check made its job.  But now clean (on
# trap 0) will check $exit to see if there is a failure in the tests
# and adjust the exit status accordingly.
exit 0

m4_pattern_allow([^URBI_(PATH|SERVER)$])         -*- shell-script -*-

AS_INIT()dnl
URBI_PREPARE()

set -e

case $VERBOSE in
  x) set -x;;
esac

# Avoid zombies and preserve debugging information.
cleanup ()
{
  exit_status=$?

  # In case we were caught by set -e, kill the children.
  children_kill
  children_harvest
  children_report

  children_sta=$(children_status remote)
  # Don't clean before calling children_status...
  test x$VERBOSE != x || children_clean

  case $exit_status:$children_sta in
    0:0) ;;
    0:*) # Maybe a children exited for SKIP etc.
	 exit $children_sta;;
    *:*) # If liburbi-check failed, there is a big problem.
	 error SOFTWARE "liburbi-check itself failed with $exit_status";;
  esac
  # rst_expect sets exit=false if it saw a failure.
  $exit
}
for signal in 1 2 13 15; do
  trap 'error $((128 + $signal)) \
	      "received signal $signal ($(kill -l $signal))"' $signal
done
trap cleanup 0

# Overriden to include the test name.
stderr ()
{
  echo >&2 "$(basename $0): $me: $@"
  echo >&2
}

# Sleep some time, but taking into account the fact that
# instrumentation slows down a lot.
my_sleep ()
{
  if $INSTRUMENT; then
    sleep $(($1 * 5))
  else
    sleep $1
  fi
}

## -------------- ##
## Main program.  ##
## -------------- ##

exec 3>&2

: ${abs_builddir='@abs_builddir@'}
check_dir abs_builddir liburbi-check
: ${abs_top_builddir='@abs_top_builddir@'}
check_dir abs_top_builddir config.status
: ${abs_top_srcdir='@abs_top_srcdir@'}
check_dir abs_top_srcdir configure.ac

# Make it absolute.
chk=$(absolute "$1")
if test ! -f "$chk.cc"; then
  fatal "no such file: $chk.cc"
fi

period=32
# ./../../../tests/2.x/andexp-pipeexp.chk -> 2.x
medir=$(basename $(dirname "$chk"))
# ./../../../tests/2.x/andexp-pipeexp.chk -> 2.x/andexp-pipeexp
me=$medir/$(basename "$chk" ".cc")
# ./../../../tests/2.x/andexp-pipeexp.chk -> andexp-pipeexp
meraw=$(basename $me)    # MERAW!

srcdir=$(absolute $srcdir)
export srcdir
# Move to a private dir.
rm -rf $me.dir
mkdir -p $me.dir
cd $me.dir

# Help debugging
set | rst_pre "$me variables"

# $URBI_SERVER.
#
# If this SDK-Remote is part of the Kernel package, then we should not
# use an installed urbi-console, but rather the one which is part of
# this package.
if test -x $abs_top_builddir/../src/urbi-console; then
  URBI_SERVER=$abs_top_builddir/../src/urbi-console
  export URBI_PATH=$abs_top_srcdir/../share
else
  # Leaves trailing files, so run it in subdir.
  find_urbi_server
fi

# compute expected output
sed -n -e 's@//= @@p' $chk.cc >output.exp
touch error.exp
echo 0 >status.exp

#start it
valgrind=$(instrument "server.val")
cmd="$valgrind $URBI_SERVER --port 0 -w server.port --period $period"
echo "$cmd" >server.cmd
$cmd >server.out 2>server.err &
children_register server

my_sleep 2

#start the test
valgrind=$(instrument "remote.val")
cmd="$valgrind ../../tests localhost $(cat server.port) $meraw"
echo "$cmd" >remote.cmd
$cmd >remote.out.raw 2>remote.err &
children_register remote

# Let some time to run the tests.
children_wait 10

# Ignore the "client errors".
sed -e '/^E client error/d' remote.out.raw >remote.out.eff
# Compare expected output with actual output.
rst_expect output remote.out
rst_pre "Error output" remote.err

# Display Valgrind report.
rst_pre "Valgrind" remote.val

# Exit with success: liburbi-check made its job.  But now clean (on
# trap 0) will check $exit to see if there is a failure in the tests
# and adjust the exit status accordingly.
exit 0

Fix make check to use the shipped kernel.

	* src/tests/liburbi-check.as: If we are part of a shipped
	Kernel, set the appropriate URBI_PATH.


//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.text.TextField;

import flump.Util;
import flump.display.Movie;
import flump.mold.MovieMold;
import flump.xfl.XflLibrary;
import flump.xfl.XflTexture;

import mx.core.UIComponent;

import spark.components.Group;
import spark.events.GridSelectionEvent;
import spark.formatters.NumberFormatter;

import starling.core.Starling;
import starling.display.DisplayObject;
import starling.display.Sprite;

import com.threerings.util.F;
import com.threerings.util.MathUtil;

import com.threerings.text.TextFieldUtil;

public class PreviewController
{
    public function show (project :ProjectConf, lib :XflLibrary) :void {
        _lib = lib;
        _project = project;

        if (_controlsWindow == null || _controlsWindow.closed) {
            createControlsWindow();
        } else {
            _controlsWindow.activate();
        }

        if (_animPreviewWindow == null || _animPreviewWindow.closed) {
            createAnimWindow();

        } else {
            _animPreviewWindow.activate();
            showInternal();
        }
    }

    protected function createAnimWindow () :void {
        _animPreviewWindow = new AnimPreviewWindow();
        _animPreviewWindow.started = function (container :starling.display.Sprite) :void {
            _container = container;
            _originIcon = Util.createOriginIcon();

            Starling.current.stage.addEventListener(Event.RESIZE, onAnimPreviewResize);
            showInternal();
        };
        _animPreviewWindow.open();
    }

    protected function createControlsWindow () :void {
        _controlsWindow = new PreviewControlsWindow();
        _controlsWindow.open();

        _controlsWindow.movies.addEventListener(GridSelectionEvent.SELECTION_CHANGE,
            function (..._) :void {
                _controlsWindow.textures.selectedIndex = -1;
                displayLibraryItem(_controlsWindow.movies.selectedItem.movie);
            });
        _controlsWindow.textures.addEventListener(GridSelectionEvent.SELECTION_CHANGE,
            function (..._) :void {
                _controlsWindow.movies.selectedIndex = -1;
                displayLibraryItem(_controlsWindow.textures.selectedItem.texture);
            });

        _controlsWindow.showAtlas.addEventListener(MouseEvent.CLICK, function (..._) :void {
            if (_atlasPreviewWindow == null || _atlasPreviewWindow.closed) {
                createAtlasWindow();
            } else {
                _atlasPreviewWindow.activate();
            }
        });
    }

    protected function createAtlasWindow () :void {
        _atlasPreviewWindow = new AtlasPreviewWindow();
        _atlasPreviewWindow.open();

        // default our atlas scale to our export scale
        var scale :Number = 1;
        if (_project.exports.length > 0) {
            const exportConf :ExportConf = _project.exports[0];
            scale = exportConf.scale;
        }
        _atlasPreviewWindow.scale.text = "" + scale;
        _atlasPreviewWindow.setScale.addEventListener(MouseEvent.CLICK, F.callback(updateAtlas));
        updateAtlas();
    }

    protected function updateAtlas () :void {
        // create our atlases
        const scale :Number = MathUtil.clamp(Number(_atlasPreviewWindow.scale.text), 0.001, 1);
        const atlases :Vector.<Atlas> = TexturePacker.withLib(_lib).baseScale(scale).createAtlases();

        const sprite :flash.display.Sprite = new flash.display.Sprite();
        for (var ii :int = 0; ii < atlases.length; ++ii) {
            var atlas :Atlas = atlases[ii];
            var atlasSprite :flash.display.Sprite = AtlasUtil.toSprite(atlas);
            var w :int = atlasSprite.width;
            var h :int = atlasSprite.height;

            // atlas info
            var tf :TextField = TextFieldUtil.newBuilder()
                .text("Atlas " + ii + ": " + int(w) + "x" + int(h))
                .color(0x0)
                .autoSizeCenter()
                .build();

            tf.x = 2;
            tf.y = sprite.height;
            sprite.addChild(tf);

            // border
            atlasSprite.graphics.lineStyle(1, 0x0000ff);
            atlasSprite.graphics.drawRect(0, 0, w, h);
            atlasSprite.y = sprite.height;
            sprite.addChild(atlasSprite);
        }

        const uic :UIComponent = new UIComponent();
        uic.addChild(sprite);

        const group :Group = _atlasPreviewWindow.bitmapLayoutGroup;
        group.removeAllElements();
        group.addElement(uic);

        // Agh. I cannot figure out how to get the group to properly resize itself when
        // new elements are added.
        group.width = sprite.width;
        group.height = sprite.height;

        //_atlasPreviewWindow.maxWidth = width;
        //_atlasPreviewWindow.maxHeight = height;
    }

    protected function showInternal () :void {
        _creator = new DisplayCreator(_lib);

        const intFormatter :NumberFormatter = new NumberFormatter();
        const formatMemory :Function = function (item :Object, ..._) :String {
            return intFormatter.format(item.memory/1024) + "k";
        };
        intFormatter.fractionalDigits = 0;

        // Use a labelFunction so column sorting works as expected
        _controlsWindow.movieMemory.labelFunction = formatMemory;
        _controlsWindow.textureMemory.labelFunction = formatMemory;

        // All explicitly exported movies
        const previewMovies :Vector.<MovieMold> =
            _lib.movies.filter(function (movie :MovieMold, ..._) :Boolean {
                return _lib.isExported(movie);
            });

        _controlsWindow.movies.dataProvider.removeAll();
        for each (var movie :MovieMold in previewMovies) {
            _controlsWindow.movies.dataProvider.addItem({
                movie: movie.id,
                memory: _creator.getMemoryUsage(movie.id),
                drawn: _creator.getMaxDrawn(movie.id)
            });
        }

        var totalUsage :int = 0;
        _controlsWindow.textures.dataProvider.removeAll();
        for each (var tex :XflTexture in _lib.textures) {
            var itemUsage :int = _creator.getMemoryUsage(tex.symbol);
            totalUsage += itemUsage;
            _controlsWindow.textures.dataProvider.addItem({texture: tex.symbol, memory: itemUsage});
        }
        _controlsWindow.totalValue.text = formatMemory({memory: totalUsage});

        var atlasSize :Number = 0;
        var atlasUsed :Number = 0;
        for each (var atlas :Atlas in TexturePacker.withLib(_lib).createAtlases()) {
            atlasSize += atlas.area;
            atlasUsed += atlas.used;
        }
        const percentFormatter :NumberFormatter = new NumberFormatter();
        percentFormatter.fractionalDigits = 2;
        _controlsWindow.atlasWasteValue.text = percentFormatter.format((1.0 - (atlasUsed/atlasSize)) * 100) + "%";

        if (previewMovies.length > 0) {
            // Play the first movie
            _controlsWindow.movies.selectedIndex = 0;
            // Grumble, wish setting the index above would fire the listener
            displayLibraryItem(previewMovies[0].id);
        }

        Starling.current.stage.color = _lib.backgroundColor;

        if (_atlasPreviewWindow != null && !_atlasPreviewWindow.closed) {
            updateAtlas();
        }
    }

    protected function displayLibraryItem (name :String) :void {
        while (_container.numChildren > 0) _container.removeChildAt(0);
        _previewSprite = _creator.createDisplayObject(name);
        _container.addChild(_previewSprite);
        _container.addChild(_originIcon);
        if (_previewSprite is Movie) {
            Starling.juggler.add(Movie(_previewSprite));
        }
        onAnimPreviewResize();
    }

    protected function onAnimPreviewResize (..._) :void {
        var bounds :Rectangle = _previewSprite.bounds;
        _previewSprite.x = _originIcon.x = ((_animPreviewWindow.width - bounds.width) * 0.5) - bounds.left;
        _previewSprite.y = _originIcon.y = ((_animPreviewWindow.height - bounds.height) * 0.5) - bounds.top;
    }

    protected var _previewSprite :starling.display.DisplayObject;
    protected var _container :starling.display.Sprite;
    protected var _originIcon :starling.display.Sprite;
    protected var _controlsWindow :PreviewControlsWindow;
    protected var _animPreviewWindow :AnimPreviewWindow;
    protected var _atlasPreviewWindow :AtlasPreviewWindow;
    protected var _creator :DisplayCreator;

    protected var _lib :XflLibrary;
    protected var _project :ProjectConf;
}
}

//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.text.TextField;

import flump.Util;
import flump.display.Movie;
import flump.mold.MovieMold;
import flump.xfl.XflLibrary;
import flump.xfl.XflTexture;

import mx.core.UIComponent;

import spark.components.Group;
import spark.events.GridSelectionEvent;
import spark.formatters.NumberFormatter;

import starling.core.Starling;
import starling.display.DisplayObject;
import starling.display.Sprite;

import com.threerings.util.F;
import com.threerings.util.MathUtil;

import com.threerings.text.TextFieldUtil;

public class PreviewController
{
    public function show (project :ProjectConf, lib :XflLibrary) :void {
        _lib = lib;
        _project = project;

        if (_controlsWindow == null || _controlsWindow.closed) {
            createControlsWindow();
        } else {
            _controlsWindow.activate();
        }

        if (_animPreviewWindow == null || _animPreviewWindow.closed) {
            createAnimWindow();

        } else {
            _animPreviewWindow.activate();
            showInternal();
        }
    }

    protected function createAnimWindow () :void {
        _animPreviewWindow = new AnimPreviewWindow();
        _animPreviewWindow.started = function (container :starling.display.Sprite) :void {
            _container = container;
            _originIcon = Util.createOriginIcon();

            Starling.current.stage.addEventListener(Event.RESIZE, onAnimPreviewResize);
            showInternal();
        };
        _animPreviewWindow.open();
    }

    protected function createControlsWindow () :void {
        _controlsWindow = new PreviewControlsWindow();
        _controlsWindow.open();

        _controlsWindow.movies.addEventListener(GridSelectionEvent.SELECTION_CHANGE,
            function (..._) :void {
                _controlsWindow.textures.selectedIndex = -1;
                displayLibraryItem(_controlsWindow.movies.selectedItem.movie);
            });
        _controlsWindow.textures.addEventListener(GridSelectionEvent.SELECTION_CHANGE,
            function (..._) :void {
                _controlsWindow.movies.selectedIndex = -1;
                displayLibraryItem(_controlsWindow.textures.selectedItem.texture);
            });

        _controlsWindow.showAtlas.addEventListener(MouseEvent.CLICK, function (..._) :void {
            if (_atlasPreviewWindow == null || _atlasPreviewWindow.closed) {
                createAtlasWindow();
            } else {
                _atlasPreviewWindow.activate();
            }
        });
    }

    protected function createAtlasWindow () :void {
        _atlasPreviewWindow = new AtlasPreviewWindow();
        _atlasPreviewWindow.open();

        // default our atlas scale to our export scale
        var scale :Number = 1;
        if (_project.exports.length > 0) {
            const exportConf :ExportConf = _project.exports[0];
            scale = exportConf.scale;
        }
        _atlasPreviewWindow.scale.text = "" + scale;
        _atlasPreviewWindow.setScale.addEventListener(MouseEvent.CLICK, F.callback(updateAtlas));
        updateAtlas();
    }

    protected function updateAtlas () :void {
        // create our atlases
        const scale :Number = MathUtil.clamp(Number(_atlasPreviewWindow.scale.text), 0.001, 1);
        const atlases :Vector.<Atlas> = TexturePacker.withLib(_lib).baseScale(scale).createAtlases();

        const sprite :flash.display.Sprite = new flash.display.Sprite();
        for (var ii :int = 0; ii < atlases.length; ++ii) {
            var atlas :Atlas = atlases[ii];
            var atlasSprite :flash.display.Sprite = AtlasUtil.toSprite(atlas);
            var w :int = atlasSprite.width;
            var h :int = atlasSprite.height;

            // atlas info
            var tf :TextField = TextFieldUtil.newBuilder()
                .text("Atlas " + ii + ": " + int(w) + "x" + int(h))
                .color(0x0)
                .autoSizeCenter()
                .build();

            tf.x = 2;
            tf.y = sprite.height;
            sprite.addChild(tf);

            // border
            atlasSprite.graphics.lineStyle(1, 0x0000ff);
            atlasSprite.graphics.drawRect(0, 0, w, h);
            atlasSprite.y = sprite.height;
            sprite.addChild(atlasSprite);
        }

        const uic :UIComponent = new UIComponent();
        uic.addChild(sprite);

        const group :Group = _atlasPreviewWindow.bitmapLayoutGroup;
        group.removeAllElements();
        group.addElement(uic);

        // Agh. I cannot figure out how to get the group to properly resize itself when
        // new elements are added.
        group.width = sprite.width;
        group.height = sprite.height;

        //_atlasPreviewWindow.maxWidth = width;
        //_atlasPreviewWindow.maxHeight = height;
    }

    protected function showInternal () :void {
        _creator = new DisplayCreator(_lib);

        const intFormatter :NumberFormatter = new NumberFormatter();
        const formatMemory :Function = function (item :Object, ..._) :String {
            return intFormatter.format(item.memory/1024) + "k";
        };
        intFormatter.fractionalDigits = 0;

        // Use a labelFunction so column sorting works as expected
        _controlsWindow.movieMemory.labelFunction = formatMemory;
        _controlsWindow.textureMemory.labelFunction = formatMemory;

        // All explicitly exported movies
        const previewMovies :Vector.<MovieMold> =
            _lib.movies.filter(function (movie :MovieMold, ..._) :Boolean {
                return _lib.isExported(movie);
            });

        _controlsWindow.movies.dataProvider.removeAll();
        for each (var movie :MovieMold in previewMovies) {
            _controlsWindow.movies.dataProvider.addItem({
                movie: movie.id,
                memory: _creator.getMemoryUsage(movie.id),
                drawn: _creator.getMaxDrawn(movie.id)
            });
        }

        var totalUsage :int = 0;
        _controlsWindow.textures.dataProvider.removeAll();
        for each (var tex :XflTexture in _lib.textures) {
            var itemUsage :int = _creator.getMemoryUsage(tex.symbol);
            totalUsage += itemUsage;
            _controlsWindow.textures.dataProvider.addItem({texture: tex.symbol, memory: itemUsage});
        }
        _controlsWindow.totalValue.text = formatMemory({memory: totalUsage});

        var atlasSize :Number = 0;
        var atlasUsed :Number = 0;
        for each (var atlas :Atlas in TexturePacker.withLib(_lib).createAtlases()) {
            atlasSize += atlas.area;
            atlasUsed += atlas.used;
        }
        const percentFormatter :NumberFormatter = new NumberFormatter();
        percentFormatter.fractionalDigits = 2;
        _controlsWindow.atlasWasteValue.text = percentFormatter.format((1.0 - (atlasUsed/atlasSize)) * 100) + "%";

        if (previewMovies.length > 0) {
            // Play the first movie
            _controlsWindow.movies.selectedIndex = 0;
            // Grumble, wish setting the index above would fire the listener
            displayLibraryItem(previewMovies[0].id);
        }

        Starling.current.stage.color = _lib.backgroundColor;

        if (_atlasPreviewWindow != null && !_atlasPreviewWindow.closed) {
            updateAtlas();
        }
    }

    protected function displayLibraryItem (name :String) :void {
        while (_container.numChildren > 0) _container.removeChildAt(0);
        _previewSprite = _creator.createDisplayObject(name);
        _previewBounds = _previewSprite.bounds;
        _container.addChild(_previewSprite);
        _container.addChild(_originIcon);
        if (_previewSprite is Movie) {
            Starling.juggler.add(Movie(_previewSprite));
        }
        onAnimPreviewResize();
    }

    protected function onAnimPreviewResize (..._) :void {
        _previewSprite.x = _originIcon.x =
            ((_animPreviewWindow.width - _previewBounds.width) * 0.5) - _previewBounds.left;
        _previewSprite.y = _originIcon.y =
            ((_animPreviewWindow.height - _previewBounds.height) * 0.5) - _previewBounds.top;
    }

    protected var _previewSprite :starling.display.DisplayObject;
    protected var _previewBounds :Rectangle;
    protected var _container :starling.display.Sprite;
    protected var _originIcon :starling.display.Sprite;
    protected var _controlsWindow :PreviewControlsWindow;
    protected var _animPreviewWindow :AnimPreviewWindow;
    protected var _atlasPreviewWindow :AtlasPreviewWindow;
    protected var _creator :DisplayCreator;

    protected var _lib :XflLibrary;
    protected var _project :ProjectConf;
}
}

Fix animation re-centering on window resize


package com.kaltura.hls
{
	import com.kaltura.hls.manifest.HLSManifestPlaylist;
	import com.kaltura.hls.manifest.HLSManifestParser;
	import com.kaltura.hls.subtitles.SubTitleParser;
	import com.kaltura.hls.subtitles.TextTrackCue;
	import com.kaltura.hls.HLSDVRTimeTrait;

	import org.osmf.traits.MediaTraitBase;
	import org.osmf.traits.MediaTraitType;
	import org.osmf.traits.TimeTrait;
	import org.osmf.traits.SeekTrait;

	import org.osmf.media.MediaElement;

	import flash.events.*;
	import flash.utils.*;

	public class SubtitleTrait extends MediaTraitBase
	{
		public static const TYPE:String = "subtitle";

		private var _playLists:Vector.<HLSManifestPlaylist> = new <HLSManifestPlaylist>[];
		private var _languages:Vector.<String> = new <String>[];
		private var _language:String = "";

		public var owningMediaElement:MediaElement;

		private var _lastCue:TextTrackCue;
		private var _lastInjectedSubtitleTime:Number = -1;

		private static var activeTrait:SubtitleTrait = null;
		private static var activeReload:HLSManifestParser;
		private static var reloadLanguage:String = null;
		private static var _reloadTimer:Timer;
		private static var _subtitleTimer:Timer;

		public function SubtitleTrait()
		{
			super(TYPE);

			activeTrait = this;

			if(!_reloadTimer)
			{
				trace("SubTitleTrait - starting reload timer");
				_reloadTimer = new Timer(1000);
				_reloadTimer.addEventListener(TimerEvent.TIMER, onReloadTimer);
				_reloadTimer.start();
			}

			if(!_subtitleTimer)
			{
				trace("SubTitleTrait - starting subtitle timer");
				_subtitleTimer = new Timer(50);
				_subtitleTimer.addEventListener(TimerEvent.TIMER, onSubtitleTimer);
				_subtitleTimer.start();
			}

		}

		/**
		 * Fired frequently to emit any new subtitle events based on playhead position.
		 */
		private static function onSubtitleTimer(e:Event):void
		{
			// If no trait/no titles, ignore it.
			if(activeTrait == null || activeTrait.activeSubtitles == null)
				return;

			// Otherwise, attempt to get the time trait and determine our current playtime.
			if(!activeTrait.owningMediaElement)
				return;

			var tt:TimeTrait = activeTrait.owningMediaElement.getTrait(MediaTraitType.TIME) as TimeTrait;
			if(!tt)
				return;

			// Great, time is knowable - so what is it?
			var curTime:Number = tt.currentTime;
			if(tt is HLSDVRTimeTrait)
				curTime = (tt as HLSDVRTimeTrait).absoluteTime;

			// This is quite verbose but useful for debugging.
			// trace("onSubtitleTimer - Current time is: " + curTime);

			// Now, fire off any subtitles that are new.
			activeTrait.emitSubtitles(activeTrait._lastInjectedSubtitleTime, curTime);
		}

		/**
		 * Actually fire subtitle events for any subtitles in the specified period.
		 */
		private function emitSubtitles( startTime:Number, endTime:Number ):void
		{
			var subtitles:Vector.<SubTitleParser> = activeSubtitles;
			var subtitleCount:int = subtitles.length;

			for ( var i:int = 0; i < subtitleCount; i++ )
			{
				var subtitle:SubTitleParser = subtitles[ i ];
				if ( subtitle.startTime > endTime ) continue;
				if ( subtitle.endTime < startTime ) continue;
				var cues:Vector.<TextTrackCue> = subtitle.textTrackCues;
				var cueCount:int = cues.length;

				var potentials:Vector.<TextTrackCue> = new Vector.<TextTrackCue>();

				for ( var j:int = 0; j < cueCount; j++ )
				{
					var cue:TextTrackCue = cues[ j ];
					if ( cue.startTime > endTime ) break;
					else if ( cue.startTime >= startTime )
					{
						potentials.push(cue);
					}
				}

				if(potentials.length > 0)
				{
					// TODO: Add support for trackid
					cue = potentials[potentials.length - 1];
					if(cue != _lastCue)
					{
						dispatchEvent(new SubtitleEvent(cue.startTime, cue.text, language));

						_lastInjectedSubtitleTime = cue.startTime;
						_lastCue = cue;
					}
				}
			}
		}

		/**
		 * Fired intermittently to check for new subtitle segments to download.
		 */
		private static function onReloadTimer(e:Event):void
		{
			// Check for any subtitles that have not been requested yet.
			if(activeTrait == null || activeTrait.activeManifest == null)
			{
				trace("SubTitleTrait - skipping reload, inactive")
				return;
			}

			// If reloading but not parsed yet.
			if(activeReload && activeReload.timestamp == -1)
			{
				trace("SubTitleTrait - skipping reload, pending download");
				return;
			}

			// Or it's a VOD or was recently reloaded.
			var man:HLSManifestParser = activeTrait.activeManifest;
			if(man &&
				(man.streamEnds
				|| (getTimer() - man.lastReloadRequestTime) < man.targetDuration * 1000 * 0.75))
			{
				trace("SubTitleTrait - skipping reload, waiting until targetDuration has expired.");
				return;
			}

			if(man)
			{
				trace("Saw manifest with age " + (getTimer() - man.lastReloadRequestTime) + " and targetDuration " + man.targetDuration * 1000 );
			}

			trace("SubTitleTrait - initiating reload of " + man.fullUrl);
			var manifest:HLSManifestParser = new HLSManifestParser();
			manifest.addEventListener(Event.COMPLETE, onManifestReloaded);
			manifest.addEventListener(IOErrorEvent.IO_ERROR, onManifestReloadFail);
			manifest.type = HLSManifestParser.SUBTITLES;
			manifest.reload(man);
			activeReload = manifest;
			reloadLanguage = activeTrait.language;
		}

		private static function onManifestReloaded(e:Event):void
		{
			if(e.target != activeReload || reloadLanguage != activeTrait.language)
			{
				trace("Got subtitle manifest reload for non-active manifest, ignoring...");
				return;
			}

			// Instate the manifest.
			trace("Subtitle manifest downloaded, instating " + reloadLanguage);
			activeTrait.instateNewManifest(reloadLanguage, e.target as HLSManifestParser);
			activeReload = null;
			reloadLanguage = null;
		}

		private static function onManifestReloadFail(e:Event):void
		{
			if(e.target != activeReload || reloadLanguage != activeTrait.language)
			{
				trace("Got subtitle manifest reload for non-active manifest, ignoring...");
				return;
			}

			trace("Subtitle manifest failed, clearing reload attempt.");
			activeReload = null;
			reloadLanguage = null;
		}

		protected function instateNewManifest(lang:String, man:HLSManifestParser):void
		{
			if(language != lang)
				return;

			if ( _language == "" ) return;
			for ( var i:int = 0; i < _playLists.length; i++ )
			{
				// If the playlist has a language associated with it, use that language
				var pLanguage:String;
				if (_playLists[ i ].language && _playLists[ i ].language != "")
					pLanguage = _playLists[ i ].language;
				else
					pLanguage = _playLists[ i ].name;

				if (pLanguage == _language )
				{
					_playLists[ i ].manifest = man;
				}
			}
		}

		public function set playLists( value:Vector.<HLSManifestPlaylist> ):void
		{
			_playLists.length = 0;
			_languages.length = 0;

			if ( !value ) return;

			for ( var i:int = 0; i < value.length; i++ )
			{
				_playLists.push( value[ i ] );
				if (value[ i ].language && value[ i ].language != "")
					_languages.push( value[ i ].language );
				else
					_languages.push( value[ i ].name );
			}
		}

		public function set language( value:String ):void
		{
			// Trigger a seek to flush buffer and get proper language.
			if(_language != value)
			{
				_language = value;

				trace("Triggering flush for proper subtitle language.");
				if(owningMediaElement)
				{
					var st:SeekTrait = owningMediaElement.getTrait(MediaTraitType.SEEK) as SeekTrait;
					var tt:TimeTrait = owningMediaElement.getTrait(MediaTraitType.TIME) as TimeTrait;

					if(st == null)
					{
						trace("   o No seek trait, skipping...");
					}

					if(tt == null)
					{
						trace("   o No time trait, skipping...");
					}

					if(st != null && tt != null)
					{
						trace("   o Initiating seek to " + tt.currentTime);
						//st.seek(tt.currentTime);
					}
				}
				else
				{
					trace("   o No media element, skipping...");
				}
			}
		}

		public function get language():String
		{
			return _language;
		}

		public function get languages():Vector.<String>
		{
			return _languages;
		}

		public function get activeManifest():HLSManifestParser
		{
			if ( _language == "" ) return null;
			for ( var i:int = 0; i < _playLists.length; i++ )
			{
				// If the playlist has a language associated with it, use that language
				var pLanguage:String;
				if (_playLists[ i ].language && _playLists[ i ].language != "")
					pLanguage = _playLists[ i ].language;
				else
					pLanguage = _playLists[ i ].name;

				if (pLanguage == _language ) return _playLists[ i ].manifest;
			}
			return null;
		}

		public function get activeSubtitles():Vector.<SubTitleParser>
		{
			var man:HLSManifestParser = activeManifest;
			if(man)
				return man.subtitles;
			return null;
		}
	}
}

package com.kaltura.hls
{
	import com.kaltura.hls.manifest.HLSManifestPlaylist;
	import com.kaltura.hls.manifest.HLSManifestParser;
	import com.kaltura.hls.subtitles.SubTitleParser;
	import com.kaltura.hls.subtitles.TextTrackCue;
	import com.kaltura.hls.HLSDVRTimeTrait;

	import org.osmf.traits.MediaTraitBase;
	import org.osmf.traits.MediaTraitType;
	import org.osmf.traits.TimeTrait;
	import org.osmf.traits.SeekTrait;

	import org.osmf.media.MediaElement;

	import flash.events.*;
	import flash.utils.*;

	public class SubtitleTrait extends MediaTraitBase
	{
		public static const TYPE:String = "subtitle";

		private var _playLists:Vector.<HLSManifestPlaylist> = new <HLSManifestPlaylist>[];
		private var _languages:Vector.<String> = new <String>[];
		private var _language:String = "";

		public var owningMediaElement:MediaElement;

		private var _lastCue:TextTrackCue;
		private var _lastInjectedSubtitleTime:Number = -1;

		private static var activeTrait:SubtitleTrait = null;
		private static var activeReload:HLSManifestParser;
		private static var reloadLanguage:String = null;
		private static var _reloadTimer:Timer;
		private static var _subtitleTimer:Timer;

		public function SubtitleTrait()
		{
			super(TYPE);

			activeTrait = this;

			if(!_reloadTimer)
			{
				trace("SubTitleTrait - starting reload timer");
				_reloadTimer = new Timer(1000);
				_reloadTimer.addEventListener(TimerEvent.TIMER, onReloadTimer);
				_reloadTimer.start();
			}

			if(!_subtitleTimer)
			{
				trace("SubTitleTrait - starting subtitle timer");
				_subtitleTimer = new Timer(50);
				_subtitleTimer.addEventListener(TimerEvent.TIMER, onSubtitleTimer);
				_subtitleTimer.start();
			}

		}

		/**
		 * Fired frequently to emit any new subtitle events based on playhead position.
		 */
		private static function onSubtitleTimer(e:Event):void
		{
			// If no trait/no titles, ignore it.
			if(activeTrait == null || activeTrait.activeSubtitles == null)
				return;

			// Otherwise, attempt to get the time trait and determine our current playtime.
			if(!activeTrait.owningMediaElement)
				return;

			var tt:TimeTrait = activeTrait.owningMediaElement.getTrait(MediaTraitType.TIME) as TimeTrait;
			if(!tt)
				return;

			// Great, time is knowable - so what is it?
			var curTime:Number = tt.currentTime;
			if(tt is HLSDVRTimeTrait)
				curTime = (tt as HLSDVRTimeTrait).absoluteTime;

			// This is quite verbose but useful for debugging.
			// trace("onSubtitleTimer - Current time is: " + curTime);

			// Now, fire off any subtitles that are new.
			activeTrait.emitSubtitles(activeTrait._lastInjectedSubtitleTime, curTime);
		}

		/**
		 * Actually fire subtitle events for any subtitles in the specified period.
		 */
		private function emitSubtitles( startTime:Number, endTime:Number ):void
		{
			var subtitles:Vector.<SubTitleParser> = activeSubtitles;
			var subtitleCount:int = subtitles.length;
			var potentials:Vector.<TextTrackCue> = new Vector.<TextTrackCue>();

			for ( var i:int = 0; i < subtitleCount; i++ )
			{
				var subtitle:SubTitleParser = subtitles[ i ];
				if ( subtitle.startTime > endTime ) continue;
				if ( subtitle.endTime < startTime ) continue;
				var cues:Vector.<TextTrackCue> = subtitle.textTrackCues;
				var cueCount:int = cues.length;

				for ( var j:int = 0; j < cueCount; j++ )
				{
					var cue:TextTrackCue = cues[ j ];
					if ( cue.startTime > endTime ) break;
					else if ( cue.startTime >= startTime )
					{
						potentials.push(cue);
					}
				}
			}

			if(potentials.length > 0)
			{
				// TODO: Add support for trackid
				cue = potentials[potentials.length - 1];
				if(cue != _lastCue)
				{
					dispatchEvent(new SubtitleEvent(cue.startTime, cue.text, language));

					_lastInjectedSubtitleTime = cue.startTime;
					_lastCue = cue;
				}
			}

			// Force last time so we eventually show proper subtitles.
			_lastInjectedSubtitleTime = endTime;

		}

		/**
		 * Fired intermittently to check for new subtitle segments to download.
		 */
		private static function onReloadTimer(e:Event):void
		{
			// Check for any subtitles that have not been requested yet.
			if(activeTrait == null || activeTrait.activeManifest == null)
			{
				trace("SubTitleTrait - skipping reload, inactive")
				return;
			}

			// If reloading but not parsed yet.
			if(activeReload && activeReload.timestamp == -1)
			{
				trace("SubTitleTrait - skipping reload, pending download");
				return;
			}

			// Or it's a VOD or was recently reloaded.
			var man:HLSManifestParser = activeTrait.activeManifest;
			if(man &&
				(man.streamEnds
				|| (getTimer() - man.lastReloadRequestTime) < man.targetDuration * 1000 * 0.75))
			{
				trace("SubTitleTrait - skipping reload, waiting until targetDuration has expired.");
				return;
			}

			if(man)
			{
				trace("Saw manifest with age " + (getTimer() - man.lastReloadRequestTime) + " and targetDuration " + man.targetDuration * 1000 );
			}

			trace("SubTitleTrait - initiating reload of " + man.fullUrl);
			var manifest:HLSManifestParser = new HLSManifestParser();
			manifest.addEventListener(Event.COMPLETE, onManifestReloaded);
			manifest.addEventListener(IOErrorEvent.IO_ERROR, onManifestReloadFail);
			manifest.type = HLSManifestParser.SUBTITLES;
			manifest.reload(man);
			activeReload = manifest;
			reloadLanguage = activeTrait.language;
		}

		private static function onManifestReloaded(e:Event):void
		{
			if(e.target != activeReload || reloadLanguage != activeTrait.language)
			{
				trace("Got subtitle manifest reload for non-active manifest, ignoring...");
				return;
			}

			// Instate the manifest.
			trace("Subtitle manifest downloaded, instating " + reloadLanguage);
			activeTrait.instateNewManifest(reloadLanguage, e.target as HLSManifestParser);
			activeReload = null;
			reloadLanguage = null;
		}

		private static function onManifestReloadFail(e:Event):void
		{
			if(e.target != activeReload || reloadLanguage != activeTrait.language)
			{
				trace("Got subtitle manifest reload for non-active manifest, ignoring...");
				return;
			}

			trace("Subtitle manifest failed, clearing reload attempt.");
			activeReload = null;
			reloadLanguage = null;
		}

		protected function instateNewManifest(lang:String, man:HLSManifestParser):void
		{
			if(language != lang)
				return;

			if ( _language == "" ) return;
			for ( var i:int = 0; i < _playLists.length; i++ )
			{
				// If the playlist has a language associated with it, use that language
				var pLanguage:String;
				if (_playLists[ i ].language && _playLists[ i ].language != "")
					pLanguage = _playLists[ i ].language;
				else
					pLanguage = _playLists[ i ].name;

				if (pLanguage == _language )
				{
					_playLists[ i ].manifest = man;
				}
			}
		}

		public function set playLists( value:Vector.<HLSManifestPlaylist> ):void
		{
			_playLists.length = 0;
			_languages.length = 0;

			if ( !value ) return;

			for ( var i:int = 0; i < value.length; i++ )
			{
				_playLists.push( value[ i ] );
				if (value[ i ].language && value[ i ].language != "")
					_languages.push( value[ i ].language );
				else
					_languages.push( value[ i ].name );
			}
		}

		public function set language( value:String ):void
		{
			// No special logic required, we will sort it out elsewhere.
			_language = value;
		}

		public function get language():String
		{
			return _language;
		}

		public function get languages():Vector.<String>
		{
			return _languages;
		}

		public function get activeManifest():HLSManifestParser
		{
			if ( _language == "" ) return null;
			for ( var i:int = 0; i < _playLists.length; i++ )
			{
				// If the playlist has a language associated with it, use that language
				var pLanguage:String;
				if (_playLists[ i ].language && _playLists[ i ].language != "")
					pLanguage = _playLists[ i ].language;
				else
					pLanguage = _playLists[ i ].name;

				if (pLanguage == _language ) return _playLists[ i ].manifest;
			}
			return null;
		}

		public function get activeSubtitles():Vector.<SubTitleParser>
		{
			var man:HLSManifestParser = activeManifest;
			if(man)
				return man.subtitles;
			return null;
		}
	}
}

Address seeking issues.

Address seeking issues.


/**
 * Copyright (c) 2009 Lance Carlson
 * See LICENSE for full license information.
 */
package flails.resource {
  import flash.events.EventDispatcher;

  import flails.clients.HTTPClientBase;
  import flails.clients.RailsClient;
  import flails.clients.ResourceClient;
  import flails.request.HTTPFilter;
  import flails.request.JSONFilter;
  import flails.request.RequestConfig;
  import flails.request.Result;

  import mx.utils.ObjectUtil;

  public class RailsResource implements IResource {
    public var requestConfig:RequestConfig;

    private var filter:HTTPFilter;
    private var config:Object;

    public function RailsResource(config:Object) {
      this.config = config;
      filter      = new JSONFilter();
    }

    public function index(data:Object = null):Result {
      return new RailsClient(collection('index'), HTTPClientBase.METHOD_GET, filter).send(requestData(data));
    }

    public function show(id:Object = null, data:Object = null):Result {
      return new RailsClient(member('show', id), HTTPClientBase.METHOD_GET, filter).send(requestData(data));
    }

    public function create(data:Object = null):Result {
      return new RailsClient(collection('create'), HTTPClientBase.METHOD_POST, filter).send(requestData(data));
    }

    public function update(id:Object = null, data:Object = null):Result {
      return new RailsClient(member('update', id), HTTPClientBase.METHOD_PUT, filter).send(requestData(data));
    }

    public function destroy(id:Object, data:Object = null):Result {
      return new RailsClient(member('destroy', id), HTTPClientBase.METHOD_DELETE, filter).send(requestData(data));
    }

    private function collection(method:String):String {
      return config.baseURL +
        "/" + config.name +
        (method == "index" || method == "create" ? "" : "/" + method) +
        (filter.extension != null ? "" : "." + filter.extension);
    }

    private function member(method:String, id:Object):String {
      return config.baseURL +
        "/" + config.name +
        (id != null ? "/" + id : "") +
        (method == "show" || method == "update" || method == "destroy" ? "" : "/" + method) +
        (filter.extension != null ? "" : "." + filter.extension);
    }

    private function requestData(data:Object):Object {
      var out:Object = new Object();

      if (requestConfig) {
        for each (var o:Object in requestConfig.extraParams) {
          out[o.name] = o.value;
        }
      }

      for (var k:Object in data) {
        out[k] = data[k];
      }

      return out;
    }
  }
}

/**
 * Copyright (c) 2009 Lance Carlson
 * See LICENSE for full license information.
 */
package flails.resource {
  import flash.events.EventDispatcher;

  import flails.clients.HTTPClientBase;
  import flails.clients.RailsClient;
  import flails.clients.ResourceClient;
  import flails.request.HTTPFilter;
  import flails.request.JSONFilter;
  import flails.request.RequestConfig;
  import flails.request.Result;

  import mx.utils.ObjectUtil;

  public class RailsResource implements IResource {
    private var filter:HTTPFilter;
    private var config:Object;

    public function RailsResource(config:Object) {
      this.config = config;
      filter      = new JSONFilter();
    }

    public function index(data:Object = null):Result {
      return new RailsClient(collection('index'), HTTPClientBase.METHOD_GET, filter).send(requestData(data));
    }

    public function show(id:Object = null, data:Object = null):Result {
      return new RailsClient(member('show', id), HTTPClientBase.METHOD_GET, filter).send(requestData(data));
    }

    public function create(data:Object = null):Result {
      return new RailsClient(collection('create'), HTTPClientBase.METHOD_POST, filter).send(requestData(data));
    }

    public function update(id:Object = null, data:Object = null):Result {
      return new RailsClient(member('update', id), HTTPClientBase.METHOD_PUT, filter).send(requestData(data));
    }

    public function destroy(id:Object, data:Object = null):Result {
      return new RailsClient(member('destroy', id), HTTPClientBase.METHOD_DELETE, filter).send(requestData(data));
    }

    private function collection(method:String):String {
      return config.baseURL +
        "/" + config.name +
        (method == "index" || method == "create" ? "" : "/" + method) +
        (filter.extension != null ? "" : "." + filter.extension);
    }

    private function member(method:String, id:Object):String {
      return config.baseURL +
        "/" + config.name +
        (id != null ? "/" + id : "") +
        (method == "show" || method == "update" || method == "destroy" ? "" : "/" + method) +
        (filter.extension != null ? "" : "." + filter.extension);
    }

    private function requestData(data:Object):Object {
      var out:Object = new Object();

      if (config.requestConfig) {
        for each (var o:Object in config.requestConfig.extraParams) {
          out[o.name] = o.value;
        }
      }

      for (var k:Object in data) {
        out[k] = data[k];
      }

      return out;
    }
  }
}

Handle RequestConfig.

Handle RequestConfig.


/* 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.hola {
    import flash.events.*;
    import flash.external.ExternalInterface;
    import org.hola.ZExternalInterface;
    import flash.net.URLRequest;
    import flash.net.URLStream;
    import flash.net.URLRequestHeader;
    import flash.net.URLRequestMethod;
    import flash.utils.ByteArray;
    import flash.utils.getTimer;
    import flash.utils.Timer;
    import org.hola.ZErr;
    import org.hola.Base64;
    import org.hola.WorkerUtils;
    import org.hola.HEvent;
    import org.hola.HSettings;

    public dynamic class JSURLStream extends URLStream {
        private static var js_api_inited : Boolean = false;
        private static var req_count : Number = 0;
        private static var reqs : Object = {};
        private var _connected : Boolean;
        private var _resource : ByteArray = new ByteArray();
        private var _curr_data : Object;
        private var _hola_managed : Boolean = false;
        private var _req_id : String;
        private var _self_load : Boolean = false;
        private var _events : Object;
        private var _size : Number;

        public function JSURLStream(){
            _hola_managed = HSettings.enabled && ZExternalInterface.avail();
            addEventListener(Event.OPEN, onopen);
            super();
            if (!_hola_managed || js_api_inited)
                return;
            // Connect calls to JS.
            ZErr.log('JSURLStream init api');
            ExternalInterface.marshallExceptions = true;
            ExternalInterface.addCallback('hola_onFragmentData',
                hola_onFragmentData);
            js_api_inited = true;
        }

        protected function _trigger(cb : String, data : Object) : void {
            if (!_hola_managed && !_self_load)
            {
                // XXX arik: need ZErr.throw
                ZErr.log('invalid trigger');
                throw new Error('invalid trigger');
            }
            ExternalInterface.call('window.hola_'+cb,
                {objectID: ExternalInterface.objectID, data: data});
        }

        override public function get connected() : Boolean {
            if (!_hola_managed)
                return super.connected;
            return _connected;
        }

        override public function get bytesAvailable() : uint {
            if (!_hola_managed)
                return super.bytesAvailable;
            return _resource.bytesAvailable;
        }

        override public function readByte() : int {
            if (!_hola_managed)
                return super.readByte();
            return _resource.readByte();
        }

        override public function readUnsignedShort() : uint {
            if (!_hola_managed)
                return super.readUnsignedShort();
            return _resource.readUnsignedShort();
        }

        override public function readBytes(bytes : ByteArray,
            offset : uint = 0, length : uint = 0) : void
        {
            if (!_hola_managed)
                return super.readBytes(bytes, offset, length);
            _resource.readBytes(bytes, offset, length);
        }

        override public function close() : void {
            if (_hola_managed || _self_load)
            {
                if (reqs[_req_id])
                {
                    delete reqs[_req_id];
                    _trigger('abortFragment', {req_id: _req_id});
                }
                WorkerUtils.removeEventListener(HEvent.WORKER_MESSAGE, onmsg);
            }
            if (super.connected)
                super.close();
            _connected = false;
        }

        override public function load(request : URLRequest) : void {
            if (_hola_managed || _self_load)
            {
                if (reqs[_req_id])
                {
                    delete reqs[_req_id];
                    _trigger('abortFragment', {req_id: _req_id});
                }
                WorkerUtils.removeEventListener(HEvent.WORKER_MESSAGE, onmsg);
            }
            _hola_managed = HSettings.enabled && ZExternalInterface.avail();
            req_count++;
            _req_id = 'req'+req_count;
            if (!_hola_managed)
                return super.load(request);
            WorkerUtils.addEventListener(HEvent.WORKER_MESSAGE, onmsg);
            reqs[_req_id] = this;
            _resource = new ByteArray();
            _trigger('requestFragment', {url: request.url, req_id: _req_id});
            this.dispatchEvent(new Event(Event.OPEN));
        }

        private function onopen(e : Event) : void { _connected = true; }

        private function onerror(e : ErrorEvent) : void {
            _delete();
            if (!_events.error)
                return;
            _trigger('onRequestEvent', {req_id: _req_id, event: 'error',
                error: e.text, text: e.toString()});
        }

        private function onprogress(e : ProgressEvent) : void {
            _size = e.bytesTotal;
            if (!_events.progress)
                return;
            _trigger('onRequestEvent', {req_id: _req_id, event: 'progress',
                loaded: e.bytesLoaded, total: e.bytesTotal,
                text: e.toString()});
        }

        private function onstatus(e : HTTPStatusEvent) : void {
            if (!_events.status)
                return;
            // XXX bahaa: get redirected/responseURL/responseHeaders
            _trigger('onRequestEvent', {req_id: _req_id, event: 'status',
                status: e.status, text: e.toString()});
        }

        private function oncomplete(e : Event) : void {
            _delete();
            if (!_events.complete)
                return;
            _trigger('onRequestEvent', {req_id: _req_id, event: 'complete',
                size: _size, text: e.toString()});
        }

        private function decode(str : String) : void {
            if (!str)
                return on_decoded_data(null);
            if (!HSettings.use_worker)
                return on_decoded_data(Base64.decode_str(str));
            var data : ByteArray = new ByteArray();
            data.shareable = true;
            data.writeUTFBytes(str);
            WorkerUtils.send({cmd: "b64.decode", id: _req_id});
            WorkerUtils.send(data);
        }

        private function onmsg(e : HEvent) : void {
            var msg : Object = e.data;
            if (!_req_id || _req_id!=msg.id || msg.cmd!="b64.decode")
                return;
            on_decoded_data(WorkerUtils.recv());
        }

        private function on_decoded_data(data : ByteArray) : void {
            if (data)
            {
                data.position = 0;
                if (_resource)
                {
                    var prev : uint = _resource.position;
                    data.readBytes(_resource, _resource.length);
                    _resource.position = prev;
                }
                else
                    _resource = data;
                // XXX arik: get finalLength from js
                var finalLength : uint = _resource.length;
                dispatchEvent(new ProgressEvent( ProgressEvent.PROGRESS, false,
                    false, _resource.length, finalLength));
            }
            // XXX arik: dispatch httpStatus/httpResponseStatus
            if (_curr_data.status)
                resourceLoadingSuccess();
        }

        private function self_load(o : Object) : void {
            _self_load = true;
            _hola_managed = false;
            _events = o.events||{};
            addEventListener(IOErrorEvent.IO_ERROR, onerror);
            addEventListener(SecurityErrorEvent.SECURITY_ERROR, onerror);
            addEventListener(ProgressEvent.PROGRESS, onprogress);
            addEventListener(HTTPStatusEvent.HTTP_STATUS, onstatus);
            addEventListener(Event.COMPLETE, oncomplete);
            var req : URLRequest = new URLRequest(o.url);
            req.method = o.method=="POST" ? URLRequestMethod.POST :
                URLRequestMethod.GET;
            // this doesn't seem to work. simply ignored
            var headers : Object = o.headers||{};
            for (var k : String in headers)
                req.requestHeaders.push(new URLRequestHeader(k, headers[k]));
            super.load(req);
        }

        private function on_fragment_data(o : Object) : void {
            _curr_data = o;
            if (o.self_load)
                return self_load(o);
            if (o.error)
                return resourceLoadingError();
            decode(o.data);
        }

        protected static function hola_onFragmentData(o : Object) : void{
            var stream : JSURLStream;
            try {
                if (!(stream = reqs[o.req_id]))
                    throw new Error('req_id not found '+o.req_id);
                stream.on_fragment_data(o);
            } catch(err : Error){
                ZErr.log('Error in hola_onFragmentData', ''+err,
                    ''+err.getStackTrace());
                if (stream)
                    stream.resourceLoadingError();
                throw err;
            }
        }

        private function _delete() : void {
            delete reqs[_req_id];
        }

        protected function resourceLoadingError() : void {
            _delete();
            dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR));
        }

        protected function resourceLoadingSuccess() : void {
            _delete();
            dispatchEvent(new Event(Event.COMPLETE));
        }
    }
}

/* 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.hola {
    import flash.events.*;
    import flash.external.ExternalInterface;
    import org.hola.ZExternalInterface;
    import flash.net.URLRequest;
    import flash.net.URLStream;
    import flash.net.URLRequestHeader;
    import flash.net.URLRequestMethod;
    import flash.utils.ByteArray;
    import flash.utils.getTimer;
    import flash.utils.Timer;
    import org.hola.ZErr;
    import org.hola.Base64;
    import org.hola.WorkerUtils;
    import org.hola.HEvent;
    import org.hola.HSettings;

    public dynamic class JSURLStream extends URLStream {
        private static var js_api_inited : Boolean = false;
        private static var req_count : Number = 0;
        private static var reqs : Object = {};
        private var _connected : Boolean;
        private var _resource : ByteArray = new ByteArray();
        private var _curr_data : Object;
        private var _hola_managed : Boolean = false;
        private var _req_id : String;
        private var _self_load : Boolean = false;
        private var _events : Object;
        private var _size : Number;

        public function JSURLStream(){
            _hola_managed = HSettings.enabled && ZExternalInterface.avail();
            addEventListener(Event.OPEN, onopen);
            super();
            if (!ZExternalInterface.avail() || js_api_inited)
                return;
            // Connect calls to JS.
            ZErr.log('JSURLStream init api');
            ExternalInterface.marshallExceptions = true;
            ExternalInterface.addCallback('hola_onFragmentData',
                hola_onFragmentData);
            js_api_inited = true;
        }

        protected function _trigger(cb : String, data : Object) : void {
            if (!_hola_managed && !_self_load)
            {
                // XXX arik: need ZErr.throw
                ZErr.log('invalid trigger');
                throw new Error('invalid trigger');
            }
            ExternalInterface.call('window.hola_'+cb,
                {objectID: ExternalInterface.objectID, data: data});
        }

        override public function get connected() : Boolean {
            if (!_hola_managed)
                return super.connected;
            return _connected;
        }

        override public function get bytesAvailable() : uint {
            if (!_hola_managed)
                return super.bytesAvailable;
            return _resource.bytesAvailable;
        }

        override public function readByte() : int {
            if (!_hola_managed)
                return super.readByte();
            return _resource.readByte();
        }

        override public function readUnsignedShort() : uint {
            if (!_hola_managed)
                return super.readUnsignedShort();
            return _resource.readUnsignedShort();
        }

        override public function readBytes(bytes : ByteArray,
            offset : uint = 0, length : uint = 0) : void
        {
            if (!_hola_managed)
                return super.readBytes(bytes, offset, length);
            _resource.readBytes(bytes, offset, length);
        }

        override public function close() : void {
            if (_hola_managed || _self_load)
            {
                if (reqs[_req_id])
                {
                    delete reqs[_req_id];
                    _trigger('abortFragment', {req_id: _req_id});
                }
                WorkerUtils.removeEventListener(HEvent.WORKER_MESSAGE, onmsg);
            }
            if (super.connected)
                super.close();
            _connected = false;
        }

        override public function load(request : URLRequest) : void {
            if (_hola_managed || _self_load)
            {
                if (reqs[_req_id])
                {
                    delete reqs[_req_id];
                    _trigger('abortFragment', {req_id: _req_id});
                }
                WorkerUtils.removeEventListener(HEvent.WORKER_MESSAGE, onmsg);
            }
            _hola_managed = HSettings.enabled && ZExternalInterface.avail();
            req_count++;
            _req_id = 'req'+req_count;
            if (!_hola_managed)
                return super.load(request);
            WorkerUtils.addEventListener(HEvent.WORKER_MESSAGE, onmsg);
            reqs[_req_id] = this;
            _resource = new ByteArray();
            _trigger('requestFragment', {url: request.url, req_id: _req_id});
            this.dispatchEvent(new Event(Event.OPEN));
        }

        private function onopen(e : Event) : void { _connected = true; }

        private function onerror(e : ErrorEvent) : void {
            _delete();
            if (!_events.error)
                return;
            _trigger('onRequestEvent', {req_id: _req_id, event: 'error',
                error: e.text, text: e.toString()});
        }

        private function onprogress(e : ProgressEvent) : void {
            _size = e.bytesTotal;
            if (!_events.progress)
                return;
            _trigger('onRequestEvent', {req_id: _req_id, event: 'progress',
                loaded: e.bytesLoaded, total: e.bytesTotal,
                text: e.toString()});
        }

        private function onstatus(e : HTTPStatusEvent) : void {
            if (!_events.status)
                return;
            // XXX bahaa: get redirected/responseURL/responseHeaders
            _trigger('onRequestEvent', {req_id: _req_id, event: 'status',
                status: e.status, text: e.toString()});
        }

        private function oncomplete(e : Event) : void {
            _delete();
            if (!_events.complete)
                return;
            _trigger('onRequestEvent', {req_id: _req_id, event: 'complete',
                size: _size, text: e.toString()});
        }

        private function decode(str : String) : void {
            if (!str)
                return on_decoded_data(null);
            if (!HSettings.use_worker)
                return on_decoded_data(Base64.decode_str(str));
            var data : ByteArray = new ByteArray();
            data.shareable = true;
            data.writeUTFBytes(str);
            WorkerUtils.send({cmd: "b64.decode", id: _req_id});
            WorkerUtils.send(data);
        }

        private function onmsg(e : HEvent) : void {
            var msg : Object = e.data;
            if (!_req_id || _req_id!=msg.id || msg.cmd!="b64.decode")
                return;
            on_decoded_data(WorkerUtils.recv());
        }

        private function on_decoded_data(data : ByteArray) : void {
            if (data)
            {
                data.position = 0;
                if (_resource)
                {
                    var prev : uint = _resource.position;
                    data.readBytes(_resource, _resource.length);
                    _resource.position = prev;
                }
                else
                    _resource = data;
                // XXX arik: get finalLength from js
                var finalLength : uint = _resource.length;
                dispatchEvent(new ProgressEvent( ProgressEvent.PROGRESS, false,
                    false, _resource.length, finalLength));
            }
            // XXX arik: dispatch httpStatus/httpResponseStatus
            if (_curr_data.status)
                resourceLoadingSuccess();
        }

        private function self_load(o : Object) : void {
            _self_load = true;
            _hola_managed = false;
            _events = o.events||{};
            addEventListener(IOErrorEvent.IO_ERROR, onerror);
            addEventListener(SecurityErrorEvent.SECURITY_ERROR, onerror);
            addEventListener(ProgressEvent.PROGRESS, onprogress);
            addEventListener(HTTPStatusEvent.HTTP_STATUS, onstatus);
            addEventListener(Event.COMPLETE, oncomplete);
            var req : URLRequest = new URLRequest(o.url);
            req.method = o.method=="POST" ? URLRequestMethod.POST :
                URLRequestMethod.GET;
            // this doesn't seem to work. simply ignored
            var headers : Object = o.headers||{};
            for (var k : String in headers)
                req.requestHeaders.push(new URLRequestHeader(k, headers[k]));
            super.load(req);
        }

        private function on_fragment_data(o : Object) : void {
            _curr_data = o;
            if (o.self_load)
                return self_load(o);
            if (o.error)
                return resourceLoadingError();
            decode(o.data);
        }

        protected static function hola_onFragmentData(o : Object) : void{
            var stream : JSURLStream;
            try {
                if (!(stream = reqs[o.req_id]))
                {
                    ZErr.log('req_id not found '+o.req_id);
                    return;
                }
                stream.on_fragment_data(o);
            } catch(err : Error){
                ZErr.log('Error in hola_onFragmentData', ''+err,
                    ''+err.getStackTrace());
                if (stream)
                    stream.resourceLoadingError();
                throw err;
            }
        }

        private function _delete() : void {
            delete reqs[_req_id];
        }

        protected function resourceLoadingError() : void {
            _delete();
            dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR));
        }

        protected function resourceLoadingSuccess() : void {
            _delete();
            dispatchEvent(new Event(Event.COMPLETE));
        }
    }
}

fix bug set managed mode after init + don't throw on req_id not found


package aerys.minko.render.geometry.primitive
{
	import aerys.minko.render.geometry.Geometry;
	import aerys.minko.render.geometry.stream.IVertexStream;
	import aerys.minko.render.geometry.stream.IndexStream;
	import aerys.minko.render.geometry.stream.StreamUsage;
	import aerys.minko.render.geometry.stream.VertexStream;
	import aerys.minko.render.geometry.stream.format.VertexFormat;

	public class ConeGeometry extends Geometry
	{
		public function ConeGeometry(numSegments		: uint	= 10,
									 vertexStreamUsage	: uint	= StreamUsage.STATIC,
									 indexStreamUsage	: uint	= StreamUsage.STATIC)
		{
			super(
				getVertexStreams(numSegments, vertexStreamUsage),
				getIndexStream(numSegments, indexStreamUsage)
			);
		}

		private function getVertexStreams(numSegments 		: uint,
										  vertexStreamUsage : uint) : Vector.<IVertexStream>
		{
			var xyz : Vector.<Number>	= new <Number>[0., .5, 0.];

			for (var segmentId : uint = 0; segmentId < numSegments; ++segmentId)
			{
				var angle : Number = (Math.PI * 2.) * (segmentId / numSegments);

				xyz.push(
					Math.cos(angle),
					-.5,
					Math.sin(angle)
				);
			}

			xyz.push(0., -.5, 0.);

			return new <IVertexStream>[new VertexStream(vertexStreamUsage, VertexFormat.XYZ, xyz)];
		}

		private function getIndexStream(numSegments 		: uint,
										indexStreamUsage	: uint) : IndexStream
		{
			var indices : Vector.<uint> = new <uint>[];

			for (var segmentId : uint = 0; segmentId < numSegments - 1; ++segmentId)
			{
				indices.push(
					0, segmentId + 1, segmentId + 2,
					numSegments + 1, segmentId + 2, segmentId + 1
				);
			}
			// close the shape
			indices.push(
				0, segmentId + 1, 1,
				numSegments + 1, 1, segmentId + 1
			);

			return new IndexStream(indexStreamUsage, indices);
		}
	}
}

package aerys.minko.render.geometry.primitive
{
	import aerys.minko.render.geometry.Geometry;
	import aerys.minko.render.geometry.stream.IVertexStream;
	import aerys.minko.render.geometry.stream.IndexStream;
	import aerys.minko.render.geometry.stream.StreamUsage;
	import aerys.minko.render.geometry.stream.VertexStream;
	import aerys.minko.render.geometry.stream.format.VertexFormat;

	public class ConeGeometry extends Geometry
	{
		public function ConeGeometry(numSegments		: uint	= 10,
									 vertexStreamUsage	: uint	= StreamUsage.STATIC,
									 indexStreamUsage	: uint	= StreamUsage.STATIC)
		{
			super(
				getVertexStreams(numSegments, vertexStreamUsage),
				getIndexStream(numSegments, indexStreamUsage)
			);
		}

		private function getVertexStreams(numSegments 		: uint,
										  vertexStreamUsage : uint) : Vector.<IVertexStream>
		{
			var xyz : Vector.<Number>	= new <Number>[0., .5, 0.];

			for (var segmentId : uint = 0; segmentId < numSegments; ++segmentId)
			{
				var angle : Number = (Math.PI * 2.) * (segmentId / numSegments);

				xyz.push(Math.cos(angle) * .5, -.5, Math.sin(angle) * .5);
			}

			xyz.push(0., -.5, 0.);

			return new <IVertexStream>[new VertexStream(vertexStreamUsage, VertexFormat.XYZ, xyz)];
		}

		private function getIndexStream(numSegments 		: uint,
										indexStreamUsage	: uint) : IndexStream
		{
			var indices : Vector.<uint> = new <uint>[];

			for (var segmentId : uint = 0; segmentId < numSegments - 1; ++segmentId)
			{
				indices.push(
					0, segmentId + 1, segmentId + 2,
					numSegments + 1, segmentId + 2, segmentId + 1
				);
			}
			// close the shape
			indices.push(
				0, segmentId + 1, 1,
				numSegments + 1, 1, segmentId + 1
			);

			return new IndexStream(indexStreamUsage, indices);
		}
	}
}

update ConeGeometry to create a cone with a radius = 0.5 instead of radius = 1


/*
* Copyright (C) 2003-2011 Igniterealtime Community Contributors
*
*     Daniel Henninger
*     Derrick Grigg <dgrigg@rogers.com>
*     Juga Paazmaya <olavic@gmail.com>
*     Nick Velloff <nick.velloff@gmail.com>
*     Sean Treadway <seant@oncotype.dk>
*     Sean Voisen <sean@voisen.org>
*     Mark Walters <mark@yourpalmark.com>
*     Michael McCarthy <mikeycmccarthy@gmail.com>
*
*
* 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 org.igniterealtime.xiff.util
{
	import org.flexunit.asserts.assertEquals;

	public class DateTimeParserTest
	{
		[Test]
		public function testDate2String():void
		{
			var date:Date = new Date( 2000, 10, 30, 0, 0 );
			var dateAsString:String = DateTimeParser.date2string( date );
			assertEquals( "2000-12-30", dateAsString );
		}
	}
}

/*
* Copyright (C) 2003-2011 Igniterealtime Community Contributors
*
*     Daniel Henninger
*     Derrick Grigg <dgrigg@rogers.com>
*     Juga Paazmaya <olavic@gmail.com>
*     Nick Velloff <nick.velloff@gmail.com>
*     Sean Treadway <seant@oncotype.dk>
*     Sean Voisen <sean@voisen.org>
*     Mark Walters <mark@yourpalmark.com>
*     Michael McCarthy <mikeycmccarthy@gmail.com>
*
*
* 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 org.igniterealtime.xiff.util
{
	import org.flexunit.asserts.assertEquals;

	public class DateTimeParserTest
	{
		[Test]
		public function testDate2String():void
		{
			var date:Date = new Date( 2000, 10, 30, 0, 0 );
			var dateAsString:String = DateTimeParser.date2string( date );
			assertEquals( "2000-11-30", dateAsString );
		}
	}
}

Revert of commit test.

Revert of commit test.