package aerys.minko.scene.node.camera
{
	import aerys.minko.ns.minko_scene;
	import aerys.minko.scene.controller.camera.CameraController;
	import aerys.minko.scene.data.CameraDataProvider;
	import aerys.minko.scene.node.AbstractSceneNode;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.type.Signal;
	import aerys.minko.type.binding.DataBindings;
	import aerys.minko.type.math.Matrix4x4;
	import aerys.minko.type.math.Ray;
	import aerys.minko.type.math.Vector4;

	import flash.geom.Point;

	use namespace minko_scene;

	public class Camera extends AbstractCamera
	{
		public static const DEFAULT_FOV		: Number	= Math.PI * .25;

        private static const TMP_VECTOR4    : Vector4   = new Vector4();

		public function get fieldOfView() : Number
		{
			return _cameraData.fieldOfView;
		}
		public function set fieldOfView(value : Number) : void
		{
			_cameraData.fieldOfView = value;
		}

		public function Camera(fieldOfView	: Number = DEFAULT_FOV,
							   zNear		: Number = AbstractCamera.DEFAULT_ZNEAR,
							   zFar			: Number = AbstractCamera.DEFAULT_ZFAR)
		{
			super(zNear, zFar);

			_cameraData.fieldOfView = fieldOfView;
		}

		override minko_scene function cloneNode() : AbstractSceneNode
		{
			var clone : Camera = new Camera(fieldOfView, zNear, zFar);

			clone.transform.copyFrom(this.transform);

			return clone as AbstractSceneNode;
		}

		override public function unproject(x : Number, y : Number, out : Ray = null) : Ray
		{
			if (!(root is Scene))
				throw new Error('Camera must be in the scene to unproject vectors.');

			out ||= new Ray();

			var sceneBindings	: DataBindings	= (root as Scene).bindings;
			var zNear			: Number		= _cameraData.zNear;
			var zFar			: Number		= _cameraData.zFar;
			var fovDiv2			: Number		= _cameraData.fieldOfView * 0.5;
			var width			: Number		= sceneBindings.getProperty('viewportWidth');
			var height			: Number		= sceneBindings.getProperty('viewportHeight');
			var xPercent		: Number		= 2.0 * (x / width - 0.5);
			var yPercent 		: Number		= 2.0 * (y / height - 0.5);
			var dx				: Number 		= Math.tan(fovDiv2) * xPercent * (width / height);
			var dy				: Number 		= -Math.tan(fovDiv2) * yPercent;

			out.origin.set(dx * zNear, dy * zNear, zNear);
			out.direction.set(dx * zNear, dy * zNear, zNear).normalize();

			localToWorld(out.origin, out.origin);
			localToWorld(out.direction, out.direction, true);

			return out;
		}

		override public function project(localToWorld : Matrix4x4, output : Point = null) : Point
		{
			output ||= new Point();

			var sceneBindings	: DataBindings	= (root as Scene).bindings;
			var width			: Number		= sceneBindings.getProperty('viewportWidth');
			var height			: Number		= sceneBindings.getProperty('viewportHeight');
			var translation		: Vector4		= localToWorld.getTranslation();
			var screenPosition	: Vector4		= _cameraData.worldToScreen.projectVector(
                translation, TMP_VECTOR4
            );

			output.x = width * ((screenPosition.x + 1.0) * .5);
			output.y = height * ((1.0 - ((screenPosition.y + 1.0) * .5)));

			return output;
		}
	}
}

package aerys.minko.scene.node.camera
{
	import aerys.minko.ns.minko_scene;
	import aerys.minko.scene.controller.camera.CameraController;
	import aerys.minko.scene.data.CameraDataProvider;
	import aerys.minko.scene.node.AbstractSceneNode;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.type.Signal;
	import aerys.minko.type.binding.DataBindings;
	import aerys.minko.type.math.Matrix4x4;
	import aerys.minko.type.math.Ray;
	import aerys.minko.type.math.Vector4;

	import flash.geom.Point;

	use namespace minko_scene;

	public class Camera extends AbstractCamera
	{
		public static const DEFAULT_FOV		: Number	= Math.PI * .25;

        private static const TMP_VECTOR4    : Vector4   = new Vector4();

		public function get fieldOfView() : Number
		{
			return _cameraData.fieldOfView;
		}
		public function set fieldOfView(value : Number) : void
		{
			_cameraData.fieldOfView = value;
		}

		public function Camera(fieldOfView	: Number = DEFAULT_FOV,
							   zNear		: Number = AbstractCamera.DEFAULT_ZNEAR,
							   zFar			: Number = AbstractCamera.DEFAULT_ZFAR)
		{
			super(zNear, zFar);

			_cameraData.fieldOfView = fieldOfView;
		}

		override minko_scene function cloneNode() : AbstractSceneNode
		{
			var clone : Camera = new Camera(fieldOfView, zNear, zFar);

			clone.transform.copyFrom(this.transform);

			return clone as AbstractSceneNode;
		}

		override public function unproject(x : Number, y : Number, out : Ray = null) : Ray
		{
			if (!(root is Scene))
				throw new Error('Camera must be in the scene to unproject vectors.');

			out ||= new Ray();

			var sceneBindings	: DataBindings	= (root as Scene).bindings;
			var zNear			: Number		= _cameraData.zNear;
			var zFar			: Number		= _cameraData.zFar;
			var fovDiv2			: Number		= _cameraData.fieldOfView * 0.5;
			var width			: Number		= sceneBindings.propertyExists('viewportWidth')
                ? sceneBindings.getProperty('viewportWidth')
                : 0.;
			var height			: Number		= sceneBindings.propertyExists('viewportHeight')
                ? sceneBindings.getProperty('viewportHeight')
                : 0.;
			var xPercent		: Number		= 2.0 * (x / width - 0.5);
			var yPercent 		: Number		= 2.0 * (y / height - 0.5);
			var dx				: Number 		= Math.tan(fovDiv2) * xPercent * (width / height);
			var dy				: Number 		= -Math.tan(fovDiv2) * yPercent;

			out.origin.set(dx * zNear, dy * zNear, zNear);
			out.direction.set(dx * zNear, dy * zNear, zNear).normalize();

			localToWorld(out.origin, out.origin);
			localToWorld(out.direction, out.direction, true);

			return out;
		}

		override public function project(localToWorld : Matrix4x4, output : Point = null) : Point
		{
			output ||= new Point();

			var sceneBindings	: DataBindings	= (root as Scene).bindings;
			var width			: Number		= sceneBindings.getProperty('viewportWidth');
			var height			: Number		= sceneBindings.getProperty('viewportHeight');
			var translation		: Vector4		= localToWorld.getTranslation();
			var screenPosition	: Vector4		= _cameraData.worldToScreen.projectVector(
                translation, TMP_VECTOR4
            );

			output.x = width * ((screenPosition.x + 1.0) * .5);
			output.y = height * ((1.0 - ((screenPosition.y + 1.0) * .5)));

			return output;
		}
	}
}

use 0 as default value when viewportWidth/viewportHeight is not defined in the scene bindings


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

    This file is a part of Weave.

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

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

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

package weave.data.BinningDefinitions
{
	import mx.utils.ObjectUtil;

	import weave.api.data.IAttributeColumn;
	import weave.api.data.IQualifiedKey;
	import weave.data.BinClassifiers.SingleValueClassifier;
	import weave.utils.AsyncSort;

	/**
	 * Creates a separate bin for every string value in a column.
	 *
	 * @author adufilie
	 */
	public class CategoryBinningDefinition extends AbstractBinningDefinition
	{
		public function CategoryBinningDefinition()
		{
			overrideBinNames.lock(); // no bin names allowed
		}

		/**
		 * This function sorts string values by their corresponding numeric values stored in _sortMap.
		 */
		private function _sortFunc(str1:String, str2:String):int
		{
			return ObjectUtil.numericCompare(_sortMap[str1], _sortMap[str2])
				|| ObjectUtil.stringCompare(str1, str2);
		}

		private var _sortMap:Object; // used by _sortFunc

		/**
		 * derive an explicit definition.
		 */
		override public function generateBinClassifiersForColumn(column:IAttributeColumn):void
		{
			// clear any existing bin classifiers
			output.removeAllObjects();

			// get all string values in the a column
			_sortMap = {};
			var strArray:Array = new Array(column.keys.length); // alloc max length
			var i:int = 0;
			var str:String;
			for each (var key:IQualifiedKey in column.keys)
			{
				str = column.getValueFromKey(key, String) as String;
				if (str && !_sortMap.hasOwnProperty(str))
				{
					strArray[int(i++)] = str;
					_sortMap[str] = column.getValueFromKey(key, Number);
				}
			}
			strArray.length = i; // truncate
			AsyncSort.sortImmediately(strArray, _sortFunc); // sort strings by corresponding numeric values
			var n:int = strArray.length;
			for (i = 0; i < n; i++)
			{
				//first get name from overrideBinNames
				str = strArray[i] as String;

				//TODO: look up replacement name once we store original + modified names together rather than a simple Array of replacement names.

				var svc:SingleValueClassifier = output.requestObject(str, SingleValueClassifier, false);
				svc.value = strArray[i];
			}

			// trigger callbacks now because we're done updating the output
			asyncResultCallbacks.triggerCallbacks();
		}
	}
}

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

    This file is a part of Weave.

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

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

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

package weave.data.BinningDefinitions
{
	import mx.utils.ObjectUtil;

	import weave.api.WeaveAPI;
	import weave.api.data.IAttributeColumn;
	import weave.api.data.IQualifiedKey;
	import weave.core.SessionManager;
	import weave.data.BinClassifiers.SingleValueClassifier;
	import weave.utils.AsyncSort;

	/**
	 * Creates a separate bin for every string value in a column.
	 *
	 * @author adufilie
	 */
	public class CategoryBinningDefinition extends AbstractBinningDefinition
	{
		public function CategoryBinningDefinition()
		{
			overrideBinNames.lock(); // no bin names allowed
			(WeaveAPI.SessionManager as SessionManager).unregisterLinkableChild(this, overrideBinNames);
		}

		/**
		 * This function sorts string values by their corresponding numeric values stored in _sortMap.
		 */
		private function _sortFunc(str1:String, str2:String):int
		{
			return ObjectUtil.numericCompare(_sortMap[str1], _sortMap[str2])
				|| ObjectUtil.stringCompare(str1, str2);
		}

		private var _sortMap:Object; // used by _sortFunc

		/**
		 * derive an explicit definition.
		 */
		override public function generateBinClassifiersForColumn(column:IAttributeColumn):void
		{
			// clear any existing bin classifiers
			output.removeAllObjects();

			// get all string values in the a column
			_sortMap = {};
			var strArray:Array = new Array(column.keys.length); // alloc max length
			var i:int = 0;
			var str:String;
			for each (var key:IQualifiedKey in column.keys)
			{
				str = column.getValueFromKey(key, String) as String;
				if (str && !_sortMap.hasOwnProperty(str))
				{
					strArray[int(i++)] = str;
					_sortMap[str] = column.getValueFromKey(key, Number);
				}
			}
			strArray.length = i; // truncate
			AsyncSort.sortImmediately(strArray, _sortFunc); // sort strings by corresponding numeric values
			var n:int = strArray.length;
			for (i = 0; i < n; i++)
			{
				//first get name from overrideBinNames
				str = strArray[i] as String;

				//TODO: look up replacement name once we store original + modified names together rather than a simple Array of replacement names.

				var svc:SingleValueClassifier = output.requestObject(str, SingleValueClassifier, false);
				svc.value = strArray[i];
			}

			// trigger callbacks now because we're done updating the output
			asyncResultCallbacks.triggerCallbacks();
		}
	}
}

hide unused variable

hide unused variable

Change-Id: I8f5219585e79a177734200d196167153c566b751


package com.dotfold.dotvimstat.model
{
	/**
	 *
	 * @author jamesmcnamee
	 *
	 */
	public class UserInfoEntity extends BaseEntity
	{
		public function UserInfoEntity()
		{
			super();
		}

		public var displayName:String;
		public var created_on:String;
		public var is_staff:Boolean;
		public var is_plus:Boolean;
		public var is_pro:Boolean;
		public var location:String;
		public var url:String;
		public var bio:String;
		public var profile_url:String;
		public var videos_url:String;
		public var total_videos_uploaded:int;
		public var total_videos_appears_in:int;
		public var total_videos_liked:int;
		public var total_contacts:int;
		public var total_albums:int;
		public var total_channels:int;
		public var portrait_small:String;
		public var portrait_medium:String;
		public var portrait_large:String;
		public var portrait_huge:String;
	}
}

package com.dotfold.dotvimstat.model
{
	import com.dotfold.dotvimstat.model.image.EntityImage;
	import com.dotfold.dotvimstat.model.image.EntityImageCollection;

	/**
	 *
	 * @author jamesmcnamee
	 *
	 */
	public class UserInfoEntity extends BaseEntity
	{
		public function UserInfoEntity()
		{
			super();
		}

		public var display_name:String;
		public var created_on:String;
		public var is_staff:Boolean;
		public var is_plus:Boolean;
		public var is_pro:Boolean;
		public var location:String;
		public var url:String;
		public var bio:String;
		public var profile_url:String;
		public var videos_url:String;
		public var total_videos_uploaded:int;
		public var total_videos_appears_in:int;
		public var total_videos_liked:int;
		public var total_contacts:int;
		public var total_albums:int;
		public var total_channels:int;

		private var _portrait_small:String
		public function get portrait_small():String
		{
			return _portrait_small;
		}

		public function set portrait_small(value:String):void
		{
			_portrait_small = value;

			var image:EntityImage = new EntityImage();
			image.url = value;
			image.size = 'small';
			images.addItem(image);
		}

		private var _portrait_medium:String
		public function get portrait_medium():String
		{
			return _portrait_medium;
		}

		public function set portrait_medium(value:String):void
		{
			_portrait_medium = value;

			var image:EntityImage = new EntityImage();
			image.url = value;
			image.size = 'medium';
			images.addItem(image);
		}

		private var _portrait_large:String
		public function get portrait_large():String
		{
			return _portrait_large;
		}

		public function set portrait_large(value:String):void
		{
			_portrait_large = value;

			var image:EntityImage = new EntityImage();
			image.url = value;
			image.size = 'large';
			images.addItem(image);
		}

		private var _portrait_huge:String
		public function get portrait_huge():String
		{
			return _portrait_huge;
		}

		public function set portrait_huge(value:String):void
		{
			_portrait_huge = value;

			var image:EntityImage = new EntityImage();
			image.url = value;
			image.size = 'huge';
			images.addItem(image);
		}

		public var images:EntityImageCollection = new EntityImageCollection();
	}
}

add UserInfoEntity

[feat] add UserInfoEntity


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

package com.threerings.flex {

import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.events.IEventDispatcher;

import flash.geom.Point;
import flash.geom.Rectangle;

import mx.controls.Menu;
import mx.controls.listClasses.BaseListData;
import mx.controls.listClasses.IListItemRenderer;
import mx.controls.menuClasses.IMenuItemRenderer;
import mx.controls.menuClasses.MenuListData;

import mx.core.mx_internal;
import mx.core.Application;
import mx.core.ClassFactory;
import mx.core.IFlexDisplayObject;
import mx.core.ScrollPolicy;

import mx.events.MenuEvent;

import mx.managers.PopUpManager;

import mx.utils.ObjectUtil;

import flexlib.controls.ScrollableArrowMenu;

import com.threerings.util.CommandEvent;

import com.threerings.flex.PopUpUtil;

import com.threerings.flex.menuClasses.CommandMenuItemRenderer;
import com.threerings.flex.menuClasses.CommandListData;

use namespace mx_internal;

/**
 * A pretty standard menu that can submit CommandEvents if menu items have "command" and possibly
 * "arg" properties. Commands are submitted to controllers for processing. Alternatively, you may
 * specify "callback" properties that specify a function closure to call, with the "arg" property
 * containing either a single arg or an array of args.
 *
 * Another property now supported is "iconObject", which is an already-instantiated
 * IFlexDisplayObject to use as the icon. This will only be applied if the "icon" property
 * (which specifies a Class) is not used.
 *
 * Example dataProvider array:
 * [ { label: "Go home", icon: homeIconClass,
 *     command: Controller.GO_HOME, arg: homeId },
 *   { type: "separator"},
     { label: "Crazytown", callback: setCrazy, arg: [ true, false ] },
 *   { label: "Other places", children: subMenuArray }
 * ];
 *
 * See "Defining menu structure and data" in the Flex manual for the full list.
 */
public class CommandMenu extends Menu
{
    /**
     * Factory method to create a command menu.
     *
     * @param items an array of menu items.
     * @param dispatcher an override event dispatcher to use for command events, rather than
     * our parent.
     */
    public static function createMenu (
        items :Array, dispatcher :IEventDispatcher = null) :CommandMenu
    {
        var menu :CommandMenu = new CommandMenu();
        menu.owner = DisplayObjectContainer(Application.application);
        menu.tabEnabled = false;
        menu.showRoot = true;
        menu.setDispatcher(dispatcher);
        Menu.popUpMenu(menu, null, items); // does not actually pop up, but needed.
        return menu;
    }

    public function CommandMenu ()
    {
        super();

        itemRenderer = new ClassFactory(CommandMenuItemRenderer);

        verticalScrollPolicy = ScrollPolicy.OFF;
        addEventListener(MenuEvent.ITEM_CLICK, itemClicked);
    }

    /**
     * Configures the event dispatcher to be used when dispatching this menu's command events.
     * Normally they will be dispatched on our parent (usually the SystemManager or something).
     */
    public function setDispatcher (dispatcher :IEventDispatcher) :void
    {
        _dispatcher = dispatcher;
    }

    /**
     * Actually pop up the menu. This can be used instead of show().
     */
    public function popUp (
        trigger :DisplayObject, popUpwards :Boolean = false, popLeftwards :Boolean = false) :void
    {
        _upping = popUpwards;
        _lefting = popLeftwards;
        var r :Rectangle = trigger.getBounds(trigger.stage);
        show(_lefting ? r.left : r.right, _upping ? r.top : r.bottom);
    }

    /**
     * Shows the menu at the specified mouse coordinates.
     */
    public function popUpAt (
        mx :int, my :int, popUpwards :Boolean = false, popLeftwards :Boolean = false) :void
    {
        _upping = popUpwards;
        _lefting = popLeftwards;
        show(mx, my);
    }

    /**
     * Shows the menu at the current mouse location.
     */
    public function popUpAtMouse (popUpwards :Boolean = false, popLeftwards :Boolean = false) :void
    {
        _upping = popUpwards;
        _lefting = popLeftwards;
        show(); // our show, with no args, pops at the mouse
    }

    /**
     * Just like our superclass's show(), except that when invoked with no args, causes the menu to
     * show at the current mouse location instead of the top-left corner of the application.
     * Also, we ensure that the resulting menu is in-bounds.
     */
    override public function show (xShow :Object = null, yShow :Object = null) :void
    {
        if (xShow == null) {
            xShow = DisplayObject(Application.application).mouseX;
        }
        if (yShow == null) {
            yShow = DisplayObject(Application.application).mouseY;
        }

        super.show(xShow, yShow);

        // reposition now that we know our size
        if (_lefting) {
            y = x - getExplicitOrMeasuredWidth();
        }
        if (_upping) {
            y = y - getExplicitOrMeasuredHeight();
        }

        PopUpUtil.fit(this);
    }

    /**
     * Callback for MenuEvent.ITEM_CLICK.
     */
    protected function itemClicked (event :MenuEvent) :void
    {
        var arg :Object = getItemProp(event.item, "arg");
        var cmdOrFn :Object = getItemProp(event.item, "command");
        if (cmdOrFn == null) {
            cmdOrFn = getItemProp(event.item, "callback");
        }
        if (cmdOrFn != null) {
            event.stopImmediatePropagation();
            CommandEvent.dispatch(_dispatcher == null ? mx_internal::parentDisplayObject :
                                  _dispatcher, cmdOrFn, arg);
        }
        // else: no warning. There may be non-command menu items mixed in.
    }

    // from ScrollableArrowMenu..
    override mx_internal function openSubMenu (row :IListItemRenderer) :void
    {
        supposedToLoseFocus = true;

        var r :Menu = getRootMenu();
        var menu :CommandMenu;

        // check to see if the menu exists, if not create it
        if (!IMenuItemRenderer(row).menu) {
            // the only differences between this method and the original method in mx.controls.Menu
            // are these few lines.
            menu = new CommandMenu();
            menu.maxHeight = this.maxHeight;
            menu.verticalScrollPolicy = this.verticalScrollPolicy;
            menu.variableRowHeight = this.variableRowHeight;

            menu.parentMenu = this;
            menu.owner = this;
            menu.showRoot = showRoot;
            menu.dataDescriptor = r.dataDescriptor;
            menu.styleName = r;
            menu.labelField = r.labelField;
            menu.labelFunction = r.labelFunction;
            menu.iconField = r.iconField;
            menu.iconFunction = r.iconFunction;
            menu.itemRenderer = r.itemRenderer;
            menu.rowHeight = r.rowHeight;
            menu.scaleY = r.scaleY;
            menu.scaleX = r.scaleX;

            // if there's data and it has children then add the items
            if (row.data && _dataDescriptor.isBranch(row.data) &&
                    _dataDescriptor.hasChildren(row.data)) {
                menu.dataProvider = _dataDescriptor.getChildren(row.data);
            }
            menu.sourceMenuBar = sourceMenuBar;
            menu.sourceMenuBarItem = sourceMenuBarItem;

            IMenuItemRenderer(row).menu = menu;
            PopUpManager.addPopUp(menu, r, false);
        }

        super.openSubMenu(row);

        // if we're lefting, upping or fitting make sure our submenu does so as well
        var submenu :Menu = IMenuItemRenderer(row).menu;
        var lefting :Boolean = _lefting;
        var upping :Boolean = _upping;
        var fitting :Rectangle = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
        if (submenu.x + submenu.getExplicitOrMeasuredWidth() > fitting.right) {
            lefting = true;
        }
        if (submenu.y + submenu.getExplicitOrMeasuredHeight() > fitting.bottom) {
            upping = true;
        }

        if (lefting) {
            submenu.x -= submenu.getExplicitOrMeasuredWidth();
        }
        if (upping) {
            var displayObj :DisplayObject = DisplayObject(row);
            var rowLoc :Point = displayObj.localToGlobal(new Point(row.x, row.y));
            submenu.y = rowLoc.y - submenu.getExplicitOrMeasuredHeight() + displayObj.height;
        }

        // if we've poped out of the boundaries, just snap it to the lower right corner, or upper
        // if upping, left if lefting
        if (submenu.x < fitting.left) {
            submenu.x = lefting ? 0 : Math.max(
                    fitting.right - submenu.getExplicitOrMeasuredWidth(), fitting.left);
        }
        if (submenu.y < fitting.top) {
            submenu.y = upping ? 0 : Math.max(
                    fitting.bottom - submenu.getExplicitOrMeasuredHeight(), fitting.top);
        }
    }

    // from List
    override protected function makeListData (data :Object, uid :String, rowNum :int) :BaseListData
    {
        // Oh, FFS.
        // We need to set up these "maxMeasuredIconWidth" fields on the MenuListData, but our
        // superclass has made those variables private.
        // We can get the values out of another MenuListData, so we just always call super()
        // to create one of those, and if we need to make a CommandListData, we construct one
        // from the fields in the MenuListData.

        var menuListData :MenuListData = super.makeListData(data, uid, rowNum) as MenuListData;

        var iconObject :IFlexDisplayObject = getItemProp(data, "iconObject") as IFlexDisplayObject;
        if (iconObject != null) {
            var cmdListData :CommandListData = new CommandListData(menuListData.label,
                menuListData.icon, iconObject, labelField, uid, this, rowNum);

            cmdListData.maxMeasuredIconWidth = menuListData.maxMeasuredIconWidth;
            cmdListData.maxMeasuredTypeIconWidth = menuListData.maxMeasuredTypeIconWidth;
            cmdListData.maxMeasuredBranchIconWidth = menuListData.maxMeasuredBranchIconWidth;
            cmdListData.useTwoColumns = menuListData.useTwoColumns;
            return cmdListData;
        }

        return menuListData;
    }

    /**
     * Get the specified property for the specified item, if any.  Somewhat similar to bits in the
     * DefaultDataDescriptor.
     */
    protected function getItemProp (item :Object, prop :String) :Object
    {
        try {
            if (item is XML) {
                return String((item as XML).attribute(prop));

            } else if (prop in item) {
                return item[prop];
            }

        } catch (e :Error) {
            // alas; fall through
        }
        return null;
    }

    protected var _dispatcher :IEventDispatcher;
    protected var _lefting :Boolean = false;
    protected var _upping :Boolean = false;
}
}

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

package com.threerings.flex {

import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.events.IEventDispatcher;

import flash.geom.Point;
import flash.geom.Rectangle;

import mx.controls.Menu;
import mx.controls.listClasses.BaseListData;
import mx.controls.listClasses.IListItemRenderer;
import mx.controls.menuClasses.IMenuItemRenderer;
import mx.controls.menuClasses.MenuListData;

import mx.core.mx_internal;
import mx.core.Application;
import mx.core.ClassFactory;
import mx.core.IFlexDisplayObject;
import mx.core.ScrollPolicy;

import mx.events.MenuEvent;

import mx.managers.PopUpManager;

import mx.utils.ObjectUtil;

import flexlib.controls.ScrollableArrowMenu;

import com.threerings.util.CommandEvent;

import com.threerings.flex.PopUpUtil;

import com.threerings.flex.menuClasses.CommandMenuItemRenderer;
import com.threerings.flex.menuClasses.CommandListData;

use namespace mx_internal;

/**
 * A pretty standard menu that can submit CommandEvents if menu items have "command" and possibly
 * "arg" properties. Commands are submitted to controllers for processing. Alternatively, you may
 * specify "callback" properties that specify a function closure to call, with the "arg" property
 * containing either a single arg or an array of args.
 *
 * Another property now supported is "iconObject", which is an already-instantiated
 * IFlexDisplayObject to use as the icon. This will only be applied if the "icon" property
 * (which specifies a Class) is not used.
 *
 * Example dataProvider array:
 * [ { label: "Go home", icon: homeIconClass,
 *     command: Controller.GO_HOME, arg: homeId },
 *   { type: "separator"},
     { label: "Crazytown", callback: setCrazy, arg: [ true, false ] },
 *   { label: "Other places", children: subMenuArray }
 * ];
 *
 * See "Defining menu structure and data" in the Flex manual for the full list.
 */
public class CommandMenu extends Menu
{
    /**
     * Factory method to create a command menu.
     *
     * @param items an array of menu items.
     * @param dispatcher an override event dispatcher to use for command events, rather than
     * our parent.
     */
    public static function createMenu (
        items :Array, dispatcher :IEventDispatcher = null) :CommandMenu
    {
        var menu :CommandMenu = new CommandMenu();
        menu.owner = DisplayObjectContainer(Application.application);
        menu.tabEnabled = false;
        menu.showRoot = true;
        menu.setDispatcher(dispatcher);
        Menu.popUpMenu(menu, null, items); // does not actually pop up, but needed.
        return menu;
    }

    public function CommandMenu ()
    {
        super();

        itemRenderer = new ClassFactory(CommandMenuItemRenderer);

        verticalScrollPolicy = ScrollPolicy.OFF;
        addEventListener(MenuEvent.ITEM_CLICK, itemClicked);
    }

    /**
     * Configures the event dispatcher to be used when dispatching this menu's command events.
     * Normally they will be dispatched on our parent (usually the SystemManager or something).
     */
    public function setDispatcher (dispatcher :IEventDispatcher) :void
    {
        _dispatcher = dispatcher;
    }

    /**
     * Sets a Rectangle (in stage coords) that the menu will attempt to keep submenus positioned
     * within.  If a submenu is too large to fit, it will position it in the lower right corner
     * of this Rectangle (or top if popping upwards, or left if popping leftwards).   This
     * value defaults to the stage bounds.
     */
    public function setBounds (fitting :Rectangle) :void
    {
        _fitting = fitting;
    }

    /**
     * Actually pop up the menu. This can be used instead of show().
     */
    public function popUp (
        trigger :DisplayObject, popUpwards :Boolean = false, popLeftwards :Boolean = false) :void
    {
        _upping = popUpwards;
        _lefting = popLeftwards;
        var r :Rectangle = trigger.getBounds(trigger.stage);
        show(_lefting ? r.left : r.right, _upping ? r.top : r.bottom);
    }

    /**
     * Shows the menu at the specified mouse coordinates.
     */
    public function popUpAt (
        mx :int, my :int, popUpwards :Boolean = false, popLeftwards :Boolean = false) :void
    {
        _upping = popUpwards;
        _lefting = popLeftwards;
        show(mx, my);
    }

    /**
     * Shows the menu at the current mouse location.
     */
    public function popUpAtMouse (popUpwards :Boolean = false, popLeftwards :Boolean = false) :void
    {
        _upping = popUpwards;
        _lefting = popLeftwards;
        show(); // our show, with no args, pops at the mouse
    }

    /**
     * Just like our superclass's show(), except that when invoked with no args, causes the menu to
     * show at the current mouse location instead of the top-left corner of the application.
     * Also, we ensure that the resulting menu is in-bounds.
     */
    override public function show (xShow :Object = null, yShow :Object = null) :void
    {
        if (xShow == null) {
            xShow = DisplayObject(Application.application).mouseX;
        }
        if (yShow == null) {
            yShow = DisplayObject(Application.application).mouseY;
        }

        super.show(xShow, yShow);

        // reposition now that we know our size
        if (_lefting) {
            y = x - getExplicitOrMeasuredWidth();
        }
        if (_upping) {
            y = y - getExplicitOrMeasuredHeight();
        }

        PopUpUtil.fit(this);
    }

    /**
     * Callback for MenuEvent.ITEM_CLICK.
     */
    protected function itemClicked (event :MenuEvent) :void
    {
        var arg :Object = getItemProp(event.item, "arg");
        var cmdOrFn :Object = getItemProp(event.item, "command");
        if (cmdOrFn == null) {
            cmdOrFn = getItemProp(event.item, "callback");
        }
        if (cmdOrFn != null) {
            event.stopImmediatePropagation();
            CommandEvent.dispatch(_dispatcher == null ? mx_internal::parentDisplayObject :
                                  _dispatcher, cmdOrFn, arg);
        }
        // else: no warning. There may be non-command menu items mixed in.
    }

    // from ScrollableArrowMenu..
    override mx_internal function openSubMenu (row :IListItemRenderer) :void
    {
        supposedToLoseFocus = true;

        var r :Menu = getRootMenu();
        var menu :CommandMenu;

        // check to see if the menu exists, if not create it
        if (!IMenuItemRenderer(row).menu) {
            // the only differences between this method and the original method in mx.controls.Menu
            // are these few lines.
            menu = new CommandMenu();
            menu.maxHeight = this.maxHeight;
            menu.verticalScrollPolicy = this.verticalScrollPolicy;
            menu.variableRowHeight = this.variableRowHeight;

            menu.parentMenu = this;
            menu.owner = this;
            menu.showRoot = showRoot;
            menu.dataDescriptor = r.dataDescriptor;
            menu.styleName = r;
            menu.labelField = r.labelField;
            menu.labelFunction = r.labelFunction;
            menu.iconField = r.iconField;
            menu.iconFunction = r.iconFunction;
            menu.itemRenderer = r.itemRenderer;
            menu.rowHeight = r.rowHeight;
            menu.scaleY = r.scaleY;
            menu.scaleX = r.scaleX;

            // if there's data and it has children then add the items
            if (row.data && _dataDescriptor.isBranch(row.data) &&
                    _dataDescriptor.hasChildren(row.data)) {
                menu.dataProvider = _dataDescriptor.getChildren(row.data);
            }
            menu.sourceMenuBar = sourceMenuBar;
            menu.sourceMenuBarItem = sourceMenuBarItem;

            IMenuItemRenderer(row).menu = menu;
            PopUpManager.addPopUp(menu, r, false);
        }

        super.openSubMenu(row);

        // if we're lefting, upping or fitting make sure our submenu does so as well
        var submenu :Menu = IMenuItemRenderer(row).menu;
        var lefting :Boolean = _lefting;
        var upping :Boolean = _upping;
        var fitting :Rectangle = _fitting != null ? _fitting :
            new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
        if (submenu.x + submenu.getExplicitOrMeasuredWidth() > fitting.right) {
            lefting = true;
        }
        if (submenu.y + submenu.getExplicitOrMeasuredHeight() > fitting.bottom) {
            upping = true;
        }

        if (lefting) {
            submenu.x -= submenu.getExplicitOrMeasuredWidth();
        }
        if (upping) {
            var displayObj :DisplayObject = DisplayObject(row);
            var rowLoc :Point = displayObj.localToGlobal(new Point(row.x, row.y));
            submenu.y = rowLoc.y - submenu.getExplicitOrMeasuredHeight() + displayObj.height;
        }

        // if we've poped out of the boundaries, just snap it to the lower right corner, or upper
        // if upping, left if lefting
        if (submenu.x < fitting.left) {
            submenu.x = lefting ? fitting.left : Math.max(
                    fitting.right - submenu.getExplicitOrMeasuredWidth(), fitting.left);
        }
        if (submenu.y < fitting.top) {
            submenu.y = upping ? fitting.top : Math.max(
                    fitting.bottom - submenu.getExplicitOrMeasuredHeight(), fitting.top);
        }
    }

    // from List
    override protected function makeListData (data :Object, uid :String, rowNum :int) :BaseListData
    {
        // Oh, FFS.
        // We need to set up these "maxMeasuredIconWidth" fields on the MenuListData, but our
        // superclass has made those variables private.
        // We can get the values out of another MenuListData, so we just always call super()
        // to create one of those, and if we need to make a CommandListData, we construct one
        // from the fields in the MenuListData.

        var menuListData :MenuListData = super.makeListData(data, uid, rowNum) as MenuListData;

        var iconObject :IFlexDisplayObject = getItemProp(data, "iconObject") as IFlexDisplayObject;
        if (iconObject != null) {
            var cmdListData :CommandListData = new CommandListData(menuListData.label,
                menuListData.icon, iconObject, labelField, uid, this, rowNum);

            cmdListData.maxMeasuredIconWidth = menuListData.maxMeasuredIconWidth;
            cmdListData.maxMeasuredTypeIconWidth = menuListData.maxMeasuredTypeIconWidth;
            cmdListData.maxMeasuredBranchIconWidth = menuListData.maxMeasuredBranchIconWidth;
            cmdListData.useTwoColumns = menuListData.useTwoColumns;
            return cmdListData;
        }

        return menuListData;
    }

    /**
     * Get the specified property for the specified item, if any.  Somewhat similar to bits in the
     * DefaultDataDescriptor.
     */
    protected function getItemProp (item :Object, prop :String) :Object
    {
        try {
            if (item is XML) {
                return String((item as XML).attribute(prop));

            } else if (prop in item) {
                return item[prop];
            }

        } catch (e :Error) {
            // alas; fall through
        }
        return null;
    }

    protected var _dispatcher :IEventDispatcher;
    protected var _lefting :Boolean = false;
    protected var _upping :Boolean = false;
    protected var _fitting :Rectangle = null;
}
}

Allow the creator to specify their own bounds if they don't want submenus to be constrained by the
stage.

git-svn-id: b675b909355d5cf946977f44a8ec5a6ceb3782e4@519 ed5b42cb-e716-0410-a449-f6a68f950b19


package aerys.minko.render.shader.compiler.graph.nodes.vertex
{
	import aerys.minko.render.shader.compiler.CRC32;
	import aerys.minko.render.shader.compiler.InstructionFlag;
	import aerys.minko.render.shader.compiler.graph.nodes.AbstractNode;
	import aerys.minko.render.shader.compiler.register.Components;

	import flash.utils.Dictionary;

	/**
	 * @private
	 * @author Romain Gilliotte
	 */
	public class Instruction extends AbstractNode
	{
		public static const MOV : uint = 0x00;
		public static const ADD : uint = 0x01;
		public static const SUB : uint = 0x02;
		public static const MUL : uint = 0x03;
		public static const DIV : uint = 0x04;
		public static const RCP : uint = 0x05;
		public static const MIN : uint = 0x06;
		public static const MAX : uint = 0x07;
		public static const FRC : uint = 0x08;
		public static const SQT : uint = 0x09;
		public static const RSQ : uint = 0x0a;
		public static const POW : uint = 0x0b;
		public static const LOG : uint = 0x0c;
		public static const EXP : uint = 0x0d;
		public static const NRM : uint = 0x0e;
		public static const SIN : uint = 0x0f;
		public static const COS : uint = 0x10;
		public static const CRS : uint = 0x11;
		public static const DP3 : uint = 0x12;
		public static const DP4 : uint = 0x13;
		public static const ABS : uint = 0x14;
		public static const NEG : uint = 0x15;
		public static const SAT : uint = 0x16;
		public static const M33 : uint = 0x17;
		public static const M44 : uint = 0x18;
		public static const M34 : uint = 0x19;
		public static const KIL	: uint = 0x27;
		public static const TEX : uint = 0x28;
		public static const SGE : uint = 0x29;
		public static const SLT : uint = 0x2a;
		public static const SEQ : uint = 0x2c;
		public static const SNE : uint = 0x2d;

		public static const MUL_MAT33 : uint = 0x100;
		public static const MUL_MAT44 : uint = 0x101;

		public static const NAME : Dictionary = new Dictionary();
		{
			NAME[MOV] = 'mov';		NAME[ADD] = 'add';		NAME[SUB] = 'sub';
			NAME[MUL] = 'mul';		NAME[DIV] = 'div';		NAME[RCP] = 'rcp';
			NAME[MIN] = 'min';		NAME[MAX] = 'max';		NAME[FRC] = 'frc';
			NAME[SQT] = 'sqt';		NAME[RSQ] = 'rsq';		NAME[POW] = 'pow';
			NAME[LOG] = 'log';		NAME[EXP] = 'exp';		NAME[NRM] = 'nrm';
			NAME[SIN] = 'sin';		NAME[COS] = 'cos';		NAME[CRS] = 'crs';
			NAME[DP3] = 'dp3';		NAME[DP4] = 'dp4';		NAME[ABS] = 'abs';
			NAME[NEG] = 'neg';		NAME[SAT] = 'sat';		NAME[M33] = 'm33';
			NAME[M44] = 'm44';		NAME[M34] = 'm34';		NAME[TEX] = 'tex';
			NAME[KIL] = 'kil';		NAME[SGE] = 'sge';		NAME[SLT] = 'slt';
			NAME[SEQ] = 'seq';		NAME[SNE] = 'sne';

			NAME[MUL_MAT33] = 'mulMat33';
			NAME[MUL_MAT44] = 'mulMat44';
		}

		private static const FLAGS : Dictionary = new Dictionary();
		{
			FLAGS[MOV] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE | InstructionFlag.LINEAR;
			FLAGS[ADD] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.COMMUTATIVE | InstructionFlag.LINEAR;
			FLAGS[SUB] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.LINEAR;
			FLAGS[MUL] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.COMMUTATIVE | InstructionFlag.LINEAR;
			FLAGS[DIV] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.LINEAR;
			FLAGS[RCP] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE | InstructionFlag.LINEAR;
			FLAGS[MIN] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.COMMUTATIVE;
			FLAGS[MAX] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.COMMUTATIVE;
			FLAGS[FRC] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE;
			FLAGS[SQT] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE;
			FLAGS[RSQ] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE;
			FLAGS[POW] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE;
			FLAGS[LOG] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE;
			FLAGS[EXP] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE;
			FLAGS[NRM] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.SINGLE;
			FLAGS[SIN] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE;
			FLAGS[COS] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE;
			FLAGS[CRS] = InstructionFlag.AVAILABLE_ALL;
			FLAGS[DP3] = InstructionFlag.AVAILABLE_ALL;
			FLAGS[DP4] = InstructionFlag.AVAILABLE_ALL;
			FLAGS[ABS] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE;
			FLAGS[NEG] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE | InstructionFlag.LINEAR;
			FLAGS[SAT] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE;
			FLAGS[M33] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.SPECIAL_MATRIX | InstructionFlag.LINEAR;
			FLAGS[M44] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.SPECIAL_MATRIX | InstructionFlag.LINEAR;
			FLAGS[M34] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.SPECIAL_MATRIX | InstructionFlag.LINEAR;
			FLAGS[KIL] = InstructionFlag.AVAILABLE_FS | InstructionFlag.SINGLE;
			FLAGS[TEX] = InstructionFlag.AVAILABLE_FS;
			FLAGS[SGE] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE;
			FLAGS[SLT] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE;
			FLAGS[SEQ] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.COMMUTATIVE;
			FLAGS[SNE] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.COMMUTATIVE;

			FLAGS[MUL_MAT33] = InstructionFlag.AVAILABLE_CPU | InstructionFlag.ASSOCIATIVE;
			FLAGS[MUL_MAT44] = InstructionFlag.AVAILABLE_CPU | InstructionFlag.ASSOCIATIVE;
		}

		private var _id : uint;

		public function get id()			: uint		{ return _id;		}
		public function get name()			: String	{ return NAME[_id];	}

		public function get argument1()		: AbstractNode	{ return getArgumentAt(0);	}
		public function get argument2() 	: AbstractNode 	{ return getArgumentAt(1);	}
		public function get component1()	: uint			{ return getComponentAt(0);	}
		public function get component2()	: uint			{ return getComponentAt(1);	}

		public function set argument1(v : AbstractNode) : void { setArgumentAt(0, v);	}
		public function set argument2(v : AbstractNode) : void { setArgumentAt(1, v);	}
		public function set component1(v : uint) 		: void { setComponentAt(0, v);	}
		public function set component2(v : uint) 		: void { setComponentAt(1, v);	}

		public function get isAssociative() : Boolean
		{
			return (FLAGS[_id] & InstructionFlag.ASSOCIATIVE) != 0;
		}

		public function get isComponentWise() : Boolean
		{
			return (FLAGS[_id] & InstructionFlag.COMPONENT_WISE) != 0;
		}

		public function get isSingle() : Boolean
		{
			return (FLAGS[_id] & InstructionFlag.SINGLE) != 0;
		}

		public function get isLinear() : Boolean
		{
			return (FLAGS[_id] & InstructionFlag.LINEAR) != 0;
		}

		public function isCommutative() : Boolean
		{
			return (FLAGS[_id] & InstructionFlag.COMMUTATIVE) != 0;
		}

		public function Instruction(id			: uint,
									argument1	: AbstractNode,
									argument2	: AbstractNode = null)
		{
			_id = id;

			var component1 : uint = id == MUL_MAT33 || id == MUL_MAT44 ?
				Components.createContinuous(0, 0, 4, 4) :
				Components.createContinuous(0, 0, argument1.size, argument1.size)

			var arguments	: Vector.<AbstractNode>	= new <AbstractNode>[argument1];
			var components	: Vector.<uint>			= new <uint>[component1];

			if (!isSingle)
			{
				var component2 : uint;

				if ((FLAGS[id] & InstructionFlag.SPECIAL_MATRIX) != 0)
					component2	= Components.createContinuous(0, 0, 4, 4);
				else if (id != TEX && id != MUL_MAT33 && id != MUL_MAT44)
					component2	= Components.createContinuous(0, 0, argument2.size, argument2.size);

				arguments.push(argument2);
				components.push(component2);
			}

			arguments.fixed = components.fixed = true;

			super(arguments, components);
		}

		override protected function computeHash() : uint
		{
			// commutative operations invert the arguments when computing the hash if arg1.crc > arg2.crc
			// that way, mul(a, b).hash == mul(b, a).hash

			var hashLeft  : String = argument1.hash.toString(16) + '_' + component1.toString(16);

			if ((FLAGS[_id] & InstructionFlag.SINGLE) != 0)
				return CRC32.computeForString(hashLeft);

			else
			{
				var hashRight : String = argument2.hash.toString(16) + '_' + component2.toString(16);

				if ((FLAGS[_id] & InstructionFlag.COMMUTATIVE) != 0 && argument1.hash > argument2.hash)
					return CRC32.computeForString(hashRight + hashLeft);
				else
					return CRC32.computeForString(hashLeft + hashRight);
			}
		}

		override protected function computeSize() : uint
		{
			switch (_id)
			{
				case DP3: case DP4:	return 1;
				case M33: case M34: case NRM: case CRS: return 3;
				case TEX: case M44: return 4;

				default:
					var nodeSize : uint;
					nodeSize = Components.getMaxWriteOffset(component1)
								- Components.getMinWriteOffset(component1) + 1;

					if (nodeSize > 4)
						throw new Error();

					if (!isSingle)
						nodeSize = Math.max(nodeSize,
							Components.getMaxWriteOffset(component2)
							- Components.getMinWriteOffset(component2) + 1
						);

					if (nodeSize < 1)
						throw new Error();

					if (nodeSize > 4)
						throw new Error();

					return nodeSize;
			}
		}

		override public function toString() : String
		{
			return name;
		}

		override public function clone() : AbstractNode
		{
			var clone : Instruction;
			if (isSingle)
			{
				clone = new Instruction(_id, argument1);
				clone.component1 = component1;
			}
			else
			{
				clone = new Instruction(_id, argument1, argument2);
				clone.component1 = component1;
				clone.component2 = component2;
			}

			return clone;
		}

	}
}

package aerys.minko.render.shader.compiler.graph.nodes.vertex
{
	import aerys.minko.render.shader.compiler.CRC32;
	import aerys.minko.render.shader.compiler.InstructionFlag;
	import aerys.minko.render.shader.compiler.graph.nodes.AbstractNode;
	import aerys.minko.render.shader.compiler.register.Components;

	import flash.utils.Dictionary;

	/**
	 * @private
	 * @author Romain Gilliotte
	 */
	public class Instruction extends AbstractNode
	{
		public static const MOV : uint = 0x00;
		public static const ADD : uint = 0x01;
		public static const SUB : uint = 0x02;
		public static const MUL : uint = 0x03;
		public static const DIV : uint = 0x04;
		public static const RCP : uint = 0x05;
		public static const MIN : uint = 0x06;
		public static const MAX : uint = 0x07;
		public static const FRC : uint = 0x08;
		public static const SQT : uint = 0x09;
		public static const RSQ : uint = 0x0a;
		public static const POW : uint = 0x0b;
		public static const LOG : uint = 0x0c;
		public static const EXP : uint = 0x0d;
		public static const NRM : uint = 0x0e;
		public static const SIN : uint = 0x0f;
		public static const COS : uint = 0x10;
		public static const CRS : uint = 0x11;
		public static const DP3 : uint = 0x12;
		public static const DP4 : uint = 0x13;
		public static const ABS : uint = 0x14;
		public static const NEG : uint = 0x15;
		public static const SAT : uint = 0x16;
		public static const M33 : uint = 0x17;
		public static const M44 : uint = 0x18;
		public static const M34 : uint = 0x19;
		public static const KIL	: uint = 0x27;
		public static const TEX : uint = 0x28;
		public static const SGE : uint = 0x29;
		public static const SLT : uint = 0x2a;
		public static const SEQ : uint = 0x2c;
		public static const SNE : uint = 0x2d;

		public static const MUL_MAT33 : uint = 0x100;
		public static const MUL_MAT44 : uint = 0x101;

		public static const NAME : Dictionary = new Dictionary();
		{
			NAME[MOV] = 'mov';		NAME[ADD] = 'add';		NAME[SUB] = 'sub';
			NAME[MUL] = 'mul';		NAME[DIV] = 'div';		NAME[RCP] = 'rcp';
			NAME[MIN] = 'min';		NAME[MAX] = 'max';		NAME[FRC] = 'frc';
			NAME[SQT] = 'sqt';		NAME[RSQ] = 'rsq';		NAME[POW] = 'pow';
			NAME[LOG] = 'log';		NAME[EXP] = 'exp';		NAME[NRM] = 'nrm';
			NAME[SIN] = 'sin';		NAME[COS] = 'cos';		NAME[CRS] = 'crs';
			NAME[DP3] = 'dp3';		NAME[DP4] = 'dp4';		NAME[ABS] = 'abs';
			NAME[NEG] = 'neg';		NAME[SAT] = 'sat';		NAME[M33] = 'm33';
			NAME[M44] = 'm44';		NAME[M34] = 'm34';		NAME[TEX] = 'tex';
			NAME[KIL] = 'kil';		NAME[SGE] = 'sge';		NAME[SLT] = 'slt';
			NAME[SEQ] = 'seq';		NAME[SNE] = 'sne';

			NAME[MUL_MAT33] = 'mulMat33';
			NAME[MUL_MAT44] = 'mulMat44';
		}

		private static const FLAGS : Dictionary = new Dictionary();
		{
			FLAGS[MOV] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE | InstructionFlag.LINEAR;
			FLAGS[ADD] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.COMMUTATIVE | InstructionFlag.LINEAR;
			FLAGS[SUB] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.LINEAR;
			FLAGS[MUL] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.COMMUTATIVE | InstructionFlag.LINEAR;
			FLAGS[DIV] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.LINEAR;
			FLAGS[RCP] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE | InstructionFlag.LINEAR;
			FLAGS[MIN] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.COMMUTATIVE;
			FLAGS[MAX] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.COMMUTATIVE;
			FLAGS[FRC] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE;
			FLAGS[SQT] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE;
			FLAGS[RSQ] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE;
			FLAGS[POW] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE;
			FLAGS[LOG] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE;
			FLAGS[EXP] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE;
			FLAGS[NRM] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.SINGLE;
			FLAGS[SIN] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE;
			FLAGS[COS] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE;
			FLAGS[CRS] = InstructionFlag.AVAILABLE_ALL;
			FLAGS[DP3] = InstructionFlag.AVAILABLE_ALL;
			FLAGS[DP4] = InstructionFlag.AVAILABLE_ALL;
			FLAGS[ABS] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE;
			FLAGS[NEG] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE | InstructionFlag.LINEAR;
			FLAGS[SAT] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.SINGLE;
			FLAGS[M33] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.SPECIAL_MATRIX | InstructionFlag.LINEAR;
			FLAGS[M44] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.SPECIAL_MATRIX | InstructionFlag.LINEAR;
			FLAGS[M34] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.SPECIAL_MATRIX | InstructionFlag.LINEAR;
			FLAGS[KIL] = InstructionFlag.AVAILABLE_FS | InstructionFlag.SINGLE;
			FLAGS[TEX] = InstructionFlag.AVAILABLE_FS;
			FLAGS[SGE] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE;
			FLAGS[SLT] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE;
			FLAGS[SEQ] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.COMMUTATIVE;
			FLAGS[SNE] = InstructionFlag.AVAILABLE_ALL | InstructionFlag.COMPONENT_WISE | InstructionFlag.COMMUTATIVE;

			FLAGS[MUL_MAT33] = InstructionFlag.AVAILABLE_CPU | InstructionFlag.ASSOCIATIVE;
			FLAGS[MUL_MAT44] = InstructionFlag.AVAILABLE_CPU | InstructionFlag.ASSOCIATIVE;
		}

		private var _id : uint;

		public function get id()			: uint		{ return _id;		}
		public function get name()			: String	{ return NAME[_id];	}

		public function get argument1()		: AbstractNode	{ return getArgumentAt(0);	}
		public function get argument2() 	: AbstractNode 	{ return getArgumentAt(1);	}
		public function get component1()	: uint			{ return getComponentAt(0);	}
		public function get component2()	: uint			{ return getComponentAt(1);	}

		public function set argument1(v : AbstractNode) : void { setArgumentAt(0, v);	}
		public function set argument2(v : AbstractNode) : void { setArgumentAt(1, v);	}
		public function set component1(v : uint) 		: void { setComponentAt(0, v);	}
		public function set component2(v : uint) 		: void { setComponentAt(1, v);	}

		public function get isAssociative() : Boolean
		{
			return (FLAGS[_id] & InstructionFlag.ASSOCIATIVE) != 0;
		}

		public function get isComponentWise() : Boolean
		{
			return (FLAGS[_id] & InstructionFlag.COMPONENT_WISE) != 0;
		}

		public function get isSingle() : Boolean
		{
			return (FLAGS[_id] & InstructionFlag.SINGLE) != 0;
		}

		public function get isLinear() : Boolean
		{
			return (FLAGS[_id] & InstructionFlag.LINEAR) != 0;
		}

		public function isCommutative() : Boolean
		{
			return (FLAGS[_id] & InstructionFlag.COMMUTATIVE) != 0;
		}

		public function Instruction(id			: uint,
									argument1	: AbstractNode,
									argument2	: AbstractNode = null)
		{
			_id = id;

			var component1 : uint = id == MUL_MAT33 || id == MUL_MAT44 ?
				Components.createContinuous(0, 0, 4, 4) :
				Components.createContinuous(0, 0, argument1.size, argument1.size)

			var arguments	: Vector.<AbstractNode>	= new <AbstractNode>[argument1];
			var components	: Vector.<uint>			= new <uint>[component1];

			if (!isSingle)
			{
				var component2 : uint;

				if ((FLAGS[id] & InstructionFlag.SPECIAL_MATRIX) != 0)
					component2	= Components.createContinuous(0, 0, 4, 4);
				else if (id != TEX && id != MUL_MAT33 && id != MUL_MAT44)
					component2	= Components.createContinuous(0, 0, argument2.size, argument2.size);

				arguments.push(argument2);
				components.push(component2);
			}

			arguments.fixed = components.fixed = true;

			super(arguments, components);
		}

		override protected function computeHash() : uint
		{
			// commutative operations invert the arguments when computing the hash if arg1.crc > arg2.crc
			// that way, mul(a, b).hash == mul(b, a).hash

			var hashLeft  : String = id.toFixed(16) + '_' + argument1.hash.toString(16)
				+ '_' + component1.toString(16);

			if ((FLAGS[_id] & InstructionFlag.SINGLE) != 0)
				return CRC32.computeForString(hashLeft);
			else
			{
				var hashRight : String = argument2.hash.toString(16) + '_' + component2.toString(16);

				if ((FLAGS[_id] & InstructionFlag.COMMUTATIVE) != 0 && argument1.hash > argument2.hash)
					return CRC32.computeForString(hashRight + hashLeft);
				else
					return CRC32.computeForString(hashLeft + hashRight);
			}
		}

		override protected function computeSize() : uint
		{
			switch (_id)
			{
				case DP3: case DP4:	return 1;
				case M33: case M34: case NRM: case CRS: return 3;
				case TEX: case M44: return 4;

				default:
					var nodeSize : uint;
					nodeSize = Components.getMaxWriteOffset(component1)
								- Components.getMinWriteOffset(component1) + 1;

					if (nodeSize > 4)
						throw new Error();

					if (!isSingle)
						nodeSize = Math.max(nodeSize,
							Components.getMaxWriteOffset(component2)
							- Components.getMinWriteOffset(component2) + 1
						);

					if (nodeSize < 1)
						throw new Error();

					if (nodeSize > 4)
						throw new Error();

					return nodeSize;
			}
		}

		override public function toString() : String
		{
			return name;
		}

		override public function clone() : AbstractNode
		{
			var clone : Instruction;
			if (isSingle)
			{
				clone = new Instruction(_id, argument1);
				clone.component1 = component1;
			}
			else
			{
				clone = new Instruction(_id, argument1, argument2);
				clone.component1 = component1;
				clone.component2 = component2;
			}

			return clone;
		}

	}
}

fix Instruction.computeHash() to prefix the string hash with the instruction id and avoid instructions with the same arguments being mixed up


package
{
	import com.kaltura.kdpfl.model.ConfigProxy;
	import com.kaltura.kdpfl.model.LayoutProxy;
	import com.kaltura.kdpfl.model.MediaProxy;
	import com.kaltura.kdpfl.plugin.IPlugin;
	import com.kaltura.kdpfl.plugin.KPluginEvent;
	import com.kaltura.kdpfl.plugin.WVPluginInfo;

	import flash.display.Sprite;

	import org.osmf.events.MediaFactoryEvent;
	import org.osmf.media.DefaultMediaFactory;
	import org.osmf.media.PluginInfoResource;
	import org.puremvc.as3.interfaces.IFacade;

	public class wvPluginCode extends Sprite implements IPlugin
	{
		protected var _flashvars : Object;

		protected var _localMediaFactory : DefaultMediaFactory;
		public function wvPluginCode()
		{
			trace('Widevine plugin v2');
			super();
		}
		public function initializePlugin(facade:IFacade):void
		{
			_flashvars = (facade.retrieveProxy(ConfigProxy.NAME) as ConfigProxy).vo.flashvars;

			_localMediaFactory = (facade.retrieveProxy(MediaProxy.NAME) as MediaProxy).vo.mediaFactory;
			var wvpinfo: WVPluginInfo = new WVPluginInfo();

			var lp:LayoutProxy = (facade.retrieveProxy(LayoutProxy.NAME) as LayoutProxy);
			for each( var i:Object in lp.components)
			{
				if(i.hasOwnProperty("className") && i.className == "KMediaPlayer" )
				{
					trace(i.ui.width,i.ui.height );
					WVPluginInfo.mediaWidth = i.ui.width;
					WVPluginInfo.mediaHeight = i.ui.height;
					break;
				}
			}

			//overriding media width/height if flashvar available
/*			if (_flashvars.widevinemediawidth)
				WVPluginInfo.mediaWidth = Number(_flashvars.widevinemediawidth);
			if (_flashvars.widevinemediaheight)
				WVPluginInfo.mediaHeight = Number(_flashvars.widevinemediaheight);*/

			_localMediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD, onOSMFPluginLoaded);
			_localMediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD_ERROR, onOSMFPluginLoadError);

			_localMediaFactory.loadPlugin(new PluginInfoResource(wvpinfo) );
			var wvm:WvMediator = new WvMediator(wvpinfo);
			facade.registerMediator(wvm);
		}
		/**
		 * Listener for the LOAD_COMPLETE event.
		 * @param e - MediaFactoryEvent
		 *
		 */
		protected function onOSMFPluginLoaded (e : MediaFactoryEvent) : void
		{
			dispatchEvent( new KPluginEvent (KPluginEvent.KPLUGIN_INIT_COMPLETE) );
		}
		/**
		 * Listener for the LOAD_ERROR event.
		 * @param e - MediaFactoryEvent
		 *
		 */
		protected function onOSMFPluginLoadError (e : MediaFactoryEvent) : void
		{
			dispatchEvent( new KPluginEvent (KPluginEvent.KPLUGIN_INIT_FAILED) );
		}
		public function setSkin(styleName:String, setSkinSize:Boolean=false):void
		{
		}
	}
}

package
{
	import com.kaltura.kdpfl.model.ConfigProxy;
	import com.kaltura.kdpfl.model.LayoutProxy;
	import com.kaltura.kdpfl.model.MediaProxy;
	import com.kaltura.kdpfl.plugin.IPlugin;
	import com.kaltura.kdpfl.plugin.KPluginEvent;
	import com.kaltura.kdpfl.plugin.WVPluginInfo;

	import flash.display.Sprite;

	import org.osmf.events.MediaFactoryEvent;
	import org.osmf.media.DefaultMediaFactory;
	import org.osmf.media.PluginInfoResource;
	import org.puremvc.as3.interfaces.IFacade;

	public dynamic class wvPluginCode extends Sprite implements IPlugin
	{
		protected var _flashvars : Object;

		protected var _localMediaFactory : DefaultMediaFactory;
		public function wvPluginCode()
		{
			trace('Widevine plugin v2');
			super();
		}
		public function initializePlugin(facade:IFacade):void
		{
			_flashvars = (facade.retrieveProxy(ConfigProxy.NAME) as ConfigProxy).vo.flashvars;

			_localMediaFactory = (facade.retrieveProxy(MediaProxy.NAME) as MediaProxy).vo.mediaFactory;
			var wvpinfo: WVPluginInfo = new WVPluginInfo();

			var lp:LayoutProxy = (facade.retrieveProxy(LayoutProxy.NAME) as LayoutProxy);
			for each( var i:Object in lp.components)
			{
				if(i.hasOwnProperty("className") && i.className == "KMediaPlayer" )
				{
					trace(i.ui.width,i.ui.height );
					WVPluginInfo.mediaWidth = i.ui.width;
					WVPluginInfo.mediaHeight = i.ui.height;
					break;
				}
			}

			//overriding media width/height if flashvar available
/*			if (_flashvars.widevinemediawidth)
				WVPluginInfo.mediaWidth = Number(_flashvars.widevinemediawidth);
			if (_flashvars.widevinemediaheight)
				WVPluginInfo.mediaHeight = Number(_flashvars.widevinemediaheight);*/

			_localMediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD, onOSMFPluginLoaded);
			_localMediaFactory.addEventListener(MediaFactoryEvent.PLUGIN_LOAD_ERROR, onOSMFPluginLoadError);

			_localMediaFactory.loadPlugin(new PluginInfoResource(wvpinfo) );
			var wvm:WvMediator = new WvMediator(wvpinfo);
			facade.registerMediator(wvm);
		}
		/**
		 * Listener for the LOAD_COMPLETE event.
		 * @param e - MediaFactoryEvent
		 *
		 */
		protected function onOSMFPluginLoaded (e : MediaFactoryEvent) : void
		{
			dispatchEvent( new KPluginEvent (KPluginEvent.KPLUGIN_INIT_COMPLETE) );
		}
		/**
		 * Listener for the LOAD_ERROR event.
		 * @param e - MediaFactoryEvent
		 *
		 */
		protected function onOSMFPluginLoadError (e : MediaFactoryEvent) : void
		{
			dispatchEvent( new KPluginEvent (KPluginEvent.KPLUGIN_INIT_FAILED) );
		}
		public function setSkin(styleName:String, setSkinSize:Boolean=false):void
		{
		}
	}
}

make widevine plugin a dynamic class: this way we can access properties dynamically via kdp.evaluate


//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.desktop.NativeApplication;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filesystem.File;
import flash.net.SharedObject;

import com.adobe.crypto.MD5;

import deng.fzip.FZip;
import deng.fzip.FZipFile;

import executor.Executor;
import executor.Future;

import flump.bytesToXML;
import flump.export.Ternary;
import flump.xfl.ParseError;
import flump.xfl.XflAnimation;
import flump.xfl.XflLibrary;

import spark.components.DataGrid;
import spark.components.List;
import spark.components.Window;
import spark.events.GridSelectionEvent;

import starling.core.Starling;

import com.threerings.util.DelayUtil;
import com.threerings.util.F;
import com.threerings.util.Log;
import com.threerings.util.StringUtil;

public class Exporter
{
    public static const NA :NativeApplication = NativeApplication.nativeApplication;

    protected static const IMPORT_ROOT :String = "IMPORT_ROOT";

    public function Exporter (win :ExporterWindow) {
        _win = win;
        _errors = _win.errors;
        _libraries = _win.libraries;
        _libraries.addEventListener(GridSelectionEvent.SELECTION_CHANGE, function (..._) :void {
            log.info("Changed", "selected", _libraries.selectedIndices);
            _win.export.enabled = _libraries.selectedIndices.length > 0;
            _win.preview.enabled = _libraries.selectedIndices.length == 1;
        });
        _win.export.addEventListener(MouseEvent.CLICK, function (..._) :void {
            for each (var status :DocStatus in _libraries.selectedItems) {
                exportFlashDocument(status);
            }
        });
        _win.preview.addEventListener(MouseEvent.CLICK, function (..._) :void {
            var previewWindow :PreviewWindow = new PreviewWindow();
            previewWindow.started = F.callback(DelayUtil.delayFrame, function (..._) :void {

                var preview :Preview = Preview(Starling.current.stage.getChildAt(0));
                var lib :XflLibrary = _libraries.selectedItem.lib;
                // TODO - animation selector in Preview
            });
            previewWindow.open();
        });
        _importChooser =
            new DirChooser(_settings, "IMPORT_ROOT", _win.importRoot, _win.browseImport);
        _importChooser.changed.add(setImport);
        setImport(new File(_importChooser.dir));
        _exportChooser =
            new DirChooser(_settings, "EXPORT_ROOT", _win.exportRoot, _win.browseExport);
    }

    protected function setImport (root :File) :void {
        _libraries.dataProvider.removeAll();
        _rootLen = root.nativePath.length + 1;
        if (_docFinder != null) _docFinder.shutdownNow();
        _docFinder = new Executor(2);
        findFlashDocuments(root, _docFinder);
    }

    protected function findFlashDocuments (base :File, exec :Executor) :void {
        Files.list(base, exec).succeeded.add(function (files :Array) :void {
            if (exec.isShutdown) return;
            for each (var file :File in files) {
                if (StringUtil.endsWith(file.nativePath, ".xfl")) {
                    addFlashDocument(file.parent);
                    return;
                }
            }
            for each (file in files) {
                if (file.isDirectory) findFlashDocuments(file, exec);
                else if (StringUtil.endsWith(file.nativePath, ".fla")) addFlashDocument(file);
            }
        });
    }

    protected function addFlashDocument (file :File) :void {
        const status :DocStatus = new DocStatus(file, _rootLen, Ternary.UNKOWN, Ternary.UNKOWN, null);
        _libraries.dataProvider.addItem(status);
        loadFlashDocument(status);
    }

    protected function exportFlashDocument (status :DocStatus) :void {
        const exportDir :File = new File(_exportChooser.dir);
        PngPublisher.dumpTextures(exportDir, status.lib);
        BetwixtPublisher.export(status.lib, status.file, exportDir);
        status.updateModified(Ternary.FALSE);
    }

    protected function loadFlashDocument (status :DocStatus) :void {
        if (StringUtil.endsWith(status.file.nativePath, ".xfl")) status.file = status.file.parent;
        if (status.file.isDirectory) {
            const name :String = status.file.nativePath.substring(_rootLen);
            const load :Future = new XflLoader().load(name, status.file);
            load.succeeded.add(function (lib :XflLibrary) :void {
                const exportDir :File = new File(_exportChooser.dir);
                const isMod :Boolean = BetwixtPublisher.modified(lib, exportDir);
                status.lib = lib;
                status.updateModified(Ternary.of(isMod));
                for each (var err :ParseError in lib.getErrors()) {
                    _errors.dataProvider.addItem(err);
                    trace(err);
                }
                status.updateValid(Ternary.of(lib.valid));
                if (status.path == "shapes") {
                    try {
                        exportFlashDocument(status);
                    } catch (e :Error) {
                        log.warning("Blew up", e);
                    } finally {
                        NA.exit(0);
                    }
                }
            });
        } else loadFla(status.file);
    }

    protected function loadFla (file :File) :void {
        log.info("Loading fla", "path", file.nativePath);
        Files.load(file).succeeded.add(function (file :File) :void {
            const zip :FZip = new FZip();
            zip.loadBytes(file.data);
            const files :Array = [];
            for (var ii :int = 0; ii < zip.getFileCount(); ii++) files.push(zip.getFileAt(ii));
            const xmls :Array = F.filter(files, function (fz :FZipFile) :Boolean {
                return StringUtil.endsWith(fz.filename, ".xml");
            });
            const anims :Array = F.filter(xmls, function (fz :FZipFile) :Boolean {
                return StringUtil.startsWith(fz.filename, "LIBRARY/Animations/");
            });
            const textures :Array = F.filter(xmls, function (fz :FZipFile) :Boolean {
                return StringUtil.startsWith(fz.filename, "LIBRARY/Textures/");
            });
            function toFn (fz :FZipFile) :String { return fz.filename };
            log.info("Loaded", "bytes", file.data.length, "anims", F.map(anims, toFn),
                "textures", F.map(textures, toFn));
            for each (var fz :FZipFile in anims) {
                new XflAnimation(fz.filename, bytesToXML(fz.content), MD5.hashBytes(fz.content));
            }
            NA.exit(0);
        });
    }

    protected var _rootLen :int;

    protected var _docFinder :Executor;
    protected var _win :ExporterWindow;
    protected var _libraries :DataGrid;
    protected var _errors :DataGrid;
    protected var _exportChooser :DirChooser;
    protected var _importChooser :DirChooser;
    protected const _settings :SharedObject = SharedObject.getLocal("flump/Exporter");

    private static const log :Log = Log.getLog(Exporter);
}
}
import flash.events.EventDispatcher;
import flash.filesystem.File;

import flump.export.Ternary;
import flump.xfl.XflLibrary;

import mx.core.IPropertyChangeNotifier;
import mx.events.PropertyChangeEvent;

class DocStatus extends EventDispatcher implements IPropertyChangeNotifier {
    public var path :String;
    public var modified :String;
    public var valid :String = QUESTION;
    public var file :File;
    public var lib :XflLibrary;

    public function DocStatus (file :File, rootLen :int, modified :Ternary, valid :Ternary, lib :XflLibrary) {
        this.file = file;
        this.lib = lib;
        path = file.nativePath.substring(rootLen);
        _uid = path;

        updateModified(modified);
        updateValid(valid);
    }

    public function updateValid (newValid :Ternary) :void {
        changeField("valid", function (..._) :void {
            if (newValid == Ternary.TRUE) valid = CHECK;
            else if (newValid == Ternary.FALSE) valid = FROWN;
            else valid = QUESTION;
        });
    }

    public function updateModified (newModified :Ternary) :void {
        changeField("modified", function (..._) :void {
            if (newModified == Ternary.TRUE) modified = CHECK;
            else if (newModified == Ternary.FALSE) modified = " ";
            else modified = QUESTION;
        });
    }

    protected function changeField(fieldName :String, modifier :Function) :void {
        const oldValue :Object = this[fieldName];
        modifier();
        const newValue :Object = this[fieldName];
        dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, fieldName, oldValue, newValue));
    }

    public function get uid () :String { return _uid; }
    public function set uid (uid :String) :void { _uid = uid; }

    protected var _uid :String;

    protected static const QUESTION :String = "?";
    protected static const FROWN :String = "☹";
    protected static const CHECK :String = "✓";
}

//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.desktop.NativeApplication;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filesystem.File;
import flash.net.SharedObject;

import com.adobe.crypto.MD5;

import deng.fzip.FZip;
import deng.fzip.FZipFile;

import executor.Executor;
import executor.Future;

import flump.bytesToXML;
import flump.export.Ternary;
import flump.xfl.ParseError;
import flump.xfl.XflAnimation;
import flump.xfl.XflLibrary;

import spark.components.DataGrid;
import spark.components.List;
import spark.components.Window;
import spark.events.GridSelectionEvent;

import starling.core.Starling;

import com.threerings.util.DelayUtil;
import com.threerings.util.F;
import com.threerings.util.Log;
import com.threerings.util.StringUtil;

public class Exporter
{
    public static const NA :NativeApplication = NativeApplication.nativeApplication;

    protected static const IMPORT_ROOT :String = "IMPORT_ROOT";

    public function Exporter (win :ExporterWindow) {
        _win = win;
        _errors = _win.errors;
        _libraries = _win.libraries;
        _libraries.addEventListener(GridSelectionEvent.SELECTION_CHANGE, function (..._) :void {
            log.info("Changed", "selected", _libraries.selectedIndices);
            _win.export.enabled = _libraries.selectedIndices.length > 0;
            _win.preview.enabled = _libraries.selectedIndices.length == 1;
        });
        _win.export.addEventListener(MouseEvent.CLICK, function (..._) :void {
            for each (var status :DocStatus in _libraries.selectedItems) {
                exportFlashDocument(status);
            }
        });
        _win.preview.addEventListener(MouseEvent.CLICK, function (..._) :void {
            var previewWindow :PreviewWindow = new PreviewWindow();
            previewWindow.started = F.callback(DelayUtil.delayFrame, function (..._) :void {

                var preview :Preview = Preview(Starling.current.stage.getChildAt(0));
                var lib :XflLibrary = _libraries.selectedItem.lib;
                // TODO - animation selector in Preview
            });
            previewWindow.open();
        });
        _importChooser =
            new DirChooser(_settings, "IMPORT_ROOT", _win.importRoot, _win.browseImport);
        _importChooser.changed.add(setImport);
        setImport(new File(_importChooser.dir));
        _exportChooser =
            new DirChooser(_settings, "EXPORT_ROOT", _win.exportRoot, _win.browseExport);
    }

    protected function setImport (root :File) :void {
        _libraries.dataProvider.removeAll();
        _rootLen = root.nativePath.length + 1;
        if (_docFinder != null) _docFinder.shutdownNow();
        _docFinder = new Executor(2);
        findFlashDocuments(root, _docFinder);
    }

    protected function findFlashDocuments (base :File, exec :Executor) :void {
        Files.list(base, exec).succeeded.add(function (files :Array) :void {
            if (exec.isShutdown) return;
            for each (var file :File in files) {
                if (StringUtil.endsWith(file.nativePath, ".xfl")) {
                    addFlashDocument(file.parent);
                    return;
                }
            }
            for each (file in files) {
                if (file.isDirectory) findFlashDocuments(file, exec);
                else if (StringUtil.endsWith(file.nativePath, ".fla")) addFlashDocument(file);
            }
        });
    }

    protected function addFlashDocument (file :File) :void {
        const status :DocStatus = new DocStatus(file, _rootLen, Ternary.UNKOWN, Ternary.UNKOWN, null);
        _libraries.dataProvider.addItem(status);
        loadFlashDocument(status);
    }

    protected function exportFlashDocument (status :DocStatus) :void {
        const exportDir :File = new File(_exportChooser.dir);
        BetwixtPublisher.publish(status.lib, status.file, exportDir);
        status.updateModified(Ternary.FALSE);
    }

    protected function loadFlashDocument (status :DocStatus) :void {
        if (StringUtil.endsWith(status.file.nativePath, ".xfl")) status.file = status.file.parent;
        if (status.file.isDirectory) {
            const name :String = status.file.nativePath.substring(_rootLen);
            const load :Future = new XflLoader().load(name, status.file);
            load.succeeded.add(function (lib :XflLibrary) :void {
                const exportDir :File = new File(_exportChooser.dir);
                const isMod :Boolean = BetwixtPublisher.modified(lib, exportDir);
                status.lib = lib;
                status.updateModified(Ternary.of(isMod));
                for each (var err :ParseError in lib.getErrors()) {
                    _errors.dataProvider.addItem(err);
                    trace(err);
                }
                status.updateValid(Ternary.of(lib.valid));
                if (status.path == "shapes") {
                    try {
                        exportFlashDocument(status);
                    } catch (e :Error) {
                        log.warning("Blew up", e);
                    } finally {
                        NA.exit(0);
                    }
                }
            });
        } else loadFla(status.file);
    }

    protected function loadFla (file :File) :void {
        log.info("Loading fla", "path", file.nativePath);
        Files.load(file).succeeded.add(function (file :File) :void {
            const zip :FZip = new FZip();
            zip.loadBytes(file.data);
            const files :Array = [];
            for (var ii :int = 0; ii < zip.getFileCount(); ii++) files.push(zip.getFileAt(ii));
            const xmls :Array = F.filter(files, function (fz :FZipFile) :Boolean {
                return StringUtil.endsWith(fz.filename, ".xml");
            });
            const anims :Array = F.filter(xmls, function (fz :FZipFile) :Boolean {
                return StringUtil.startsWith(fz.filename, "LIBRARY/Animations/");
            });
            const textures :Array = F.filter(xmls, function (fz :FZipFile) :Boolean {
                return StringUtil.startsWith(fz.filename, "LIBRARY/Textures/");
            });
            function toFn (fz :FZipFile) :String { return fz.filename };
            log.info("Loaded", "bytes", file.data.length, "anims", F.map(anims, toFn),
                "textures", F.map(textures, toFn));
            for each (var fz :FZipFile in anims) {
                new XflAnimation(fz.filename, bytesToXML(fz.content), MD5.hashBytes(fz.content));
            }
            NA.exit(0);
        });
    }

    protected var _rootLen :int;

    protected var _docFinder :Executor;
    protected var _win :ExporterWindow;
    protected var _libraries :DataGrid;
    protected var _errors :DataGrid;
    protected var _exportChooser :DirChooser;
    protected var _importChooser :DirChooser;
    protected const _settings :SharedObject = SharedObject.getLocal("flump/Exporter");

    private static const log :Log = Log.getLog(Exporter);
}
}
import flash.events.EventDispatcher;
import flash.filesystem.File;

import flump.export.Ternary;
import flump.xfl.XflLibrary;

import mx.core.IPropertyChangeNotifier;
import mx.events.PropertyChangeEvent;

class DocStatus extends EventDispatcher implements IPropertyChangeNotifier {
    public var path :String;
    public var modified :String;
    public var valid :String = QUESTION;
    public var file :File;
    public var lib :XflLibrary;

    public function DocStatus (file :File, rootLen :int, modified :Ternary, valid :Ternary, lib :XflLibrary) {
        this.file = file;
        this.lib = lib;
        path = file.nativePath.substring(rootLen);
        _uid = path;

        updateModified(modified);
        updateValid(valid);
    }

    public function updateValid (newValid :Ternary) :void {
        changeField("valid", function (..._) :void {
            if (newValid == Ternary.TRUE) valid = CHECK;
            else if (newValid == Ternary.FALSE) valid = FROWN;
            else valid = QUESTION;
        });
    }

    public function updateModified (newModified :Ternary) :void {
        changeField("modified", function (..._) :void {
            if (newModified == Ternary.TRUE) modified = CHECK;
            else if (newModified == Ternary.FALSE) modified = " ";
            else modified = QUESTION;
        });
    }

    protected function changeField(fieldName :String, modifier :Function) :void {
        const oldValue :Object = this[fieldName];
        modifier();
        const newValue :Object = this[fieldName];
        dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, fieldName, oldValue, newValue));
    }

    public function get uid () :String { return _uid; }
    public function set uid (uid :String) :void { _uid = uid; }

    protected var _uid :String;

    protected static const QUESTION :String = "?";
    protected static const FROWN :String = "☹";
    protected static const CHECK :String = "✓";
}

Stop dumping the textures individually

Stop dumping the textures individually