/*
	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.ui
{
	import flash.events.Event;

	import mx.collections.CursorBookmark;
	import mx.collections.ICollectionView;
	import mx.collections.IList;
	import mx.collections.IViewCursor;
	import mx.controls.Tree;
	import mx.core.ScrollPolicy;
	import mx.core.mx_internal;
	import mx.utils.ObjectUtil;

	import weave.utils.EventUtils;

	/**
	 * This class features a correctly behaving auto scroll policy and scrollToIndex().
	 * @author adufilie
	 */
	public class CustomTree extends Tree
	{
		public function CustomTree()
		{
			super();
			addEventListener("scroll", updateHScrollLater);
		}

		///////////////////////////////////////////////////////////////////////////////
		// solution for automatic maxHorizontalScrollPosition calculation
		// modified from http://www.frishy.com/2007/09/autoscrolling-for-flex-tree/

		// we need to override maxHorizontalScrollPosition because setting
		// Tree's maxHorizontalScrollPosition adds an indent value to it,
		// which we don't need as measureWidthOfItems seems to return exactly
		// what we need.  Not only that, but getIndent() seems to be broken
		// anyways (SDK-12578).

		// I hate using mx_internal stuff, but we can't do
		// super.super.maxHorizontalScrollPosition in AS 3, so we have to
		// emulate it.
		override public function get maxHorizontalScrollPosition():Number
		{
			if (isNaN(mx_internal::_maxHorizontalScrollPosition))
				return 0;

			return mx_internal::_maxHorizontalScrollPosition;
		}

		override public function set maxHorizontalScrollPosition(value:Number):void
		{
			if (ObjectUtil.numericCompare(mx_internal::_maxHorizontalScrollPosition, value) != 0)
			{
				mx_internal::_maxHorizontalScrollPosition = value;
				dispatchEvent(new Event("maxHorizontalScrollPositionChanged"));

				scrollAreaChanged = true;
				invalidateDisplayList();
			}
		}

		private const updateHScrollLater:Function = EventUtils.generateDelayedCallback(this, updateHScrollNow, 0);

		private function updateHScrollNow():void
		{
			// we call measureWidthOfItems to get the max width of the item renderers.
			// then we see how much space we need to scroll, setting maxHorizontalScrollPosition appropriately
			var widthOfVisibleItems:int = measureWidthOfItems(verticalScrollPosition - offscreenExtraRowsTop, listItems.length);
			var maxHSP:Number = widthOfVisibleItems - (unscaledWidth - viewMetrics.left - viewMetrics.right);

			var hspolicy:String = ScrollPolicy.ON;
			if (maxHSP <= 0)
			{
				maxHSP = 0;
				horizontalScrollPosition = 0;

				// horizontal scroll is kept on except when there is no vertical scroll
				// this avoids an infinite hide/show loop where hiding/showing the h-scroll bar affects the max h-scroll value
				if (maxVerticalScrollPosition == 0)
					hspolicy = ScrollPolicy.OFF;
			}

			maxHorizontalScrollPosition = maxHSP;

			if (horizontalScrollPolicy != hspolicy)
				horizontalScrollPolicy = hspolicy;
		}

		/**
		 * @param itemTest A function to test for a matching item:  function(item:Object):Boolean
		 * @return The matching item, if found.
		 */
		public function scrollToAndSelectMatchingItem(itemTest:Function):Object
		{
			var i:int = 0;
			var cursor:IViewCursor = collection.createCursor();
			do
			{
				if (itemTest(cursor.current))
				{
					// set selection before scrollToIndex() or it won't scroll
					selectedItems = [cursor.current];
					scrollToIndex(i);
					return cursor.current;
				}
				i++;
			}
			while (cursor.moveNext());

			// no selection
			selectedItems = [];
			return null;
		}

		///////////////////////////////////////////////////////////////////////////////
		// solution for display bugs when hierarchical data changes

		private var _dataProvider:Object; // remembers previous value that was passed to "set dataProvider"
		private var _rootItem:Object;

		override public function set dataProvider(value:Object):void
		{
			_dataProvider = value;
			super.dataProvider = value;
			_rootItem = mx_internal::_hasRoot ? mx_internal::_rootModel.createCursor().current : null;
		}

		/**
		 * This function must be called whenever the hierarchical data changes.
		 * Otherwise, the Tree will not display properly.
		 */
		public function refreshDataProvider():void
		{
			var _firstVisibleItem:Object = firstVisibleItem;
			var _selectedItems:Array = selectedItems;
			var _openItems:Array = openItems.concat();

			// use value previously passed to "set dataProvider" in order to create a new collection wrapper.
			dataProvider = _dataProvider;
			// commitProperties() behaves as desired when both dataProvider and openItems are set.
			openItems = _openItems;

			validateNow(); // necessary in order to select previous items and scroll back to the correct position

			if (showRoot || _firstVisibleItem != _rootItem)
			{
				// scroll to the previous item, but only if it is within scroll range
				var vsp:int = getItemIndex(_firstVisibleItem);
				if (vsp >= 0 && vsp <= maxVerticalScrollPosition)
					firstVisibleItem = _firstVisibleItem;
			}

			// selectedItems must be set last to avoid a bug where the Tree scrolls to the top.
			selectedItems = _selectedItems;
		}

		/**
		 * This contains a workaround for a problem in List.configureScrollBars relying on a non-working function CursorBookmark.getViewIndex().
		 * This fixes the bug where the tree would scroll all the way from the bottom to the top when a node is collapsed.
		 */
		override protected function configureScrollBars():void
		{
			var ac:ICollectionView = actualCollection;
			var ai:IViewCursor = actualIterator;
			var rda:Boolean = runningDataEffect;

			runningDataEffect = true;
			actualCollection = ac || collection; // avoids null pointer error
			actualIterator = ai || iterator;

			// This is not a perfect scrolling solution.  It looks ok when there is a partial row showing at the bottom.
			var mvsp:int = Math.max(0, collection.length - listItems.length + 1);
			if (verticalScrollPosition > mvsp)
				verticalScrollPosition = mvsp;

			super.configureScrollBars();

			runningDataEffect = rda;
			actualCollection = ac;
			actualIterator = ai;
		}

		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
		{
			updateHScrollLater();

			// If showRoot is false and root is showing, force commitProperties() to fix the problem.
			// This workaround requires that the data descriptor reports that the root item is a branch and it has children, even if it doesn't.
			if (!showRoot && _rootItem && itemToItemRenderer(_rootItem))
			{
				mx_internal::showRootChanged = true;
				commitProperties();
			}

			// "iterator" is a HierarchicalViewCursor, and its movePrevious()/moveNext()/seek() functions do not work if "current" is null.
			// Calling refreshDataProvider() returns the tree to a working state.
			if (iterator && iterator.current == null)
				refreshDataProvider();

			super.updateDisplayList(unscaledWidth, unscaledHeight);
		}

		private var _pendingScrollToIndex:int = -1;
		override public function scrollToIndex(index:int):Boolean
		{
			if (index < -1)
			{
				index /= -2;
				if (index != _pendingScrollToIndex)
				{
					_pendingScrollToIndex = -1;
					return false;
				}
			}
			_pendingScrollToIndex = -1;

			if (maxVerticalScrollPosition == 0 && index > 0)
			{
				_pendingScrollToIndex = index;
				callLater(scrollToIndex, [index * -2]);
				return false;
			}

			return super.scrollToIndex(index);
		}

	}
}

/*
	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.ui
{
	import flash.events.Event;

	import mx.collections.CursorBookmark;
	import mx.collections.ICollectionView;
	import mx.collections.IList;
	import mx.collections.IViewCursor;
	import mx.controls.Tree;
	import mx.core.ScrollPolicy;
	import mx.core.mx_internal;
	import mx.utils.ObjectUtil;

	import weave.utils.EventUtils;

	/**
	 * This class features a correctly behaving auto scroll policy and scrollToIndex().
	 * @author adufilie
	 */
	public class CustomTree extends Tree
	{
		public function CustomTree()
		{
			super();
			addEventListener("scroll", updateHScrollLater);
		}

		///////////////////////////////////////////////////////////////////////////////
		// solution for automatic maxHorizontalScrollPosition calculation
		// modified from http://www.frishy.com/2007/09/autoscrolling-for-flex-tree/

		// we need to override maxHorizontalScrollPosition because setting
		// Tree's maxHorizontalScrollPosition adds an indent value to it,
		// which we don't need as measureWidthOfItems seems to return exactly
		// what we need.  Not only that, but getIndent() seems to be broken
		// anyways (SDK-12578).

		// I hate using mx_internal stuff, but we can't do
		// super.super.maxHorizontalScrollPosition in AS 3, so we have to
		// emulate it.
		override public function get maxHorizontalScrollPosition():Number
		{
			if (isNaN(mx_internal::_maxHorizontalScrollPosition))
				return 0;

			return mx_internal::_maxHorizontalScrollPosition;
		}

		override public function set maxHorizontalScrollPosition(value:Number):void
		{
			if (ObjectUtil.numericCompare(mx_internal::_maxHorizontalScrollPosition, value) != 0)
			{
				mx_internal::_maxHorizontalScrollPosition = value;
				dispatchEvent(new Event("maxHorizontalScrollPositionChanged"));

				scrollAreaChanged = true;
				invalidateDisplayList();
			}
		}

		private const updateHScrollLater:Function = EventUtils.generateDelayedCallback(this, updateHScrollNow, 0);

		private function updateHScrollNow():void
		{
			// we call measureWidthOfItems to get the max width of the item renderers.
			// then we see how much space we need to scroll, setting maxHorizontalScrollPosition appropriately
			var widthOfVisibleItems:int = measureWidthOfItems(verticalScrollPosition - offscreenExtraRowsTop, listItems.length);
			var maxHSP:Number = widthOfVisibleItems - (unscaledWidth - viewMetrics.left - viewMetrics.right);

			var hspolicy:String = ScrollPolicy.ON;
			if (maxHSP <= 0)
			{
				maxHSP = 0;
				horizontalScrollPosition = 0;

				// horizontal scroll is kept on except when there is no vertical scroll
				// this avoids an infinite hide/show loop where hiding/showing the h-scroll bar affects the max h-scroll value
				if (maxVerticalScrollPosition == 0)
					hspolicy = ScrollPolicy.OFF;
			}

			maxHorizontalScrollPosition = maxHSP;

			if (horizontalScrollPolicy != hspolicy)
				horizontalScrollPolicy = hspolicy;
		}

		/**
		 * @param itemTest A function to test for a matching item:  function(item:Object):Boolean
		 * @return The matching item, if found.
		 */
		public function scrollToAndSelectMatchingItem(itemTest:Function):Object
		{
			var i:int = 0;
			var cursor:IViewCursor = collection.createCursor();
			do
			{
				if (itemTest(cursor.current))
				{
					// set selection before scrollToIndex() or it won't scroll
					selectedItems = [cursor.current];
					scrollToIndex(i);
					return cursor.current;
				}
				i++;
			}
			while (cursor.moveNext());

			// no selection
			selectedItems = [];
			return null;
		}

		///////////////////////////////////////////////////////////////////////////////
		// solution for display bugs when hierarchical data changes

		private var _dataProvider:Object; // remembers previous value that was passed to "set dataProvider"
		private var _rootItem:Object;

		override public function set dataProvider(value:Object):void
		{
			_dataProvider = value;
			super.dataProvider = value;
			_rootItem = mx_internal::_hasRoot ? mx_internal::_rootModel.createCursor().current : null;
		}

		/**
		 * This function must be called whenever the hierarchical data changes.
		 * Otherwise, the Tree will not display properly.
		 */
		public function refreshDataProvider():void
		{
			var _firstVisibleItem:Object = firstVisibleItem;
			var _selectedItems:Array = selectedItems;
			var _openItems:Array = openItems.concat();

			// use value previously passed to "set dataProvider" in order to create a new collection wrapper.
			dataProvider = _dataProvider;
			// commitProperties() behaves as desired when both dataProvider and openItems are set.
			openItems = _openItems;

			validateNow(); // necessary in order to select previous items and scroll back to the correct position

			if (showRoot || _firstVisibleItem != _rootItem)
			{
				// scroll to the previous item, but only if it is within scroll range
				var vsp:int = getItemIndex(_firstVisibleItem);
				if (vsp >= 0 && vsp <= maxVerticalScrollPosition)
					firstVisibleItem = _firstVisibleItem;
			}

			// selectedItems must be set last to avoid a bug where the Tree scrolls to the top.
			selectedItems = _selectedItems;
		}

		/**
		 * This contains a workaround for a problem in List.configureScrollBars relying on a non-working function CursorBookmark.getViewIndex().
		 * This fixes the bug where the tree would scroll all the way from the bottom to the top when a node is collapsed.
		 */
		override protected function configureScrollBars():void
		{
			var ac:ICollectionView = actualCollection;
			var ai:IViewCursor = actualIterator;
			var rda:Boolean = runningDataEffect;

			runningDataEffect = true;
			actualCollection = ac || collection;
			actualIterator = ai || iterator;

			// This is not a perfect scrolling solution.  It looks ok when there is a partial row showing at the bottom.
			var mvsp:int = actualCollection ? Math.max(0, actualCollection.length - listItems.length + 1) : 0;
			if (verticalScrollPosition > mvsp)
				verticalScrollPosition = mvsp;

			super.configureScrollBars();

			runningDataEffect = rda;
			actualCollection = ac;
			actualIterator = ai;
		}

		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
		{
			updateHScrollLater();

			// If showRoot is false and root is showing, force commitProperties() to fix the problem.
			// This workaround requires that the data descriptor reports that the root item is a branch and it has children, even if it doesn't.
			if (!showRoot && _rootItem && itemToItemRenderer(_rootItem))
			{
				mx_internal::showRootChanged = true;
				commitProperties();
			}

			// "iterator" is a HierarchicalViewCursor, and its movePrevious()/moveNext()/seek() functions do not work if "current" is null.
			// Calling refreshDataProvider() returns the tree to a working state.
			if (iterator && iterator.current == null)
				refreshDataProvider();

			super.updateDisplayList(unscaledWidth, unscaledHeight);
		}

		private var _pendingScrollToIndex:int = -1;
		override public function scrollToIndex(index:int):Boolean
		{
			if (index < -1)
			{
				index /= -2;
				if (index != _pendingScrollToIndex)
				{
					_pendingScrollToIndex = -1;
					return false;
				}
			}
			_pendingScrollToIndex = -1;

			if (maxVerticalScrollPosition == 0 && index > 0)
			{
				_pendingScrollToIndex = index;
				callLater(scrollToIndex, [index * -2]);
				return false;
			}

			return super.scrollToIndex(index);
		}

	}
}

fix null pointer error

fix null pointer error


package classes
{
	/**
	 AGORA - an interactive and web-based argument mapping tool that stimulates reasoning,
	 reflection, critique, deliberation, and creativity in individual argument construction
	 and in collaborative or adversarial settings.
	 Copyright (C) 2011 Georgia Institute of Technology

	 This program is free software: you can redistribute it and/or modify
	 it under the terms of the GNU Affero General Public License as
	 published by the Free Software Foundation, either version 3 of the
	 License, or (at your option) any later version.

	 This program is distributed in the hope that it will be useful,
	 but WITHOUT ANY WARRANTY; without even the implied warranty of
	 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	 GNU Affero General Public License for more details.

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

	 */
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;

	import mx.controls.Alert;

	import org.osmf.layout.AbsoluteLayoutFacet;

	public class Language
	{
		//I will set the language to either GERMAN, RUSSIAN or ENGLISH
		//based on this, you could read the values into the variables
		//by default, the language is EN-US

		public static const GERMAN:String = "GER";
		public static const ENGLISH:String = "EN-US";
		public static const RUSSIAN:String = "RUS";
		public static var language:String = GERMAN;

		public static var xml:XML;
		private static var ready:Boolean=false;

		public static function init():void
		{
			[Embed(source="../../../translation.xml", mimeType="application/octet-stream")]
			const MyData:Class;
			var byteArray:ByteArray = new MyData() as ByteArray;
			var x:XML = new XML(byteArray.readUTFBytes(byteArray.length));
			xml = x;
			ready=true;
		}

		/**The key function. Use this to look up a label from the translation document according to the set language.*/

		public static function lookup(label:String):String{
			if(!ready){
				init();
			}
			trace("Now looking up:" + label);
			var lbl:XMLList = xml.descendants(label);
			var lang:XMLList = lbl.descendants(language);
			var output:String = lang.attribute("text");
			if(!output){
				output = "error | ошибка | fehler --- There was a problem getting the text for this item. The label was: " + label;
			}
			trace("Output is: " + output);
			return output;
		}

	}
}

package classes
{
	/**
	 AGORA - an interactive and web-based argument mapping tool that stimulates reasoning,
	 reflection, critique, deliberation, and creativity in individual argument construction
	 and in collaborative or adversarial settings.
	 Copyright (C) 2011 Georgia Institute of Technology

	 This program is free software: you can redistribute it and/or modify
	 it under the terms of the GNU Affero General Public License as
	 published by the Free Software Foundation, either version 3 of the
	 License, or (at your option) any later version.

	 This program is distributed in the hope that it will be useful,
	 but WITHOUT ANY WARRANTY; without even the implied warranty of
	 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	 GNU Affero General Public License for more details.

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

	 */
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;

	import mx.controls.Alert;

	import org.osmf.layout.AbsoluteLayoutFacet;

	public class Language
	{
		//I will set the language to either GERMAN, RUSSIAN or ENGLISH
		//based on this, you could read the values into the variables
		//by default, the language is EN-US

		public static const GERMAN:String = "GER";
		public static const ENGLISH:String = "EN-US";
		public static const RUSSIAN:String = "RUS";
		public static var language:String = ENGLISH;

		public static var xml:XML;
		private static var ready:Boolean=false;

		public static function init():void
		{
			[Embed(source="../../../translation.xml", mimeType="application/octet-stream")]
			const MyData:Class;
			var byteArray:ByteArray = new MyData() as ByteArray;
			var x:XML = new XML(byteArray.readUTFBytes(byteArray.length));
			xml = x;
			ready=true;
		}

		/**The key function. Use this to look up a label from the translation document according to the set language.*/

		public static function lookup(label:String):String{
			if(!ready){
				init();
			}
			trace("Now looking up:" + label);
			var lbl:XMLList = xml.descendants(label);
			var lang:XMLList = lbl.descendants(language);
			var output:String = lang.attribute("text");
			if(!output){
				output = "error | ошибка | fehler --- There was a problem getting the text for this item. The label was: " + label;
			}
			trace("Output is: " + output);
			return output;
		}

	}
}

Change default language to ENGLISH

Change default language to ENGLISH


//
// Flump - Copyright 2012 Three Rings Design

package flump.xfl {

import flash.geom.Matrix;
import flash.geom.Point;

import flump.MatrixUtil;
import flump.mold.KeyframeMold;

import com.threerings.util.XmlUtil;

public class XflKeyframe
{
    use namespace xflns;

    public static function parse (lib :XflLibrary, baseLocation :String, xml :XML,
        flipbook :Boolean) :KeyframeMold {

        var kf :KeyframeMold = new KeyframeMold();
        kf.index = XmlUtil.getIntAttr(xml, "index");
        kf.location = baseLocation + ":" + kf.index;
        kf.duration = XmlUtil.getNumberAttr(xml, "duration", 1);
        kf.label = XmlUtil.getStringAttr(xml, "name", null);
        kf.ease = XmlUtil.getNumberAttr(xml, "acceleration", 0) / 100;

        if (flipbook) return kf;
        var symbolXml :XML;
        for each (var frameEl :XML in xml.elements.elements()) {
            if (frameEl.name().localName == "DOMSymbolInstance") {
                if (symbolXml != null)  {
                    lib.addError(kf, ParseError.CRIT, "There can be only one symbol instance at " +
                        "a time in a keyframe.");
                } else symbolXml = frameEl;
            } else {
                lib.addError(kf, ParseError.CRIT, "Non-symbols may not be in movie layers");
            }
        }

        if (symbolXml == null) return kf; // Purely labelled frame

        if (XmlUtil.hasChild(xml, "tweens")) {
            lib.addError(kf, ParseError.WARN, "Custom easing is not supported");
        }

        kf.id = kf.libraryItem = XmlUtil.getStringAttr(symbolXml, "libraryItemName");
        kf.visible = XmlUtil.getBooleanAttr(symbolXml, "isVisible", true);

        var matrix :Matrix = new Matrix();

        // Read the matrix transform
        if (symbolXml.matrix != null) {
            const matrixXml :XML = symbolXml.matrix.Matrix[0];
            function m (name :String, def :Number) :Number {
                return matrixXml == null ? def : XmlUtil.getNumberAttr(matrixXml, name, def);
            }
            matrix = new Matrix(m("a", 1), m("b", 0), m("c", 0), m("d", 1), m("tx", 0), m("ty", 0));

            // Back out of translation
            var rewound :Matrix = matrix.clone();
            rewound.tx = rewound.ty = 0;

            var p0 :Point = rewound.transformPoint(new Point(0, 0));
            var p1 :Point = rewound.transformPoint(new Point(1, 0));
            kf.rotation = Math.atan2(p1.y - p0.y, p1.x - p0.x);

            // Back out of rotation
            rewound.rotate(-kf.rotation);

            p0 = rewound.transformPoint(new Point(0, 0));
            p1 = rewound.transformPoint(new Point(1, 1));

            kf.scaleX = p1.x - p0.x;
            kf.scaleY = p1.y - p0.y;

            // var skewX :Number = p1.x - 1;
            // var skewY :Number = p1.y - 1;
        }

        // Read the pivot point
        if (symbolXml.transformationPoint != null) {
            var pivotXml :XML = symbolXml.transformationPoint.Point[0];
            if (pivotXml != null) {
                kf.pivotX = XmlUtil.getNumberAttr(pivotXml, "x", 0);
                kf.pivotY = XmlUtil.getNumberAttr(pivotXml, "y", 0);

                // Translate to the pivot point
                var orig :Matrix = matrix.clone();
                matrix.identity();
                matrix.translate(kf.pivotX, kf.pivotY);
                matrix.concat(orig);
            }
        }

        // Now that the matrix and pivot point have been read, apply translation
        kf.x = matrix.tx;
        kf.y = matrix.ty;

        // Read the alpha
        if (symbolXml.color != null) {
            var colorXml :XML = symbolXml.color.Color[0];
            if (colorXml != null) {
                kf.alpha = XmlUtil.getNumberAttr(colorXml, "alphaMultiplier", 1);
            }
        }
        return kf;
    }
}
}

//
// Flump - Copyright 2012 Three Rings Design

package flump.xfl {

import flash.geom.Matrix;
import flash.geom.Point;

import flump.MatrixUtil;
import flump.mold.KeyframeMold;

import com.threerings.util.XmlUtil;

public class XflKeyframe
{
    use namespace xflns;

    public static function parse (lib :XflLibrary, baseLocation :String, xml :XML,
        flipbook :Boolean) :KeyframeMold {

        var kf :KeyframeMold = new KeyframeMold();
        kf.index = XmlUtil.getIntAttr(xml, "index");
        kf.location = baseLocation + ":" + kf.index;
        kf.duration = XmlUtil.getNumberAttr(xml, "duration", 1);
        kf.label = XmlUtil.getStringAttr(xml, "name", null);
        kf.ease = XmlUtil.getNumberAttr(xml, "acceleration", 0) / 100;

        if (flipbook) return kf;
        var symbolXml :XML;
        for each (var frameEl :XML in xml.elements.elements()) {
            if (frameEl.name().localName == "DOMSymbolInstance") {
                if (symbolXml != null)  {
                    lib.addError(kf, ParseError.CRIT, "There can be only one symbol instance at " +
                        "a time in a keyframe.");
                } else symbolXml = frameEl;
            } else {
                lib.addError(kf, ParseError.CRIT, "Non-symbols may not be in movie layers");
            }
        }

        if (symbolXml == null) return kf; // Purely labelled frame

        if (XmlUtil.getBooleanAttr(xml, "hasCustomEase", false)) {
            lib.addError(kf, ParseError.WARN, "Custom easing is not supported");
        }

        kf.id = kf.libraryItem = XmlUtil.getStringAttr(symbolXml, "libraryItemName");
        kf.visible = XmlUtil.getBooleanAttr(symbolXml, "isVisible", true);

        var matrix :Matrix = new Matrix();

        // Read the matrix transform
        if (symbolXml.matrix != null) {
            const matrixXml :XML = symbolXml.matrix.Matrix[0];
            function m (name :String, def :Number) :Number {
                return matrixXml == null ? def : XmlUtil.getNumberAttr(matrixXml, name, def);
            }
            matrix = new Matrix(m("a", 1), m("b", 0), m("c", 0), m("d", 1), m("tx", 0), m("ty", 0));

            // Back out of translation
            var rewound :Matrix = matrix.clone();
            rewound.tx = rewound.ty = 0;

            var p0 :Point = rewound.transformPoint(new Point(0, 0));
            var p1 :Point = rewound.transformPoint(new Point(1, 0));
            kf.rotation = Math.atan2(p1.y - p0.y, p1.x - p0.x);

            // Back out of rotation
            rewound.rotate(-kf.rotation);

            p0 = rewound.transformPoint(new Point(0, 0));
            p1 = rewound.transformPoint(new Point(1, 1));

            kf.scaleX = p1.x - p0.x;
            kf.scaleY = p1.y - p0.y;

            // var skewX :Number = p1.x - 1;
            // var skewY :Number = p1.y - 1;
        }

        // Read the pivot point
        if (symbolXml.transformationPoint != null) {
            var pivotXml :XML = symbolXml.transformationPoint.Point[0];
            if (pivotXml != null) {
                kf.pivotX = XmlUtil.getNumberAttr(pivotXml, "x", 0);
                kf.pivotY = XmlUtil.getNumberAttr(pivotXml, "y", 0);

                // Translate to the pivot point
                var orig :Matrix = matrix.clone();
                matrix.identity();
                matrix.translate(kf.pivotX, kf.pivotY);
                matrix.concat(orig);
            }
        }

        // Now that the matrix and pivot point have been read, apply translation
        kf.x = matrix.tx;
        kf.y = matrix.ty;

        // Read the alpha
        if (symbolXml.color != null) {
            var colorXml :XML = symbolXml.color.Color[0];
            if (colorXml != null) {
                kf.alpha = XmlUtil.getNumberAttr(colorXml, "alphaMultiplier", 1);
            }
        }
        return kf;
    }
}
}

Change the way custom easing is detected.


package aerys.minko.render.shader
{
	import aerys.minko.ns.minko_render;
	import aerys.minko.ns.minko_shader;
	import aerys.minko.render.RenderTarget;
	import aerys.minko.render.resource.Context3DResource;
	import aerys.minko.render.resource.Program3DResource;
	import aerys.minko.render.shader.compiler.graph.ShaderGraph;
	import aerys.minko.render.shader.compiler.graph.nodes.AbstractNode;
	import aerys.minko.render.shader.part.ShaderPart;
	import aerys.minko.type.Signal;
	import aerys.minko.type.binding.DataBindings;

	import flash.utils.getQualifiedClassName;
	import aerys.minko.type.binding.Signature;
	import aerys.minko.render.ShaderDataBindingsProxy;

	use namespace minko_shader;

	/**
	 * The base class to extend in order to create ActionScript shaders
	 * and program the GPU using AS3.
	 *
	 * @author Jean-Marc Le Roux
	 * @author Romain Gilliotte
	 *
	 * @see aerys.minko.render.shader.ShaderPart
	 * @see aerys.minko.render.shader.ShaderInstance
	 * @see aerys.minko.render.shader.ShaderSignature
	 * @see aerys.minko.render.shader.ShaderDataBindings
	 */
	public class Shader extends ShaderPart
	{
		use namespace minko_shader;
		use namespace minko_render;

		minko_shader var _meshBindings		: ShaderDataBindingsProxy		= null;
		minko_shader var _sceneBindings		: ShaderDataBindingsProxy		= null;
		minko_shader var _kills				: Vector.<AbstractNode>			= new <AbstractNode>[];

		private var _name					: String						= null;
		private var _enabled				: Boolean						= true;
		private var _defaultSettings		: ShaderSettings				= new ShaderSettings(null);

		private var _instances				: Vector.<ShaderInstance>		= new <ShaderInstance>[];
		private var _numActiveInstances		: uint							= 0;
		private var _numRenderedInstances	: uint							= 0;
		private var _settings				: Vector.<ShaderSettings>		= new <ShaderSettings>[];
		private var _programs				: Vector.<Program3DResource>	= new <Program3DResource>[];

		private var _begin					: Signal						= new Signal('Shader.begin');
		private var _end					: Signal						= new Signal('Shader.end');

		/**
		 * The name of the shader. Default value is the qualified name of the
		 * ActionScript shader class (example: "aerys.minko.render.effect.basic::BasicShader").
		 *
		 * @return
		 *
		 */
		public function get name() : String
		{
			return _name;
		}
		public function set name(value : String) : void
		{
			_name = value;
		}

		/**
		 * The signal executed when the shader (one of its forks) is used
		 * for rendering for the very first time during the current frame.
		 * Callbacks for this signal must accept the following arguments:
		 *

		 *
shader : Shader, the shader executing the signal

		 *
context : Context3D, the context used for rendering

		 *
backBuffer : RenderTarget, the render target used as the back-buffer

		 *

		 *
		 * @return
		 *
		 */
		public function get begin() : Signal
		{
			return _begin;
		}

		/**
		 * The signal executed when the shader (one of its forks) is used
		 * for rendering for the very last time during the current frame.
		 * Callbacks for this signal must accept the following arguments:
		 *

		 *
shader : Shader, the shader executing the signal

		 *
context : Context3D, the context used for rendering

		 *
backBuffer : RenderTarget, the render target used as the back-buffer

		 *

		 *
		 * @return
		 *
		 */
		public function get end() : Signal
		{
			return _end;
		}

		/**
		 * Whether the shader (and all its forks) are enabled for rendering
		 * or not.
		 *
		 * @return
		 *
		 */
		public function get enabled() : Boolean
		{
			return _enabled;
		}
		public function set enabled(value : Boolean) : void
		{
			_enabled = value;
		}

		/**
		 *
		 * @param priority Default value is 0.
		 * @param renderTarget Default value is null.
		 *
		 */
		public function Shader(renderTarget	: RenderTarget	= null,
							   priority		: Number		= 0.0)
		{
			super(this);

			_defaultSettings.renderTarget = renderTarget;
			_defaultSettings.priority = priority;

			_name = getQualifiedClassName(this);
		}

		public function fork(sceneBindings	: DataBindings,
							 meshBindings	: DataBindings) : ShaderInstance
		{
			var pass : ShaderInstance = findPass(sceneBindings, meshBindings);

			if (!pass)
			{
				var signature	: Signature			= new Signature();
				var config		: ShaderSettings	= findOrCreateSettings(
					sceneBindings, meshBindings
				);

				signature.mergeWith(config.signature);

				var program		: Program3DResource	= null;

				if (config.enabled)
				{
					program = findOrCreateProgram(sceneBindings, meshBindings);
					signature.mergeWith(program.signature);
				}

				pass = new ShaderInstance(this, config, program, signature);
				pass.retained.add(shaderInstanceRetainedHandler);
				pass.released.add(shaderInstanceReleasedHandler);

				_instances.push(pass);
			}

			return pass;
		}

		public function disposeUnusedResources() : void
		{
			var numInstances	: uint = _instances.length;
			var currentId		: uint = 0;

			for (var instanceId : uint = 0; instanceId < numInstances; ++instanceId)
			{
				var passInstance : ShaderInstance = _instances[instanceId];

				if (!passInstance.isDisposable)
					_instances[currentId++] = passInstance;
			}

			_instances.length = currentId;
		}

		/**
		 * Override this method to initialize the settings
		 * - such as the blending operands or the triangle culling - of the shader.
		 * This values can be read from both the mesh and the scene bindings.
		 *
		 * @param settings
		 *
		 * @see aerys.minko.render.shader.ShaderSettings
		 *
		 */
		protected function initializeSettings(settings : ShaderSettings) : void
		{
			// nothing
		}

		/**
		 * The getVertexPosition() method is called to evaluate the vertex shader
		 * program that shall be executed on the GPU.
		 *
		 * @return The position of the vertex in clip space (normalized screen space).
		 *
		 */
		protected function getVertexPosition() : SFloat
		{
			throw new Error("The method 'getVertexPosition' must be implemented.");
		}

		/**
		 * The getPixelColor() method is called to evaluate the fragment shader
		 * program that shall be executed on the GPU.
		 *
		 * @return The color of the pixel on the screen.
		 *
		 */
		protected function getPixelColor() : SFloat
		{
			throw new Error("The method 'getPixelColor' must be implemented.");
		}

		private function findPass(sceneBindings	: DataBindings,
								  meshBindings	: DataBindings) : ShaderInstance
		{
			var numPasses : int = _instances.length;

			for (var passId : uint = 0; passId < numPasses; ++passId)
				if (_instances[passId].signature.isValid(sceneBindings, meshBindings))
					return _instances[passId];

			return null;
		}

		private function findOrCreateProgram(sceneBindings	: DataBindings,
											 meshBindings	: DataBindings) : Program3DResource
		{
			var numPrograms	: int = _programs.length;
			var program 	: Program3DResource;

			for (var programId : uint = 0; programId < numPrograms; ++programId)
				if (_programs[programId].signature.isValid(sceneBindings, meshBindings))
					return _programs[programId];

			var signature		: Signature		= new Signature();

			_meshBindings	= new ShaderDataBindingsProxy(meshBindings, signature, Signature.SOURCE_MESH);
			_sceneBindings	= new ShaderDataBindingsProxy(sceneBindings, signature, Signature.SOURCE_SCENE);

			var vertexPosition	: AbstractNode	= getVertexPosition()._node;
			var pixelColor		: AbstractNode	= getPixelColor()._node;
			var shaderGraph		: ShaderGraph	= new ShaderGraph(vertexPosition, pixelColor, _kills);

			program			= shaderGraph.generateProgram(_name, signature);
			_meshBindings	= null;
			_sceneBindings	= null;
			_kills.length	= 0;

			_programs.push(program);

			return program;
		}

		private function findOrCreateSettings(sceneBindings	: DataBindings,
											  meshBindings 	: DataBindings) : ShaderSettings
		{
			var numConfigs	: int 				= _settings.length;
			var config		: ShaderSettings	= null;

			for (var configId : int = 0; configId < numConfigs; ++configId)
				if (_settings[configId].signature.isValid(sceneBindings, meshBindings))
					return _settings[configId];

			var signature : Signature = new Signature();

			config			= _defaultSettings.clone(signature);
			_meshBindings	= new ShaderDataBindingsProxy(meshBindings, signature, Signature.SOURCE_MESH);
			_sceneBindings	= new ShaderDataBindingsProxy(sceneBindings, signature, Signature.SOURCE_SCENE);

			initializeSettings(config);

			_meshBindings	= null;
			_sceneBindings	= null;

			_settings.push(config);

			return config;
		}

		private function shaderInstanceRetainedHandler(instance : ShaderInstance,
													   numUses	: uint) : void
		{
			if (numUses == 1)
			{
				++_numActiveInstances;

				instance.begin.add(shaderInstanceBeginHandler);
				instance.end.add(shaderInstanceEndHandler);
			}
		}

		private function shaderInstanceReleasedHandler(instance : ShaderInstance,
													   numUses	: uint) : void
		{
			if (numUses == 0)
			{
				--_numActiveInstances;

				instance.begin.remove(shaderInstanceBeginHandler);
				instance.end.remove(shaderInstanceEndHandler);
			}
		}

		private function shaderInstanceBeginHandler(instance 	: ShaderInstance,
													context		: Context3DResource,
													backBuffer	: RenderTarget) : void
		{
			if (_numRenderedInstances == 0)
				_begin.execute(this, context, backBuffer);
		}

		private function shaderInstanceEndHandler(instance		: ShaderInstance,
												  context		: Context3DResource,
												  backBuffer	: RenderTarget) : void
		{
			_numRenderedInstances++;

			if (_numRenderedInstances == _numActiveInstances)
			{
				_numRenderedInstances = 0;
				_end.execute(this, context, backBuffer);
			}
		}
	}
}

package aerys.minko.render.shader
{
	import aerys.minko.ns.minko_render;
	import aerys.minko.ns.minko_shader;
	import aerys.minko.render.RenderTarget;
	import aerys.minko.render.ShaderDataBindingsProxy;
	import aerys.minko.render.resource.Context3DResource;
	import aerys.minko.render.resource.Program3DResource;
	import aerys.minko.render.shader.compiler.graph.ShaderGraph;
	import aerys.minko.render.shader.compiler.graph.nodes.AbstractNode;
	import aerys.minko.render.shader.part.ShaderPart;
	import aerys.minko.type.Signal;
	import aerys.minko.type.binding.DataBindings;
	import aerys.minko.type.binding.Signature;

	import flash.utils.getQualifiedClassName;

	use namespace minko_shader;

	/**
	 * The base class to extend in order to create ActionScript shaders
	 * and program the GPU using AS3.
	 *
	 * @author Jean-Marc Le Roux
	 * @author Romain Gilliotte
	 *
	 * @see aerys.minko.render.shader.ShaderPart
	 * @see aerys.minko.render.shader.ShaderInstance
	 * @see aerys.minko.render.shader.ShaderSignature
	 * @see aerys.minko.render.shader.ShaderDataBindings
	 */
	public class Shader extends ShaderPart
	{
		use namespace minko_shader;
		use namespace minko_render;

		minko_shader var _meshBindings		: ShaderDataBindingsProxy		= null;
		minko_shader var _sceneBindings		: ShaderDataBindingsProxy		= null;
		minko_shader var _kills				: Vector.<AbstractNode>			= new <AbstractNode>[];

		private var _name					: String						= null;
		private var _enabled				: Boolean						= true;
		private var _defaultSettings		: ShaderSettings				= new ShaderSettings(null);

		private var _instances				: Vector.<ShaderInstance>		= new <ShaderInstance>[];
		private var _numActiveInstances		: uint							= 0;
		private var _numRenderedInstances	: uint							= 0;
		private var _settings				: Vector.<ShaderSettings>		= new <ShaderSettings>[];
		private var _programs				: Vector.<Program3DResource>	= new <Program3DResource>[];

		private var _begin					: Signal						= new Signal('Shader.begin');
		private var _end					: Signal						= new Signal('Shader.end');

		/**
		 * The name of the shader. Default value is the qualified name of the
		 * ActionScript shader class (example: "aerys.minko.render.effect.basic::BasicShader").
		 *
		 * @return
		 *
		 */
		public function get name() : String
		{
			return _name;
		}
		public function set name(value : String) : void
		{
			_name = value;
		}

		/**
		 * The signal executed when the shader (one of its forks) is used
		 * for rendering for the very first time during the current frame.
		 * Callbacks for this signal must accept the following arguments:
		 *

		 *
shader : Shader, the shader executing the signal

		 *
context : Context3D, the context used for rendering

		 *
backBuffer : RenderTarget, the render target used as the back-buffer

		 *

		 *
		 * @return
		 *
		 */
		public function get begin() : Signal
		{
			return _begin;
		}

		/**
		 * The signal executed when the shader (one of its forks) is used
		 * for rendering for the very last time during the current frame.
		 * Callbacks for this signal must accept the following arguments:
		 *

		 *
shader : Shader, the shader executing the signal

		 *
context : Context3D, the context used for rendering

		 *
backBuffer : RenderTarget, the render target used as the back-buffer

		 *

		 *
		 * @return
		 *
		 */
		public function get end() : Signal
		{
			return _end;
		}

		/**
		 * Whether the shader (and all its forks) are enabled for rendering
		 * or not.
		 *
		 * @return
		 *
		 */
		public function get enabled() : Boolean
		{
			return _enabled;
		}
		public function set enabled(value : Boolean) : void
		{
			_enabled = value;
		}

		/**
		 *
		 * @param priority Default value is 0.
		 * @param renderTarget Default value is null.
		 *
		 */
		public function Shader(renderTarget	: RenderTarget	= null,
							   priority		: Number		= 0.0)
		{
			super(this);

			_defaultSettings.renderTarget = renderTarget;
			_defaultSettings.priority = priority;

			_name = getQualifiedClassName(this);
		}

		public function fork(sceneBindings	: DataBindings,
							 meshBindings	: DataBindings) : ShaderInstance
		{
			var pass : ShaderInstance = findPass(sceneBindings, meshBindings);

			if (!pass)
			{
				var signature	: Signature			= new Signature();
				var config		: ShaderSettings	= findOrCreateSettings(
					sceneBindings, meshBindings
				);

				signature.mergeWith(config.signature);

				var program		: Program3DResource	= null;

				if (config.enabled)
				{
					program = findOrCreateProgram(sceneBindings, meshBindings);
					signature.mergeWith(program.signature);
				}

				pass = new ShaderInstance(this, config, program, signature);
				pass.retained.add(shaderInstanceRetainedHandler);
				pass.released.add(shaderInstanceReleasedHandler);

				_instances.push(pass);
			}

			return pass;
		}

		public function disposeUnusedResources() : void
		{
			var numInstances	: uint = _instances.length;
			var currentId		: uint = 0;

			for (var instanceId : uint = 0; instanceId < numInstances; ++instanceId)
			{
				var passInstance : ShaderInstance = _instances[instanceId];

				if (!passInstance.isDisposable)
					_instances[currentId++] = passInstance;
			}

			_instances.length = currentId;
		}

		/**
		 * Override this method to initialize the settings
		 * - such as the blending operands or the triangle culling - of the shader.
		 * This values can be read from both the mesh and the scene bindings.
		 *
		 * @param settings
		 *
		 * @see aerys.minko.render.shader.ShaderSettings
		 *
		 */
		protected function initializeSettings(settings : ShaderSettings) : void
		{
			// nothing
		}

		/**
		 * The getVertexPosition() method is called to evaluate the vertex shader
		 * program that shall be executed on the GPU.
		 *
		 * @return The position of the vertex in clip space (normalized screen space).
		 *
		 */
		protected function getVertexPosition() : SFloat
		{
			throw new Error("The method 'getVertexPosition' must be implemented.");
		}

		/**
		 * The getPixelColor() method is called to evaluate the fragment shader
		 * program that shall be executed on the GPU.
		 *
		 * @return The color of the pixel on the screen.
		 *
		 */
		protected function getPixelColor() : SFloat
		{
			throw new Error("The method 'getPixelColor' must be implemented.");
		}

		private function findPass(sceneBindings	: DataBindings,
								  meshBindings	: DataBindings) : ShaderInstance
		{
			var numPasses : int = _instances.length;

			for (var passId : uint = 0; passId < numPasses; ++passId)
				if (_instances[passId].signature.isValid(sceneBindings, meshBindings))
					return _instances[passId];

			return null;
		}

		private function findOrCreateProgram(sceneBindings	: DataBindings,
											 meshBindings	: DataBindings) : Program3DResource
		{
			var numPrograms	: int = _programs.length;
			var program 	: Program3DResource;

			for (var programId : uint = 0; programId < numPrograms; ++programId)
				if (_programs[programId].signature.isValid(sceneBindings, meshBindings))
					return _programs[programId];

			var signature		: Signature		= new Signature();

			_meshBindings	= new ShaderDataBindingsProxy(meshBindings, signature, Signature.SOURCE_MESH);
			_sceneBindings	= new ShaderDataBindingsProxy(sceneBindings, signature, Signature.SOURCE_SCENE);

			var vertexPosition	: AbstractNode	= getVertexPosition()._node;
			var pixelColor		: AbstractNode	= getPixelColor()._node;
			var shaderGraph		: ShaderGraph	= new ShaderGraph(vertexPosition, pixelColor, _kills);

			program			= shaderGraph.generateProgram(_name, signature);
			_meshBindings	= null;
			_sceneBindings	= null;
			_kills.length	= 0;

			_programs.push(program);

			return program;
		}

		private function findOrCreateSettings(sceneBindings	: DataBindings,
											  meshBindings 	: DataBindings) : ShaderSettings
		{
			var numConfigs	: int 				= _settings.length;
			var config		: ShaderSettings	= null;

			for (var configId : int = 0; configId < numConfigs; ++configId)
				if (_settings[configId].signature.isValid(sceneBindings, meshBindings))
					return _settings[configId];

			var signature : Signature = new Signature();

			config			= _defaultSettings.clone(signature);
			_meshBindings	= new ShaderDataBindingsProxy(meshBindings, signature, Signature.SOURCE_MESH);
			_sceneBindings	= new ShaderDataBindingsProxy(sceneBindings, signature, Signature.SOURCE_SCENE);

			initializeSettings(config);

			_meshBindings	= null;
			_sceneBindings	= null;

			_settings.push(config);

			return config;
		}

		private function shaderInstanceRetainedHandler(instance : ShaderInstance,
													   numUses	: uint) : void
		{
			if (numUses == 1)
			{
				++_numActiveInstances;

				instance.begin.add(shaderInstanceBeginHandler);
				instance.end.add(shaderInstanceEndHandler);
			}
		}

		private function shaderInstanceReleasedHandler(instance : ShaderInstance,
													   numUses	: uint) : void
		{
			if (numUses == 0)
			{
				--_numActiveInstances;

				instance.begin.remove(shaderInstanceBeginHandler);
				instance.end.remove(shaderInstanceEndHandler);
			}
		}

		private function shaderInstanceBeginHandler(instance 	: ShaderInstance,
													context		: Context3DResource,
													backBuffer	: RenderTarget) : void
		{
			if (_numRenderedInstances == 0)
				_begin.execute(this, context, backBuffer);
		}

		private function shaderInstanceEndHandler(instance		: ShaderInstance,
												  context		: Context3DResource,
												  backBuffer	: RenderTarget) : void
		{
			_numRenderedInstances++;

			if (_numRenderedInstances == _numActiveInstances)
			{
				_numRenderedInstances = 0;
				_end.execute(this, context, backBuffer);
			}
		}
	}
}

refactor imports

refactor imports


package aerys.minko.type.math
{
	import mx.charts.chartClasses.NumericAxis;
	import mx.effects.easing.Quartic;

	public class Quaternion
	{
		private static const TMP_QUATERNION : Quaternion = new Quaternion();

		public function get r() : Number { return _r; }
		public function get i() : Number { return _i; }
		public function get j() : Number { return _j; }
		public function get k() : Number { return _k; }

		protected var _r : Number;
		protected var _i : Number;
		protected var _j : Number;
		protected var _k : Number;

		public static function isEqual(q1 : Quaternion, q2 : Quaternion) : Boolean
		{
			return q1._r == q2._r && q1._i == q2._i && q1._j == q2._j && q1._k == q2._k;
		}

		public static function isNotEqual(q1 : Quaternion, q2 : Quaternion) : Boolean
		{
			return !isEqual(q1, q2);
		}

		public static function norm(q : Quaternion) : Number
		{
			return q._r * q._r + q._i * q._i + q._j * q._j + q._k * q._k;
		}

		public static function absolute(q : Quaternion) : Number
		{
			return Math.sqrt(Quaternion.norm(q));
		}

		public static function add(q1 : Quaternion, q2 : Quaternion, out : Quaternion = null) : Quaternion
		{
			out ||= new Quaternion();
			out._r = q1._r + q2._r;
			out._i = q1._i + q2._i;
			out._j = q1._j + q2._j;
			out._k = q1._k + q2._k;
			return out;
		}

		public static function substract(q1 : Quaternion, q2 : Quaternion, out : Quaternion = null) : Quaternion
		{
			out ||= new Quaternion();
			out._r = q1._r - q2._r;
			out._i = q1._i - q2._i;
			out._j = q1._j - q2._j;
			out._k = q1._k - q2._k;
			return out;
		}

		public static function multiplyScalar(q : Quaternion, f : Number, out : Quaternion = null) : Quaternion
		{
			out ||= new Quaternion();
			out._r = q._r * f;
			out._i = q._i * f;
			out._j = q._j * f;
			out._k = q._k * f;
			return out;
		}

		public static function multiply(q1 : Quaternion, q2 : Quaternion, out : Quaternion = null) : Quaternion
		{
			out ||= new Quaternion();

			var t0 : Number = (q1._k - q1._j) * (q2._j - q2._k);
			var t1 : Number = (q1._r + q1._i) * (q2._r + q2._i);
			var t2 : Number = (q1._r - q1._i) * (q2._j + q2._k);
			var t3 : Number = (q1._k + q1._j) * (q2._r - q2._i);
			var t4 : Number = (q1._k - q1._i) * (q2._i - q2._j);
			var t5 : Number = (q1._k + q1._i) * (q2._i + q2._j);
			var t6 : Number = (q1._r + q1._j) * (q2._r - q2._k);
			var t7 : Number = (q1._r - q1._j) * (q2._r + q2._k);
			var t8 : Number = t5 + t6 + t7;
			var t9 : Number = (t4 + t8) / 2;

			out._r = t0 + t9 - t5;
			out._i = t1 + t9 - t8;
			out._j = t2 + t9 - t7;
			out._k = t3 + t9 - t6;

			return out;
		}

		public static function divideScalar(q : Quaternion, f : Number, out : Quaternion = null) : Quaternion
		{
			return Quaternion.multiplyScalar(q, 1 / f, out);
		}

		public static function divide(q1 : Quaternion, q2 : Quaternion, out : Quaternion = null) : Quaternion
		{
			Quaternion.invert(q2, TMP_QUATERNION);
			Quaternion.multiply(q1, TMP_QUATERNION, out);
			return out;
		}

		public static function copy(q : Quaternion, out : Quaternion = null) : Quaternion
		{
			out ||= new Quaternion();
			out._r = q._r;
			out._i = q._i;
			out._j = q._j;
			out._k = q._k;
			return out;
		}

		public static function negate(q : Quaternion, out : Quaternion = null) : Quaternion
		{
			out ||= new Quaternion();
			out._r = - q._r;
			out._i = - q._i;
			out._j = - q._j;
			out._k = - q._k;
			return out;
		}

		public static function conjugate(q : Quaternion, out : Quaternion = null) : Quaternion
		{
			out ||= new Quaternion();
			out._r = q._r;
			out._i = - q._i;
			out._j = - q._j;
			out._k = - q._k;
			return out;
		}

		public static function square(q : Quaternion, out : Quaternion = null) : Quaternion
		{
			out ||= new Quaternion();

			var tmp : Number = 2 * q._r;
			out._r = q._r * q._r - (q._i * q._i + q._j * q._j + q._k * q._k);
			out._i = tmp * q._i;
			out._j = tmp * q._j;
			out._k = tmp * q._k;
			return out;
		}

		public static function invert(q : Quaternion, out : Quaternion = null) : Quaternion
		{
			out ||= new Quaternion();

			var tmp : Number = Quaternion.norm(q);
			out._r = q._r / tmp;
			out._i = - q._i / tmp;
			out._j = - q._j / tmp;
			out._k = - q._k / tmp;

			return out;
		}

		public function Quaternion(r : Number = 0,
								   i : Number = 0,
								   j : Number = 0,
								   k : Number = 0)
		{
			_r = r;
			_i = i;
			_j = j;
			_k = k;
		}

		public function isEqual(q : Quaternion) : Boolean
		{
			return Quaternion.isEqual(this, q);
		}

		public function isNotEqual(q : Quaternion) : Boolean
		{
			return Quaternion.isNotEqual(this, q);
		}

		public function substract(q : Quaternion) : Quaternion
		{
			return Quaternion.substract(this, q, this);
		}

		public function add(q : Quaternion) : Quaternion
		{
			return Quaternion.add(this, q, this);
		}

		public function multiplyScalar(f : Number) : Quaternion
		{
			return Quaternion.multiplyScalar(this, f, this);
		}

		public function multiply(q : Quaternion) : Quaternion
		{
			return Quaternion.multiply(this, q, this);
		}

		public function divideScalar(f : Number) : Quaternion
		{
			return Quaternion.divideScalar(this, f, this);
		}

		public function divide(q : Quaternion) : Quaternion
		{
			return Quaternion.divide(this, q, this);
		}

		public function clone() : Quaternion
		{
			return Quaternion.copy(this);
		}

		public function negate() : Quaternion
		{
			return Quaternion.negate(this, this);
		}

		public function conjugate() : Quaternion
		{
			return Quaternion.conjugate(this, this);
		}

		public function square() : Quaternion
		{
			return Quaternion.square(this, this);
		}

		public function invert() : Quaternion
		{
			return Quaternion.invert(this, this);
		}

		public function toString() : String
		{
			return '[Quaternion r="' + _r + '" i="' + _i + '" j="' + _j + '" k="' + _k + '"]';
		}

	}
}

package aerys.minko.type.math
{
	public class Quaternion
	{
		private static const TMP_QUATERNION : Quaternion = new Quaternion();

		public function get r() : Number { return _r; }
		public function get i() : Number { return _i; }
		public function get j() : Number { return _j; }
		public function get k() : Number { return _k; }

		protected var _r : Number;
		protected var _i : Number;
		protected var _j : Number;
		protected var _k : Number;

		public static function isEqual(q1 : Quaternion, q2 : Quaternion) : Boolean
		{
			return q1._r == q2._r && q1._i == q2._i && q1._j == q2._j && q1._k == q2._k;
		}

		public static function isNotEqual(q1 : Quaternion, q2 : Quaternion) : Boolean
		{
			return !isEqual(q1, q2);
		}

		public static function norm(q : Quaternion) : Number
		{
			return q._r * q._r + q._i * q._i + q._j * q._j + q._k * q._k;
		}

		public static function absolute(q : Quaternion) : Number
		{
			return Math.sqrt(Quaternion.norm(q));
		}

		public static function add(q1 : Quaternion, q2 : Quaternion, out : Quaternion = null) : Quaternion
		{
			out ||= new Quaternion();
			out._r = q1._r + q2._r;
			out._i = q1._i + q2._i;
			out._j = q1._j + q2._j;
			out._k = q1._k + q2._k;
			return out;
		}

		public static function substract(q1 : Quaternion, q2 : Quaternion, out : Quaternion = null) : Quaternion
		{
			out ||= new Quaternion();
			out._r = q1._r - q2._r;
			out._i = q1._i - q2._i;
			out._j = q1._j - q2._j;
			out._k = q1._k - q2._k;
			return out;
		}

		public static function multiplyScalar(q : Quaternion, f : Number, out : Quaternion = null) : Quaternion
		{
			out ||= new Quaternion();
			out._r = q._r * f;
			out._i = q._i * f;
			out._j = q._j * f;
			out._k = q._k * f;
			return out;
		}

		public static function multiply(q1 : Quaternion, q2 : Quaternion, out : Quaternion = null) : Quaternion
		{
			out ||= new Quaternion();

			var t0 : Number = (q1._k - q1._j) * (q2._j - q2._k);
			var t1 : Number = (q1._r + q1._i) * (q2._r + q2._i);
			var t2 : Number = (q1._r - q1._i) * (q2._j + q2._k);
			var t3 : Number = (q1._k + q1._j) * (q2._r - q2._i);
			var t4 : Number = (q1._k - q1._i) * (q2._i - q2._j);
			var t5 : Number = (q1._k + q1._i) * (q2._i + q2._j);
			var t6 : Number = (q1._r + q1._j) * (q2._r - q2._k);
			var t7 : Number = (q1._r - q1._j) * (q2._r + q2._k);
			var t8 : Number = t5 + t6 + t7;
			var t9 : Number = (t4 + t8) / 2;

			out._r = t0 + t9 - t5;
			out._i = t1 + t9 - t8;
			out._j = t2 + t9 - t7;
			out._k = t3 + t9 - t6;

			return out;
		}

		public static function divideScalar(q : Quaternion, f : Number, out : Quaternion = null) : Quaternion
		{
			return Quaternion.multiplyScalar(q, 1 / f, out);
		}

		public static function divide(q1 : Quaternion, q2 : Quaternion, out : Quaternion = null) : Quaternion
		{
			Quaternion.invert(q2, TMP_QUATERNION);
			Quaternion.multiply(q1, TMP_QUATERNION, out);
			return out;
		}

		public static function copy(q : Quaternion, out : Quaternion = null) : Quaternion
		{
			out ||= new Quaternion();
			out._r = q._r;
			out._i = q._i;
			out._j = q._j;
			out._k = q._k;
			return out;
		}

		public static function negate(q : Quaternion, out : Quaternion = null) : Quaternion
		{
			out ||= new Quaternion();
			out._r = - q._r;
			out._i = - q._i;
			out._j = - q._j;
			out._k = - q._k;
			return out;
		}

		public static function conjugate(q : Quaternion, out : Quaternion = null) : Quaternion
		{
			out ||= new Quaternion();
			out._r = q._r;
			out._i = - q._i;
			out._j = - q._j;
			out._k = - q._k;
			return out;
		}

		public static function square(q : Quaternion, out : Quaternion = null) : Quaternion
		{
			out ||= new Quaternion();

			var tmp : Number = 2 * q._r;
			out._r = q._r * q._r - (q._i * q._i + q._j * q._j + q._k * q._k);
			out._i = tmp * q._i;
			out._j = tmp * q._j;
			out._k = tmp * q._k;
			return out;
		}

		public static function invert(q : Quaternion, out : Quaternion = null) : Quaternion
		{
			out ||= new Quaternion();

			var tmp : Number = Quaternion.norm(q);
			out._r = q._r / tmp;
			out._i = - q._i / tmp;
			out._j = - q._j / tmp;
			out._k = - q._k / tmp;

			return out;
		}

		public function Quaternion(r : Number = 0,
								   i : Number = 0,
								   j : Number = 0,
								   k : Number = 0)
		{
			_r = r;
			_i = i;
			_j = j;
			_k = k;
		}

		public function isEqual(q : Quaternion) : Boolean
		{
			return Quaternion.isEqual(this, q);
		}

		public function isNotEqual(q : Quaternion) : Boolean
		{
			return Quaternion.isNotEqual(this, q);
		}

		public function substract(q : Quaternion) : Quaternion
		{
			return Quaternion.substract(this, q, this);
		}

		public function add(q : Quaternion) : Quaternion
		{
			return Quaternion.add(this, q, this);
		}

		public function multiplyScalar(f : Number) : Quaternion
		{
			return Quaternion.multiplyScalar(this, f, this);
		}

		public function multiply(q : Quaternion) : Quaternion
		{
			return Quaternion.multiply(this, q, this);
		}

		public function divideScalar(f : Number) : Quaternion
		{
			return Quaternion.divideScalar(this, f, this);
		}

		public function divide(q : Quaternion) : Quaternion
		{
			return Quaternion.divide(this, q, this);
		}

		public function clone() : Quaternion
		{
			return Quaternion.copy(this);
		}

		public function negate() : Quaternion
		{
			return Quaternion.negate(this, this);
		}

		public function conjugate() : Quaternion
		{
			return Quaternion.conjugate(this, this);
		}

		public function square() : Quaternion
		{
			return Quaternion.square(this, this);
		}

		public function invert() : Quaternion
		{
			return Quaternion.invert(this, this);
		}

		public function toString() : String
		{
			return '[Quaternion r="' + _r + '" i="' + _i + '" j="' + _j + '" k="' + _k + '"]';
		}

	}
}

Remove unused imports

Remove unused imports


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

    CONFIG::LOGGING {
        import org.mangui.hls.utils.Log;
    }
    public class DemuxHelper {
        public static function probe(data : ByteArray,
                                     level : Level,
                                     audioselect : Function,
                                     progress : Function,
                                     complete : Function,
                                     error : Function,
                                     videometadata : Function,
                                     id3tagfound : Function,
                                     audioOnly : Boolean) : Demuxer {
            data.position = 0;
            CONFIG::LOGGING {
                Log.debug("probe fragment type");
            }
            var aac_match : Boolean = AACDemuxer.probe(data);
            var mp3_match : Boolean = MP3Demuxer.probe(data);
            var ts_match : Boolean = TSDemuxer.probe(data);
            CONFIG::LOGGING {
                Log.debug("AAC/MP3/TS match:" + aac_match + "/" + mp3_match + "/" + ts_match);
            }
            /* prioritize level info :
             * if ts_match && codec_avc  => TS demuxer
             * if aac_match && codec_aac => AAC demuxer
             * if mp3_match && codec_mp3 => MP3 demuxer
             * if no codec info in Manifest, use fallback order : AAC/MP3/TS
             */
            if (ts_match && level.codec_h264) {
                CONFIG::LOGGING {
                    Log.debug("TS match + H264 signaled in Manifest, use TS demuxer");
                }
                return new TSDemuxer(audioselect, progress, complete, error, videometadata, audioOnly);
            } else if (aac_match && level.codec_aac) {
                CONFIG::LOGGING {
                    Log.debug("AAC match + AAC signaled in Manifest, use AAC demuxer");
                }
                return new AACDemuxer(audioselect, progress, complete, error, id3tagfound);
            } else if (mp3_match && level.codec_mp3) {
                CONFIG::LOGGING {
                    Log.debug("MP3 match + MP3 signaled in Manifest, use MP3 demuxer");
                }
                return new MP3Demuxer(audioselect, progress, complete, error, id3tagfound);
            } else if (aac_match) {
                return new AACDemuxer(audioselect, progress, complete, error, id3tagfound);
            } else if (mp3_match) {
                return new MP3Demuxer(audioselect, progress, complete, error, id3tagfound);
            } else if (ts_match) {
                return new TSDemuxer(audioselect, progress, complete, error, videometadata, audioOnly);
            } else {
                CONFIG::LOGGING {
                    Log.debug("probe fails");
                }
                return null;
            }
        }
    }
}

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

    CONFIG::LOGGING {
        import org.mangui.hls.utils.Log;
    }
    public class DemuxHelper {
        public static function probe(data : ByteArray,
                                     level : Level,
                                     audioselect : Function,
                                     progress : Function,
                                     complete : Function,
                                     error : Function,
                                     videometadata : Function,
                                     id3tagfound : Function,
                                     audioOnly : Boolean) : Demuxer {
            data.position = 0;
            CONFIG::LOGGING {
                Log.debug("probe fragment type");
            }
            var aac_match : Boolean = AACDemuxer.probe(data);
            var mp3_match : Boolean = MP3Demuxer.probe(data);
            var ts_match : Boolean = TSDemuxer.probe(data);
            CONFIG::LOGGING {
                Log.debug("AAC/MP3/TS match:" + aac_match + "/" + mp3_match + "/" + ts_match);
            }
            /* prioritize level info :
             * if ts_match && codec_avc  => TS demuxer
             * if aac_match && codec_aac => AAC demuxer
             * if mp3_match && codec_mp3 => MP3 demuxer
             * if no codec info in Manifest, use fallback order : AAC/MP3/TS
             */
            if (ts_match && level && level.codec_h264) {
                CONFIG::LOGGING {
                    Log.debug("TS match + H264 signaled in Manifest, use TS demuxer");
                }
                return new TSDemuxer(audioselect, progress, complete, error, videometadata, audioOnly);
            } else if (aac_match && level && level.codec_aac) {
                CONFIG::LOGGING {
                    Log.debug("AAC match + AAC signaled in Manifest, use AAC demuxer");
                }
                return new AACDemuxer(audioselect, progress, complete, error, id3tagfound);
            } else if (mp3_match && level && level.codec_mp3) {
                CONFIG::LOGGING {
                    Log.debug("MP3 match + MP3 signaled in Manifest, use MP3 demuxer");
                }
                return new MP3Demuxer(audioselect, progress, complete, error, id3tagfound);
            } else if (aac_match) {
                return new AACDemuxer(audioselect, progress, complete, error, id3tagfound);
            } else if (mp3_match) {
                return new MP3Demuxer(audioselect, progress, complete, error, id3tagfound);
            } else if (ts_match) {
                return new TSDemuxer(audioselect, progress, complete, error, videometadata, audioOnly);
            } else {
                CONFIG::LOGGING {
                    Log.debug("probe fails");
                }
                return null;
            }
        }
    }
}

Make probe Level parameter optional

[Mangui.DemuxHelper] Make probe Level parameter optional

Selection logic ensures proper Demuxer is used anyway


/* ***** BEGIN LICENSE BLOCK *****
 *
 * This file is part of Weave.
 *
 * The Initial Developer of Weave is the Institute for Visualization
 * and Perception Research at the University of Massachusetts Lowell.
 * Portions created by the Initial Developer are Copyright (C) 2008-2015
 * the Initial Developer. All Rights Reserved.
 *
 * 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/.
 *
 * ***** END LICENSE BLOCK ***** */

package weavejs.data.column
{
	import weavejs.WeaveAPI;
	import weavejs.api.data.Aggregation;
	import weavejs.api.data.ColumnMetadata;
	import weavejs.api.data.DataType;
	import weavejs.api.data.IBaseColumn;
	import weavejs.api.data.IPrimitiveColumn;
	import weavejs.api.data.IQualifiedKey;
	import weavejs.util.AsyncSort;
	import weavejs.util.Dictionary2D;
	import weavejs.util.JS;
	import weavejs.util.StandardLib;

	/**
	 * @author adufilie
	 */
	public class StringColumn extends AbstractAttributeColumn implements IPrimitiveColumn, IBaseColumn
	{
		public function StringColumn(metadata:Object = null)
		{
			super(metadata);

			dataTask = new ColumnDataTask(this, filterStringValue, handleDataTaskComplete);
			dataCache = new Dictionary2D();
			Weave.getCallbacks(_asyncSort).addImmediateCallback(this, handleSortComplete);
		}

		override public function getMetadata(propertyName:String):String
		{
			var value:String = super.getMetadata(propertyName);
			if (!value && propertyName == ColumnMetadata.DATA_TYPE)
				return DataType.STRING;
			return value;
		}

		/**
		 * Sorted list of unique string values.
		 */
		private var _uniqueStrings:Array = [];

		/**
		 * String -> index in sorted _uniqueStrings
		 */
		private var _uniqueStringLookup:Object;

		public function setRecords(keys:Array, stringData:Array):void
		{
			dataTask.begin(keys, stringData);
			_asyncSort.abort();

			_uniqueStrings.length = 0;
			_uniqueStringLookup = {};
			_stringToNumberFunction = null;
			_numberToStringFunction = null;

			// compile the number format function from the metadata
			var numberFormat:String = getMetadata(ColumnMetadata.NUMBER);
			if (numberFormat)
			{
				try
				{
					_stringToNumberFunction = JS.compile(numberFormat, [ColumnMetadata.STRING, 'array'], errorHandler);
				}
				catch (e:Error)
				{
					JS.error(e);
				}
			}

			// compile the string format function from the metadata
			var stringFormat:String = getMetadata(ColumnMetadata.STRING);
			if (stringFormat)
			{
				try
				{
					_numberToStringFunction = JS.compile(stringFormat, [ColumnMetadata.NUMBER], errorHandler);
				}
				catch (e:Error)
				{
					JS.error(e);
				}
			}
		}

		private function errorHandler(e:*):void
		{
			var str:String = e is Error ? e.message : String(e);
			str = StandardLib.substitute("Error in script for AttributeColumn {0}:\n{1}", Weave.stringify(_metadata), str);
			if (_lastError != str)
			{
				_lastError = str;
				JS.error(e);
			}
		}

		private var _lastError:String;

		// variables that do not get reset after async task
		private var _stringToNumberFunction:Function = null;
		private var _numberToStringFunction:Function = null;

		private function filterStringValue(value:String):Boolean
		{
			if (!value)
				return false;

			// keep track of unique strings
			if (_uniqueStringLookup[value] === undefined)
			{
				_uniqueStrings.push(value);
				// initialize mapping
				_uniqueStringLookup[value] = -1;
			}

			return true;
		}

		private function handleDataTaskComplete():void
		{
			// begin sorting unique strings previously listed
			_asyncSort.beginSort(_uniqueStrings, AsyncSort.compareCaseInsensitive);
		}

		private var _asyncSort:AsyncSort = Weave.disposableChild(this, AsyncSort);

		private function handleSortComplete():void
		{
			if (!_asyncSort.result)
				return;

			_i = 0;
			_numberToString = {};
			// high priority because not much can be done without data
			WeaveAPI.Scheduler.startTask(this, _iterate, WeaveAPI.TASK_PRIORITY_HIGH, asyncComplete);
		}

		private var _i:int;
		private var _numberToString:Object = {};
		private var _stringToNumber:Object = {};

		private function _iterate(stopTime:int):Number
		{
			for (; _i < _uniqueStrings.length; _i++)
			{
				if (JS.now() > stopTime)
					return _i / _uniqueStrings.length;

				var string:String = _uniqueStrings[_i];
				_uniqueStringLookup[string] = _i;

				if (_stringToNumberFunction != null)
				{
					var number:Number = StandardLib.asNumber(_stringToNumberFunction(string));
					_stringToNumber[string] = number;
					_numberToString[number] = string;
				}
			}
			return 1;
		}

		private function asyncComplete():void
		{
			// cache needs to be cleared after async task completes because some values may have been cached while the task was busy
			dataCache = new Dictionary2D();
			triggerCallbacks();
		}

		// find the closest string value at a given normalized value
		public function deriveStringFromNumber(number:Number):String
		{
			if (_metadata && _metadata[ColumnMetadata.NUMBER])
			{
				if (_numberToString.hasOwnProperty(number))
					return _numberToString[number];

				if (_numberToStringFunction != null)
					return _numberToString[number] = StandardLib.asString(_numberToStringFunction(number));
			}
			else if (number == int(number) && 0 <= number && number < _uniqueStrings.length)
			{
				return _uniqueStrings[int(number)];
			}
			return '';
		}

		override protected function generateValue(key:IQualifiedKey, dataType:Class):Object
		{
			var array:Array = dataTask.map_key_arrayData.get(key);

			if (dataType === String)
				return aggregate(array, _metadata ? _metadata[ColumnMetadata.AGGREGATION] : null) || '';

			var string:String = getValueFromKey(key, String);

			if (dataType === Number)
			{
				if (_stringToNumberFunction != null)
					return Number(_stringToNumber[string]);

				return Number(_uniqueStringLookup[string]);
			}

			if (dataType === IQualifiedKey)
			{
				var type:String = _metadata ? _metadata[ColumnMetadata.DATA_TYPE] : null;
				if (!type)
					type = DataType.STRING;
				return WeaveAPI.QKeyManager.getQKey(type, string);
			}

			return null;
		}

		/**
		 * Aggregates an Array of Strings into a single String.
		 * @param strings An Array of Strings.
		 * @param aggregation One of the constants in weave.api.data.Aggregation.
		 * @return An aggregated String.
		 * @see weave.api.data.Aggregation
		 */
		public static function aggregate(strings:Array, aggregation:String):String
		{
			if (!strings)
				return undefined;

			if (!aggregation)
				aggregation = Aggregation.DEFAULT;

			switch (aggregation)
			{
				default:
				case Aggregation.SAME:
					var first:String = strings[0];
					for each (var value:String in strings)
						if (value != first)
							return Weave.lang(Aggregation.AMBIGUOUS_DATA);
					return first;

				case Aggregation.FIRST:
					return strings[0];

				case Aggregation.LAST:
					return strings[strings.length - 1];
			}
			return null;
		}

		public static function getSupportedAggregationModes():Array
		{
			return [Aggregation.SAME, Aggregation.FIRST, Aggregation.LAST];
		}
	}
}

/* ***** BEGIN LICENSE BLOCK *****
 *
 * This file is part of Weave.
 *
 * The Initial Developer of Weave is the Institute for Visualization
 * and Perception Research at the University of Massachusetts Lowell.
 * Portions created by the Initial Developer are Copyright (C) 2008-2015
 * the Initial Developer. All Rights Reserved.
 *
 * 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/.
 *
 * ***** END LICENSE BLOCK ***** */

package weavejs.data.column
{
	import weavejs.WeaveAPI;
	import weavejs.api.data.Aggregation;
	import weavejs.api.data.ColumnMetadata;
	import weavejs.api.data.DataType;
	import weavejs.api.data.IBaseColumn;
	import weavejs.api.data.IPrimitiveColumn;
	import weavejs.api.data.IQualifiedKey;
	import weavejs.util.AsyncSort;
	import weavejs.util.Dictionary2D;
	import weavejs.util.JS;
	import weavejs.util.StandardLib;

	/**
	 * @author adufilie
	 */
	public class StringColumn extends AbstractAttributeColumn implements IPrimitiveColumn, IBaseColumn
	{
		public function StringColumn(metadata:Object = null)
		{
			super(metadata);

			dataTask = new ColumnDataTask(this, filterStringValue, handleDataTaskComplete);
			dataCache = new Dictionary2D();
			Weave.getCallbacks(_asyncSort).addImmediateCallback(this, handleSortComplete);
		}

		override public function getMetadata(propertyName:String):String
		{
			var value:String = super.getMetadata(propertyName);
			if (!value && propertyName == ColumnMetadata.DATA_TYPE)
				return DataType.STRING;
			return value;
		}

		/**
		 * Sorted list of unique string values.
		 */
		private var _uniqueStrings:Array = [];

		/**
		 * String -> index in sorted _uniqueStrings
		 */
		private var _uniqueStringLookup:Object = new JS.Map();

		public function setRecords(keys:Array, stringData:Array):void
		{
			dataTask.begin(keys, stringData);
			_asyncSort.abort();

			_uniqueStrings.length = 0;
			_uniqueStringLookup.clear();
			_stringToNumberFunction = null;
			_numberToStringFunction = null;

			// compile the number format function from the metadata
			var numberFormat:String = getMetadata(ColumnMetadata.NUMBER);
			if (numberFormat)
			{
				try
				{
					_stringToNumberFunction = JS.compile(numberFormat, [ColumnMetadata.STRING, 'array'], errorHandler);
				}
				catch (e:Error)
				{
					JS.error(e);
				}
			}

			// compile the string format function from the metadata
			var stringFormat:String = getMetadata(ColumnMetadata.STRING);
			if (stringFormat)
			{
				try
				{
					_numberToStringFunction = JS.compile(stringFormat, [ColumnMetadata.NUMBER], errorHandler);
				}
				catch (e:Error)
				{
					JS.error(e);
				}
			}
		}

		private function errorHandler(e:*):void
		{
			var str:String = e is Error ? e.message : String(e);
			str = StandardLib.substitute("Error in script for AttributeColumn {0}:\n{1}", Weave.stringify(_metadata), str);
			if (_lastError != str)
			{
				_lastError = str;
				JS.error(e);
			}
		}

		private var _lastError:String;

		// variables that do not get reset after async task
		private var _stringToNumberFunction:Function = null;
		private var _numberToStringFunction:Function = null;

		private function filterStringValue(value:String):Boolean
		{
			if (!value)
				return false;

			// keep track of unique strings
			if (!_uniqueStringLookup.has(value))
			{
				_uniqueStrings.push(value);
				// initialize mapping
				_uniqueStringLookup.set(value, -1);
			}

			return true;
		}

		private function handleDataTaskComplete():void
		{
			// begin sorting unique strings previously listed
			_asyncSort.beginSort(_uniqueStrings, AsyncSort.compareCaseInsensitive);
		}

		private var _asyncSort:AsyncSort = Weave.disposableChild(this, AsyncSort);

		private function handleSortComplete():void
		{
			if (!_asyncSort.result)
				return;

			_i = 0;
			_numberToString = {};
			// high priority because not much can be done without data
			WeaveAPI.Scheduler.startTask(this, _iterate, WeaveAPI.TASK_PRIORITY_HIGH, asyncComplete);
		}

		private var _i:int;
		private var _numberToString:Object = {};
		private var _stringToNumber:Object = {};

		private function _iterate(stopTime:int):Number
		{
			for (; _i < _uniqueStrings.length; _i++)
			{
				if (JS.now() > stopTime)
					return _i / _uniqueStrings.length;

				var string:String = _uniqueStrings[_i];
				_uniqueStringLookup.set(string, _i);

				if (_stringToNumberFunction != null)
				{
					var number:Number = StandardLib.asNumber(_stringToNumberFunction(string));
					_stringToNumber[string] = number;
					_numberToString[number] = string;
				}
			}
			return 1;
		}

		private function asyncComplete():void
		{
			// cache needs to be cleared after async task completes because some values may have been cached while the task was busy
			dataCache = new Dictionary2D();
			triggerCallbacks();
		}

		// find the closest string value at a given normalized value
		public function deriveStringFromNumber(number:Number):String
		{
			if (_metadata && _metadata[ColumnMetadata.NUMBER])
			{
				if (_numberToString.hasOwnProperty(number))
					return _numberToString[number];

				if (_numberToStringFunction != null)
					return _numberToString[number] = StandardLib.asString(_numberToStringFunction(number));
			}
			else if (number == int(number) && 0 <= number && number < _uniqueStrings.length)
			{
				return _uniqueStrings[int(number)];
			}
			return '';
		}

		override protected function generateValue(key:IQualifiedKey, dataType:Class):Object
		{
			var array:Array = dataTask.map_key_arrayData.get(key);

			if (dataType === String)
				return aggregate(array, _metadata ? _metadata[ColumnMetadata.AGGREGATION] : null) || '';

			var string:String = getValueFromKey(key, String);

			if (dataType === Number)
			{
				if (_stringToNumberFunction != null)
					return Number(_stringToNumber[string]);

				return Number(_uniqueStringLookup.get(string));
			}

			if (dataType === IQualifiedKey)
			{
				var type:String = _metadata ? _metadata[ColumnMetadata.DATA_TYPE] : null;
				if (!type)
					type = DataType.STRING;
				return WeaveAPI.QKeyManager.getQKey(type, string);
			}

			return null;
		}

		/**
		 * Aggregates an Array of Strings into a single String.
		 * @param strings An Array of Strings.
		 * @param aggregation One of the constants in weave.api.data.Aggregation.
		 * @return An aggregated String.
		 * @see weave.api.data.Aggregation
		 */
		public static function aggregate(strings:Array, aggregation:String):String
		{
			if (!strings)
				return undefined;

			if (!aggregation)
				aggregation = Aggregation.DEFAULT;

			switch (aggregation)
			{
				default:
				case Aggregation.SAME:
					var first:String = strings[0];
					for each (var value:String in strings)
						if (value != first)
							return Weave.lang(Aggregation.AMBIGUOUS_DATA);
					return first;

				case Aggregation.FIRST:
					return strings[0];

				case Aggregation.LAST:
					return strings[strings.length - 1];
			}
			return null;
		}

		public static function getSupportedAggregationModes():Array
		{
			return [Aggregation.SAME, Aggregation.FIRST, Aggregation.LAST];
		}
	}
}

Change StringColumn to use Map instead of Object


//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import flash.utils.ByteArray;

import flump.bytesToXML;
import flump.xfl.XflLibrary;
import flump.xfl.XflMovie;

import com.threerings.util.Log;

public class BetwixtPublisher
{
    public static function modified (lib :XflLibrary, metadata :File) :Boolean
    {
        if (!metadata.exists) return true;

        var stream :FileStream = new FileStream();
        stream.open(metadata, FileMode.READ);
        var bytes :ByteArray = new ByteArray();
        stream.readBytes(bytes);

        var md5 :String = null;
        switch (Files.getExtension(metadata)) {
        case "xml":
            var xml :XML = bytesToXML(bytes);
            md5 = xml.@md5;
            break;

        case "json":
            var json :Object = JSON.parse(bytes.readUTFBytes(bytes.length));
            md5 = json.md5;
            break;
        }

        return md5 != lib.md5;
    }

    public static function publish (lib :XflLibrary, source: File, authoredDevice :DeviceType,
        exportDir :File) :void {
        var packers :Array = [
            new Packer(DeviceType.IPHONE_RETINA, authoredDevice, lib),
            new Packer(DeviceType.IPHONE, authoredDevice, lib)
        ];

        const destDir :File = exportDir.resolvePath(lib.location);
        destDir.createDirectory();

        for each (var packer :Packer in packers) {
            for each (var atlas :Atlas in packer.atlases) {
                atlas.publish(exportDir);
            }
        }

        publishMetadata(lib, packers, authoredDevice, destDir.resolvePath("resources.xml"));
        publishMetadata(lib, packers, authoredDevice, destDir.resolvePath("resources.json"));
    }

    protected static function publishMetadata (lib :XflLibrary, packers :Array,
        authoredDevice :DeviceType, dest :File) :void {
        var out :FileStream = new FileStream();
        out.open(dest, FileMode.WRITE);

        switch (Files.getExtension(dest)) {
        case "xml":
            var xml :XML = <resources md5={lib.md5}/>;
            var prefix :String = lib.location.replace("/", "_") + "_";
            for each (var movie :XflMovie in lib.movies) {
                var movieXml :XML = movie.toXML();
                movieXml.@authoredDevice = authoredDevice.name();
                movieXml.@name = prefix + movieXml.@name;
                xml.appendChild(movieXml);
            }
            var groupsXml :XML = <textureGroups/>;
            xml.appendChild(groupsXml);
            for each (var packer :Packer in packers) {
                var groupXml :XML = <textureGroup target={packer.targetDevice}/>;
                groupsXml.appendChild(groupXml);
                for each (var atlas :Atlas in packer.atlases) {
                    groupXml.appendChild(atlas.toXML());
                }
            }
            for each (var texture :XML in groupsXml..texture) {
                texture.@name = prefix + texture.@name;
            }
            out.writeUTFBytes(xml.toString());
            break;

        case "json":
            var json :Object = {
                md5: lib.md5,
                movies: lib.movies,
                atlases: packers[0].atlases
            };
            var pretty :Boolean = false;
            out.writeUTFBytes(JSON.stringify(json, null, pretty ? "  " : null));
            break;
        }

        out.close();
    }

    private static const log :Log = Log.getLog(BetwixtPublisher);
}
}

//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import flash.utils.ByteArray;

import flump.bytesToXML;
import flump.xfl.XflLibrary;
import flump.xfl.XflMovie;

import com.threerings.util.Log;

public class BetwixtPublisher
{
    public static function modified (lib :XflLibrary, metadata :File) :Boolean
    {
        if (!metadata.exists) return true;

        var stream :FileStream = new FileStream();
        stream.open(metadata, FileMode.READ);
        var bytes :ByteArray = new ByteArray();
        stream.readBytes(bytes);

        var md5 :String = null;
        switch (Files.getExtension(metadata)) {
        case "xml":
            var xml :XML = bytesToXML(bytes);
            md5 = xml.@md5;
            break;

        case "json":
            var json :Object = JSON.parse(bytes.readUTFBytes(bytes.length));
            md5 = json.md5;
            break;
        }

        return md5 != lib.md5;
    }

    public static function publish (lib :XflLibrary, source: File, authoredDevice :DeviceType,
        exportDir :File) :void {
        var packers :Array = [
            new Packer(DeviceType.IPHONE_RETINA, authoredDevice, lib),
            new Packer(DeviceType.IPHONE, authoredDevice, lib)
        ];

        const destDir :File = exportDir.resolvePath(lib.location);
        destDir.createDirectory();

        for each (var packer :Packer in packers) {
            for each (var atlas :Atlas in packer.atlases) {
                atlas.publish(exportDir);
            }
        }

        publishMetadata(lib, packers, authoredDevice, destDir.resolvePath("resources.xml"));
        publishMetadata(lib, packers, authoredDevice, destDir.resolvePath("resources.json"));
    }

    protected static function publishMetadata (lib :XflLibrary, packers :Array,
        authoredDevice :DeviceType, dest :File) :void {
        var out :FileStream = new FileStream();
        out.open(dest, FileMode.WRITE);

        switch (Files.getExtension(dest)) {
        case "xml":
            var xml :XML = <resources md5={lib.md5}/>;
            var prefix :String = lib.location + "/";
            for each (var movie :XflMovie in lib.movies) {
                var movieXml :XML = movie.toXML();
                movieXml.@authoredDevice = authoredDevice.name();
                movieXml.@name = prefix + movieXml.@name;
                for each (var kf :XML in movieXml..kf) {
                    kf.@ref = prefix + kf.@ref;
                }
                xml.appendChild(movieXml);
            }
            var groupsXml :XML = <textureGroups/>;
            xml.appendChild(groupsXml);
            for each (var packer :Packer in packers) {
                var groupXml :XML = <textureGroup target={packer.targetDevice}/>;
                groupsXml.appendChild(groupXml);
                for each (var atlas :Atlas in packer.atlases) {
                    groupXml.appendChild(atlas.toXML());
                }
            }
            for each (var texture :XML in groupsXml..texture) {
                texture.@name = prefix + texture.@name;
            }
            out.writeUTFBytes(xml.toString());
            break;

        case "json":
            var json :Object = {
                md5: lib.md5,
                movies: lib.movies,
                atlases: packers[0].atlases
            };
            var pretty :Boolean = false;
            out.writeUTFBytes(JSON.stringify(json, null, pretty ? "  " : null));
            break;
        }

        out.close();
    }

    private static const log :Log = Log.getLog(BetwixtPublisher);
}
}

Use slashes for prefixes, and prefix symbol references too.


package net.manaca.loaderqueue
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.utils.clearInterval;
import flash.utils.setInterval;

/**
 * 任务队列总进度更新时派发
 * @eventType flash.events.Event.CHANGE
 */
[Event(name="change", type="flash.events.Event")]
/**
 * 任务队列完成时派发
 * @eventType flash.events.Event.COMPLETE
 */
[Event(name="complete", type="flash.events.Event")]

/**
 * 用于计算一个加载集合和总进度.
 * @author Sean Zou
 *
 */
public class LoaderProgress extends EventDispatcher
{
    //==========================================================================
    //  Constructor
    //==========================================================================
    /**
     * 构造函数.
     *
     */
    public function LoaderProgress()
    {
    }
    //==========================================================================
    //  Variables
    //==========================================================================
    private var items:Array = [];
    private var isStart:Boolean = false;
    private var updateInterval:int;
    //==========================================================================
    //  Properties
    //==========================================================================
    private var _totalProgress:Number;
    /**
     * 总进度
     * @return
     *
     */
    public function get totalProgress():Number
    {
        return _totalProgress;
    }
    //==========================================================================
    //  Methods
    //==========================================================================
    /**
     * 添加一个需要计算的下载对象
     * @param loaderAdapter
     *
     */
    public function addItem(loaderAdapter:ILoaderAdapter):void
    {
        if(items.indexOf(loaderAdapter) == -1)
        {
            items.push(loaderAdapter);

            if(isStart)
            {
                update();
            }
        }
    }

    /**
     * 删除一个需要计算的下载对象
     * @param loaderAdapter
     *
     */
    public function removeItem(loaderAdapter:ILoaderAdapter):void
    {
        var index:int = items.indexOf(loaderAdapter);
        if(index != -1)
        {
            items.splice(index, 1);
            if(isStart)
            {
                update();
            }
        }
    }

    /**
     * 开始计算
     *
     */
    public function start():void
    {
        updateInterval = setInterval(update, 100);
        isStart = true;
    }

    /**
     * 结束计算
     *
     */
    public function stop():void
    {
        clearInterval(updateInterval);
        isStart = false;
    }

    /**
     * 销毁该对象
     *
     */
    public function dispose():void
    {
        stop();
        items = null;
    }

    /**
     * 更新进度
     * @private
     */
    private function update():void
    {
        var itemsLen:int = items.length;
        var loader:ILoaderAdapter;
        var tp:Number = 0;
        for (var i:int = 0; i < itemsLen; i++)
        {
            loader = items[i];
            if(!isNaN(loader.bytesLoaded / loader.bytesTotal))
            {
                tp += loader.bytesLoaded / loader.bytesTotal;
            }
        }
        _totalProgress = tp / itemsLen;
        dispatchEvent(new Event(Event.CHANGE));
        if(_totalProgress == 1 || itemsLen == 0)
        {
            dispatchEvent(new Event(Event.COMPLETE));
            stop();
        }
    }
}
}

package net.manaca.loaderqueue
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.utils.clearInterval;
import flash.utils.setInterval;

/**
 * 任务队列总进度更新时派发
 * @eventType flash.events.Event.CHANGE
 */
[Event(name="change", type="flash.events.Event")]
/**
 * 任务队列完成时派发
 * @eventType flash.events.Event.COMPLETE
 */
[Event(name="complete", type="flash.events.Event")]

/**
 * 用于计算一个加载集合和总进度.
 * @author Sean Zou
 *
 */
public class LoaderProgress extends EventDispatcher
{
    //==========================================================================
    //  Constructor
    //==========================================================================
    /**
     * 构造函数.
     *
     */
    public function LoaderProgress()
    {
    }
    //==========================================================================
    //  Variables
    //==========================================================================
    private var items:Array = [];
    private var isStarted:Boolean = false;
    private var updateInterval:int;
    //==========================================================================
    //  Properties
    //==========================================================================
    private var _totalProgress:Number;
    /**
     * 总进度
     * @return
     *
     */
    public function get totalProgress():Number
    {
        return _totalProgress;
    }
    //==========================================================================
    //  Methods
    //==========================================================================
    /**
     * 添加一个需要计算的下载对象
     * @param loaderAdapter
     *
     */
    public function addItem(loaderAdapter:ILoaderAdapter):void
    {
        if(items.indexOf(loaderAdapter) == -1)
        {
            items.push(loaderAdapter);

            if(isStarted)
            {
                update();
            }
        }
    }

    /**
     * 删除一个需要计算的下载对象
     * @param loaderAdapter
     *
     */
    public function removeItem(loaderAdapter:ILoaderAdapter):void
    {
        var index:int = items.indexOf(loaderAdapter);
        if(index != -1)
        {
            items.splice(index, 1);
            if(isStarted)
            {
                update();
            }
        }
    }

    /**
     * 开始计算
     *
     */
    public function start():void
    {
        updateInterval = setInterval(update, 100);
        isStarted = true;
    }

    /**
     * 结束计算
     *
     */
    public function stop():void
    {
        clearInterval(updateInterval);
        isStarted = false;
    }

    /**
     * 销毁该对象
     *
     */
    public function dispose():void
    {
        stop();
        items = null;
    }

    /**
     * 更新进度
     * @private
     */
    private function update():void
    {
        var itemsLen:int = items.length;
        var loader:ILoaderAdapter;
        var tp:Number = 0;
        for (var i:int = 0; i < itemsLen; i++)
        {
            loader = items[i];
            if(!isNaN(loader.bytesLoaded / loader.bytesTotal))
            {
                tp += loader.bytesLoaded / loader.bytesTotal;
            }
        }
        _totalProgress = tp / itemsLen;
        dispatchEvent(new Event(Event.CHANGE));
        if(_totalProgress == 1 || itemsLen == 0)
        {
            dispatchEvent(new Event(Event.COMPLETE));
            stop();
        }
    }
}
}

Rename isStart to isStarted

Rename isStart to isStarted