/*
 * 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.v4
{
    import com.google.analytics.campaign.CampaignKey;
    import com.google.analytics.core.Domain;
    import com.google.analytics.core.DomainNameMode;
    import com.google.analytics.core.Organic;
    import com.google.analytics.core.ServerOperationMode;
    import com.google.analytics.debug.DebugConfiguration;
    import com.google.analytics.utils.Timespan;

    /**
     * Google Analytic Tracker Code (GATC)'s configuration / state component.
     * This encapsulates all the configurations for the entire GATC module.
     */
    public class Configuration
    {

        private var _debug:DebugConfiguration;

        private var _version:String = "4.3as";

        /**
         * Sampling percentage of visitors to track.
         * @private
         */
        private var _sampleRate:Number = 1; //100%

        private var _trackingLimitPerSession:int = 500;

        private var _domain:Domain;

        private var _organic:Organic = new Organic();

        /**
         * Substring of host names to ignore when auto decorating href anchor elements for outbound link tracking.
         * @private
         */
        //private var _ignoredOutboundHosts:Array = [];

        /**
         * This is the cse path that needs to be ignored for Google.
         * All referers with path cse from google donmains will be ignored from organic and referrer campaigns.
         * @private
         */
        public  var googleCsePath:String = "cse";

        /**
         * The parameter used by google for the search keyword.
         * @private
         */
        public var googleSearchParam:String = "q";

        /**
         * Google string value.
         * @private
         */
        public var google:String = "google";

        /**
         * Name used by the SharedObject (read-only)
         */
        private var _cookieName:String = "analytics";

        /**
         * Unique domain hash for cookies.
         */
        public var allowDomainHash:Boolean  = true;

        /**
         * Enable use of anchors for campaigns.
         */
        public var allowAnchor:Boolean      = false ;

        /**
         * Enable linker functionality.
         */
        public var allowLinker:Boolean      = false ;

        /**
         * Indicates if has site overlay.
         */
        public var hasSiteOverlay:Boolean   = false ;

        /**
         * The rate of token being released into the token bucket.
         * Unit for this parameter is number of token released per second.
         * This is set to 0.20 right now, which translates to 1 token released every 5 seconds.
         */
        public var tokenRate:Number        = 0.20;

        /**
         * Default cookie expiration time in seconds. (6 months).
         */
        public var conversionTimeout:Number = Timespan.sixmonths;

        /**
         * Default inactive session timeout in seconds (30 minutes).
         */
        public var sessionTimeout:Number = Timespan.thirtyminutes;

        /**
        * Default idle timer loop time in seconds (30 seconds).
        */
        public var idleLoop:Number    = 30;

        /**
        * Default idle timer inactivity time in seconds (1 minute).
        */
        public var idleTimeout:Number = 60;

        /**
         * Upper limit for number of href anchor tags to examine.
         *
If this number is set to -1, then we will examine all the href anchor tags.

         *
In other words, a -1 value indicates that there is no upper limit.

         *
Note: maybe use Number.INFINITY instead of -1

         */
        public var maxOutboundLinkExamined:Number = 1000;

        /**
         * The number of tokens available at the start of the session.
         */
        public var tokenCliff:int = 10;

        /**
         * Capacity of the token bucket.
         */
        public var bucketCapacity:Number = 10;

        /**
         * Detect client browser information flag.
         */
        public var detectClientInfo:Boolean  = true;

        /**
         * Flash version detection option.
         */
        public var detectFlash:Boolean = true;

        /**
         * Set document title detection option.
         */
        public var detectTitle:Boolean = true;

        /**
         * The campaign key value of the application.
         * @see com.google.analytics.campaign.CampaignKey
         */
        public var campaignKey:CampaignKey = new CampaignKey();

        /**
         * Track campaign information flag.
         */
        public var campaignTracking:Boolean = true;

        /**
         * Boolean flag to indicate if outbound links for subdomains of the current domain
         * needs to be considered as outbound links. Default value is false.
         */
        public var isTrackOutboundSubdomains:Boolean = false;

        /**
         * Actual service model.
         *
Note : "service" is wrong we name it server

         */
        public var serverMode:ServerOperationMode = ServerOperationMode.remote;

        /**
         * Local service mode GIF url.
         */
        public var localGIFpath:String = "/__utm.gif";

        /**
         * The remote service mode GIF url.
         */
        public var remoteGIFpath:String = "http://www.google-analytics.com/__utm.gif";

        /**
         * The secure remote service mode GIF url.
         */
        public var secureRemoteGIFpath:String = "https://ssl.google-analytics.com/__utm.gif";

        /**
         * Default cookie path to set in document header.
         */
        public var cookiePath:String = "/" ; //SharedObjectPath

        /**
         * Delimiter for e-commerce transaction fields.
         */
        public var transactionFieldDelim:String = "|";

        /**
         * The domain name value.
         */
        public var domainName:String = "";

        /**
         * To be able to track in local mode (when protocol is file://)
         */
        public var allowLocalTracking:Boolean = true;

        /**
         * Creates a new Configuration instance.
         */
        public function Configuration( debug:DebugConfiguration = null )
        {
            _debug = debug;

            _domain = new Domain( DomainNameMode.auto, "", _debug );
            serverMode = ServerOperationMode.remote;

            _initOrganicSources();
        }

        /**
         * @private
         */
        private function _initOrganicSources():void
        {
            addOrganicSource( google,            googleSearchParam );
            addOrganicSource( "yahoo",          "p"                );
            addOrganicSource( "msn",            "q"                );
            addOrganicSource( "aol",            "query"            );
            addOrganicSource( "aol",            "encquery"         );
            addOrganicSource( "lycos",          "query"            );
            addOrganicSource( "ask",            "q"                );
            addOrganicSource( "altavista",      "q"                );
            addOrganicSource( "netscape",       "query"            );
            addOrganicSource( "cnn",            "query"            );
            addOrganicSource( "looksmart",      "qt"               );
            addOrganicSource( "about",          "terms"            );
            addOrganicSource( "mamma",          "query"            );
            addOrganicSource( "alltheweb",      "q"                );
            addOrganicSource( "gigablast",      "q"                );
            addOrganicSource( "voila",          "rdata"            );
            addOrganicSource( "virgilio",       "qs"               );
            addOrganicSource( "live",           "q"                );
            addOrganicSource( "baidu",          "wd"               );
            addOrganicSource( "alice",          "qs"               );
            addOrganicSource( "yandex",         "text"             );
            addOrganicSource( "najdi",          "q"                );
            addOrganicSource( "aol",            "q"                );
            addOrganicSource( "club-internet",  "q"                );
            addOrganicSource( "mama",           "query"            );
            addOrganicSource( "seznam",         "q"                );
            addOrganicSource( "search",         "q"                );
            addOrganicSource( "wp",             "szukaj"           );
            addOrganicSource( "onet",           "qt"               );
            addOrganicSource( "netsprint",      "q"                );
            addOrganicSource( "google.interia", "q"                );
            addOrganicSource( "szukacz",        "q"                );
            addOrganicSource( "yam",            "k"                );
            addOrganicSource( "pchome",         "q"                );
            addOrganicSource( "kvasir",         "searchExpr"       );
            addOrganicSource( "sesam",          "q"                );
            addOrganicSource( "ozu",            "q"                );
            addOrganicSource( "terra",          "query"            );
            addOrganicSource( "nostrum",        "query"            );
            addOrganicSource( "mynet",          "q"                );
            addOrganicSource( "ekolay",         "q"                );
            addOrganicSource( "search.ilse",    "search_for"       );
        }

        /**
         * Indicates the name of the cookie.
         */
        public function get cookieName():String
        {
            return _cookieName;
        }

        /**
         * Indicates the version String representation of the application.
         */
        public function get version():String
        {
            return _version;
        }

        /**
        * Domain name for cookies.
        * (auto | none | domain)
        * If this variable is set to "auto",
        * then we will try to resolve the domain name
        * based on the HTMLDocument object.
        *
        * note:
        * for Flash we try to auto detect
        * the domain name by using the URL info
        * if we are in HTTP or HTTPS
        *
        * if we can not detect the protocol or find file://
        * then the "auto" domain is none.
        */
        public function get domain():Domain
        {
            return _domain;
        }

        /**
         * Indicates the Organic reference.
         */
        public function get organic():Organic
        {
            return _organic;
        }

//        /**
//         * Indicates the collection (Array) of all organic sources.
//         */
//        public function get organicSources():Array
//        {
//            return _organicSources;
//        }
//
//        /**
//         * @private
//         */
//        public function set organicSources(sources:Array):void
//        {
//            _organicSources = sources;
//        }

        /**
         * Indicates the sample rate value of the application.
         */
        public function get sampleRate():Number
        {
            return _sampleRate;
        }

        /**
         * Sampling percentage of visitors to track.
         */
        public function set sampleRate( value:Number ):void
        {
            if( value <= 0 )
            {
                value = 0.1;
            }

            if( value > 1 )
            {
                value = 1;
            }

            value = Number( value.toFixed( 2 ) );

            _sampleRate = value;
        }

        /**
         * This is the max number of tracking requests to the backend
         * allowed per session.
         */
        public function get trackingLimitPerSession():int
        {
            return _trackingLimitPerSession;
        }

        /**
         * Adds a new organic source.
         * @param engine The engine value.
         * @param keyword The keyword of the specified engine value.
         */
        public function addOrganicSource(engine:String, keyword:String):void
        {
            try
            {
                _organic.addSource( engine, keyword );
            }
            catch( e:Error )
            {
                if( _debug && _debug.active )
                {
                    _debug.warning( e.message );
                }
            }
        }

    }
}

/*
 * 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.v4
{
    import com.google.analytics.campaign.CampaignKey;
    import com.google.analytics.core.Domain;
    import com.google.analytics.core.DomainNameMode;
    import com.google.analytics.core.Organic;
    import com.google.analytics.core.ServerOperationMode;
    import com.google.analytics.debug.DebugConfiguration;
    import com.google.analytics.utils.Timespan;

    /**
     * Google Analytic Tracker Code (GATC)'s configuration / state component.
     * This encapsulates all the configurations for the entire GATC module.
     */
    public class Configuration
    {

        private var _debug:DebugConfiguration;

        private var _version:String = "4.3as";

        /**
         * Sampling percentage of visitors to track.
         * @private
         */
        private var _sampleRate:Number = 1; //100%

        private var _trackingLimitPerSession:int = 500;

        private var _domain:Domain;

        private var _organic:Organic = new Organic();

        /**
         * Substring of host names to ignore when auto decorating href anchor elements for outbound link tracking.
         * @private
         */
        //private var _ignoredOutboundHosts:Array = [];

        /**
         * This is the cse path that needs to be ignored for Google.
         * All referers with path cse from google donmains will be ignored from organic and referrer campaigns.
         * @private
         */
        public  var googleCsePath:String = "cse";

        /**
         * The parameter used by google for the search keyword.
         * @private
         */
        public var googleSearchParam:String = "q";

        /**
         * Google string value.
         * @private
         */
        public var google:String = "google";

        /**
         * Name used by the SharedObject (read-only)
         */
        private var _cookieName:String = "analytics";

        /**
         * Unique domain hash for cookies.
         */
        public var allowDomainHash:Boolean  = true;

        /**
         * Enable use of anchors for campaigns.
         */
        public var allowAnchor:Boolean      = false ;

        /**
         * Enable linker functionality.
         */
        public var allowLinker:Boolean      = false ;

        /**
         * Indicates if has site overlay.
         */
        public var hasSiteOverlay:Boolean   = false ;

        /**
         * The rate of token being released into the token bucket.
         * Unit for this parameter is number of token released per second.
         * This is set to 0.20 right now, which translates to 1 token released every 5 seconds.
         */
        public var tokenRate:Number        = 0.20;

        /**
         * Default cookie expiration time in seconds. (6 months).
         */
        public var conversionTimeout:Number = Timespan.sixmonths;

        /**
         * Default inactive session timeout in seconds (30 minutes).
         */
        public var sessionTimeout:Number = Timespan.thirtyminutes;

        /**
         * Upper limit for number of href anchor tags to examine.
         *
If this number is set to -1, then we will examine all the href anchor tags.

         *
In other words, a -1 value indicates that there is no upper limit.

         *
Note: maybe use Number.INFINITY instead of -1

         */
        public var maxOutboundLinkExamined:Number = 1000;

        /**
         * The number of tokens available at the start of the session.
         */
        public var tokenCliff:int = 10;

        /**
         * Capacity of the token bucket.
         */
        public var bucketCapacity:Number = 10;

        /**
         * Detect client browser information flag.
         */
        public var detectClientInfo:Boolean  = true;

        /**
         * Flash version detection option.
         */
        public var detectFlash:Boolean = true;

        /**
         * Set document title detection option.
         */
        public var detectTitle:Boolean = true;

        /**
         * The campaign key value of the application.
         * @see com.google.analytics.campaign.CampaignKey
         */
        public var campaignKey:CampaignKey = new CampaignKey();

        /**
         * Track campaign information flag.
         */
        public var campaignTracking:Boolean = true;

        /**
         * Boolean flag to indicate if outbound links for subdomains of the current domain
         * needs to be considered as outbound links. Default value is false.
         */
        public var isTrackOutboundSubdomains:Boolean = false;

        /**
         * Actual service model.
         *
Note : "service" is wrong we name it server

         */
        public var serverMode:ServerOperationMode = ServerOperationMode.remote;

        /**
         * Local service mode GIF url.
         */
        public var localGIFpath:String = "/__utm.gif";

        /**
         * The remote service mode GIF url.
         */
        public var remoteGIFpath:String = "http://www.google-analytics.com/__utm.gif";

        /**
         * The secure remote service mode GIF url.
         */
        public var secureRemoteGIFpath:String = "https://ssl.google-analytics.com/__utm.gif";

        /**
         * Default cookie path to set in document header.
         */
        public var cookiePath:String = "/" ; //SharedObjectPath

        /**
         * Delimiter for e-commerce transaction fields.
         */
        public var transactionFieldDelim:String = "|";

        /**
         * The domain name value.
         */
        public var domainName:String = "";

        /**
         * To be able to track in local mode (when protocol is file://)
         */
        public var allowLocalTracking:Boolean = true;

        /**
         * Creates a new Configuration instance.
         */
        public function Configuration( debug:DebugConfiguration = null )
        {
            _debug = debug;

            _domain = new Domain( DomainNameMode.auto, "", _debug );
            serverMode = ServerOperationMode.remote;

            _initOrganicSources();
        }

        /**
         * @private
         */
        private function _initOrganicSources():void
        {
            addOrganicSource( google,            googleSearchParam );
            addOrganicSource( "yahoo",          "p"                );
            addOrganicSource( "msn",            "q"                );
            addOrganicSource( "aol",            "query"            );
            addOrganicSource( "aol",            "encquery"         );
            addOrganicSource( "lycos",          "query"            );
            addOrganicSource( "ask",            "q"                );
            addOrganicSource( "altavista",      "q"                );
            addOrganicSource( "netscape",       "query"            );
            addOrganicSource( "cnn",            "query"            );
            addOrganicSource( "looksmart",      "qt"               );
            addOrganicSource( "about",          "terms"            );
            addOrganicSource( "mamma",          "query"            );
            addOrganicSource( "alltheweb",      "q"                );
            addOrganicSource( "gigablast",      "q"                );
            addOrganicSource( "voila",          "rdata"            );
            addOrganicSource( "virgilio",       "qs"               );
            addOrganicSource( "live",           "q"                );
            addOrganicSource( "baidu",          "wd"               );
            addOrganicSource( "alice",          "qs"               );
            addOrganicSource( "yandex",         "text"             );
            addOrganicSource( "najdi",          "q"                );
            addOrganicSource( "aol",            "q"                );
            addOrganicSource( "club-internet",  "q"                );
            addOrganicSource( "mama",           "query"            );
            addOrganicSource( "seznam",         "q"                );
            addOrganicSource( "search",         "q"                );
            addOrganicSource( "wp",             "szukaj"           );
            addOrganicSource( "onet",           "qt"               );
            addOrganicSource( "netsprint",      "q"                );
            addOrganicSource( "google.interia", "q"                );
            addOrganicSource( "szukacz",        "q"                );
            addOrganicSource( "yam",            "k"                );
            addOrganicSource( "pchome",         "q"                );
            addOrganicSource( "kvasir",         "searchExpr"       );
            addOrganicSource( "sesam",          "q"                );
            addOrganicSource( "ozu",            "q"                );
            addOrganicSource( "terra",          "query"            );
            addOrganicSource( "nostrum",        "query"            );
            addOrganicSource( "mynet",          "q"                );
            addOrganicSource( "ekolay",         "q"                );
            addOrganicSource( "search.ilse",    "search_for"       );
        }

        /**
         * Indicates the name of the cookie.
         */
        public function get cookieName():String
        {
            return _cookieName;
        }

        /**
         * Indicates the version String representation of the application.
         */
        public function get version():String
        {
            return _version;
        }

        /**
        * Domain name for cookies.
        * (auto | none | domain)
        * If this variable is set to "auto",
        * then we will try to resolve the domain name
        * based on the HTMLDocument object.
        *
        * note:
        * for Flash we try to auto detect
        * the domain name by using the URL info
        * if we are in HTTP or HTTPS
        *
        * if we can not detect the protocol or find file://
        * then the "auto" domain is none.
        */
        public function get domain():Domain
        {
            return _domain;
        }

        /**
         * Indicates the Organic reference.
         */
        public function get organic():Organic
        {
            return _organic;
        }

//        /**
//         * Indicates the collection (Array) of all organic sources.
//         */
//        public function get organicSources():Array
//        {
//            return _organicSources;
//        }
//
//        /**
//         * @private
//         */
//        public function set organicSources(sources:Array):void
//        {
//            _organicSources = sources;
//        }

        /**
         * Indicates the sample rate value of the application.
         */
        public function get sampleRate():Number
        {
            return _sampleRate;
        }

        /**
         * Sampling percentage of visitors to track.
         */
        public function set sampleRate( value:Number ):void
        {
            if( value <= 0 )
            {
                value = 0.1;
            }

            if( value > 1 )
            {
                value = 1;
            }

            value = Number( value.toFixed( 2 ) );

            _sampleRate = value;
        }

        /**
         * This is the max number of tracking requests to the backend
         * allowed per session.
         */
        public function get trackingLimitPerSession():int
        {
            return _trackingLimitPerSession;
        }

        /**
         * Adds a new organic source.
         * @param engine The engine value.
         * @param keyword The keyword of the specified engine value.
         */
        public function addOrganicSource(engine:String, keyword:String):void
        {
            try
            {
                _organic.addSource( engine, keyword );
            }
            catch( e:Error )
            {
                if( _debug && _debug.active )
                {
                    _debug.warning( e.message );
                }
            }
        }

    }
}

remove params related to idle timer

remove params related to idle timer


package {
  import flash.display.Sprite;
  import flash.external.ExternalInterface;
  import flash.system.Security;
  import flash.net.NetStream;
  import flash.events.*;
  import flash.utils.setTimeout;
  import flash.display.StageAlign;

  import org.osmf.containers.MediaContainer;
  import org.osmf.elements.VideoElement;
  import org.osmf.display.ScaleMode;
  import org.osmf.layout.LayoutMetadata;
  import org.osmf.layout.LayoutMode;
  import org.osmf.layout.HorizontalAlign;
  import org.osmf.layout.VerticalAlign;
  import flash.display.StageScaleMode;
  import flash.display.StageAlign;

  import org.osmf.net.NetStreamLoadTrait;
  import org.osmf.net.StreamingURLResource;
  import org.osmf.net.StreamType;
  import org.osmf.metadata.MetadataNamespaces

  import org.osmf.logging.Log;

  import org.osmf.media.*;
  import org.osmf.events.*;

  import org.osmf.traits.MediaTraitType;

  import org.osmf.smil.SMILPluginInfo;

  CONFIG::LOGGING {
    import logging.ExternalLoggerFactory;
    import org.osmf.logging.Logger;
    import org.osmf.logging.Log;
  }

  [SWF(width="640", height="360")]
  public class RTMP extends Sprite {
    private var playbackId:String;
    private var mediaFactory:DefaultMediaFactory;
    private var mediaContainer:MediaContainer;
    private var videoElement:VideoElement;
    private var mediaPlayer:MediaPlayer;
    private var netStream:NetStream;
    private var mediaElement:MediaElement;
    private var netStreamLoadTrait:NetStreamLoadTrait;
    private var urlResource:StreamingURLResource;
    private var playbackState:String = "IDLE";
    private var isLive:Boolean = false;
    private var useAppInstance:Boolean = false;
    private var proxyType:String = "none";

    CONFIG::LOGGING {
      private static const logInit:Boolean = initLog();
      private static const logger:Logger = org.osmf.logging.Log.getLogger("RTMP");

      private static function initLog():Boolean {
        Log.loggerFactory = new ExternalLoggerFactory();
        return true;
      }
    }

    public function RTMP() {
      Security.allowDomain('*');
      Security.allowInsecureDomain('*');

      playbackId = this.root.loaderInfo.parameters.playbackId;
      isLive = this.root.loaderInfo.parameters.playbackType == 'live';
      useAppInstance = this.root.loaderInfo.parameters.useAppInstance == 'true';
      proxyType = this.root.loaderInfo.parameters.proxyType;
      mediaFactory = new DefaultMediaFactory();
      mediaContainer = new MediaContainer();

      //set mediaContainer layout
      mediaContainer.clipChildren = true;
      mediaContainer.layoutMetadata.percentWidth = 100;
      mediaContainer.layoutMetadata.percentHeight = 100;
      mediaContainer.width = stage.stageWidth;
      mediaContainer.height = stage.stageHeight;

      stage.align = StageAlign.TOP;
      stage.scaleMode = StageScaleMode.NO_SCALE; //We handle scaling ourselves

      stage.addEventListener(Event.RESIZE, _onStageResize);

      setupCallbacks();
      setupGetters();

      _triggerEvent('flashready');

      stage.scaleMode = StageScaleMode.NO_SCALE;
      stage.align = StageAlign.TOP_LEFT;

      if (stage) {
        resize();
      } else {
        addEventListener(Event.ADDED_TO_STAGE, resize);
      }

      stage.addEventListener(Event.RESIZE, resize);
    }

    private function resize(e:Event = null):void {
      if(mediaElement && mediaContainer && stage){
        mediaContainer.width = stage.stageWidth;
        mediaContainer.height = stage.stageHeight;
        setScaleMode(mediaElement, stage.stageWidth, stage.stageHeight);
      }
    }

    private function setupCallbacks():void {
      ExternalInterface.addCallback("playerPlay", playerPlay);
      ExternalInterface.addCallback("playerResume", playerPlay);
      ExternalInterface.addCallback("playerPause", playerPause);
      ExternalInterface.addCallback("playerStop", playerStop);
      ExternalInterface.addCallback("playerSeek", playerSeek);
      ExternalInterface.addCallback("playerVolume", playerVolume);
      ExternalInterface.addCallback("playerScaling", playerScaling);
      ExternalInterface.addCallback("setLevel", setLevel);
    }

    private function setupGetters():void {
      ExternalInterface.addCallback("getState", getState);
      ExternalInterface.addCallback("getPosition", getPosition);
      ExternalInterface.addCallback("getDuration", getDuration);
      ExternalInterface.addCallback("getCurrentLevel", getCurrentLevel);
      ExternalInterface.addCallback("getBytesLoaded", getBytesLoaded);
      ExternalInterface.addCallback("getBytesTotal", getBytesTotal);
      ExternalInterface.addCallback("getNumLevels", getNumLevels);
      ExternalInterface.addCallback("getBitrateForLevel", getBitrateForLevel);
      ExternalInterface.addCallback("isDynamicStream", isDynamicStream);
      ExternalInterface.addCallback("isAutoSwitchLevels", isAutoSwitchLevels);
    }

    private function getBytesTotal():Number {
      if (netStream) {
        return netStream.bytesTotal;
      }
      else {
          return 0;
      }
    }
    private function getBytesLoaded():Number {
        if (netStream) {
          return netStream.bytesLoaded;
        }
        else {
            return 0;
        }
    }

    private function onTraitAdd(event:MediaElementEvent):void {
      if (mediaElement.hasTrait(MediaTraitType.LOAD)) {
        netStreamLoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as NetStreamLoadTrait;
        netStreamLoadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoaded);
      }
    }

    private function onLoaded(event:LoadEvent):void {
      _triggerEvent("onloaded")
      netStream = netStreamLoadTrait.netStream;
      netStream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
      mediaPlayer.play();
    }

    private function netStatusHandler(event:NetStatusEvent):void {
      if (playbackState == "ENDED") {
        return;
      } else if (event.info.code == "NetStream.Buffer.Full") {
        _changeStateAndNotify('PLAYING');
      } else if (event.info.code == "NetStream.Buffer.Empty" || event.info.code == "NetStream.Seek.Notify") {
        _changeStateAndNotify('PLAYING_BUFFERING');
      }
    }

    private function setScaleMode(mediaElement:MediaElement, width:Number, height:Number):void {
      var layout:LayoutMetadata = new LayoutMetadata();
      layout.width  = width;
      layout.height = height;
      layout.layoutMode = LayoutMode.HORIZONTAL;
      layout.horizontalAlign = HorizontalAlign.CENTER;
      layout.verticalAlign = VerticalAlign.MIDDLE;
      layout.scaleMode = ScaleMode.LETTERBOX;

      mediaElement.removeMetadata(LayoutMetadata.LAYOUT_NAMESPACE);
      mediaElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout);
    }

    private function playerPlay(url:String=null):void {
      try {
        if (!mediaElement) {
          var streamType:String = (isLive ? StreamType.LIVE : StreamType.RECORDED);

          urlResource = new StreamingURLResource(url, streamType, NaN, NaN, null, useAppInstance, null, proxyType);

          var startLevel:int = int(this.root.loaderInfo.parameters.startLevel);

          if (this.root.loaderInfo.parameters.switchRules != "") {
            var switchRules:Object = JSON.parse(this.root.loaderInfo.parameters.switchRules.replace(/&quote;/g, '"'));
            urlResource.addMetadataValue(MetadataNamespaces.RESOURCE_INITIAL_SWITCH_RULES, switchRules);
          }

          if (startLevel > -1) {
            urlResource.addMetadataValue(MetadataNamespaces.RESOURCE_INITIAL_INDEX, startLevel);
          }

          var pluginResource:MediaResourceBase = new PluginInfoResource(new SMILPluginInfo());

          // Load the plugin.
          mediaFactory.loadPlugin(pluginResource);

          //create new MediaPlayer - it controls your media provided in media property
          mediaPlayer = new MediaPlayer();

          mediaPlayer.bufferTime = this.root.loaderInfo.parameters.bufferTime;
          mediaPlayer.autoPlay = false;
          mediaPlayer.autoDynamicStreamSwitch = this.root.loaderInfo.parameters.autoSwitch == 'true';
          mediaPlayer.addEventListener(TimeEvent.CURRENT_TIME_CHANGE, onTimeUpdated);
          mediaPlayer.addEventListener(TimeEvent.DURATION_CHANGE, onTimeUpdated);
          mediaPlayer.addEventListener(TimeEvent.COMPLETE, onFinish);
          mediaPlayer.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError);
          mediaPlayer.addEventListener(DynamicStreamEvent.SWITCHING_CHANGE, onLevelSwitching);

          mediaElement = mediaFactory.createMediaElement(urlResource);
          mediaElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd);

          mediaContainer.addMediaElement(mediaElement);

          mediaPlayer.media = mediaElement;

          //Set the player scaling
          playerScaling(this.root.loaderInfo.parameters.scaling);

          addChild(mediaContainer);
          resize();

          _changeStateAndNotify('PLAYING_BUFFERING')
          _triggerEvent('playbackready');
        } else {
          mediaPlayer.play();
          _changeStateAndNotify('PLAYING')
        }
      } catch (err:Error) {
        debugLog('Catch error: ' + err.messsage);
        _changeStateAndNotify('ERROR')
      }
    }

    private function onLevelSwitching(event:DynamicStreamEvent):void {
      if (event.switching) {
        _triggerEvent('levelChanging');
      }
      else {
        _triggerEvent('levelChanged');
      }
    }

    private function onMediaError(event:MediaErrorEvent):void {
      debugLog("MediaPlayer error: " + event.toString());
    }

    private function playerPause():void {
      mediaPlayer.pause();
      _changeStateAndNotify('PAUSED')
    }

    private function playerSeek(seconds:Number):void {
      mediaPlayer.seek(seconds);
    }

    private function playerStop():void {
      mediaPlayer.stop();
      _changeStateAndNotify('IDLE')
    }

    private function playerVolume(level:Number):void {
      mediaPlayer.volume = level/100;
    }

    private function playerScaling(scaling: String):void {
      if(!mediaElement) return;

      //layoutMetadata needs to be added to the mediaElement depicting what scaling the video should have
      var layoutMetadata:LayoutMetadata = new LayoutMetadata();
      layoutMetadata.percentWidth = 100;
      layoutMetadata.percentHeight = 100;

      //The following is required for correct alignment in letterbox scaling
      layoutMetadata.layoutMode = LayoutMode.HORIZONTAL
      layoutMetadata.horizontalAlign = HorizontalAlign.CENTER;
      layoutMetadata.verticalAlign = VerticalAlign.TOP;

      switch(scaling){
       case 'stretch':
         layoutMetadata.scaleMode = ScaleMode.STRETCH;
         break;
       case 'zoom':
         layoutMetadata.scaleMode = ScaleMode.ZOOM;
         break;
       case 'none':
         layoutMetadata.scaleMode = ScaleMode.NONE;
         break;
       //Letterbox is the default scale mode
       case 'letterbox':
       default:
         layoutMetadata.scaleMode = ScaleMode.LETTERBOX;
         break;
      }

      //Assign layoutMetadata to mediaElement
      mediaElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutMetadata);
    }

    private function setLevel(level:int):void {
      if (level == -1) {
        mediaPlayer.autoDynamicStreamSwitch = true;
      }
      else {
        mediaPlayer.autoDynamicStreamSwitch = false;
        mediaPlayer.switchDynamicStreamIndex(level);
      }
    }

    private function getState():String {
      return playbackState;
    }

    private function getPosition():Number {
      if (isLive) return 1;
      return mediaPlayer.currentTime;
    }

    private function getDuration():Number {
      if (isLive) return 1;
      return mediaPlayer.duration;
    }

    private function getCurrentLevel():Number {
      return mediaPlayer.currentDynamicStreamIndex;
    }

    private function getNumLevels():Number {
      return mediaPlayer.numDynamicStreams;
    }

    private function getBitrateForLevel(i:Number):Number {
      return mediaPlayer.getBitrateForDynamicStreamIndex(i);
    }

    private function isDynamicStream():Boolean {
      return mediaPlayer.isDynamicStream;
    }

    private function isAutoSwitchLevels():Boolean {
      return mediaPlayer.autoDynamicStreamSwitch;
    }

    private function onTimeUpdated(event:TimeEvent):void {
      _triggerEvent('progress');
      _triggerEvent('timeupdate');
    }

    private function onFinish(event:TimeEvent):void {
      mediaPlayer.stop();
      _changeStateAndNotify('ENDED')
    }

    protected function _onStageResize(event : Event) : void {
      mediaContainer.width = stage.stageWidth;
      mediaContainer.height = stage.stageHeight;
    }

    private function _triggerEvent(name: String):void {
      ExternalInterface.call('Clappr.Mediator.trigger("' + playbackId + ':' + name +'")');
    }

    private function debugLog(msg:String):void {
      CONFIG::LOGGING {
        if (logger != null) {
          logger.info(msg);
        }
      }
    }

    private function _changeStateAndNotify(state: String):void {
      playbackState = state;
      _triggerEvent('statechanged');
    }
  }
}

package {
  import flash.display.Sprite;
  import flash.external.ExternalInterface;
  import flash.system.Security;
  import flash.net.NetStream;
  import flash.events.*;
  import flash.utils.setTimeout;
  import flash.display.StageAlign;

  import org.osmf.containers.MediaContainer;
  import org.osmf.elements.VideoElement;
  import org.osmf.display.ScaleMode;
  import org.osmf.layout.LayoutMetadata;
  import org.osmf.layout.LayoutMode;
  import org.osmf.layout.HorizontalAlign;
  import org.osmf.layout.VerticalAlign;
  import flash.display.StageScaleMode;
  import flash.display.StageAlign;

  import org.osmf.net.NetStreamLoadTrait;
  import org.osmf.net.StreamingURLResource;
  import org.osmf.net.StreamType;
  import org.osmf.metadata.MetadataNamespaces

  import org.osmf.logging.Log;

  import org.osmf.media.*;
  import org.osmf.events.*;

  import org.osmf.traits.MediaTraitType;

  import org.osmf.smil.SMILPluginInfo;

  CONFIG::LOGGING {
    import logging.ExternalLoggerFactory;
    import org.osmf.logging.Logger;
    import org.osmf.logging.Log;
  }

  [SWF(width="640", height="360")]
  public class RTMP extends Sprite {
    private var playbackId:String;
    private var mediaFactory:DefaultMediaFactory;
    private var mediaContainer:MediaContainer;
    private var videoElement:VideoElement;
    private var mediaPlayer:MediaPlayer;
    private var netStream:NetStream;
    private var mediaElement:MediaElement;
    private var netStreamLoadTrait:NetStreamLoadTrait;
    private var urlResource:StreamingURLResource;
    private var playbackState:String = "IDLE";
    private var isLive:Boolean = false;
    private var useAppInstance:Boolean = false;
    private var proxyType:String = "none";

    CONFIG::LOGGING {
      private static const logInit:Boolean = initLog();
      private static const logger:Logger = org.osmf.logging.Log.getLogger("RTMP");

      private static function initLog():Boolean {
        Log.loggerFactory = new ExternalLoggerFactory();
        return true;
      }
    }

    public function RTMP() {
      Security.allowDomain('*');
      Security.allowInsecureDomain('*');

      playbackId = this.root.loaderInfo.parameters.playbackId;
      isLive = this.root.loaderInfo.parameters.playbackType == 'live';
      useAppInstance = this.root.loaderInfo.parameters.useAppInstance == 'true';
      proxyType = this.root.loaderInfo.parameters.proxyType;
      mediaFactory = new DefaultMediaFactory();
      mediaContainer = new MediaContainer();

      //set mediaContainer layout
      mediaContainer.clipChildren = true;
      mediaContainer.layoutMetadata.percentWidth = 100;
      mediaContainer.layoutMetadata.percentHeight = 100;
      mediaContainer.width = stage.stageWidth;
      mediaContainer.height = stage.stageHeight;

      stage.align = StageAlign.TOP;
      stage.scaleMode = StageScaleMode.NO_SCALE; //We handle scaling ourselves

      stage.addEventListener(Event.RESIZE, _onStageResize);

      setupCallbacks();
      setupGetters();

      _triggerEvent('flashready');

      stage.scaleMode = StageScaleMode.NO_SCALE;
      stage.align = StageAlign.TOP_LEFT;

      if (stage) {
        resize();
      } else {
        addEventListener(Event.ADDED_TO_STAGE, resize);
      }

      stage.addEventListener(Event.RESIZE, resize);
    }

    private function resize(e:Event = null):void {
      if(mediaElement && mediaContainer && stage){
        mediaContainer.width = stage.stageWidth;
        mediaContainer.height = stage.stageHeight;
        setScaleMode(mediaElement, stage.stageWidth, stage.stageHeight);
      }
    }

    private function setupCallbacks():void {
      ExternalInterface.addCallback("playerPlay", playerPlay);
      ExternalInterface.addCallback("playerResume", playerPlay);
      ExternalInterface.addCallback("playerPause", playerPause);
      ExternalInterface.addCallback("playerStop", playerStop);
      ExternalInterface.addCallback("playerSeek", playerSeek);
      ExternalInterface.addCallback("playerVolume", playerVolume);
      ExternalInterface.addCallback("playerScaling", playerScaling);
      ExternalInterface.addCallback("setLevel", setLevel);
    }

    private function setupGetters():void {
      ExternalInterface.addCallback("getState", getState);
      ExternalInterface.addCallback("getPosition", getPosition);
      ExternalInterface.addCallback("getDuration", getDuration);
      ExternalInterface.addCallback("getCurrentLevel", getCurrentLevel);
      ExternalInterface.addCallback("getBytesLoaded", getBytesLoaded);
      ExternalInterface.addCallback("getBytesTotal", getBytesTotal);
      ExternalInterface.addCallback("getNumLevels", getNumLevels);
      ExternalInterface.addCallback("getBitrateForLevel", getBitrateForLevel);
      ExternalInterface.addCallback("isDynamicStream", isDynamicStream);
      ExternalInterface.addCallback("isAutoSwitchLevels", isAutoSwitchLevels);
    }

    private function getBytesTotal():Number {
      if (netStream) {
        return netStream.bytesTotal;
      }
      else {
          return 0;
      }
    }
    private function getBytesLoaded():Number {
        if (netStream) {
          return netStream.bytesLoaded;
        }
        else {
            return 0;
        }
    }

    private function onTraitAdd(event:MediaElementEvent):void {
      if (mediaElement.hasTrait(MediaTraitType.LOAD)) {
        netStreamLoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as NetStreamLoadTrait;
        netStreamLoadTrait.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoaded);
      }
    }

    private function onLoaded(event:LoadEvent):void {
      _triggerEvent("onloaded")
      netStream = netStreamLoadTrait.netStream;
      netStream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
      mediaPlayer.play();
    }

    private function netStatusHandler(event:NetStatusEvent):void {
      if (playbackState == "ENDED") {
        return;
      } else if (event.info.code == "NetStream.Buffer.Full") {
        _changeStateAndNotify('PLAYING');
      } else if (event.info.code == "NetStream.Buffer.Empty" || event.info.code == "NetStream.Seek.Notify") {
        _changeStateAndNotify('PLAYING_BUFFERING');
      }
    }

    private function setScaleMode(mediaElement:MediaElement, width:Number, height:Number):void {
      var layout:LayoutMetadata = new LayoutMetadata();
      layout.width  = width;
      layout.height = height;
      layout.layoutMode = LayoutMode.HORIZONTAL;
      layout.horizontalAlign = HorizontalAlign.CENTER;
      layout.verticalAlign = VerticalAlign.MIDDLE;
      layout.scaleMode = ScaleMode.LETTERBOX;

      mediaElement.removeMetadata(LayoutMetadata.LAYOUT_NAMESPACE);
      mediaElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout);
    }

    private function playerPlay(url:String=null):void {
      try {
        if (!mediaElement) {
          var streamType:String = (isLive ? StreamType.LIVE : StreamType.RECORDED);

          urlResource = new StreamingURLResource(url, streamType, NaN, NaN, null, useAppInstance, null, proxyType);

          var startLevel:int = int(this.root.loaderInfo.parameters.startLevel);

          if (this.root.loaderInfo.parameters.switchRules != "") {
            var switchRules:Object = JSON.parse(this.root.loaderInfo.parameters.switchRules.replace(/&quote;/g, '"'));
            urlResource.addMetadataValue(MetadataNamespaces.RESOURCE_INITIAL_SWITCH_RULES, switchRules);
          }

          if (startLevel > -1) {
            urlResource.addMetadataValue(MetadataNamespaces.RESOURCE_INITIAL_INDEX, startLevel);
          }

          var pluginResource:MediaResourceBase = new PluginInfoResource(new SMILPluginInfo());

          // Load the plugin.
          mediaFactory.loadPlugin(pluginResource);

          //create new MediaPlayer - it controls your media provided in media property
          mediaPlayer = new MediaPlayer();

          mediaPlayer.bufferTime = this.root.loaderInfo.parameters.bufferTime;
          mediaPlayer.autoPlay = false;
          mediaPlayer.autoDynamicStreamSwitch = this.root.loaderInfo.parameters.autoSwitch == 'true';
          mediaPlayer.addEventListener(TimeEvent.CURRENT_TIME_CHANGE, onTimeUpdated);
          mediaPlayer.addEventListener(TimeEvent.DURATION_CHANGE, onTimeUpdated);
          mediaPlayer.addEventListener(TimeEvent.COMPLETE, onFinish);
          mediaPlayer.addEventListener(MediaErrorEvent.MEDIA_ERROR, onMediaError);
          mediaPlayer.addEventListener(DynamicStreamEvent.SWITCHING_CHANGE, onLevelSwitching);

          mediaElement = mediaFactory.createMediaElement(urlResource);
          mediaElement.addEventListener(MediaElementEvent.TRAIT_ADD, onTraitAdd);

          mediaContainer.addMediaElement(mediaElement);

          mediaPlayer.media = mediaElement;

          //Set the player scaling
          playerScaling(this.root.loaderInfo.parameters.scaling);

          addChild(mediaContainer);
          resize();

          _changeStateAndNotify('PLAYING_BUFFERING')
          _triggerEvent('playbackready');
        } else {
          mediaPlayer.play();
          _changeStateAndNotify('PLAYING')
        }
      } catch (err:Error) {
        debugLog('Catch error: ' + err.messsage);
        _changeStateAndNotify('ERROR')
      }
    }

    private function onLevelSwitching(event:DynamicStreamEvent):void {
      if (event.switching) {
        _triggerEvent('levelChanging');
      }
      else {
        _triggerEvent('levelChanged');
      }
    }

    private function onMediaError(event:MediaErrorEvent):void {
      debugLog("MediaPlayer error: " + event.toString());
    }

    private function playerPause():void {
      mediaPlayer.pause();
      _changeStateAndNotify('PAUSED')
    }

    private function playerSeek(seconds:Number):void {
      mediaPlayer.seek(seconds);
    }

    private function playerStop():void {
      mediaPlayer.stop();
      _changeStateAndNotify('IDLE')
    }

    private function playerVolume(level:Number):void {
      mediaPlayer.volume = level/100;
    }

    private function playerScaling(scaling: String):void {
      if(!mediaElement) return;

      //layoutMetadata needs to be added to the mediaElement depicting what scaling the video should have
      var layoutMetadata:LayoutMetadata = new LayoutMetadata();
      layoutMetadata.percentWidth = 100;
      layoutMetadata.percentHeight = 100;

      //The following is required for correct alignment in letterbox scaling
      layoutMetadata.layoutMode = LayoutMode.HORIZONTAL
      layoutMetadata.horizontalAlign = HorizontalAlign.CENTER;
      layoutMetadata.verticalAlign = VerticalAlign.TOP;

      switch(scaling){
       case 'stretch':
         layoutMetadata.scaleMode = ScaleMode.STRETCH;
         break;
       case 'zoom':
         layoutMetadata.scaleMode = ScaleMode.ZOOM;
         break;
       case 'none':
         layoutMetadata.scaleMode = ScaleMode.NONE;
         break;
       //Letterbox is the default scale mode
       case 'letterbox':
       default:
         layoutMetadata.scaleMode = ScaleMode.LETTERBOX;
         break;
      }

      //Assign layoutMetadata to mediaElement
      mediaElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutMetadata);
    }

    private function setLevel(level:int):void {
      if (level == -1) {
        mediaPlayer.autoDynamicStreamSwitch = true;
      }
      else {
        mediaPlayer.autoDynamicStreamSwitch = false;
        mediaPlayer.switchDynamicStreamIndex(level);
      }
    }

    private function getState():String {
      return playbackState;
    }

    private function getPosition():Number {
      if (isLive) return 1;
      return mediaPlayer.currentTime;
    }

    private function getDuration():Number {
      if (isLive) return 1;
      return mediaPlayer.duration;
    }

    private function getCurrentLevel():Number {
      return mediaPlayer.currentDynamicStreamIndex;
    }

    private function getNumLevels():Number {
      return mediaPlayer.numDynamicStreams;
    }

    private function getBitrateForLevel(i:Number):Number {
      return mediaPlayer.getBitrateForDynamicStreamIndex(i);
    }

    private function isDynamicStream():Boolean {
      return mediaPlayer.isDynamicStream;
    }

    private function isAutoSwitchLevels():Boolean {
      return mediaPlayer.autoDynamicStreamSwitch;
    }

    private function onTimeUpdated(event:TimeEvent):void {
      _triggerEvent('progress');
      _triggerEvent('timeupdate');
    }

    private function onFinish(event:TimeEvent):void {
      mediaPlayer.stop();
      _changeStateAndNotify('ENDED')
    }

    protected function _onStageResize(event : Event) : void {
      mediaContainer.width = stage.stageWidth;
      mediaContainer.height = stage.stageHeight;
    }

    private function _triggerEvent(name: String):void {
      ExternalInterface.call('Clappr.Mediator.trigger("' + playbackId + ':' + name +'")');
    }

    private function debugLog(msg:String):void {
      CONFIG::LOGGING {
        if (logger != null) {
          logger.info(msg);
        }
        ExternalInterface.call('ClapprRTMPLog("[debug] ' + msg + '")');
      }
    }

    private function _changeStateAndNotify(state: String):void {
      playbackState = state;
      _triggerEvent('statechanged');
      ExternalInterface.call('ClapprRTMPLog("state changed to ' + state + '")');
    }
  }
}

add external logging information for debugging


package aerys.minko.scene.controller.debug
{
	import aerys.minko.render.geometry.primitive.CubeGeometry;
	import aerys.minko.render.geometry.stream.iterator.VertexIterator;
	import aerys.minko.render.geometry.stream.iterator.VertexReference;
	import aerys.minko.render.material.Material;
	import aerys.minko.render.material.basic.BasicMaterial;
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.node.Mesh;
	import aerys.minko.type.enum.Blending;
	import aerys.minko.type.math.Vector4;

	public final class VertexNormalsDebugController extends AbstractController
	{
		private var _vertexNormalMaterial	: Material;

		public function VertexNormalsDebugController()
		{
			super(Mesh);

			initialize();
		}

		private function initialize() : void
		{
			var vertexNormalBasicMaterial : Material = new BasicMaterial({
				diffuseColor 	: 0xffff007f,
				blending		: Blending.ALPHA
			});

			_vertexNormalMaterial = vertexNormalBasicMaterial;

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

		private function targetAddedHandler(ctrl	: VertexPositionsDebugController,
											target	: Mesh) : void
		{
			var vertices : VertexIterator = new VertexIterator(target.geometry.getVertexStream(0));

			for each (var vertex : VertexReference in vertices)
			{
				var normal : Mesh = new Mesh(
					CubeGeometry.cubeGeometry, _vertexNormalMaterial, '__normal__'
				);

				normal.transform
					.orientTo(
						new Vector4(vertex.nx, vertex.ny, vertex.nz),
						new Vector4(vertex.x, vertex.y, vertex.z)
					)
					.prependTranslation(0., 0., 0.05)
					.prependScale(0.01, 0.01, 0.1)

				target.parent.addChild(normal);
			}
		}

		private function targetRemovedHandler(ctrl		: VertexPositionsDebugController,
											  target	: Mesh) : void
		{
			for each (var position : Mesh in target.parent.get("/mesh[name='__normal__']"))
			position.parent = null;
		}
	}
}

package aerys.minko.scene.controller.debug
{
	import aerys.minko.render.geometry.primitive.CubeGeometry;
	import aerys.minko.render.geometry.stream.iterator.VertexIterator;
	import aerys.minko.render.geometry.stream.iterator.VertexReference;
	import aerys.minko.render.material.Material;
	import aerys.minko.render.material.basic.BasicMaterial;
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.node.Mesh;
	import aerys.minko.type.enum.Blending;
	import aerys.minko.type.math.Vector4;

	public final class VertexNormalsDebugController extends AbstractController
	{
		private var _vertexNormalMaterial	: Material;

		public function VertexNormalsDebugController(vertexNormalMaterial : Material = null)
		{
			super(Mesh);

			initialize(vertexNormalMaterial);
		}

		private function initialize(vertexNormalMaterial : Material) : void
		{
			_vertexNormalMaterial = vertexNormalMaterial;
			if (!_vertexNormalMaterial)
			{
				_vertexNormalMaterial = new BasicMaterial({
					diffuseColor 	: 0xffff007f,
					blending		: Blending.ALPHA
				});
			}

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

		private function targetAddedHandler(ctrl	: VertexPositionsDebugController,
											target	: Mesh) : void
		{
			var vertices : VertexIterator = new VertexIterator(target.geometry.getVertexStream(0));

			for each (var vertex : VertexReference in vertices)
			{
				var normal : Mesh = new Mesh(
					CubeGeometry.cubeGeometry, _vertexNormalMaterial, '__normal__'
				);

				normal.transform
					.orientTo(
						new Vector4(vertex.nx, vertex.ny, vertex.nz),
						new Vector4(vertex.x, vertex.y, vertex.z)
					)
					.prependTranslation(0., 0., 0.05)
					.prependScale(0.01, 0.01, 0.1)

				target.parent.addChild(normal);
			}
		}

		private function targetRemovedHandler(ctrl		: VertexPositionsDebugController,
											  target	: Mesh) : void
		{
			for each (var position : Mesh in target.parent.get("/mesh[name='__normal__']"))
			position.parent = null;
		}
	}
}

add optional material argument for the VertexNormalsDebugController


package battlecode.client.viewer.render {
    import battlecode.client.viewer.MatchController;
    import battlecode.common.MapLocation;
    import battlecode.common.Team;
    import battlecode.common.TerrainTile;
    import battlecode.events.MatchEvent;
    import battlecode.world.GameMap;

    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.ColorTransform;
    import flash.geom.Rectangle;

    import mx.containers.Canvas;
    import mx.core.UIComponent;

    public class DrawMap extends Canvas {
        private var controller:MatchController;
        private var origin:MapLocation;

        // various canvases for layering and quick toggling of features
        private var mapCanvas:UIComponent;
        private var gridCanvas:UIComponent;
        private var oreCanvas:UIComponent;
        private var groundUnitCanvas:UIComponent;

        // optimizations for caching
        private var lastRound:uint = 0;

        public function DrawMap(controller:MatchController) {
            super();

            this.controller = controller;
            this.controller.addEventListener(MatchEvent.ROUND_CHANGE, onRoundChange);
            this.controller.addEventListener(MatchEvent.MATCH_CHANGE, onMatchChange);
            this.addEventListener(Event.ENTER_FRAME, onEnterFrame);

            this.mapCanvas = new UIComponent();
            this.gridCanvas = new UIComponent();
            this.oreCanvas = new UIComponent();
            this.groundUnitCanvas = new UIComponent();

            this.mapCanvas.cacheAsBitmap = true;
            this.gridCanvas.cacheAsBitmap = true;

            this.addChild(mapCanvas);
            this.addChild(oreCanvas);
            this.addChild(gridCanvas);
            this.addChild(groundUnitCanvas);
        }

        ///////////////////////////////////////////////////////
        ////////////////// UTILITY METHODS ////////////////////
        ///////////////////////////////////////////////////////

        public function getMapWidth():uint {
            if (controller.match)
                return controller.match.getMap().getWidth() * RenderConfiguration.GRID_SIZE;
            return 0;
        }

        public function getMapHeight():uint {
            if (controller.match)
                return controller.match.getMap().getHeight() * RenderConfiguration.GRID_SIZE + 5;
            return 0;
        }

        private function getGridSize():Number {
            return RenderConfiguration.getGridSize();
        }

        ///////////////////////////////////////////////////////
        ////////////////// DRAWING METHODS ////////////////////
        ///////////////////////////////////////////////////////

        public function redrawAll():void {
            drawMap();
            drawGridlines();
            drawUnits();
            drawOre();

            var o:DrawObject;

            for each (o in controller.currentState.getGroundRobots()) {
                o.draw(true);
            }

            this.scrollRect = new Rectangle(this.mapCanvas.x, this.mapCanvas.y,
                    getMapWidth() * RenderConfiguration.getScalingFactor(),
                    getMapHeight() * RenderConfiguration.getScalingFactor());
        }

        private function drawMap():void {
            var i:uint, j:uint, tile:TerrainTile;
            var map:GameMap = controller.match.getMap();
            var terrain:Array = map.getTerrainTiles();
            var colorTransform:ColorTransform, scalar:uint;
            var g:Number = getGridSize();

            origin = map.getOrigin();

            this.mapCanvas.graphics.clear();

            // draw terrain
            for (i = 0; i < map.getHeight(); i++) {
                for (j = 0; j < map.getWidth(); j++) {
                    tile = terrain[i][j] as TerrainTile;
                    if (tile.getType() == TerrainTile.LAND) {
                        scalar = 0xFF * 0.9;
                        colorTransform = new ColorTransform(0, 0, 0, 1, scalar, scalar, scalar, 0);
                        this.mapCanvas.graphics.beginFill(colorTransform.color, 1.0);
                        this.mapCanvas.graphics.drawRect(j * g, i * g, g, g);
                        this.mapCanvas.graphics.endFill();
                    } else {
                        colorTransform = new ColorTransform(0, 0, 0, 1, 0x00, 0x00, 0x99, 0);
                        this.mapCanvas.graphics.beginFill(colorTransform.color, 1.0);
                        this.mapCanvas.graphics.drawRect(j * g, i * g, g, g);
                        this.mapCanvas.graphics.endFill();
                    }
                }
            }

            // draw void outlines
            for (i = 0; i < map.getHeight(); i++) {
                for (j = 0; j < map.getWidth(); j++) {
                    tile = terrain[i][j] as TerrainTile;
                    if (tile.getType() == TerrainTile.VOID) {
                        this.mapCanvas.graphics.lineStyle(2, 0xFFFFFF);
                        if (i > 0 && terrain[i-1][j].getType() == TerrainTile.LAND) {
                            this.mapCanvas.graphics.moveTo(j * g, i * g);
                            this.mapCanvas.graphics.lineTo((j + 1) * g, i * g);
                        }
                        if (j > 0 && terrain[i][j-1].getType() == TerrainTile.LAND) {
                            this.mapCanvas.graphics.moveTo(j * g, i * g);
                            this.mapCanvas.graphics.lineTo(j * g, (i + 1) * g);
                        }
                        if (i < getMapHeight() - 1 && terrain[i+1][j].getType() == TerrainTile.LAND) {
                            this.mapCanvas.graphics.moveTo(j * g, (i + 1) * g);
                            this.mapCanvas.graphics.lineTo((j + 1) * g, (i + 1) * g);
                        }
                        if (j < getMapWidth() - 1 && terrain[i][j+1].getType() == TerrainTile.LAND) {
                            this.mapCanvas.graphics.moveTo((j + 1) * g, i * g);
                            this.mapCanvas.graphics.lineTo((j + 1) * g, (i + 1) * g);
                        }
                        this.mapCanvas.graphics.lineStyle();
                    }
                }
            }
        }

        private function drawGridlines():void {
            var i:uint, j:uint;
            var map:GameMap = controller.match.getMap();

            this.gridCanvas.graphics.clear();
            for (i = 0; i < map.getHeight(); i++) {
                for (j = 0; j < map.getWidth(); j++) {
                    this.gridCanvas.graphics.lineStyle(.5, 0x999999, 0.3);
                    this.gridCanvas.graphics.drawRect(j * getGridSize(), i * getGridSize(), getGridSize(), getGridSize());
                }
            }
        }

        private function drawOre():void {
            var initialOre:Array = controller.match.getMap().getInitialOre();
            var terrain:Array = controller.match.getMap().getTerrainTiles();
            var oreMined:Array = controller.currentState.getOreMined();
            var i:uint, j:uint;

            this.oreCanvas.graphics.clear();
            this.oreCanvas.graphics.lineStyle();
            var g:Number = getGridSize();
            for (i = 0; i < oreMined.length; i++) {
                for (j = 0; j < oreMined[i].length; j++) {
                    var tile:TerrainTile = terrain[i][j] as TerrainTile;
                    if (tile.getType() == TerrainTile.VOID) {
                        continue;
                    }
                    var density:Number = Math.min(1, (initialOre[i][j] - oreMined[i][j]) / controller.match.getMaxInitialOre());
                    if (density <= 0) {
                        continue;
                    }
                    // green
                    //var scalarR:uint = (1 - density) * 0x99 + 0x33;
                    //var scalarG:uint = 0xFF - (1 - density) * 0x33;
                    //var scalarB:uint = (1 - density) * 0xCC;

                    // orange
                    //var scalarR:uint = 0xFF - (1 - density) * 0x33;
                    //var scalarG:uint = (1 - density) * 0x33 + 0x99;
                    //var scalarB:uint = (1 - density) * 0x99 + 0x33;

                    // purple
                    //var scalarR:uint = (1 - density) * 0x66 + 0x66;
                    //var scalarG:uint = (1 - density) * 0x33;
                    //var scalarB:uint = (1 - density) * 0x33 + 0x99;

                    // grey
                    var scalarR:uint = (1 - density) * 0x66 + 0x66;
                    var scalarG:uint = (1 - density) * 0x66 + 0x66;
                    var scalarB:uint = (1 - density) * 0x66 + 0x66;

                    var colorTransform:ColorTransform = new ColorTransform(0, 0, 0, 1, scalarR, scalarG, scalarB, 0);
                    this.oreCanvas.graphics.beginFill(colorTransform.color, 1.0);
                    this.oreCanvas.graphics.drawRect(j * getGridSize(), i * getGridSize(), getGridSize(), getGridSize());
                    this.oreCanvas.graphics.endFill();
                }
            }
        }

        private function drawUnits():void {
            var loc:MapLocation, i:uint, j:uint, robot:DrawRobot;
            var groundRobots:Object = controller.currentState.getGroundRobots();

            while (groundUnitCanvas.numChildren > 0)
                groundUnitCanvas.removeChildAt(0);

            for each (robot in groundRobots) {
                loc = robot.getLocation();
                j = (loc.getX() - origin.getX());
                i = (loc.getY() - origin.getY());
                robot.x = j * getGridSize() + getGridSize() / 2;
                robot.y = i * getGridSize() + getGridSize() / 2;
                robot.addEventListener(MouseEvent.CLICK, onRobotSelect, false, 0, true);
                groundUnitCanvas.addChild(robot);
                robot.draw();
            }
        }

        private function updateUnits():void {
            var loc:MapLocation, i:uint, j:uint, robot:DrawRobot;
            var groundRobots:Object = controller.currentState.getGroundRobots();

            for each (robot in groundRobots) {
                loc = robot.getLocation();
                j = (loc.getX() - origin.getX());
                i = (loc.getY() - origin.getY());
                robot.x = j * getGridSize() + getGridSize() / 2;
                robot.y = i * getGridSize() + getGridSize() / 2;
                if (!robot.parent && robot.isAlive()) {
                    robot.addEventListener(MouseEvent.CLICK, onRobotSelect, false, 0, true);
                    groundUnitCanvas.addChild(robot);
                }
                robot.draw();
            }
        }

        ///////////////////////////////////////////////////////
        //////////////////// EVENT HANDLERS ///////////////////
        ///////////////////////////////////////////////////////

        private function onEnterFrame(e:Event):void {
            gridCanvas.visible = RenderConfiguration.showGridlines();
            groundUnitCanvas.visible = RenderConfiguration.showGround();
            oreCanvas.visible = RenderConfiguration.showOre();
        }

        private function onRoundChange(e:MatchEvent):void {
            if (e.currentRound < lastRound) {
                drawUnits();
            }
            updateUnits();
            drawOre();

            lastRound = e.currentRound;

            this.visible = (e.currentRound != 0);
        }

        private function onMatchChange(e:MatchEvent):void {
            redrawAll();
        }

        private function onRobotSelect(e:MouseEvent):void {
            var x:Number, y:Number;

            if (RenderConfiguration.isTournament())
                return;

            if (controller.selectedRobot && controller.selectedRobot.parent) {
                controller.selectedRobot.setSelected(false);
                x = controller.selectedRobot.x;
                y = controller.selectedRobot.y;
                controller.selectedRobot.draw(true);
                controller.selectedRobot.x = x;
                controller.selectedRobot.y = y;
            }

            var robot:DrawRobot = e.currentTarget as DrawRobot;
            robot.setSelected(true);
            x = robot.x;
            y = robot.y;
            robot.draw(true);
            robot.x = x;
            robot.y = y;
            controller.selectedRobot = robot;
        }

    }

}

package battlecode.client.viewer.render {
    import battlecode.client.viewer.MatchController;
    import battlecode.common.MapLocation;
    import battlecode.common.Team;
    import battlecode.common.TerrainTile;
    import battlecode.events.MatchEvent;
    import battlecode.world.GameMap;

    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.ColorTransform;
    import flash.geom.Rectangle;

    import mx.containers.Canvas;
    import mx.core.UIComponent;

    public class DrawMap extends Canvas {
        private var controller:MatchController;
        private var origin:MapLocation;

        // various canvases for layering and quick toggling of features
        private var mapCanvas:UIComponent;
        private var gridCanvas:UIComponent;
        private var oreCanvas:UIComponent;
        private var groundUnitCanvas:UIComponent;

        // optimizations for caching
        private var lastRound:uint = 0;

        public function DrawMap(controller:MatchController) {
            super();

            this.controller = controller;
            this.controller.addEventListener(MatchEvent.ROUND_CHANGE, onRoundChange);
            this.controller.addEventListener(MatchEvent.MATCH_CHANGE, onMatchChange);
            this.addEventListener(Event.ENTER_FRAME, onEnterFrame);

            this.mapCanvas = new UIComponent();
            this.gridCanvas = new UIComponent();
            this.oreCanvas = new UIComponent();
            this.groundUnitCanvas = new UIComponent();

            this.mapCanvas.cacheAsBitmap = true;
            this.gridCanvas.cacheAsBitmap = true;

            this.addChild(mapCanvas);
            this.addChild(oreCanvas);
            this.addChild(gridCanvas);
            this.addChild(groundUnitCanvas);
        }

        ///////////////////////////////////////////////////////
        ////////////////// UTILITY METHODS ////////////////////
        ///////////////////////////////////////////////////////

        public function getMapWidth():uint {
            if (controller.match)
                return controller.match.getMap().getWidth() * RenderConfiguration.GRID_SIZE;
            return 0;
        }

        public function getMapHeight():uint {
            if (controller.match)
                return controller.match.getMap().getHeight() * RenderConfiguration.GRID_SIZE + 5;
            return 0;
        }

        private function getGridSize():Number {
            return RenderConfiguration.getGridSize();
        }

        ///////////////////////////////////////////////////////
        ////////////////// DRAWING METHODS ////////////////////
        ///////////////////////////////////////////////////////

        public function redrawAll():void {
            drawMap();
            drawGridlines();
            drawUnits();
            drawOre();

            var o:DrawObject;

            for each (o in controller.currentState.getGroundRobots()) {
                o.draw(true);
            }

            this.scrollRect = new Rectangle(this.mapCanvas.x, this.mapCanvas.y,
                    getMapWidth() * RenderConfiguration.getScalingFactor(),
                    getMapHeight() * RenderConfiguration.getScalingFactor());
        }

        private function drawMap():void {
            var i:uint, j:uint, tile:TerrainTile;
            var map:GameMap = controller.match.getMap();
            var terrain:Array = map.getTerrainTiles();
            var colorTransform:ColorTransform, scalar:uint;
            var g:Number = getGridSize();

            origin = map.getOrigin();

            this.mapCanvas.graphics.clear();

            // draw terrain
            for (i = 0; i < map.getHeight(); i++) {
                for (j = 0; j < map.getWidth(); j++) {
                    tile = terrain[i][j] as TerrainTile;
                    if (tile.getType() == TerrainTile.LAND) {
                        scalar = 0xFF * 0.9;
                        colorTransform = new ColorTransform(0, 0, 0, 1, scalar, scalar, scalar, 0);
                        this.mapCanvas.graphics.beginFill(colorTransform.color, 1.0);
                        this.mapCanvas.graphics.drawRect(j * g, i * g, g, g);
                        this.mapCanvas.graphics.endFill();
                    } else {
                        colorTransform = new ColorTransform(0, 0, 0, 1, 0x00, 0x00, 0x99, 0);
                        this.mapCanvas.graphics.beginFill(colorTransform.color, 1.0);
                        this.mapCanvas.graphics.drawRect(j * g, i * g, g, g);
                        this.mapCanvas.graphics.endFill();
                    }
                }
            }

            // draw void outlines
            for (i = 0; i < map.getHeight(); i++) {
                for (j = 0; j < map.getWidth(); j++) {
                    tile = terrain[i][j] as TerrainTile;
                    if (tile.getType() == TerrainTile.VOID) {
                        this.mapCanvas.graphics.lineStyle(2, 0xFFFFFF);
                        if (i > 0 && terrain[i-1][j].getType() == TerrainTile.LAND) {
                            this.mapCanvas.graphics.moveTo(j * g, i * g);
                            this.mapCanvas.graphics.lineTo((j + 1) * g, i * g);
                        }
                        if (j > 0 && terrain[i][j-1].getType() == TerrainTile.LAND) {
                            this.mapCanvas.graphics.moveTo(j * g, i * g);
                            this.mapCanvas.graphics.lineTo(j * g, (i + 1) * g);
                        }
                        if (i < map.getHeight() - 1 && terrain[i+1][j].getType() == TerrainTile.LAND) {
                            this.mapCanvas.graphics.moveTo(j * g, (i + 1) * g);
                            this.mapCanvas.graphics.lineTo((j + 1) * g, (i + 1) * g);
                        }
                        if (j < map.getWidth() - 1 && terrain[i][j+1].getType() == TerrainTile.LAND) {
                            this.mapCanvas.graphics.moveTo((j + 1) * g, i * g);
                            this.mapCanvas.graphics.lineTo((j + 1) * g, (i + 1) * g);
                        }
                        this.mapCanvas.graphics.lineStyle();
                    }
                }
            }
        }

        private function drawGridlines():void {
            var i:uint, j:uint;
            var map:GameMap = controller.match.getMap();

            this.gridCanvas.graphics.clear();
            for (i = 0; i < map.getHeight(); i++) {
                for (j = 0; j < map.getWidth(); j++) {
                    this.gridCanvas.graphics.lineStyle(.5, 0x999999, 0.3);
                    this.gridCanvas.graphics.drawRect(j * getGridSize(), i * getGridSize(), getGridSize(), getGridSize());
                }
            }
        }

        private function drawOre():void {
            var initialOre:Array = controller.match.getMap().getInitialOre();
            var terrain:Array = controller.match.getMap().getTerrainTiles();
            var oreMined:Array = controller.currentState.getOreMined();
            var i:uint, j:uint;

            this.oreCanvas.graphics.clear();
            this.oreCanvas.graphics.lineStyle();
            var g:Number = getGridSize();
            for (i = 0; i < oreMined.length; i++) {
                for (j = 0; j < oreMined[i].length; j++) {
                    var tile:TerrainTile = terrain[i][j] as TerrainTile;
                    if (tile.getType() == TerrainTile.VOID) {
                        continue;
                    }
                    var density:Number = Math.min(1, (initialOre[i][j] - oreMined[i][j]) / controller.match.getMaxInitialOre());
                    if (density <= 0) {
                        continue;
                    }
                    // green
                    //var scalarR:uint = (1 - density) * 0x99 + 0x33;
                    //var scalarG:uint = 0xFF - (1 - density) * 0x33;
                    //var scalarB:uint = (1 - density) * 0xCC;

                    // orange
                    //var scalarR:uint = 0xFF - (1 - density) * 0x33;
                    //var scalarG:uint = (1 - density) * 0x33 + 0x99;
                    //var scalarB:uint = (1 - density) * 0x99 + 0x33;

                    // purple
                    //var scalarR:uint = (1 - density) * 0x66 + 0x66;
                    //var scalarG:uint = (1 - density) * 0x33;
                    //var scalarB:uint = (1 - density) * 0x33 + 0x99;

                    // grey
                    var scalarR:uint = (1 - density) * 0x66 + 0x66;
                    var scalarG:uint = (1 - density) * 0x66 + 0x66;
                    var scalarB:uint = (1 - density) * 0x66 + 0x66;

                    var colorTransform:ColorTransform = new ColorTransform(0, 0, 0, 1, scalarR, scalarG, scalarB, 0);
                    this.oreCanvas.graphics.beginFill(colorTransform.color, 1.0);
                    this.oreCanvas.graphics.drawRect(j * getGridSize(), i * getGridSize(), getGridSize(), getGridSize());
                    this.oreCanvas.graphics.endFill();
                }
            }
        }

        private function drawUnits():void {
            var loc:MapLocation, i:uint, j:uint, robot:DrawRobot;
            var groundRobots:Object = controller.currentState.getGroundRobots();

            while (groundUnitCanvas.numChildren > 0)
                groundUnitCanvas.removeChildAt(0);

            for each (robot in groundRobots) {
                loc = robot.getLocation();
                j = (loc.getX() - origin.getX());
                i = (loc.getY() - origin.getY());
                robot.x = j * getGridSize() + getGridSize() / 2;
                robot.y = i * getGridSize() + getGridSize() / 2;
                robot.addEventListener(MouseEvent.CLICK, onRobotSelect, false, 0, true);
                groundUnitCanvas.addChild(robot);
                robot.draw();
            }
        }

        private function updateUnits():void {
            var loc:MapLocation, i:uint, j:uint, robot:DrawRobot;
            var groundRobots:Object = controller.currentState.getGroundRobots();

            for each (robot in groundRobots) {
                loc = robot.getLocation();
                j = (loc.getX() - origin.getX());
                i = (loc.getY() - origin.getY());
                robot.x = j * getGridSize() + getGridSize() / 2;
                robot.y = i * getGridSize() + getGridSize() / 2;
                if (!robot.parent && robot.isAlive()) {
                    robot.addEventListener(MouseEvent.CLICK, onRobotSelect, false, 0, true);
                    groundUnitCanvas.addChild(robot);
                }
                robot.draw();
            }
        }

        ///////////////////////////////////////////////////////
        //////////////////// EVENT HANDLERS ///////////////////
        ///////////////////////////////////////////////////////

        private function onEnterFrame(e:Event):void {
            gridCanvas.visible = RenderConfiguration.showGridlines();
            groundUnitCanvas.visible = RenderConfiguration.showGround();
            oreCanvas.visible = RenderConfiguration.showOre();
        }

        private function onRoundChange(e:MatchEvent):void {
            if (e.currentRound < lastRound) {
                drawUnits();
            }
            updateUnits();
            drawOre();

            lastRound = e.currentRound;

            this.visible = (e.currentRound != 0);
        }

        private function onMatchChange(e:MatchEvent):void {
            redrawAll();
        }

        private function onRobotSelect(e:MouseEvent):void {
            var x:Number, y:Number;

            if (RenderConfiguration.isTournament())
                return;

            if (controller.selectedRobot && controller.selectedRobot.parent) {
                controller.selectedRobot.setSelected(false);
                x = controller.selectedRobot.x;
                y = controller.selectedRobot.y;
                controller.selectedRobot.draw(true);
                controller.selectedRobot.x = x;
                controller.selectedRobot.y = y;
            }

            var robot:DrawRobot = e.currentTarget as DrawRobot;
            robot.setSelected(true);
            x = robot.x;
            y = robot.y;
            robot.draw(true);
            robot.x = x;
            robot.y = y;
            controller.selectedRobot = robot;
        }

    }

}

fix void outline drawing

fix void outline drawing


package stdio {
  import flash.display.*
  import flash.events.*
  import flash.utils.*
  import flash.net.*

  public class StandardProcess implements Process {
    private const buffered_stdin: BufferedStream = new BufferedStream
    private const stdin_socket: SocketStream = new SocketStream
    private const readline_socket: SocketStream = new SocketStream

    private const stdout_socket: SocketStream = new SocketStream
    private const stderr_socket: SocketStream = new SocketStream

    private var _env: Object
    private var _prompt: String = "> "

    public function StandardProcess(env: Object) {
      _env = env
    }

    public function initialize(callback: Function): void {
      if (available) {
        connect(callback)
      } else {
        callback()
      }
    }

    public function get available(): Boolean {
      return env["stdio.enabled"]
    }

    private function get http_url(): String {
      return env["stdio.http"]
    }

    private function get interactive(): Boolean {
      return env["stdio.interactive"] === "true"
    }

    private function connect(callback: Function): void {
      stdin_socket.onopen = onopen
      readline_socket.onopen = onopen
      stdout_socket.onopen = onopen
      stderr_socket.onopen = onopen

      var n: int = 0

      function onopen(): void {
        if (++n === 3) {
          callback()
        }
      }

      stdin_socket.ondata = buffered_stdin.write
      stdin_socket.onclose = buffered_stdin.close
      readline_socket.ondata = buffered_stdin.write
      readline_socket.onclose = buffered_stdin.close

      const stdin_port: int = get_int("stdio.in")
      const readline_port: int = get_int("stdio.readline")

      if (interactive) {
        readline_socket.connect("localhost", readline_port)
      } else {
        stdin_socket.connect("localhost", stdin_port)
      }

      const stdout_port: int = get_int("stdio.out")
      const stderr_port: int = get_int("stdio.err")

      stdout_socket.connect("localhost", stdout_port)
      stderr_socket.connect("localhost", stderr_port)

      function get_int(name: String): int {
        return parseInt(env[name])
      }
    }

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

    public function get env(): * {
      return _env
    }

    public function get argv(): Array {
      if (env["stdio.argv"] === "") {
        return []
      } else {
        return env["stdio.argv"].split(" ").map(
          function (argument: String, ...rest: Array): String {
            return decodeURIComponent(argument)
          }
        )
      }
    }

    public function puts(value: *): void {
      if (available) {
        if (interactive) {
          readline_socket.puts("!" + value)
        } else {
          stdout.puts(value)
        }
      } else {
        debug.show("puts: " + value)
      }
    }

    public function warn(value: *): void {
      if (available) {
        stderr.puts(value)
      } else {
        debug.show("warn: " + value)
      }
    }

    public function die(value: *): void {
      if (available) {
        warn(value); exit(-1)
      } else {
        throw new Error("fatal error: " + String(value))
      }
    }

    public function style(styles: String, string: String): String {
      const codes: Object = {
        none: 0, bold: 1, italic: 3, underline: 4, inverse: 7,
        black: 30, red: 31, green: 32, yellow: 33, blue: 34,
        magenta: 35, cyan: 36, white: 37, gray: 90, grey: 90
      }

      if (styles === "") {
        return string
      } else {
        return styles.split(/\s+/).map(
          function (style: String, ...rest: Array): String {
            if (style in codes) {
              return escape_sequence(codes[style])
            } else {
              throw new Error("style not supported: " + style)
            }
          }
        ).join("") + string + escape_sequence(0)
      }

      function escape_sequence(code: int): String {
        return "\x1b[" + code + "m"
      }
    }

    public function gets(callback: Function): void {
      if (available) {
        if (interactive) {
          readline_socket.puts("?" + _prompt)
        }

        stdin.gets(callback)
      } else {
        callback(null)
      }
    }

    public function set prompt(value: String): void {
      _prompt = value
    }

    public function get stdin(): InputStream {
      return buffered_stdin
    }

    public function get stdout(): OutputStream {
      return stdout_socket
    }

    public function get stderr(): OutputStream {
      return stderr_socket
    }

    public function handle(error: *): void {
      if (error is UncaughtErrorEvent) {
        UncaughtErrorEvent(error).preventDefault()
        handle(UncaughtErrorEvent(error).error)
        die("run-swf: uncaught error")
      } else if (error is Error) {
        // Important: Avoid the `Error(x)` casting syntax.
        http_post("/error", (error as Error).getStackTrace())
      } else if (error is ErrorEvent) {
        http_post("/error", (error as ErrorEvent).text)
      } else {
        http_post("/error", String(error))
      }
    }

    private function shell_quote(word: String): String {
      if (/^[-=.,\w]+$/.test(word)) {
        return word
      } else {
        return "'" + word.replace(/'/g, "'\\''") + "'"
      }
    }

    public function shell(
      command: *,
      callback: Function,
      errback: Function = null
    ): void {
      if (available) {
        if (command is Array) {
          command = command.map(
            function (word: String, ...rest: Array): String {
              return shell_quote(word)
            }
          ).join(" ")
        }

        http_post("/shell", command, function (data: String): void {
          const result: XML = new XML(data)
          const status: int = result.@status
          const stdout: String = result.stdout.text()
          const stderr: String = result.stderr.text()

          if (status === 0) {
            if (callback.length === 1) {
              callback(stdout)
            } else {
              callback(stdout, stderr)
            }
          } else if (errback === null) {
            warn(stderr)
          } else if (errback.length === 1) {
            errback(status)
          } else if (errback.length === 2) {
            errback(status, stderr)
          } else {
            errback(status, stderr, stdout)
          }
        })
      } else {
        throw new Error("cannot execute command: process not available")
      }
    }

    public function exit(status: int = 0): void {
      if (available) {
        when_ready(function (): void {
          http_post("/exit", String(status))
        })
      } else {
        throw new Error("cannot exit: process not available")
      }
    }

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

    private var n_pending_requests: int = 0
    private var ready_callbacks: Array = []

    private function when_ready(callback: Function): void {
      if (n_pending_requests === 0) {
        callback()
      } else {
        ready_callbacks.push(callback)
      }
    }

    private function handle_ready(): void {
      for each (var callback: Function in ready_callbacks) {
        callback()
      }

      ready_callbacks = []
    }

    private function http_post(
      path: String, content: String, callback: Function = null
    ): void {
      const request: URLRequest = new URLRequest(http_url + path)

      request.method = "POST"
      request.data = content

      const loader: URLLoader = new URLLoader

      ++n_pending_requests

      loader.addEventListener(
        Event.COMPLETE,
        function (event: Event): void {
          if (callback !== null) {
            callback(loader.data)
          }

          if (--n_pending_requests === 0) {
            handle_ready()
          }
        }
      )

      loader.load(request)
    }
  }
}

package stdio {
  import flash.display.*
  import flash.events.*
  import flash.utils.*
  import flash.net.*

  public class StandardProcess implements Process {
    private const buffered_stdin: BufferedStream = new BufferedStream
    private const stdin_socket: SocketStream = new SocketStream
    private const readline_socket: SocketStream = new SocketStream

    private const stdout_socket: SocketStream = new SocketStream
    private const stderr_socket: SocketStream = new SocketStream

    private var _env: Object
    private var _prompt: String = "> "

    public function StandardProcess(env: Object) {
      _env = env
    }

    public function initialize(callback: Function): void {
      if (available) {
        connect(callback)
      } else {
        callback()
      }
    }

    public function get available(): Boolean {
      return env["stdio.enabled"]
    }

    private function get http_url(): String {
      return env["stdio.http"]
    }

    private function get interactive(): Boolean {
      return env["stdio.interactive"] === "true"
    }

    private function connect(callback: Function): void {
      stdin_socket.onopen = onopen
      readline_socket.onopen = onopen
      stdout_socket.onopen = onopen
      stderr_socket.onopen = onopen

      var n: int = 0

      function onopen(): void {
        if (++n === 3) {
          callback()
        }
      }

      stdin_socket.ondata = buffered_stdin.write
      stdin_socket.onclose = buffered_stdin.close
      readline_socket.ondata = buffered_stdin.write
      readline_socket.onclose = buffered_stdin.close

      const stdin_port: int = get_int("stdio.in")
      const readline_port: int = get_int("stdio.readline")

      if (interactive) {
        readline_socket.connect("localhost", readline_port)
      } else {
        stdin_socket.connect("localhost", stdin_port)
      }

      const stdout_port: int = get_int("stdio.out")
      const stderr_port: int = get_int("stdio.err")

      stdout_socket.connect("localhost", stdout_port)
      stderr_socket.connect("localhost", stderr_port)

      function get_int(name: String): int {
        return parseInt(env[name])
      }
    }

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

    public function get env(): * {
      return _env
    }

    public function get argv(): Array {
      if (env["stdio.argv"] === "") {
        return []
      } else {
        return env["stdio.argv"].split(" ").map(
          function (argument: String, ...rest: Array): String {
            return decodeURIComponent(argument)
          }
        )
      }
    }

    public function puts(value: *): void {
      if (available) {
        if (interactive) {
          readline_socket.puts("!" + value)
        } else {
          stdout.puts(value)
        }
      } else {
        debug.show("puts: " + value)
      }
    }

    public function warn(value: *): void {
      if (available) {
        stderr.puts(value)
      } else {
        debug.show("warn: " + value)
      }
    }

    public function die(value: *): void {
      if (available) {
        warn(value); exit(-1)
      } else {
        throw new Error("fatal error: " + String(value))
      }
    }

    public function style(styles: String, string: String): String {
      const codes: Object = {
        none: 0, bold: 1, italic: 3, underline: 4, inverse: 7,
        black: 30, red: 31, green: 32, yellow: 33, blue: 34,
        magenta: 35, cyan: 36, white: 37, gray: 90, grey: 90
      }

      if (styles === "") {
        return string
      } else {
        return styles.split(/\s+/).map(
          function (style: String, ...rest: Array): String {
            if (style in codes) {
              return escape_sequence(codes[style])
            } else {
              throw new Error("style not supported: " + style)
            }
          }
        ).join("") + string + escape_sequence(0)
      }

      function escape_sequence(code: int): String {
        return "\x1b[" + code + "m"
      }
    }

    public function gets(callback: Function): void {
      if (available) {
        if (interactive) {
          readline_socket.puts("?" + _prompt)
        }

        stdin.gets(callback)
      } else {
        callback(null)
      }
    }

    public function set prompt(value: String): void {
      _prompt = value
    }

    public function get stdin(): InputStream {
      return buffered_stdin
    }

    public function get stdout(): OutputStream {
      return stdout_socket
    }

    public function get stderr(): OutputStream {
      return stderr_socket
    }

    public function handle(error: *): void {
      if (error is UncaughtErrorEvent) {
        UncaughtErrorEvent(error).preventDefault()
        handle(UncaughtErrorEvent(error).error)
        exit(-1)
      } else if (error is Error) {
        // Important: Avoid the `Error(x)` casting syntax.
        http_post("/error", (error as Error).getStackTrace())
      } else if (error is ErrorEvent) {
        http_post("/error", (error as ErrorEvent).text)
      } else {
        http_post("/error", String(error))
      }
    }

    private function shell_quote(word: String): String {
      if (/^[-=.,\w]+$/.test(word)) {
        return word
      } else {
        return "'" + word.replace(/'/g, "'\\''") + "'"
      }
    }

    public function shell(
      command: *,
      callback: Function,
      errback: Function = null
    ): void {
      if (available) {
        if (command is Array) {
          command = command.map(
            function (word: String, ...rest: Array): String {
              return shell_quote(word)
            }
          ).join(" ")
        }

        http_post("/shell", command, function (data: String): void {
          const result: XML = new XML(data)
          const status: int = result.@status
          const stdout: String = result.stdout.text()
          const stderr: String = result.stderr.text()

          if (status === 0) {
            if (callback.length === 1) {
              callback(stdout)
            } else {
              callback(stdout, stderr)
            }
          } else if (errback === null) {
            warn(stderr)
          } else if (errback.length === 1) {
            errback(status)
          } else if (errback.length === 2) {
            errback(status, stderr)
          } else {
            errback(status, stderr, stdout)
          }
        })
      } else {
        throw new Error("cannot execute command: process not available")
      }
    }

    public function exit(status: int = 0): void {
      if (available) {
        when_ready(function (): void {
          http_post("/exit", String(status))
        })
      } else {
        throw new Error("cannot exit: process not available")
      }
    }

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

    private var n_pending_requests: int = 0
    private var ready_callbacks: Array = []

    private function when_ready(callback: Function): void {
      if (n_pending_requests === 0) {
        callback()
      } else {
        ready_callbacks.push(callback)
      }
    }

    private function handle_ready(): void {
      for each (var callback: Function in ready_callbacks) {
        callback()
      }

      ready_callbacks = []
    }

    private function http_post(
      path: String, content: String, callback: Function = null
    ): void {
      const request: URLRequest = new URLRequest(http_url + path)

      request.method = "POST"
      request.data = content

      const loader: URLLoader = new URLLoader

      ++n_pending_requests

      loader.addEventListener(
        Event.COMPLETE,
        function (event: Event): void {
          if (callback !== null) {
            callback(loader.data)
          }

          if (--n_pending_requests === 0) {
            handle_ready()
          }
        }
      )

      loader.load(request)
    }
  }
}

Remove "uncaught error" notice.

Remove "uncaught error" notice.


package flash.events {

public class Event
{
    public static const CONNECT :String = "connect";
    public static const CLOSE :String = "close";
    public static const COMPLETE:String = "complete";

    public function Event (type :String, bubbles :Boolean = false, cancelable :Boolean = false)
    {
        if (bubbles || cancelable) {
            throw new Error("Not implemented");
        }
        _type = type;
    }

    public function get type () :String
    {
        return _type;
    }

    public function get target () :Object
    {
        return null;
    }

    public function clone () :Event
    {
        return new Event(_type);
    }

    private var _type :String;
}

}

package flash.events {

public class Event
{
    public static const CONNECT :String = "connect";
    public static const CLOSE :String = "close";
    public static const COMPLETE:String = "complete";
    public static const UNLOAD:String = "unload";

    public function Event (type :String, bubbles :Boolean = false, cancelable :Boolean = false)
    {
        if (bubbles || cancelable) {
            throw new Error("Not implemented");
        }
        _type = type;
    }

    public function get type () :String
    {
        return _type;
    }

    public function get target () :Object
    {
        return null;
    }

    public function clone () :Event
    {
        return new Event(_type);
    }

    private var _type :String;
}

}

Add UNLOAD.

Add UNLOAD.