package goplayer
{
  import flash.ui.Keyboard

  public class Application extends Component
    implements SkinSWFLoaderListener, MovieHandler, PlayerListener
  {
    private const background : Background
      = new Background(0x000000, 1)
    private const contentLayer : Component
      = new Component
    private const debugLayer : Component
      = new EphemeralComponent

    private var configuration : Configuration

    private var api : StreamioAPI

    private var skinSWF : SkinSWF = null
    private var movie : Movie = null
    private var player : Player = null
    private var view : Component = null

    private var _listener : ApplicationListener = null

    public function Application(parameters : Object)
    {
      this.configuration = ConfigurationParser.parse(parameters)

      api = new StreamioAPI
        (configuration.apiURL,
         new StandardHTTP,
         configuration.trackerID)

      addChild(background)
      addChild(contentLayer)
      addChild(debugLayer)

      installLogger()
    }

    public function set listener(value : ApplicationListener) : void
    { _listener = value }

    private function installLogger() : void
    { new DebugLoggerInstaller(debugLayer).execute() }

    override protected function initialize() : void
    {
      onkeydown(stage, handleKeyDown)

      if (configuration.skinURL)
        loadSkin()
      else
        lookUpMovie()
    }

    private function loadSkin() : void
    { new SkinSWFLoader(configuration.skinURL, this).execute() }

    public function handleSkinSWFLoaded(swf : SkinSWF) : void
    {
      skinSWF = swf
      lookUpMovie()
    }

    private function lookUpMovie() : void
    {
      debug("Looking up Streamio video “" + configuration.movieID + "”...")
      api.fetchMovie(configuration.movieID, this)
    }

    public function handleMovie(movie : Movie) : void
    {
      this.movie = movie

      logMovieInformation()
      createPlayer()

      if (configuration.enableAutoplay)
        player.start()
    }

    private function logMovieInformation() : void
    {
      debug("Movie “" + movie.title + "” found.")
      debug("Will use " + configuration.bitratePolicy + ".")

      const bitrates : Array = []

      for each (var stream : RTMPStream in movie.rtmpStreams)
        bitrates.push(stream.bitrate)

      if (bitrates.length == 0)
        debug("No RTMP streams available.")
      else
        debug("Available RTMP streams: " + bitrates.join(", "))

      if (!configuration.enableRTMP)
        debug("Will not use RTMP (disabled by configuration).")
    }

    private function createPlayer() : void
    {
      if (player != null)
        player.destroy()

      const kit : PlayerKit = new PlayerKit
        (movie, configuration.bitratePolicy,
         configuration.enableRTMP, api)

      player = kit.player
      player.listener = this

      if (skinSWF)
        view = new SkinnedPlayerView(kit.video, player, viewConfiguration)
      else
        view = new SimplePlayerView(kit.video, player)

      contentLayer.addChild(view)
    }

    private function get viewConfiguration() : SkinnedPlayerViewConfiguration
    {
      const result : SkinnedPlayerViewConfiguration
        = new SkinnedPlayerViewConfiguration

      result.skin = skinSWF.getSkin()
      result.enableChrome = configuration.enableChrome
      result.enableTitle = configuration.enableTitle
      result.enablePlayPauseButton = configuration.enablePlayPauseButton
      result.enableElapsedTime = configuration.enableElapsedTime
      result.enableSeekBar = configuration.enableSeekBar
      result.enableTotalTime = configuration.enableTotalTime
      result.enableVolumeControl = configuration.enableVolumeControl
      result.enableFullscreenButton = configuration.enableFullscreenButton

      return result
    }

    public function handleKeyDown(key : Key) : void
    {
      if (key.code == Keyboard.ENTER)
        debugLayer.visible = !debugLayer.visible
      else if (player != null)
        $handleKeyDown(key)
    }

    private function $handleKeyDown(key : Key) : void
    {
      if (key.code == Keyboard.SPACE)
        player.togglePaused()
      else if (key.code == Keyboard.LEFT)
        player.seekBy(Duration.seconds(-3))
      else if (key.code == Keyboard.RIGHT)
        player.seekBy(Duration.seconds(+3))
      else if (key.code == Keyboard.UP)
        player.changeVolumeBy(+.1)
      else if (key.code == Keyboard.DOWN)
        player.changeVolumeBy(-.1)
    }

    public function handleMovieFinishedPlaying() : void
    {
      if (configuration.enableLooping)
        debug("Looping."), player.rewind()
      else if (_listener != null)
        _listener.handlePlaybackEnded()
    }

    public function handleCurrentTimeChanged() : void
    {
      if (_listener != null)
        _listener.handleCurrentTimeChanged()
    }

    public function play() : void
    {
      if (player != null)
        $play()
    }

    private function $play() : void
    {
      if (player.started)
        player.paused = false
      else
        player.start()
    }

    public function pause() : void
    {
      if (player != null)
        player.paused = true
    }

    public function stop() : void
    {
      if (player != null)
        player.stop()
    }

    public function get currentTime() : Duration
    { return player.currentTime }

    public function set currentTime(value : Duration) : void
    { player.currentTime = value }

    public function get duration() : Duration
    { return player.duration }
  }
}

package goplayer
{
  import flash.ui.Keyboard

  public class Application extends Component
    implements SkinSWFLoaderListener, MovieHandler, PlayerListener
  {
    private const background : Background
      = new Background(0x000000, 1)
    private const contentLayer : Component
      = new Component
    private const debugLayer : Component
      = new EphemeralComponent

    private var configuration : Configuration

    private var api : StreamioAPI

    private var skinSWF : SkinSWF = null
    private var movie : Movie = null
    private var player : Player = null
    private var view : Component = null

    private var _listener : ApplicationListener = null

    public function Application(parameters : Object)
    {
      installLogger()

      this.configuration = ConfigurationParser.parse(parameters)

      api = new StreamioAPI
        (configuration.apiURL,
         new StandardHTTP,
         configuration.trackerID)

      addChild(background)
      addChild(contentLayer)
      addChild(debugLayer)
    }

    public function set listener(value : ApplicationListener) : void
    { _listener = value }

    private function installLogger() : void
    { new DebugLoggerInstaller(debugLayer).execute() }

    override protected function initialize() : void
    {
      onkeydown(stage, handleKeyDown)

      if (configuration.skinURL)
        loadSkin()
      else
        lookUpMovie()
    }

    private function loadSkin() : void
    { new SkinSWFLoader(configuration.skinURL, this).execute() }

    public function handleSkinSWFLoaded(swf : SkinSWF) : void
    {
      skinSWF = swf
      lookUpMovie()
    }

    private function lookUpMovie() : void
    {
      debug("Looking up Streamio video “" + configuration.movieID + "”...")
      api.fetchMovie(configuration.movieID, this)
    }

    public function handleMovie(movie : Movie) : void
    {
      this.movie = movie

      logMovieInformation()
      createPlayer()

      if (configuration.enableAutoplay)
        player.start()
    }

    private function logMovieInformation() : void
    {
      debug("Movie “" + movie.title + "” found.")
      debug("Will use " + configuration.bitratePolicy + ".")

      const bitrates : Array = []

      for each (var stream : RTMPStream in movie.rtmpStreams)
        bitrates.push(stream.bitrate)

      if (bitrates.length == 0)
        debug("No RTMP streams available.")
      else
        debug("Available RTMP streams: " + bitrates.join(", "))

      if (!configuration.enableRTMP)
        debug("Will not use RTMP (disabled by configuration).")
    }

    private function createPlayer() : void
    {
      if (player != null)
        player.destroy()

      const kit : PlayerKit = new PlayerKit
        (movie, configuration.bitratePolicy,
         configuration.enableRTMP, api)

      player = kit.player
      player.listener = this

      if (skinSWF)
        view = new SkinnedPlayerView(kit.video, player, viewConfiguration)
      else
        view = new SimplePlayerView(kit.video, player)

      contentLayer.addChild(view)
    }

    private function get viewConfiguration() : SkinnedPlayerViewConfiguration
    {
      const result : SkinnedPlayerViewConfiguration
        = new SkinnedPlayerViewConfiguration

      result.skin = skinSWF.getSkin()
      result.enableChrome = configuration.enableChrome
      result.enableTitle = configuration.enableTitle
      result.enablePlayPauseButton = configuration.enablePlayPauseButton
      result.enableElapsedTime = configuration.enableElapsedTime
      result.enableSeekBar = configuration.enableSeekBar
      result.enableTotalTime = configuration.enableTotalTime
      result.enableVolumeControl = configuration.enableVolumeControl
      result.enableFullscreenButton = configuration.enableFullscreenButton

      return result
    }

    public function handleKeyDown(key : Key) : void
    {
      if (key.code == Keyboard.ENTER)
        debugLayer.visible = !debugLayer.visible
      else if (player != null)
        $handleKeyDown(key)
    }

    private function $handleKeyDown(key : Key) : void
    {
      if (key.code == Keyboard.SPACE)
        player.togglePaused()
      else if (key.code == Keyboard.LEFT)
        player.seekBy(Duration.seconds(-3))
      else if (key.code == Keyboard.RIGHT)
        player.seekBy(Duration.seconds(+3))
      else if (key.code == Keyboard.UP)
        player.changeVolumeBy(+.1)
      else if (key.code == Keyboard.DOWN)
        player.changeVolumeBy(-.1)
    }

    public function handleMovieFinishedPlaying() : void
    {
      if (configuration.enableLooping)
        debug("Looping."), player.rewind()
      else if (_listener != null)
        _listener.handlePlaybackEnded()
    }

    public function handleCurrentTimeChanged() : void
    {
      if (_listener != null)
        _listener.handleCurrentTimeChanged()
    }

    public function play() : void
    {
      if (player != null)
        $play()
    }

    private function $play() : void
    {
      if (player.started)
        player.paused = false
      else
        player.start()
    }

    public function pause() : void
    {
      if (player != null)
        player.paused = true
    }

    public function stop() : void
    {
      if (player != null)
        player.stop()
    }

    public function get currentTime() : Duration
    { return player.currentTime }

    public function set currentTime(value : Duration) : void
    { player.currentTime = value }

    public function get duration() : Duration
    { return player.duration }
  }
}

Install logger before doing anything else.


/*
#
# Copyright (c) 2005-2009 rPath, Inc.
#
# All rights reserved
#
*/

/*
#
# Copyright (c) 2009 rPath, Inc.
#
# This program is distributed under the terms of the MIT License as found
# in a file called LICENSE. If it is not present, the license
# is always available at http://www.opensource.org/licenses/mit-license.php.
#
# This program is distributed in the hope that it will be useful, but
# without any waranty; without even the implied warranty of merchantability
# or fitness for a particular purpose. See the MIT License for full details.
*/

package com.rpath.raf.util
{
    import flash.utils.Dictionary;

    import mx.collections.ArrayCollection;
    import mx.core.Application;
    import mx.core.FlexGlobals;
    import mx.core.IFlexDisplayObject;
    import mx.formatters.NumberBaseRoundType;
    import mx.formatters.NumberFormatter;
    import mx.managers.PopUpManager;
    import mx.managers.PopUpManagerChildList;

    public class UIHelper
    {

        public static function checkBooleans(...args):Boolean
        {
            for each (var b:* in args)
            {
                if (b is Array || b is ArrayCollection)
                {
                    for each (var c:* in b)
                    {
                        // allow for nested arrays
                        checkBooleans(c);
                    }
                }
                else
                {
                    if (!b)
                        return false;
                }
            }
            return true;
        }

        public static function checkOneOf(...args):Boolean
        {
            for each (var b:* in args)
            {
                if (b)
                    return true;
            }
            return false;
        }

        public static function formattedDate(unixTimestamp:Number):String
        {
            if (isNaN(unixTimestamp))
                return "";

            var date:Date = new Date(unixTimestamp * 1000);
            /*
             * Note that we add 1 to month b/c January is 0 in Flex
             */
            return padLeft(date.getMonth() +1) + "/" + padLeft(date.getDate()) +
                "/" + padLeft(date.getFullYear()) + " " + padLeft(date.getHours()) +
                ":" + padLeft(date.getMinutes()) + ":" + padLeft(date.getSeconds());
        }

        private static function padLeft(number:Number):String
        {
            var strNum:String = number.toString();
            if (number.toString().length == 1)
                strNum = "0" + strNum;

            return strNum;
        }

        /**
         * Replace \r\n with \n, replace \r with \n
         */
        public static function processCarriageReturns(value:String):String
        {
            if (!value)
                return value;

            var cr:String = String.fromCharCode(13);
            var crRegex:RegExp = new RegExp(cr, "gm");

            var crnl:String = String.fromCharCode(13, 10);
            var crnlRegex:RegExp = new RegExp(crnl, "gm");

            // process CRNL first
            value = value.replace(crnlRegex, '\n');

            // process CR
            value = value.replace(crRegex, '\n');

            return value;
        }

        private static var popupModelMap:Dictionary = new Dictionary(true);
        private static var popupOwnerMap:Dictionary = new Dictionary(true);

        public static function createPopup(clazz:Class):*
        {
            var popup:Object = PopUpManager.createPopUp(FlexGlobals.topLevelApplication as Application,
                clazz, false, PopUpManagerChildList.APPLICATION) as clazz;
            return popup as IFlexDisplayObject;
        }

        public static function createSingletonPopupForModel(clazz:Class, model:Object, owner:Object=null):*
        {
            var popup:Object;

            popup = popupForModel(model);
            if (popup == null)
            {
                popup = PopUpManager.createPopUp(FlexGlobals.topLevelApplication as Application,
                    clazz, false, PopUpManagerChildList.APPLICATION) as clazz;

                popupModelMap[model] = popup;

                if (owner)
                {
                    popupOwnerMap[popup] = owner;
                }
            }

            return popup as IFlexDisplayObject;
        }

        public static function popupForModel(model:Object):*
        {
            return popupModelMap[model];
        }

        public static function removePopupForModel(model:Object):void
        {
            var popup:IFlexDisplayObject = popupModelMap[model];
            if (popup)
            {
                delete popupModelMap[model];
                delete popupOwnerMap[popup];
            }

        }

        public static function removePopupsForOwner(owner:Object):void
        {
            for (var popup:* in popupOwnerMap)
            {
                if (popupOwnerMap[popup] === owner)
                {
                    delete popupOwnerMap[popup];
                    // scan the model map too
                    for (var model:* in popupModelMap)
                    {
                        if (popupModelMap[model] === popup)
                        {
                            delete popupModelMap[model];
                        }
                    }
                }
            }
        }

        public static function popupsForOwner(owner:Object):Array
        {
            var result:Array = [];
            for (var popup:* in popupOwnerMap)
            {
                if (popupOwnerMap[popup] === owner)
                {
                    result.push(popup);
                }
            }

            return result;
        }

        public static function closePopupsForOwner(owner:Object):void
        {
            for each (var popup:* in UIHelper.popupsForOwner(owner))
            {
                PopUpManager.removePopUp(popup);
            }

            removePopupsForOwner(owner);
        }

        // make bytes human readable
        public static function humanReadableSize(bytes:int, precision:int=1):String
        {
            var s:String = bytes + ' bytes';

            var nf:NumberFormatter = new NumberFormatter();
            nf.precision = precision;
            nf.useThousandsSeparator = true;
            nf.useNegativeSign = true;
            nf.rounding = NumberBaseRoundType.NEAREST;

            if (bytes > 1073741824)
            {
                s = nf.format((bytes / 1073741824.0)) + ' GB' + ' (' + (s) + ')';
            }
            else if (bytes > 1048576)
            {
                s = nf.format((bytes / 1048576.0)) + ' MB' + ' (' + (s) + ')';
            }
            else if (bytes > 1024)
            {
                s = nf.format((bytes / 1024.0)) + ' KB' + ' (' + (s) + ')';
            }

            return s;
        }
    }
}

/*
#
# Copyright (c) 2005-2009 rPath, Inc.
#
# All rights reserved
#
*/

/*
#
# Copyright (c) 2009 rPath, Inc.
#
# This program is distributed under the terms of the MIT License as found
# in a file called LICENSE. If it is not present, the license
# is always available at http://www.opensource.org/licenses/mit-license.php.
#
# This program is distributed in the hope that it will be useful, but
# without any waranty; without even the implied warranty of merchantability
# or fitness for a particular purpose. See the MIT License for full details.
*/

package com.rpath.raf.util
{
    import flash.utils.Dictionary;

    import mx.collections.ArrayCollection;
    import spark.components.Application;
    import mx.core.FlexGlobals;
    import mx.core.IFlexDisplayObject;
    import mx.formatters.NumberBaseRoundType;
    import mx.formatters.NumberFormatter;
    import mx.managers.PopUpManager;
    import mx.managers.PopUpManagerChildList;

    public class UIHelper
    {

        public static function checkBooleans(...args):Boolean
        {
            for each (var b:* in args)
            {
                if (b is Array || b is ArrayCollection)
                {
                    for each (var c:* in b)
                    {
                        // allow for nested arrays
                        checkBooleans(c);
                    }
                }
                else
                {
                    if (!b)
                        return false;
                }
            }
            return true;
        }

        public static function checkOneOf(...args):Boolean
        {
            for each (var b:* in args)
            {
                if (b)
                    return true;
            }
            return false;
        }

        public static function formattedDate(unixTimestamp:Number):String
        {
            if (isNaN(unixTimestamp))
                return "";

            var date:Date = new Date(unixTimestamp * 1000);
            /*
             * Note that we add 1 to month b/c January is 0 in Flex
             */
            return padLeft(date.getMonth() +1) + "/" + padLeft(date.getDate()) +
                "/" + padLeft(date.getFullYear()) + " " + padLeft(date.getHours()) +
                ":" + padLeft(date.getMinutes()) + ":" + padLeft(date.getSeconds());
        }

        private static function padLeft(number:Number):String
        {
            var strNum:String = number.toString();
            if (number.toString().length == 1)
                strNum = "0" + strNum;

            return strNum;
        }

        /**
         * Replace \r\n with \n, replace \r with \n
         */
        public static function processCarriageReturns(value:String):String
        {
            if (!value)
                return value;

            var cr:String = String.fromCharCode(13);
            var crRegex:RegExp = new RegExp(cr, "gm");

            var crnl:String = String.fromCharCode(13, 10);
            var crnlRegex:RegExp = new RegExp(crnl, "gm");

            // process CRNL first
            value = value.replace(crnlRegex, '\n');

            // process CR
            value = value.replace(crRegex, '\n');

            return value;
        }

        private static var popupModelMap:Dictionary = new Dictionary(true);
        private static var popupOwnerMap:Dictionary = new Dictionary(true);

        public static function createPopup(clazz:Class):*
        {
            var popup:Object = PopUpManager.createPopUp(FlexGlobals.topLevelApplication as Application,
                clazz, false, PopUpManagerChildList.APPLICATION) as clazz;
            return popup as IFlexDisplayObject;
        }

        public static function createSingletonPopupForModel(clazz:Class, model:Object, owner:Object=null):*
        {
            var popup:Object;

            popup = popupForModel(model);
            if (popup == null)
            {
                popup = PopUpManager.createPopUp(FlexGlobals.topLevelApplication as Application,
                    clazz, false, PopUpManagerChildList.APPLICATION) as clazz;

                popupModelMap[model] = popup;

                if (owner)
                {
                    popupOwnerMap[popup] = owner;
                }
            }

            return popup as IFlexDisplayObject;
        }

        public static function popupForModel(model:Object):*
        {
            return popupModelMap[model];
        }

        public static function removePopupForModel(model:Object):void
        {
            var popup:IFlexDisplayObject = popupModelMap[model];
            if (popup)
            {
                delete popupModelMap[model];
                delete popupOwnerMap[popup];
            }

        }

        public static function removePopupsForOwner(owner:Object):void
        {
            for (var popup:* in popupOwnerMap)
            {
                if (popupOwnerMap[popup] === owner)
                {
                    delete popupOwnerMap[popup];
                    // scan the model map too
                    for (var model:* in popupModelMap)
                    {
                        if (popupModelMap[model] === popup)
                        {
                            delete popupModelMap[model];
                        }
                    }
                }
            }
        }

        public static function popupsForOwner(owner:Object):Array
        {
            var result:Array = [];
            for (var popup:* in popupOwnerMap)
            {
                if (popupOwnerMap[popup] === owner)
                {
                    result.push(popup);
                }
            }

            return result;
        }

        public static function closePopupsForOwner(owner:Object):void
        {
            for each (var popup:* in UIHelper.popupsForOwner(owner))
            {
                PopUpManager.removePopUp(popup);
            }

            removePopupsForOwner(owner);
        }

        // make bytes human readable
        public static function humanReadableSize(bytes:int, precision:int=1):String
        {
            var s:String = bytes + ' bytes';

            var nf:NumberFormatter = new NumberFormatter();
            nf.precision = precision;
            nf.useThousandsSeparator = true;
            nf.useNegativeSign = true;
            nf.rounding = NumberBaseRoundType.NEAREST;

            if (bytes > 1073741824)
            {
                s = nf.format((bytes / 1073741824.0)) + ' GB' + ' (' + (s) + ')';
            }
            else if (bytes > 1048576)
            {
                s = nf.format((bytes / 1048576.0)) + ' MB' + ' (' + (s) + ')';
            }
            else if (bytes > 1024)
            {
                s = nf.format((bytes / 1024.0)) + ' KB' + ' (' + (s) + ')';
            }

            return s;
        }
    }
}

replace mx Application import with spark one


package stdio {
  internal class StreamBuffer implements InputStream, OutputStream {
    public var buffer: String = ""
    public var closed: Boolean = false

    public function puts(value: Object): void {
      write(value + "\n")
    }

    public function write(value: Object): void {
      buffer += value.toString()
      satisfy_read_requests()
    }

    public function close(): void {
      closed = true
      satisfy_read_requests()
    }

    // -----------------------------------------------------

    private const requests: Array = []

    private function satisfy_read_requests(): void {
      while (has_requests && next_request.ready) {
        next_request.satisfy()
        requests.shift()
      }
    }

    private function get has_requests(): Boolean {
      return requests.length > 0
    }

    private function get next_request(): ReadRequest {
      return requests[0]
    }

    // -----------------------------------------------------

    public function gets(callback: Function): void {
      add_read_request(new ReadLineRequest(this, callback))
    }

    public function read(callback: Function): void {
      add_read_request(new ReadChunkRequest(this, callback))
    }

    private function add_read_request(request: ReadRequest): void {
      requests.push(request)
      satisfy_read_requests()
    }

    public function get emptied(): Boolean {
      return closed && !buffer.length
    }

    public function get ready(): Boolean {
      return new ReadChunkRequest(this, null).ready
    }
  }
}

package stdio {
  internal class StreamBuffer implements InputStream, OutputStream {
    public var buffer: String = ""
    public var closed: Boolean = false

    public function puts(value: Object): void {
      write(value + "\n")
    }

    public function write(value: Object): void {
      buffer += value.toString()
      satisfy_read_requests()
    }

    public function close(): void {
      closed = true
      satisfy_read_requests()
    }

    // -----------------------------------------------------

    private const requests: Array = []

    private function satisfy_read_requests(): void {
      while (requests.length > 0 && requests[0].ready) {
        // Note: `shift()` must run before `satisfy()`.
        requests.shift().satisfy()
      }
    }

    // -----------------------------------------------------

    public function gets(callback: Function): void {
      add_read_request(new ReadLineRequest(this, callback))
    }

    public function read(callback: Function): void {
      add_read_request(new ReadChunkRequest(this, callback))
    }

    private function add_read_request(request: ReadRequest): void {
      requests.push(request)
      satisfy_read_requests()
    }

    public function get emptied(): Boolean {
      return closed && !buffer.length
    }

    public function get ready(): Boolean {
      return new ReadChunkRequest(this, null).ready
    }
  }
}

Fix subtle side-effect-related bug.

Fix subtle side-effect-related bug.


package widgets.supportClasses
{

import com.esri.ags.FeatureSet;
import com.esri.ags.Graphic;
import com.esri.ags.layers.FeatureLayer;
import com.esri.ags.layers.supportClasses.CodedValue;
import com.esri.ags.layers.supportClasses.CodedValueDomain;
import com.esri.ags.layers.supportClasses.FeatureType;
import com.esri.ags.layers.supportClasses.Field;
import com.esri.ags.layers.supportClasses.LayerDetails;

import mx.formatters.DateFormatter;

[Bindable]
public class ResultAttributes
{
    public var attributes:Object;
    public var title:String;
    public var content:String;
    public var link:String;
    public var linkAlias:String;

    public static function toResultAttributes(fields:XMLList,
                                              textDirection:String = null,
                                              graphic:Graphic = null,
                                              featureSet:FeatureSet = null,
                                              layer:FeatureLayer = null,
                                              layerDetails:LayerDetails = null,
                                              widgetTitle:String = null,
                                              titleField:String = null,
                                              linkField:String = null,
                                              linkAlias:String = null):ResultAttributes
    {
        var resultAttributes:ResultAttributes = new ResultAttributes;

        var value:String = "";
        var title:String = "";
        var content:String = "";
        var link:String = "";
        var linkAlias:String;

        var fieldsXMLList:XMLList = fields ? fields.field : null;
        if (fields && fields[0].@all[0] == "true")
        {
            if (layerDetails.fields)
            {
                for each (var field:Field in layerDetails.fields)
                {
                    if (field.name in graphic.attributes)
                    {
                        displayFields(field.name, getFieldXML(field.name, fieldsXMLList), field);
                    }
                }
            }
            else
            {
                for (var fieldName:String in graphic.attributes)
                {
                    displayFields(fieldName, getFieldXML(fieldName, fieldsXMLList), null);
                }
            }
        }
        else
        {
            for each (var fieldXML:XML in fieldsXMLList) // display the fields in the same order as specified
            {
                if (fieldXML.@name[0] in graphic.attributes)
                {
                    displayFields(fieldXML.@name[0], fieldXML, getField(layer, fieldXML.@name[0]));
                }
            }
        }
        resultAttributes.attributes = graphic.attributes;
        resultAttributes.title = title ? title : widgetTitle;
        resultAttributes.content = content;
        resultAttributes.link = link ? link : null;
        resultAttributes.linkAlias = linkAlias;

        function displayFields(fieldName:String, fieldXML:XML, field:Field):void
        {
            var fieldNameTextValue:String = graphic.attributes[fieldName];
            value = fieldNameTextValue ? fieldNameTextValue : "";

            if (value)
            {
                var isDateField:Boolean;
                var useUTC:Boolean;
                var dateFormat:String;
                if (fieldXML)
                {
                    useUTC = fieldXML.format.@useutc[0] || fieldXML.@useutc[0] == "true";
                    dateFormat = fieldXML.format.@dateformat[0] || fieldXML.@dateformat[0];
                    if (dateFormat)
                    {
                        isDateField = true;
                    }
                }
                if (!isDateField && field)
                {
                    isDateField = field.type == Field.TYPE_DATE;
                }
                if (isDateField)
                {
                    var dateMS:Number = Number(value);
                    if (!isNaN(dateMS))
                    {
                        value = msToDate(dateMS, dateFormat, useUTC);
                    }
                }
                else
                {
                    var typeID:String = layerDetails.typeIdField ? graphic.attributes[layerDetails.typeIdField] : null;
                    if (fieldName == layerDetails.typeIdField)
                    {
                        var featureType:FeatureType = getFeatureType(layer, typeID);
                        if (featureType && featureType.name)
                        {
                            value = featureType.name;
                        }
                    }
                    else
                    {
                        var codedValue:CodedValue = getCodedValue(layer, fieldName, value, typeID);
                        if (codedValue)
                        {
                            value = codedValue.name;
                        }
                    }
                }
            }

            if (titleField && fieldName.toUpperCase() == titleField.toUpperCase())
            {
                title = value;
            }
            else if (linkField && fieldName.toUpperCase() == linkField.toUpperCase())
            {
                link = value;
                linkAlias = linkAlias;
            }
            else if (fieldName.toUpperCase() != "SHAPE_LENGTH" && fieldName.toUpperCase() != "SHAPE_AREA")
            {
                var fieldLabel:String;

                if (fieldXML && fieldXML.@alias[0])
                {
                    fieldLabel = fieldXML.@alias[0];
                }
                else
                {
                    fieldLabel = featureSet.fieldAliases[fieldName];
                }

                if (textDirection && textDirection == "rtl")
                {
                    content += value + " :" + fieldLabel + "\n";
                }
                else
                {
                    content += fieldLabel + ": " + value + "\n";
                }
            }
        }

        return resultAttributes;
    }

    private static function getFieldXML(fieldName:String, fields:XMLList):XML
    {
        var result:XML;

        for each (var fieldXML:XML in fields)
        {
            if (fieldName == fieldXML.@name[0])
            {
                result = fieldXML;
                break;
            }
        }

        return result;
    }

    private static function getField(layer:FeatureLayer, fieldName:String):Field
    {
        var result:Field;

        if (layer)
        {
            for each (var field:Field in layer.layerDetails.fields)
            {
                if (fieldName == field.name)
                {
                    result = field;
                    break;
                }
            }
        }

        return result;
    }

    private static function getFeatureType(layer:FeatureLayer, typeID:String):FeatureType
    {
        var result:FeatureType;

        if (layer)
        {
            for each (var featureType:FeatureType in layer.layerDetails.types)
            {
                if (typeID == featureType.id)
                {
                    result = featureType;
                    break;
                }
            }
        }

        return result;
    }

    private static function msToDate(ms:Number, dateFormat:String, useUTC:Boolean):String
    {
        var date:Date = new Date(ms);
        if (date.milliseconds == 999) // workaround for REST bug
        {
            date.milliseconds++;
        }
        if (useUTC)
        {
            date.minutes += date.timezoneOffset;
        }

        if (dateFormat)
        {
            var dateFormatter:DateFormatter = new DateFormatter();
            dateFormatter.formatString = dateFormat;
            var result:String = dateFormatter.format(date);
            if (result)
            {
                return result;
            }
            else
            {
                return dateFormatter.error;
            }
        }
        else
        {
            return date.toLocaleString();
        }
    }

    private static function getCodedValue(layer:FeatureLayer, fieldName:String, fieldValue:String, typeID:String):CodedValue
    {
        var result:CodedValue;

        var codedValueDomain:CodedValueDomain;
        if (typeID)
        {
            var featureType:FeatureType = getFeatureType(layer, typeID);
            if (featureType)
            {
                codedValueDomain = featureType.domains[fieldName] as CodedValueDomain;
            }
        }
        else
        {
            var field:Field = getField(layer, fieldName);
            if (field)
            {
                codedValueDomain = field.domain as CodedValueDomain;
            }
        }

        if (codedValueDomain)
        {
            for each (var codedValue:CodedValue in codedValueDomain.codedValues)
            {
                if (fieldValue == codedValue.code)
                {
                    result = codedValue;
                    break;
                }
            }
        }

        return result;
    }
}

}

package widgets.supportClasses
{

import com.esri.ags.FeatureSet;
import com.esri.ags.Graphic;
import com.esri.ags.layers.FeatureLayer;
import com.esri.ags.layers.supportClasses.CodedValue;
import com.esri.ags.layers.supportClasses.CodedValueDomain;
import com.esri.ags.layers.supportClasses.FeatureType;
import com.esri.ags.layers.supportClasses.Field;
import com.esri.ags.layers.supportClasses.LayerDetails;

import mx.formatters.DateFormatter;

[Bindable]
public class ResultAttributes
{
    public var attributes:Object;
    public var title:String;
    public var content:String;
    public var link:String;
    public var linkAlias:String;

    public static function toResultAttributes(fields:XMLList,
                                              textDirection:String = null,
                                              graphic:Graphic = null,
                                              featureSet:FeatureSet = null,
                                              layer:FeatureLayer = null,
                                              layerDetails:LayerDetails = null,
                                              fallbackTitle:String = null,
                                              titleField:String = null,
                                              linkField:String = null,
                                              linkAlias:String = null):ResultAttributes
    {
        var resultAttributes:ResultAttributes = new ResultAttributes;

        var value:String = "";
        var title:String = "";
        var content:String = "";
        var link:String = "";
        var linkAlias:String;

        var fieldsXMLList:XMLList = fields ? fields.field : null;
        if (fields && fields[0].@all[0] == "true")
        {
            if (layerDetails.fields)
            {
                for each (var field:Field in layerDetails.fields)
                {
                    if (field.name in graphic.attributes)
                    {
                        displayFields(field.name, getFieldXML(field.name, fieldsXMLList), field);
                    }
                }
            }
            else
            {
                for (var fieldName:String in graphic.attributes)
                {
                    displayFields(fieldName, getFieldXML(fieldName, fieldsXMLList), null);
                }
            }
        }
        else
        {
            for each (var fieldXML:XML in fieldsXMLList) // display the fields in the same order as specified
            {
                if (fieldXML.@name[0] in graphic.attributes)
                {
                    displayFields(fieldXML.@name[0], fieldXML, getField(layer, fieldXML.@name[0]));
                }
            }
        }

        resultAttributes.attributes = graphic.attributes;
        resultAttributes.title = title ? title : fallbackTitle;
        resultAttributes.content = content;
        resultAttributes.link = link ? link : null;
        resultAttributes.linkAlias = linkAlias;

        function displayFields(fieldName:String, fieldXML:XML, field:Field):void
        {
            var fieldNameTextValue:String = graphic.attributes[fieldName];
            value = fieldNameTextValue ? fieldNameTextValue : "";

            if (value)
            {
                var isDateField:Boolean;
                var useUTC:Boolean;
                var dateFormat:String;
                if (fieldXML)
                {
                    useUTC = fieldXML.format.@useutc[0] || fieldXML.@useutc[0] == "true";
                    dateFormat = fieldXML.format.@dateformat[0] || fieldXML.@dateformat[0];
                    if (dateFormat)
                    {
                        isDateField = true;
                    }
                }
                if (!isDateField && field)
                {
                    isDateField = field.type == Field.TYPE_DATE;
                }
                if (isDateField)
                {
                    var dateMS:Number = Number(value);
                    if (!isNaN(dateMS))
                    {
                        value = msToDate(dateMS, dateFormat, useUTC);
                    }
                }
                else
                {
                    var typeID:String = layerDetails.typeIdField ? graphic.attributes[layerDetails.typeIdField] : null;
                    if (fieldName == layerDetails.typeIdField)
                    {
                        var featureType:FeatureType = getFeatureType(layer, typeID);
                        if (featureType && featureType.name)
                        {
                            value = featureType.name;
                        }
                    }
                    else
                    {
                        var codedValue:CodedValue = getCodedValue(layer, fieldName, value, typeID);
                        if (codedValue)
                        {
                            value = codedValue.name;
                        }
                    }
                }
            }

            if (titleField && fieldName.toUpperCase() == titleField.toUpperCase())
            {
                title = value;
            }
            else if (linkField && fieldName.toUpperCase() == linkField.toUpperCase())
            {
                link = value;
                linkAlias = linkAlias;
            }
            else if (fieldName.toUpperCase() != "SHAPE_LENGTH" && fieldName.toUpperCase() != "SHAPE_AREA")
            {
                var fieldLabel:String;

                if (fieldXML && fieldXML.@alias[0])
                {
                    fieldLabel = fieldXML.@alias[0];
                }
                else
                {
                    fieldLabel = featureSet.fieldAliases[fieldName];
                }

                if (textDirection && textDirection == "rtl")
                {
                    content += value + " :" + fieldLabel + "\n";
                }
                else
                {
                    content += fieldLabel + ": " + value + "\n";
                }
            }
        }

        return resultAttributes;
    }

    private static function getFieldXML(fieldName:String, fields:XMLList):XML
    {
        var result:XML;

        for each (var fieldXML:XML in fields)
        {
            if (fieldName == fieldXML.@name[0])
            {
                result = fieldXML;
                break;
            }
        }

        return result;
    }

    private static function getField(layer:FeatureLayer, fieldName:String):Field
    {
        var result:Field;

        if (layer)
        {
            for each (var field:Field in layer.layerDetails.fields)
            {
                if (fieldName == field.name)
                {
                    result = field;
                    break;
                }
            }
        }

        return result;
    }

    private static function getFeatureType(layer:FeatureLayer, typeID:String):FeatureType
    {
        var result:FeatureType;

        if (layer)
        {
            for each (var featureType:FeatureType in layer.layerDetails.types)
            {
                if (typeID == featureType.id)
                {
                    result = featureType;
                    break;
                }
            }
        }

        return result;
    }

    private static function msToDate(ms:Number, dateFormat:String, useUTC:Boolean):String
    {
        var date:Date = new Date(ms);
        if (date.milliseconds == 999) // workaround for REST bug
        {
            date.milliseconds++;
        }
        if (useUTC)
        {
            date.minutes += date.timezoneOffset;
        }

        if (dateFormat)
        {
            var dateFormatter:DateFormatter = new DateFormatter();
            dateFormatter.formatString = dateFormat;
            var result:String = dateFormatter.format(date);
            if (result)
            {
                return result;
            }
            else
            {
                return dateFormatter.error;
            }
        }
        else
        {
            return date.toLocaleString();
        }
    }

    private static function getCodedValue(layer:FeatureLayer, fieldName:String, fieldValue:String, typeID:String):CodedValue
    {
        var result:CodedValue;

        var codedValueDomain:CodedValueDomain;
        if (typeID)
        {
            var featureType:FeatureType = getFeatureType(layer, typeID);
            if (featureType)
            {
                codedValueDomain = featureType.domains[fieldName] as CodedValueDomain;
            }
        }
        else
        {
            var field:Field = getField(layer, fieldName);
            if (field)
            {
                codedValueDomain = field.domain as CodedValueDomain;
            }
        }

        if (codedValueDomain)
        {
            for each (var codedValue:CodedValue in codedValueDomain.codedValues)
            {
                if (fieldValue == codedValue.code)
                {
                    result = codedValue;
                    break;
                }
            }
        }

        return result;
    }
}

}

Rename default title argument name in ResultAttributes#toResultAttributes.


package dse{
	import com.hurlant.crypto.prng.Random;
	import com.hurlant.crypto.rsa.RSAKey;
	import com.hurlant.util.Hex;

	import flash.external.ExternalInterface;
	import flash.utils.ByteArray;
	public class KeyGenerator
	{
		public static function generateKeys():void{
			var exp:String = "10001";
			var rsa:RSAKey = RSAKey.generate(1024, exp);
			ExternalInterface.call("setvalue", "publickey", rsa.n.toString());
			ExternalInterface.call("setvalue", "d", rsa.d.toString());
			ExternalInterface.call("setvalue", "p", rsa.p.toString());
			ExternalInterface.call("setvalue", "q", rsa.q.toString());
			ExternalInterface.call("setvalue", "dmp", rsa.dmp1.toString());
			ExternalInterface.call("setvalue", "dmq", rsa.dmq1.toString());
			ExternalInterface.call("setvalue", "qinv", rsa.coeff.toString());
			var data:ByteArray, prehashedkey:ByteArray, hashedkey:ByteArray;

			var r:Random = new Random;
			var rankey:ByteArray = new ByteArray
			r.nextBytes(rankey, 32);
			ExternalInterface.call("setvalue", "rk", Hex.fromArray(rankey));
		}
	}
}

package dse{
	import com.hurlant.crypto.prng.Random;
	import com.hurlant.crypto.rsa.RSAKey;
	import com.hurlant.util.Hex;
	import com.hurlant.crypto.prng.TLSPRF;

	import flash.external.ExternalInterface;
	import flash.utils.ByteArray;
	public class KeyGenerator
	{
		public static function generateKeys():void{
			var exp:String = "10001";
			var rsa:RSAKey = RSAKey.generate(1024, exp);
			ExternalInterface.call("setvalue", "publickey", rsa.n.toString());
			ExternalInterface.call("setvalue", "d", rsa.d.toString());
			ExternalInterface.call("setvalue", "p", rsa.p.toString());
			ExternalInterface.call("setvalue", "q", rsa.q.toString());
			ExternalInterface.call("setvalue", "dmp", rsa.dmp1.toString());
			ExternalInterface.call("setvalue", "dmq", rsa.dmq1.toString());
			ExternalInterface.call("setvalue", "qinv", rsa.coeff.toString());
			var data:ByteArray, prehashedkey:ByteArray, hashedkey:ByteArray;

			var r:Random = new Random(TLSPRF);
			var rankey:ByteArray = new ByteArray;
			r.nextBytes(rankey, 32);
			ExternalInterface.call("setvalue", "rk", Hex.fromArray(rankey));
		}
	}
}

change random used for generating aes to TLS from ARC4


package aerys.minko.scene.controller.mesh
{
	import aerys.minko.ns.minko_math;
	import aerys.minko.render.geometry.Geometry;
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.node.Group;
	import aerys.minko.scene.node.ISceneNode;
	import aerys.minko.scene.node.Mesh;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.scene.node.camera.AbstractCamera;
	import aerys.minko.type.binding.DataBindings;
	import aerys.minko.type.binding.DataProvider;
	import aerys.minko.type.enum.FrustumCulling;
	import aerys.minko.type.math.BoundingBox;
	import aerys.minko.type.math.BoundingSphere;
	import aerys.minko.type.math.Matrix4x4;
	import aerys.minko.type.math.Vector4;

	/**
	 * The MeshVisibilityController watches the Mesh and the active Camera of a Scene
	 * to determine whether the object is actually inside the view frustum or not.
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public final class MeshVisibilityController extends AbstractController
	{
		use namespace minko_math;

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

		private static const STATE_UNDEFINED	: uint		= 0;
		private static const STATE_INSIDE		: uint		= 1;
		private static const STATE_OUTSIDE		: uint		= 2;

		private var _mesh			    : Mesh;
		private var _state			    : uint;
		private var _lastTest		    : int;
		private var _boundingBox	    : BoundingBox;
		private var _boundingSphere	    : BoundingSphere;

		private var _data				: DataProvider;

        private var _frustumCulling     : uint;
        private var _insideFrustum      : Boolean;
//        private var _data.computedVisibility : Boolean;

		public function get frustumCulling() : uint
		{
			return _frustumCulling;
		}
		public function set frustumCulling(value : uint) : void
		{
			_frustumCulling = value;
			if (_mesh && _mesh.root is Scene)
            	testCulling();
		}

		public function get insideFrustum() : Boolean
		{
			return _insideFrustum;
		}

        public function get computedVisibility() : Boolean
        {
            return _data.computedVisibility;
        }

		public function MeshVisibilityController()
		{
			super(Mesh);

			initialize();
		}

		private function initialize() : void
		{
			_data = new DataProvider();
			_data.setProperty('computedVisibility', false);

			_boundingBox = new BoundingBox(Vector4.ZERO, Vector4.ONE);
			_boundingSphere = new BoundingSphere(Vector4.ZERO, 0.);

            _state = STATE_UNDEFINED;

			targetAdded.add(targetAddedHandler);
			targetRemoved.add(targetRemovedHandler);
		}

		private function targetAddedHandler(ctrl	: MeshVisibilityController,
											target	: Mesh) : void
		{
			if (_mesh != null)
				throw new Error();

			_mesh = target;

			target.added.add(addedHandler);
			target.removed.add(removedHandler);

			if (target.root is Scene)
				addedHandler(target, target.root as Scene);

			if (_frustumCulling)
				testCulling();
		}

		private function targetRemovedHandler(ctrl		: MeshVisibilityController,
											  target	: Mesh) : void
		{
			_mesh = null;

			target.added.remove(addedHandler);
			target.removed.remove(removedHandler);

			if (target.root is Scene)
				removedHandler(target, target.root as Scene);
		}

		private function addedHandler(mesh : Mesh, ancestor : Group) : void
		{
			var scene : Scene = mesh.scene;

			if (!scene)
				return ;

			scene.bindings.addCallback('worldToScreen', worldToScreenChangedHandler);

            meshLocalToWorldChangedHandler(mesh, mesh.getLocalToWorldTransform());
			mesh.localToWorldTransformChanged.add(meshLocalToWorldChangedHandler);
            mesh.visibilityChanged.add(visiblityChangedHandler);
            mesh.parent.computedVisibilityChanged.add(visiblityChangedHandler);
            mesh.removed.add(meshRemovedHandler);
		}

        private function meshRemovedHandler(mesh : Mesh, ancestor : Group) : void
        {
            if (!mesh.parent)
                ancestor.computedVisibilityChanged.remove(visiblityChangedHandler);
        }

		private function removedHandler(mesh : Mesh, ancestor : Group) : void
		{
			var scene : Scene = ancestor.scene;

			if (!scene)
				return ;

			scene.bindings.removeCallback('worldToScreen', worldToScreenChangedHandler);

			mesh.localToWorldTransformChanged.remove(meshLocalToWorldChangedHandler);
            mesh.visibilityChanged.remove(visiblityChangedHandler);
            mesh.removed.remove(meshRemovedHandler);
			if (mesh.parent)
				mesh.parent.computedVisibilityChanged.remove(visiblityChangedHandler);
		}

        private function visiblityChangedHandler(node : ISceneNode, visibility : Boolean) : void
        {
			var computedVisibility : Boolean = _mesh.visible && _mesh.parent.computedVisibility
				&& (_frustumCulling == FrustumCulling.DISABLED || _insideFrustum);

			_data.computedVisibility = computedVisibility;
            _mesh.computedVisibilityChanged.execute(_mesh, computedVisibility);
        }

		private function worldToScreenChangedHandler(bindings	    : DataBindings,
                                                     propertyName	: String,
                                                     oldValue		: Matrix4x4,
                                                     newValue		: Matrix4x4) : void
		{
			testCulling();
		}

		private function meshLocalToWorldChangedHandler(mesh : Mesh, transform : Matrix4x4) : void
		{
			var geom 	: Geometry 	= _mesh.geometry;
			var culling	: uint		= _frustumCulling;

			if (!geom.boundingBox || !geom.boundingSphere || culling == FrustumCulling.DISABLED)
				return ;

			if (culling & FrustumCulling.BOX)
				transform.transformRawVectors(geom.boundingBox._vertices, _boundingBox._vertices);

			if (culling & FrustumCulling.SPHERE)
			{
				var center 	: Vector4 	= transform.transformVector(geom.boundingSphere.center);
				var scale 	: Vector4 	= transform.deltaTransformVector(Vector4.ONE);
				var radius	: Number	= geom.boundingSphere.radius * Math.max(
					Math.abs(scale.x), Math.abs(scale.y), Math.abs(scale.z)
				);

				_boundingSphere.update(center, radius);
			}

			testCulling();
		}

		private function testCulling() : void
		{
			var culling	: uint	= _frustumCulling;

			if (culling != FrustumCulling.DISABLED)
			{
				_data.computedVisibility = true;
				return;
			}

			if (_mesh && _mesh.geometry.boundingBox && _mesh.visible)
			{
				var camera : AbstractCamera = (_mesh.root as Scene).activeCamera;

				if (!camera)
					return ;

				_lastTest = camera.frustum.testBoundingVolume(
					_boundingSphere,
					_boundingBox,
					null,
					culling,
					_lastTest
				);

				var inside : Boolean = _lastTest == -1;

				if (inside && _state != STATE_INSIDE)
				{
					_insideFrustum = true;
                    _data.computedVisibility = _mesh.parent.computedVisibility && _mesh.visible;
                    _mesh.computedVisibilityChanged.execute(_mesh, computedVisibility);
					_state = STATE_INSIDE;
				}
				else if (!inside && _state != STATE_OUTSIDE)
				{
					_insideFrustum = false;
                    _data.computedVisibility = false;
                    _mesh.computedVisibilityChanged.execute(_mesh, false);
					_state = STATE_OUTSIDE;
				}
			}
		}

		override public function clone() : AbstractController
		{
			return new MeshVisibilityController();;
		}
	}
}

package aerys.minko.scene.controller.mesh
{
	import aerys.minko.ns.minko_math;
	import aerys.minko.render.geometry.Geometry;
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.node.Group;
	import aerys.minko.scene.node.ISceneNode;
	import aerys.minko.scene.node.Mesh;
	import aerys.minko.scene.node.Scene;
	import aerys.minko.scene.node.camera.AbstractCamera;
	import aerys.minko.type.binding.DataBindings;
	import aerys.minko.type.binding.DataProvider;
	import aerys.minko.type.enum.FrustumCulling;
	import aerys.minko.type.math.BoundingBox;
	import aerys.minko.type.math.BoundingSphere;
	import aerys.minko.type.math.Matrix4x4;
	import aerys.minko.type.math.Vector4;

	/**
	 * The MeshVisibilityController watches the Mesh and the active Camera of a Scene
	 * to determine whether the object is actually inside the view frustum or not.
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public final class MeshVisibilityController extends AbstractController
	{
		use namespace minko_math;

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

		private static const STATE_UNDEFINED	: uint		= 0;
		private static const STATE_INSIDE		: uint		= 1;
		private static const STATE_OUTSIDE		: uint		= 2;

		private var _mesh			    : Mesh;
		private var _state			    : uint;
		private var _lastTest		    : int;
		private var _boundingBox	    : BoundingBox;
		private var _boundingSphere	    : BoundingSphere;

		private var _data				: DataProvider;

        private var _frustumCulling     : uint;
        private var _insideFrustum      : Boolean;

		public function get frustumCulling() : uint
		{
			return _frustumCulling;
		}
		public function set frustumCulling(value : uint) : void
		{
			_frustumCulling = value;
			if (_mesh && _mesh.root is Scene)
            	testCulling();
		}

		public function get insideFrustum() : Boolean
		{
			return _insideFrustum;
		}

        public function get computedVisibility() : Boolean
        {
            return _data.computedVisibility;
        }

		public function MeshVisibilityController()
		{
			super(Mesh);

			initialize();
		}

		private function initialize() : void
		{
			_data = new DataProvider();
			_data.setProperty('computedVisibility', false);

			_boundingBox = new BoundingBox(Vector4.ZERO, Vector4.ONE);
			_boundingSphere = new BoundingSphere(Vector4.ZERO, 0.);

            _state = STATE_UNDEFINED;

			targetAdded.add(targetAddedHandler);
			targetRemoved.add(targetRemovedHandler);
		}

		private function targetAddedHandler(ctrl	: MeshVisibilityController,
											target	: Mesh) : void
		{
			if (_mesh != null)
				throw new Error();

			_mesh = target;

			target.added.add(addedHandler);
			target.removed.add(removedHandler);

			if (target.root is Scene)
				addedHandler(target, target.root as Scene);

			if (_frustumCulling)
				testCulling();
		}

		private function targetRemovedHandler(ctrl		: MeshVisibilityController,
											  target	: Mesh) : void
		{
			_mesh = null;

			target.added.remove(addedHandler);
			target.removed.remove(removedHandler);

			if (target.root is Scene)
				removedHandler(target, target.root as Scene);
		}

		private function addedHandler(mesh : Mesh, ancestor : Group) : void
		{
			var scene : Scene = mesh.scene;

			if (!scene)
				return ;

			scene.bindings.addCallback('worldToScreen', worldToScreenChangedHandler);

            meshLocalToWorldChangedHandler(mesh, mesh.getLocalToWorldTransform());
			mesh.localToWorldTransformChanged.add(meshLocalToWorldChangedHandler);
            mesh.computedVisibilityChanged.add(computedVisiblityChangedHandler);
            mesh.bindings.addProvider(_data);
		}

		private function removedHandler(mesh : Mesh, ancestor : Group) : void
		{
			var scene : Scene = ancestor.scene;

			if (!scene)
				return ;

			scene.bindings.removeCallback('worldToScreen', worldToScreenChangedHandler);

			mesh.localToWorldTransformChanged.remove(meshLocalToWorldChangedHandler);
            mesh.computedVisibilityChanged.remove(computedVisiblityChangedHandler);
            mesh.bindings.removeProvider(_data);
		}

        private function computedVisiblityChangedHandler(node               : ISceneNode,
                                                         computedVisibility : Boolean) : void
        {
            _data.computedVisibility = computedVisibility;
        }

		private function worldToScreenChangedHandler(bindings	    : DataBindings,
                                                     propertyName	: String,
                                                     oldValue		: Matrix4x4,
                                                     newValue		: Matrix4x4) : void
		{
			testCulling();
		}

		private function meshLocalToWorldChangedHandler(mesh : Mesh, transform : Matrix4x4) : void
		{
			var geom 	: Geometry 	= _mesh.geometry;
			var culling	: uint		= _frustumCulling;

			if (!geom.boundingBox || !geom.boundingSphere || culling == FrustumCulling.DISABLED)
				return ;

			if (culling & FrustumCulling.BOX)
				transform.transformRawVectors(geom.boundingBox._vertices, _boundingBox._vertices);

			if (culling & FrustumCulling.SPHERE)
			{
				var center 	: Vector4 	= transform.transformVector(geom.boundingSphere.center);
				var scale 	: Vector4 	= transform.deltaTransformVector(Vector4.ONE);
				var radius	: Number	= geom.boundingSphere.radius * Math.max(
					Math.abs(scale.x), Math.abs(scale.y), Math.abs(scale.z)
				);

				_boundingSphere.update(center, radius);
			}

			testCulling();
		}

		private function testCulling() : void
		{
			var culling	: uint	= _frustumCulling;

			if (culling != FrustumCulling.DISABLED)
			{
				_data.computedVisibility = true;
				return;
			}

			if (_mesh && _mesh.geometry.boundingBox && _mesh.visible)
			{
				var camera : AbstractCamera = (_mesh.root as Scene).activeCamera;

				if (!camera)
					return ;

				_lastTest = camera.frustum.testBoundingVolume(
					_boundingSphere,
					_boundingBox,
					null,
					culling,
					_lastTest
				);

				var inside : Boolean = _lastTest == -1;

				if (inside && _state != STATE_INSIDE)
				{
					_insideFrustum = true;
                    _data.computedVisibility = _mesh.parent.computedVisibility && _mesh.visible;
                    _mesh.computedVisibilityChanged.execute(_mesh, computedVisibility);
					_state = STATE_INSIDE;
				}
				else if (!inside && _state != STATE_OUTSIDE)
				{
					_insideFrustum = false;
                    _data.computedVisibility = false;
                    _mesh.computedVisibilityChanged.execute(_mesh, false);
					_state = STATE_OUTSIDE;
				}
			}
		}

		override public function clone() : AbstractController
		{
			return new MeshVisibilityController();
		}
	}
}

fix MeshVisiblityController to make sure it adds its data provider to the mesh bindings when its added to the scene


/*
 * Copyright 2008 Adobe Systems Inc., 2008 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Contributor(s):
 *   Zwetan Kjukov <zwetan@gmail.com>.
 *   Marc Alcaraz <ekameleon@gmail.com>.
 */

package com.google.analytics.core
{

    /**
     * The domain name mode enumeration class.
     */
    public class DomainNameMode
    {
        /**
         * @private
         */
        private var _value:int;

        /**
         * @private
         */
        private var _name:String;

        /**
         * Creates a new DomainNameMode instance.
         * @param value The enumeration value representation.
         * @param name The enumeration name representation.
         */
        public function DomainNameMode( value:int = 0, name:String = "" )
        {
            _value = value;
            _name  = name;
        }

        /**
         * Returns the primitive value of the object.
         * @return the primitive value of the object.
         */
        public function valueOf():int
        {
            return _value;
        }

        /**
         * Returns the String representation of the object.
         * @return the String representation of the object.
         */
        public function toString():String
        {
            return _name;
        }

        /**
         * Determinates the "none" DomainNameMode value.
         *
"none" is used in the following two situations :

         *
- You want to disable tracking across hosts.

         *
- You want to set up tracking across two separate domains.

         *
Cross- domain tracking requires configuration of the setAllowLinker() and link() methods.

         */
        public static const none:DomainNameMode    = new DomainNameMode( 0, "none" );

        /**
         * Attempts to automaticaly resolve the domain name.
         */
        public static const auto:DomainNameMode    = new DomainNameMode( 1, "auto" );

        /**
         * Custom is used to set explicitly to your domain name if your website spans multiple hostnames,
         * and you want to track visitor behavior across all hosts.
         *
For example, if you have two hosts : server1.example.com and server2.example.com,
         * you would set the domain name as follows :
         *

         * pageTracker.setDomainName( new Domain( DomainName.custom, ".example.com" ) ) ;
         *

         */
        public static const custom:DomainNameMode  = new DomainNameMode( 2, "custom" );

    }
}

fix asdoc comment again

fix asdoc comment again


package krewfw.builtin_actor.system {

    import krewfw.core.KrewActor;

    /**
     * Base class for event-driven command player.
     */
    //------------------------------------------------------------
    public class KrewScenarioPlayer extends KrewActor {

        // You can customize object keys.
        public var TRIGGER_KEY    :String = "trigger_key";
        public var TRIGGER_PARAMS :String = "trigger_params";
        public var METHOD         :String = "method";
        public var PARAMS         :String = "params";
        public var NEXT           :String = "next";

        private var _eventList:Array;
        private var _eventsByTrigger:Object;

        private var _triggers:Object = {};
        private var _methods:Object  = {};

        //------------------------------------------------------------
        public function KrewScenarioPlayer() {
            displayable = false;
        }

        protected override function onDispose():void {
            _eventList       = null;
            _eventsByTrigger = null;
            _triggers        = null;
            _methods         = null;
        }

        //------------------------------------------------------------
        // public
        //------------------------------------------------------------

        /**
         * @params eventList Example:
         *

         * [
         *     {
         *         "trigger_key" : "start_turn",
         *         "trigger_params": {"turn": 1},
         *         "method": "dialog",
         *         "params": {
         *             "messages": [ ... ]
         *         },
         *         "next": [
         *             {
         *                 "method": "overlay",
         *                 "params": { ... }
         *             }
         *         ]
         *     },
         *     ...
         * ]
         *

         */
        public function setData(eventList:Array):void {
            _eventList = eventList;

            _eventsByTrigger = {};
            for each (var eventData:Object in _eventList) {
                var triggerKey:String = eventData[TRIGGER_KEY];
                if (!triggerKey) { continue; }

                if (!_eventsByTrigger[triggerKey]) {
                    _eventsByTrigger[triggerKey] = [];
                }
                _eventsByTrigger[triggerKey].push(eventData);
            }
        }

        /**
         * @param checker Schema: function(eventArgs;Object, triggerParams:Object):Boolean
         */
        public function addTrigger(triggerKey:String, eventName:String, checker:Function):void {
            _triggers[triggerKey] = new TriggerInfo(eventName, checker);
        }

        /**
         * @param triggerInfoList Example:
         *

         * [
         *     ["triggerKey", "eventName", checkerFunc],
         *     ...
         * ]
         *

         */
        public function addTriggers(triggerInfoList:Array):void {
            for each (var info:Array in triggerInfoList) {
                addTrigger(info[0], info[1], info[2]);
            }
        }

        /**
         * @param handler Schema: function(params:Object, onComplete:Function):void
         */
        public function addMethod(methodName:String, handler:Function):void {
            _methods[methodName] = handler;
        }

        /**
         * @param triggerInfoList Example:
         *

         * [
         *     ["methodName", methodFunc],
         *     ...
         * ]
         *

         */
        public function addMethods(methodList:Array):void {
            for each (var info:Array in methodList) {
                addMethod(info[0], info[1]);
            }
        }

        /**
         * Activate player.
         * Please call this after setData(), addTriggers(), addMethods(), and init().
         */
        public function activate():void {
            for (var triggerKey:String in _eventsByTrigger) {
                _listenEvent(triggerKey);
            }
        }

        //------------------------------------------------------------
        // private
        //------------------------------------------------------------

        private function _listenEvent(triggerKey:String):void {
            var info:TriggerInfo = _triggers[triggerKey];
            if (!info) {
                throw new Error('[KrewEventPlayer] trigger not registered: ' + triggerKey);
                return;
            }

            listen(info.eventName, function(eventArgs:Object):void {
                for each (var eventData:Object in _eventsByTrigger[triggerKey]) {

                    var triggerParams:Object = eventData[TRIGGER_PARAMS];
                    if (!info.checker(eventArgs, triggerParams)) { continue; }

                    _callMethod(eventData);
                }
            });
        }

        private function _callMethod(eventData:Object):void {
            var methodName:String = eventData[METHOD];
            if (!methodName) {
                throw new Error('[KrewEventPlayer] method name not found. (trigger: '
                                + eventData[TRIGGER_KEY] + ')');
                return;
            }

            var method:Function = _methods[methodName];
            if (method == null) {
                throw new Error('[KrewEventPlayer] method not registered: ' + methodName);
                return;
            }

            method(eventData[PARAMS], function():void {
                _callNextMethod(eventData);
            });
        }

        private function _callNextMethod(parentEventData:Object):void {
            if (!parentEventData.next) { return; }

            for each (var nextEventData:Object in parentEventData.next) {
                _callMethod(nextEventData);
            }
        }

    }
}

class TriggerInfo {

    public var eventName:String;
    public var checker:Function;

    public function TriggerInfo(eventName:String, checker:Function) {
        this.eventName = eventName;
        this.checker   = checker;
    }

}

package krewfw.builtin_actor.system {

    import krewfw.core.KrewActor;

    /**
     * Base class for event-driven command player.
     */
    //------------------------------------------------------------
    public class KrewScenarioPlayer extends KrewActor {

        // You can customize object keys.
        public var TRIGGER_KEY    :String = "trigger_key";
        public var TRIGGER_PARAMS :String = "trigger_params";
        public var METHOD         :String = "method";
        public var PARAMS         :String = "params";
        public var NEXT           :String = "next";

        private var _eventList:Array;
        private var _eventsByTrigger:Object;

        private var _triggers:Object = {};
        private var _methods:Object  = {};

        // internal event
        public static const ACTIVATE:String = "ksp.activate";

        //------------------------------------------------------------
        public function KrewScenarioPlayer() {
            displayable = false;
        }

        protected override function onDispose():void {
            _eventList       = null;
            _eventsByTrigger = null;
            _triggers        = null;
            _methods         = null;
        }

        //------------------------------------------------------------
        // public
        //------------------------------------------------------------

        /**
         * @params eventList Example:
         *

         * [
         *     {
         *         "trigger_key" : "start_turn",
         *         "trigger_params": {"turn": 1},
         *         "method": "dialog",
         *         "params": {
         *             "messages": [ ... ]
         *         },
         *         "next": [
         *             {
         *                 "method": "overlay",
         *                 "params": { ... }
         *             }
         *         ]
         *     },
         *     ...
         * ]
         *

         */
        public function setData(eventList:Array):void {
            _eventList = eventList;

            _eventsByTrigger = {};
            for each (var eventData:Object in _eventList) {
                var triggerKey:String = eventData[TRIGGER_KEY];
                if (!triggerKey) { continue; }

                if (!_eventsByTrigger[triggerKey]) {
                    _eventsByTrigger[triggerKey] = [];
                }
                _eventsByTrigger[triggerKey].push(eventData);
            }
        }

        /**
         * @param checker Schema: function(eventArgs;Object, triggerParams:Object):Boolean
         */
        public function addTrigger(triggerKey:String, eventName:String, checker:Function):void {
            _triggers[triggerKey] = new TriggerInfo(eventName, checker);
        }

        /**
         * @param triggerInfoList Example:
         *

         * [
         *     ["triggerKey", "eventName", checkerFunc],
         *     ...
         * ]
         *

         */
        public function addTriggers(triggerInfoList:Array):void {
            for each (var info:Array in triggerInfoList) {
                addTrigger(info[0], info[1], info[2]);
            }
        }

        /**
         * @param handler Schema: function(params:Object, onComplete:Function):void
         */
        public function addMethod(methodName:String, handler:Function):void {
            _methods[methodName] = handler;
        }

        /**
         * @param triggerInfoList Example:
         *

         * [
         *     ["methodName", methodFunc],
         *     ...
         * ]
         *

         */
        public function addMethods(methodList:Array):void {
            for each (var info:Array in methodList) {
                addMethod(info[0], info[1]);
            }
        }

        /**
         * Activate player.
         * Please call this after setData(), addTriggers(), addMethods(), and init().
         */
        public function activate():void {
            for (var triggerKey:String in _eventsByTrigger) {
                _listenEvent(triggerKey);
            }
            sendMessage(KrewScenarioPlayer.ACTIVATE);
        }

        //------------------------------------------------------------
        // private
        //------------------------------------------------------------

        private function _listenEvent(triggerKey:String):void {
            var info:TriggerInfo = _triggers[triggerKey];
            if (!info) {
                throw new Error('[KrewEventPlayer] trigger not registered: ' + triggerKey);
                return;
            }

            listen(info.eventName, function(eventArgs:Object):void {
                for each (var eventData:Object in _eventsByTrigger[triggerKey]) {

                    var triggerParams:Object = eventData[TRIGGER_PARAMS];
                    if (!info.checker(eventArgs, triggerParams)) { continue; }

                    _callMethod(eventData);
                }
            });
        }

        private function _callMethod(eventData:Object):void {
            var methodName:String = eventData[METHOD];
            if (!methodName) {
                throw new Error('[KrewEventPlayer] method name not found. (trigger: '
                                + eventData[TRIGGER_KEY] + ')');
                return;
            }

            var method:Function = _methods[methodName];
            if (method == null) {
                throw new Error('[KrewEventPlayer] method not registered: ' + methodName);
                return;
            }

            method(eventData[PARAMS], function():void {
                _callNextMethod(eventData);
            });
        }

        private function _callNextMethod(parentEventData:Object):void {
            if (!parentEventData.next) { return; }

            for each (var nextEventData:Object in parentEventData.next) {
                _callMethod(nextEventData);
            }
        }

    }
}

class TriggerInfo {

    public var eventName:String;
    public var checker:Function;

    public function TriggerInfo(eventName:String, checker:Function) {
        this.eventName = eventName;
        this.checker   = checker;
    }

}

Update KrewScenarioPlayer

Update KrewScenarioPlayer


//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.display.Sprite;
import flash.filesystem.File;
import flash.geom.Rectangle;

public class Atlas
{
    public var name :String;
    public var w :int, h :int, id :int;
    public var bins :Vector.<Rectangle> = new Vector.<Rectangle>();
    public const textures :Vector.<PackedTexture> = new Vector.<PackedTexture>();

    public function Atlas(name :String, w :int, h :int) {
        this.name = name;
        this.w = w;
        this.h = h;
        bins.push(new Rectangle(0, 0, w, h));
    }

    public function place (tex :PackedTexture, target :Rectangle, rotated :Boolean) :void {
        tex.atlasX = target.x;
        tex.atlasY = target.y;
        tex.atlasRotated = rotated;
        textures.push(tex);
        trace("Packer " + tex);
        var used :Rectangle =
            new Rectangle(tex.atlasX, tex.atlasY, rotated ? tex.h : tex.w, rotated ? tex.w : tex.h);
        const newBins :Vector.<Rectangle> = new Vector.<Rectangle>();
        for each (var bin :Rectangle in bins) {
            for each (var newBin :Rectangle in subtract(bin, used)) {
                newBins.push(newBin);
            }
        }
        bins = newBins;
    }

    public function subtract (space :Rectangle, area :Rectangle) :Vector.<Rectangle> {
        const left :Vector.<Rectangle> = new Vector.<Rectangle>();
        if (space.x < area.x) {
            left.push(new Rectangle(space.x, space.y, area.left - space.x, space.height));
        }
        if (space.right > area.right) {
            left.push(new Rectangle(area.right, space.y, space.right - area.right, space.height));
        }
        if (space.y < area.y) {
            left.push(new Rectangle(space.x, space.y, space.width, area.top - space.y));
        }
        if (space.bottom > area.bottom) {
            left.push(new Rectangle(space.x, area.bottom, space.width, space.bottom - area.bottom));
        }
        return left;
    }

    public function publish (dir :File) :void {
        var constructed :Sprite = new Sprite();
        for each (var tex :PackedTexture in textures) {
            constructed.addChild(tex.holder);
            tex.holder.x = tex.atlasX;
            tex.holder.y = tex.atlasY;
        }
        PngPublisher.publish(dir.resolvePath(name + ".png"), w, h, constructed);
    }

    public function toXml () :String {
        var xml :String = "<atlas name='" + name + "' filename='" + name + ".png'>\n";
        for each (var tex :PackedTexture in textures) {
            xml += "  <texture name='" + tex.tex.name + "' xOffset='" + tex.offset.x +
                "' yOffset='" + tex.offset.y + "' md5='" + tex.tex.md5 +
                "' xAtlas='" + tex.atlasX + "' yAtlas='" + tex.atlasY + "'/>\n";
        }
        return xml + "</atlas>\n";
    }
}
}

//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.display.Sprite;
import flash.filesystem.File;
import flash.geom.Rectangle;

public class Atlas
{
    public var name :String;
    public var w :int, h :int, id :int;
    public var bins :Vector.<Rectangle> = new Vector.<Rectangle>();
    public const textures :Vector.<PackedTexture> = new Vector.<PackedTexture>();

    public function Atlas(name :String, w :int, h :int) {
        this.name = name;
        this.w = w;
        this.h = h;
        bins.push(new Rectangle(0, 0, w, h));
    }

    public function place (tex :PackedTexture, target :Rectangle, rotated :Boolean) :void {
        tex.atlasX = target.x;
        tex.atlasY = target.y;
        tex.atlasRotated = rotated;
        textures.push(tex);
        trace("Packer " + tex);
        var used :Rectangle =
            new Rectangle(tex.atlasX, tex.atlasY, rotated ? tex.h : tex.w, rotated ? tex.w : tex.h);
        const newBins :Vector.<Rectangle> = new Vector.<Rectangle>();
        for each (var bin :Rectangle in bins) {
            for each (var newBin :Rectangle in subtract(bin, used)) {
                newBins.push(newBin);
            }
        }
        bins = newBins;
    }

    public function subtract (space :Rectangle, area :Rectangle) :Vector.<Rectangle> {
        const left :Vector.<Rectangle> = new Vector.<Rectangle>();
        if (space.x < area.x) {
            left.push(new Rectangle(space.x, space.y, area.left - space.x, space.height));
        }
        if (space.right > area.right) {
            left.push(new Rectangle(area.right, space.y, space.right - area.right, space.height));
        }
        if (space.y < area.y) {
            left.push(new Rectangle(space.x, space.y, space.width, area.top - space.y));
        }
        if (space.bottom > area.bottom) {
            left.push(new Rectangle(space.x, area.bottom, space.width, space.bottom - area.bottom));
        }
        return left;
    }

    public function publish (dir :File) :void {
        var constructed :Sprite = new Sprite();
        for each (var tex :PackedTexture in textures) {
            constructed.addChild(tex.holder);
            tex.holder.x = tex.atlasX;
            tex.holder.y = tex.atlasY;
        }
        PngPublisher.publish(dir.resolvePath(name + ".png"), w, h, constructed);
    }

    public function toXml () :String {
        var xml :String = "<atlas name='" + name + "' filename='" + name + ".png'>\n";
        for each (var tex :PackedTexture in textures) {
            xml += "  <texture name='" + tex.tex.name + "' xOffset='" + tex.offset.x +
                "' yOffset='" + tex.offset.y + "' md5='" + tex.tex.md5 +
                "' xAtlas='" + tex.atlasX + "' yAtlas='" + tex.atlasY +
                "' wAtlas='" + tex.w + "' hAtlas='" + tex.h + "'/>\n";
        }
        return xml + "</atlas>\n";
    }
}
}

Include the width of the image in the atlas in the xml


//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.IDataOutput;

import com.adobe.images.PNGEncoder;

import flump.SwfTexture;
import flump.mold.AtlasMold;
import flump.mold.AtlasTextureMold;

import com.threerings.util.Arrays;

public class Atlas
{
    // The empty border size around the right and bottom edges of each texture, to prevent bleeding
    public static const PADDING :int = 1;

    public var name :String;

    public function Atlas (name :String, w :int, h :int) {
        this.name = name;
        _width = w;
        _height = h;
        _mask = Arrays.create(_width * _height, false);
    }

    public function get area () :int { return _width * _height; }

    public function get filename () :String { return name + ".png"; }

    public function get used () :int {
        var used :int = 0;
        _nodes.forEach(function (n :Node, ..._) :void { used += n.bounds.width * n.bounds.height; });
        return used;
    }

    public function writePNG (bytes :IDataOutput) :void {
        var constructed :Sprite = new Sprite();
        _nodes.forEach(function (node :Node, ..._) :void {
            const tex :SwfTexture = node.texture;
            const bm :Bitmap = new Bitmap(node.texture.toBitmapData(), "auto", true);
            constructed.addChild(bm);
            bm.x = node.bounds.x;
            bm.y = node.bounds.y;
        });
        const bd :BitmapData =
            SwfTexture.renderToBitmapData(constructed, _width, _height);
        bytes.writeBytes(PNGEncoder.encode(bd));
    }

    public function toMold () :AtlasMold {
        const mold :AtlasMold = new AtlasMold();
        mold.file = name + ".png";
        _nodes.forEach(function (node :Node, ..._) :void {
            const tex :SwfTexture = node.texture;
            const texMold :AtlasTextureMold = new AtlasTextureMold();
            texMold.symbol = tex.symbol;
            texMold.bounds = new Rectangle(node.bounds.x, node.bounds.y, tex.w, tex.h);
            texMold.offset = new Point(tex.offset.x, tex.offset.y);
            mold.textures.push(texMold);
        });
        return mold;
    }

    // Try to place a texture in this atlas, return true if it fit
    public function place (tex :SwfTexture) :Boolean {
        var w :int = tex.w + PADDING;
        var h :int = tex.h + PADDING;
        if (w > _width || h > _height) {
            return false;
        }

        var found :Boolean = false;
        for (var yy :int = 0; yy < _height - h && !found; ++yy) {
            for (var xx :int = 0; xx <= _width - w; ++xx) {
                // if our right-most pixel is masked, jump ahead by that much
                if (maskAt(xx + w - 1, yy)) {
                    xx += w;
                    continue;
                }

                if (!isMasked(xx, yy, w, h)) {
                    _nodes.push(new Node(xx, yy, tex));
                    setMasked(xx, yy, w, h);
                    found = true;
                    break;
                }
            }
        }

        return found;
    }

    protected function isMasked (x :int, y :int, w :int, h :int) :Boolean {
        var xMax :int = x + w - 1;
        var yMax :int = y + h - 1;
        // fail fast on extents
        if (maskAt(x, y) || maskAt(x, yMax) || maskAt(xMax, y) || maskAt(xMax, yMax)) {
            return true;
        }

        for (var yy :int = y + 1; yy < yMax; ++yy) {
            for (var xx :int = x + 1; xx < xMax; ++xx) {
                if (maskAt(xx, yy)) {
                    return true;
                }
            }
        }
        return false;
    }

    protected function setMasked (x :int, y :int, w: int, h :int) :void {
        for (var yy :int = y; yy < y + h; ++yy) {
            for (var xx :int = x; xx < x + w; ++xx) {
                _mask[(yy * _width) + xx] = true;
            }
        }
    }

    protected function maskAt (xx :int, yy :int) :Boolean {
        return _mask[(yy * _width) + xx];
    }

    protected var _nodes :Array = [];
    protected var _width :int;
    protected var _height :int;
    protected var _mask :Array;
}
}

import flash.geom.Rectangle;

import flump.SwfTexture;

class Node
{
    public var bounds :Rectangle;
    public var texture :SwfTexture;

    public function Node (x :int, y :int, texture :SwfTexture) {
        this.texture = texture;
        this.bounds = new Rectangle(x, y, texture.w, texture.h);
    }
}

//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.IDataOutput;

import com.adobe.images.PNGEncoder;

import flump.SwfTexture;
import flump.mold.AtlasMold;
import flump.mold.AtlasTextureMold;

import com.threerings.util.Arrays;

public class Atlas
{
    // The empty border size around the right and bottom edges of each texture, to prevent bleeding
    public static const PADDING :int = 1;

    public var name :String;

    public function Atlas (name :String, w :int, h :int) {
        this.name = name;
        _width = w;
        _height = h;
        _mask = Arrays.create(_width * _height, false);
    }

    public function get area () :int { return _width * _height; }

    public function get filename () :String { return name + ".png"; }

    public function get used () :int {
        var used :int = 0;
        _nodes.forEach(function (n :Node, ..._) :void { used += n.bounds.width * n.bounds.height; });
        return used;
    }

    public function writePNG (bytes :IDataOutput) :void {
        var constructed :Sprite = new Sprite();
        _nodes.forEach(function (node :Node, ..._) :void {
            const tex :SwfTexture = node.texture;
            const bm :Bitmap = new Bitmap(node.texture.toBitmapData(), "auto", true);
            constructed.addChild(bm);
            bm.x = node.bounds.x;
            bm.y = node.bounds.y;
        });
        const bd :BitmapData =
            SwfTexture.renderToBitmapData(constructed, _width, _height);
        bytes.writeBytes(PNGEncoder.encode(bd));
    }

    public function toMold () :AtlasMold {
        const mold :AtlasMold = new AtlasMold();
        mold.file = name + ".png";
        _nodes.forEach(function (node :Node, ..._) :void {
            const tex :SwfTexture = node.texture;
            const texMold :AtlasTextureMold = new AtlasTextureMold();
            texMold.symbol = tex.symbol;
            texMold.bounds = new Rectangle(node.bounds.x, node.bounds.y, tex.w, tex.h);
            texMold.offset = new Point(tex.offset.x, tex.offset.y);
            mold.textures.push(texMold);
        });
        return mold;
    }

    // Try to place a texture in this atlas, return true if it fit
    public function place (tex :SwfTexture) :Boolean {
        var w :int = tex.w + PADDING;
        var h :int = tex.h + PADDING;
        if (w > _width || h > _height) {
            return false;
        }

        var found :Boolean = false;
        for (var yy :int = 0; yy <= _height - h && !found; ++yy) {
            for (var xx :int = 0; xx <= _width - w; ++xx) {
                // if our right-most pixel is masked, jump ahead by that much
                if (maskAt(xx + w - 1, yy)) {
                    xx += w;
                    continue;
                }

                if (!isMasked(xx, yy, w, h)) {
                    _nodes.push(new Node(xx, yy, tex));
                    setMasked(xx, yy, w, h);
                    found = true;
                    break;
                }
            }
        }

        return found;
    }

    protected function isMasked (x :int, y :int, w :int, h :int) :Boolean {
        var xMax :int = x + w - 1;
        var yMax :int = y + h - 1;
        // fail fast on extents
        if (maskAt(x, y) || maskAt(x, yMax) || maskAt(xMax, y) || maskAt(xMax, yMax)) {
            return true;
        }

        for (var yy :int = y + 1; yy < yMax; ++yy) {
            for (var xx :int = x + 1; xx < xMax; ++xx) {
                if (maskAt(xx, yy)) {
                    return true;
                }
            }
        }
        return false;
    }

    protected function setMasked (x :int, y :int, w: int, h :int) :void {
        for (var yy :int = y; yy < y + h; ++yy) {
            for (var xx :int = x; xx < x + w; ++xx) {
                _mask[(yy * _width) + xx] = true;
            }
        }
    }

    protected function maskAt (xx :int, yy :int) :Boolean {
        return _mask[(yy * _width) + xx];
    }

    protected var _nodes :Array = [];
    protected var _width :int;
    protected var _height :int;
    protected var _mask :Array;
}
}

import flash.geom.Rectangle;

import flump.SwfTexture;

class Node
{
    public var bounds :Rectangle;
    public var texture :SwfTexture;

    public function Node (x :int, y :int, texture :SwfTexture) {
        this.texture = texture;
        this.bounds = new Rectangle(x, y, texture.w, texture.h);
    }
}

Fix an off-by-one error causing an occasional infinite loop