package {
    import flash.display.Sprite;
    import flash.system.Security;
    import flash.net.NetConnection;
    import flash.external.ExternalInterface;
    import flash.events.Event;
    import flash.events.AsyncErrorEvent
    import flash.events.NetStatusEvent;
    import flash.events.SecurityErrorEvent;
    import flash.events.IOErrorEvent

    public class NetConnectionPolyfill extends Sprite {
        public const VERSION:String = CONFIG::version;

        private var _nc:NetConnection;

        private var _jsLogProxyName: String = "NetConnection.onFlashLog";
        private var _jsReadyProxyName: String = "NetConnection.onReady";
        private var _jsAsyncErrorEventProxyName: String = "NetConnection.onAsyncErrorEvent";
        private var _jsIOErrorEventProxyName: String = "NetConnection.onIOErrorEvent";
        private var _jsNetStatusEventProxyName: String = "NetConnection.onNetStatusEvent";
        private var _jsSecurityErrorEventProxyName: String = "NetConnection.onSecurityErrorEvent";
        private var _jsClientCallProxyName: String = "NetConnection.onClientCall";

        public function NetConnectionPolyfill() {
            log('info', 'New NetConnection instance');
            addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
        }
        private function init():void {
            Security.allowDomain("*");
            Security.allowInsecureDomain("*");

            if(ExternalInterface.available) {
                registerExternalMethods();
            }

            _nc = new NetConnection();

            _nc.addEventListener(NetStatusEvent.NET_STATUS, onNetStatusEvent);
            _nc.addEventListener(IOErrorEvent.IO_ERROR, onIOErrorEvent);
            _nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityErrorEvent);
            _nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAyncErrorEvent);

            callExternalInterface(_jsReadyProxyName);
        }

        private function registerExternalMethods():void {
            try {
                ExternalInterface.addCallback("nc_addHeader", onAddHeaderCalled);
                ExternalInterface.addCallback("nc_call", onCallCalled);
                ExternalInterface.addCallback("nc_close", onCloseCalled);
                ExternalInterface.addCallback("nc_connect", onConnectCalled);

                ExternalInterface.addCallback("nc_getProperty", onGetPropertyCalled);
                ExternalInterface.addCallback("nc_setProperty", onSetPropertyCalled);
                ExternalInterface.addCallback("nc_setClient", onSetClientCalled);

            } catch (e:Error) {
                log("error", e.message);
            } finally {}
        }

        private function onAddedToStage(event: Event):void {
            init();
            removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
        }

        private function onAyncErrorEvent(event: AsyncErrorEvent): void {
            callExternalInterface(_jsAsyncErrorEventProxyName, event.type, event.error);
        }

        private function onIOErrorEvent(event:IOErrorEvent): void {
            callExternalInterface(_jsIOErrorEventProxyName, event.type, event.text);
        }

        private function onSecurityErrorEvent(event: SecurityErrorEvent): void {
            callExternalInterface(_jsSecurityErrorEventProxyName, event.type, event.text);
        }

        private function onNetStatusEvent(event: NetStatusEvent): void {
            callExternalInterface(_jsNetStatusEventProxyName, event.type, event.info);
        }

        private function onAddHeaderCalled(opeartion: String, mustUnderstand: Boolean = false, param: Object = null):void {
            this._nc.addHeader(opeartion, mustUnderstand, param);
        }

        private function onCallCalled(command: String, ... args):void {
            try {
                log('info', 'Calling '+command);
                var __incomingArgs:* = args as Array;
                var __newArgs:Array = [command, null].concat(__incomingArgs);
                var __sanitizedArgs:Array = cleanObject(__newArgs);
                this._nc.call.apply(this._nc, __sanitizedArgs);
            } catch (e: Error) {
                log('error', e.message);
            }
        }

        private function onCloseCalled():void {
            this._nc.close();
        }

        private function onConnectCalled(command:*, ...args):void {
            log('info', 'Connecting to '+command);
            var __incomingArgs:* = args as Array;
            var __newArgs:Array = [command].concat(__incomingArgs);
            var __sanitizedArgs:Array = cleanObject(__newArgs);
            this._nc.connect.apply(this._nc, __sanitizedArgs);
        }

        private function onSetClientCalled(methods: Array):void {
            this._nc.client = new Object();
            try {
                for (var i = 0; i < methods.length; i++) {
                    var method = methods[i];
                    this._nc.client[method] = function(... args) {
                        callExternalInterface(_jsClientCallProxyName, method, args);
                    }
                }
            } catch (e: Error) {
                log('error', e.message);
            }
        }

        private function onGetPropertyCalled(pPropertyName:String = ""):* {
            if (this._nc.hasOwnProperty(pPropertyName)) {
                if (this._nc[pPropertyName] is Function) {
                    log('warning', 'It is not possible to get a function as a property');
                    return null;
                }
                return this._nc[pPropertyName];
            }
            return null;
        }

        private function onSetPropertyCalled(pPropertyName: String, value: *):void {
            switch(pPropertyName) {
                case "objectEncoding":
                    this._nc.objectEncoding = value as uint;
                    break;
                case "proxyType":
                    this._nc.proxyType = value as String;
                    break;
                case "maxPeerConnections":
                    this._nc.maxPeerConnections = value as uint;
                    break;
                default:
                    log('warning', 'Property '+pPropertyName+ ' cannot be set.');
            }
        }

        private function log(level: String, message: *):void {
            if (loaderInfo.parameters.debug != undefined && loaderInfo.parameters.debug == "true") {
                this.callExternalInterface(_jsLogProxyName, level, cleanObject(message));
            }
        }

        private function callExternalInterface(proxyName: String, ...args):void {
            if (ExternalInterface.available) {
                var __incomingArgs:* = args as Array;
                var __newArgs:Array = [proxyName, ExternalInterface.objectID].concat(__incomingArgs);
                var __sanitizedArgs:Array = cleanObject(__newArgs);
                ExternalInterface.call.apply(null, __sanitizedArgs);
            }
        }

        private function cleanObject(o:*):* {
            if (o == null) {
                return null;
            }
            if (o is String) {
                return o.split("\\").join("\\\\");
            } else if (o is Array) {
                var __sanitizedArray:Array = new Array();

                for each (var __item in o){
                    __sanitizedArray.push(cleanObject(__item));
                }

                return __sanitizedArray;
            } else if (typeof(o) == 'object') {
                var __sanitizedObject:Object = new Object();

                for (var __i in o){
                    __sanitizedObject[__i] = cleanObject(o[__i]);
                }

                return __sanitizedObject;
            } else {
                return o;
            }
        }
    }
}

package {
    import flash.display.Sprite;
    import flash.system.Security;
    import flash.net.NetConnection;
    import flash.net.Responder;
    import flash.external.ExternalInterface;
    import flash.events.Event;
    import flash.events.AsyncErrorEvent
    import flash.events.NetStatusEvent;
    import flash.events.SecurityErrorEvent;
    import flash.events.IOErrorEvent

    public class NetConnectionPolyfill extends Sprite {
        public const VERSION:String = CONFIG::version;

        private var _nc:NetConnection;

        private var _jsLogProxyName: String = "NetConnection.onFlashLog";
        private var _jsReadyProxyName: String = "NetConnection.onReady";
        private var _jsAsyncErrorEventProxyName: String = "NetConnection.onAsyncErrorEvent";
        private var _jsIOErrorEventProxyName: String = "NetConnection.onIOErrorEvent";
        private var _jsNetStatusEventProxyName: String = "NetConnection.onNetStatusEvent";
        private var _jsSecurityErrorEventProxyName: String = "NetConnection.onSecurityErrorEvent";
        private var _jsClientCallProxyName: String = "NetConnection.onClientCall";
        private var _jsClientCallResultProxyName: String = "NetConnection.onClientCallResult";

        public function NetConnectionPolyfill() {
            log('info', 'New NetConnection instance');
            addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
        }
        private function init():void {
            Security.allowDomain("*");
            Security.allowInsecureDomain("*");

            if(ExternalInterface.available) {
                registerExternalMethods();
            }

            _nc = new NetConnection();

            _nc.addEventListener(NetStatusEvent.NET_STATUS, onNetStatusEvent);
            _nc.addEventListener(IOErrorEvent.IO_ERROR, onIOErrorEvent);
            _nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityErrorEvent);
            _nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAyncErrorEvent);

            callExternalInterface(_jsReadyProxyName);
        }

        private function registerExternalMethods():void {
            try {
                ExternalInterface.addCallback("nc_addHeader", onAddHeaderCalled);
                ExternalInterface.addCallback("nc_call", onCallCalled);
                ExternalInterface.addCallback("nc_close", onCloseCalled);
                ExternalInterface.addCallback("nc_connect", onConnectCalled);

                ExternalInterface.addCallback("nc_getProperty", onGetPropertyCalled);
                ExternalInterface.addCallback("nc_setProperty", onSetPropertyCalled);
                ExternalInterface.addCallback("nc_setClient", onSetClientCalled);

            } catch (e:Error) {
                log("error", e.message);
            } finally {}
        }

        private function onAddedToStage(event: Event):void {
            init();
            removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
        }

        private function onAyncErrorEvent(event: AsyncErrorEvent): void {
            callExternalInterface(_jsAsyncErrorEventProxyName, event.type, event.error);
        }

        private function onIOErrorEvent(event:IOErrorEvent): void {
            callExternalInterface(_jsIOErrorEventProxyName, event.type, event.text);
        }

        private function onSecurityErrorEvent(event: SecurityErrorEvent): void {
            callExternalInterface(_jsSecurityErrorEventProxyName, event.type, event.text);
        }

        private function onNetStatusEvent(event: NetStatusEvent): void {
            callExternalInterface(_jsNetStatusEventProxyName, event.type, event.info);
        }

        private function onAddHeaderCalled(opeartion: String, mustUnderstand: Boolean = false, param: Object = null):void {
            this._nc.addHeader(opeartion, mustUnderstand, param);
        }

        private function onCallCalled(command: String, handlerId: String, ... args):void {
            try {
                log('info', 'Calling command: '+command);
                var responder: Responder = new Responder(function(result: Object) {
                    callExternalInterface(_jsClientCallResultProxyName, handlerId, null, cleanObject(result));
                }, function(error: Object) {
                    callExternalInterface(_jsClientCallResultProxyName, handlerId, cleanObject(error));
                });

                var __incomingArgs:* = args as Array;
                var __newArgs:Array = [command, responder].concat(cleanObject(__incomingArgs));
                this._nc.call.apply(this._nc, __newArgs);
            } catch (e: Error) {
                log('error', e.message);
            }
        }

        private function onCloseCalled():void {
            this._nc.close();
        }

        private function onConnectCalled(command:*, ...args):void {
            log('info', 'Connecting to '+command);
            var __incomingArgs:* = args as Array;
            var __newArgs:Array = [command].concat(__incomingArgs);
            var __sanitizedArgs:Array = cleanObject(__newArgs);
            this._nc.connect.apply(this._nc, __sanitizedArgs);
        }

        private function onSetClientCalled(methods: Array):void {
            var self = this;
            this._nc.client = new Object();
            try {
                for (var i = 0; i < methods.length; i++) {
                    var method = methods[i];
                    log('info', 'Creating method '+method);
                    var createMethod = function(method) {
                        var m = method;
                        return function(... args) {
                            var _incomingArgs:* = args as Array;
                            callExternalInterface.apply(self, [_jsClientCallProxyName, m].concat(_incomingArgs));
                        }
                    }
                    this._nc.client[method] = createMethod(method);
                }
            } catch (e: Error) {
                log('error', e.message);
            }
        }

        private function onGetPropertyCalled(pPropertyName:String = ""):* {
            if (this._nc.hasOwnProperty(pPropertyName)) {
                if (this._nc[pPropertyName] is Function) {
                    log('warning', 'It is not possible to get a function as a property');
                    return null;
                }
                return this._nc[pPropertyName];
            }
            return null;
        }

        private function onSetPropertyCalled(pPropertyName: String, value: *):void {
            switch(pPropertyName) {
                case "objectEncoding":
                    this._nc.objectEncoding = value as uint;
                    break;
                case "proxyType":
                    this._nc.proxyType = value as String;
                    break;
                case "maxPeerConnections":
                    this._nc.maxPeerConnections = value as uint;
                    break;
                default:
                    log('warning', 'Property '+pPropertyName+ ' cannot be set.');
            }
        }

        private function log(level: String, message: *):void {
            if (loaderInfo.parameters.debug != undefined && loaderInfo.parameters.debug == "true") {
                this.callExternalInterface(_jsLogProxyName, level, cleanObject(message));
            }
        }

        private function callExternalInterface(proxyName: String, ...args):void {
            if (ExternalInterface.available) {
                var __incomingArgs:* = args as Array;
                var __newArgs:Array = [proxyName, ExternalInterface.objectID].concat(__incomingArgs);
                var __sanitizedArgs:Array = cleanObject(__newArgs);
                ExternalInterface.call.apply(null, __sanitizedArgs);
            }
        }

        private function cleanObject(o:*):* {
            if (o == null) {
                return null;
            }
            if (o is String) {
                return o.split("\\").join("\\\\");
            } else if (o is Array) {
                var __sanitizedArray:Array = new Array();

                for each (var __item in o){
                    __sanitizedArray.push(cleanObject(__item));
                }

                return __sanitizedArray;
            } else if (typeof(o) == 'object') {
                var __sanitizedObject:Object = new Object();

                for (var __i in o){
                    __sanitizedObject[__i] = cleanObject(o[__i]);
                }

                return __sanitizedObject;
            } else {
                return o;
            }
        }
    }
}

Implement call responder

feat(call): Implement call responder

Create a new Responder when call method is invoked. The responder will call external interface with either the result or an error.

NetConnection-polyfill should implement the static method "onClientCallResult" which will receive the result of a call invoke.


// This ActionScript file defines a list of values that are considered
// important for checking various ActionScript operations.
// It defines 2 variables:
// - "values": The array of values to be checked
// - "names": The array of corresponding string representations for values.
//            It's suggested to use these instead of using values directly to
//            avoid spurious toString and valueOf calls.

printall = new Object ();
printall.valueOf = function () {
  trace ("valueOf called");
  return this;
};
printall.toString = function () {
  trace ("toString called");
  return this;
};

tostring = new Object ();
tostring.toString = function () {
  trace ("toString called with " + arguments);
  return this;
};

valueof = new Object ();
valueof.valueOf = function () {
  trace ("valueOf called with " + arguments);
  return this;
};

nothing = new Object ();
nothing.__proto__ = undefined;
values = [
  undefined,
  null,
  true, false,
  0, 1, 0.5, -1, -0.5, Infinity, -Infinity, NaN,
  "", "0", "-0", "0.0", "1", "Hello World!", "true", "_level0",
  this, new Object (), Function, printall, tostring, valueof, nothing ];

var l = values.length;
var v = function () {
  trace (this.nr + ": valueOf!");
  return this.v;
};
var s = function () {
  trace (this.nr + ": toString!");
  return this.v;
};
for (i = 0; i < l; i++) {
  var o = new Object ();
  o.nr = i;
  o.valueOf = v;
  o.toString = s;
  o.v = values[i];
  values.push (o);
};

names = [];
for (i = 0; i < values.length; i++) {
  names[i] = "(" + i + ") " + values[i] + " (" + typeof (values[i]) + ")";
};

// This ActionScript file defines a list of values that are considered
// important for checking various ActionScript operations.
// It defines 2 variables:
// - "values": The array of values to be checked
// - "names": The array of corresponding string representations for values.
//            It's suggested to use these instead of using values directly to
//            avoid spurious toString and valueOf calls.

printall = new Object ();
printall.valueOf = function () {
  trace ("valueOf called");
  return this;
};
printall.toString = function () {
  trace ("toString called");
  return this;
};

printtostring = new Object ();
printtostring.toString = function () {
  trace ("toString called with " + arguments);
  return this;
};

printvalueof = new Object ();
printvalueof.valueOf = function () {
  trace ("valueOf called with " + arguments);
  return this;
};

nothing = new Object ();
nothing.__proto__ = undefined;
values = [
  undefined,
  null,
  true, false,
  0, 1, 0.5, -1, -0.5, Infinity, -Infinity, NaN,
  "", "0", "-0", "0.0", "1", "Hello World!", "true", "_level0",
  this, new Object (), Function, printall, printtostring, printvalueof, nothing ];

var l = values.length;
var v = function () {
  trace (this.nr + ": valueOf!");
  return this.v;
};
var s = function () {
  trace (this.nr + ": toString!");
  return this.v;
};
for (i = 0; i < l; i++) {
  var o = new Object ();
  o.nr = i;
  o.valueOf = v;
  o.toString = s;
  o.v = values[i];
  values.push (o);
};

names = [];
for (i = 0; i < values.length; i++) {
  names[i] = "(" + i + ") " + values[i] + " (" + typeof (values[i]) + ")";
};

Rename valueof and tostring to printvalueof and printtostring in values.as

To avoid non-determinism with having multiple variables using different case


package com.kaltura.kdpfl
{
	import com.kaltura.kdpfl.controller.InitMacroCommand;
	import com.kaltura.kdpfl.controller.LayoutReadyCommand;
	import com.kaltura.kdpfl.controller.PlaybackCompleteCommand;
	import com.kaltura.kdpfl.controller.SequenceItemPlayEndCommand;
	import com.kaltura.kdpfl.controller.SequenceSkipNextCommand;
	import com.kaltura.kdpfl.controller.StartupCommand;
	import com.kaltura.kdpfl.controller.media.InitChangeMediaMacroCommand;
	import com.kaltura.kdpfl.controller.media.LiveStreamCommand;
	import com.kaltura.kdpfl.controller.media.MediaReadyCommand;
	import com.kaltura.kdpfl.events.DynamicEvent;
	import com.kaltura.kdpfl.model.ExternalInterfaceProxy;
	import com.kaltura.kdpfl.model.type.DebugLevel;
	import com.kaltura.kdpfl.model.type.NotificationType;
	import com.kaltura.kdpfl.view.controls.KTrace;
	import com.kaltura.kdpfl.view.media.KMediaPlayerMediator;
	import com.kaltura.puremvc.as3.core.KView;

	import flash.display.DisplayObject;

	import mx.utils.ObjectProxy;

	import org.osmf.media.MediaPlayerState;
	import org.puremvc.as3.interfaces.IFacade;
	import org.puremvc.as3.interfaces.IMediator;
	import org.puremvc.as3.interfaces.IProxy;
	import org.puremvc.as3.patterns.facade.Facade;

	public class ApplicationFacade extends Facade implements IFacade
	{
		/**
		 * The current version of the KDP.
		 */
		public var kdpVersion : String = "v3.6.17";

		/**
		 * save any mediator name that is registered to this array in order to delete at any time
		 * (the pure mvc don't support it as built-in function)
		 */
		private var _mediatorNameArray : Array = new Array();
		/**
		 * save any proxy name that is registered to this array in order to delete at any time
		 * (the pure mvc don't support it as built-in function)
		 */
		private var _proxyNameArray : Array = new Array();
		/**
		 * save any notification that create a command name that is registered to this array in order to delete at any time
		 * (the pure mvc don't support it as built-in function)
		 */
		private var _commandNameArray : Array = new Array();

		/**
		 * The bindObject create dynamicly all attributes that need to be binded on it
		 */
		public var bindObject:ObjectProxy = new ObjectProxy();
		/**
		 * a reference to KDP3 main application
		 */
		private var _app : DisplayObject;

		/**
		 * the url of the kdp
		 */
		public var appFolder : String;
		public var debugMode : Boolean = false;
		/**
		 *
		 * will affect the traces that will be sent. See DebugLevel enum
		 */
		public var debugLevel:int;

		private var externalInterface : ExternalInterfaceProxy;

		/**
		 * return the one and only instance of the ApplicationFacade,
		 * if not exist it will be created.
		 * @return
		 *
		 */
		public static function getInstance() : ApplicationFacade
		{
			if (instance == null) instance = new ApplicationFacade();
			return instance as ApplicationFacade;
		}

		/**
		 * All this simply does is fire a notification which is routed to
		 * "StartupCommand" via the "registerCommand" handlers
		 * @param app
		 *
		 */
		public function start(app:DisplayObject):void
		{
			CONFIG::isSDK46 {
				kdpVersion += ".sdk46";
			}

			_app = app;
			appFolder = app.root.loaderInfo.url;
			appFolder = appFolder.substr(0, appFolder.lastIndexOf('/') + 1);

			sendNotification(NotificationType.STARTUP, app);
			externalInterface = retrieveProxy(ExternalInterfaceProxy.NAME) as ExternalInterfaceProxy;
		}

		/**
		 * Created to trace all notifications for debug
		 * @param notificationName
		 * @param body
		 * @param type
		 *
		 */
		override public function sendNotification(notificationName:String, body:Object = null, type:String = null):void {
			if (debugMode) {
				var s:String;
				if ((notificationName == NotificationType.BYTES_DOWNLOADED_CHANGE && debugLevel == DebugLevel.HIGH) ||
					(notificationName == NotificationType.PLAYER_UPDATE_PLAYHEAD && (debugLevel == DebugLevel.HIGH || debugLevel == DebugLevel.MEDIUM)) ||
					(notificationName != NotificationType.PLAYER_UPDATE_PLAYHEAD && notificationName != NotificationType.BYTES_DOWNLOADED_CHANGE))
				 {
					if (notificationName == NotificationType.PLAYER_STATE_CHANGE)
						s = 'Sent ' + notificationName + ' ==> ' + body.toString();
					else {
						s = 'Sent ' + notificationName;
						if (body) {
							var found:Boolean = false;
							for (var o:* in body) {
								s += ", " + o + ":" + body[o];
								found = true;
							}
							if (!found) {
								s += ", " + body.toString();
							}
						}
					}
				}

				if (s && s != "null") {
					var curTime:Number = 0;
					var kmediaPlayerMediator:KMediaPlayerMediator = retrieveMediator(KMediaPlayerMediator.NAME) as KMediaPlayerMediator;
					if (kmediaPlayerMediator &&
						kmediaPlayerMediator.player &&
						kmediaPlayerMediator.player.state!=MediaPlayerState.LOADING &&
						kmediaPlayerMediator.player.state!=MediaPlayerState.UNINITIALIZED &&
						kmediaPlayerMediator.player.state!=MediaPlayerState.PLAYBACK_ERROR)
					{
						curTime = kmediaPlayerMediator.getCurrentTime();
					}
					var date:Date = new Date();

					KTrace.getInstance().log(date.toTimeString(), ":", s, ", playhead position:", curTime);
				}

			}

			super.sendNotification(notificationName, body, type);
			//For external Flash/Flex application application listening to the KDP events
			_app.dispatchEvent(new DynamicEvent(notificationName, body));

			//For external Javascript application listening to the KDP events
			if (externalInterface)
				externalInterface.notifyJs(notificationName, body);

		}

		/**
		 * controls the routing of notifications to our controllers,
		 * we all know them as commands
		 *
		 */
		override protected function initializeController():void
		{
			super.initializeController();
			registerCommand(NotificationType.STARTUP, StartupCommand);

			// we do both init start KDP life cycle, and start to load the entry simultaneously
			registerCommand(NotificationType.INITIATE_APP, InitMacroCommand);

			//There are several things that need to be done as soon as the layout of the kdp is ready.
			registerCommand(NotificationType.LAYOUT_READY, LayoutReadyCommand );
			//when one call change media we fire the load media command again
			registerCommand(NotificationType.CHANGE_MEDIA, InitChangeMediaMacroCommand);

			registerCommand (NotificationType.LIVE_ENTRY, LiveStreamCommand );

			registerCommand (NotificationType.MEDIA_LOADED, MediaReadyCommand );

			registerCommand (NotificationType.PLAYBACK_COMPLETE, PlaybackCompleteCommand);

			registerCommand(NotificationType.SEQUENCE_ITEM_PLAY_END, SequenceItemPlayEndCommand);

			registerCommand(NotificationType.SEQUENCE_SKIP_NEXT, SequenceSkipNextCommand);
		}

		override protected function initializeView():void
		{
			if ( view != null ) return;
			view = KView.getInstance();
		}

		override protected function initializeFacade():void
		{
			initializeView();
			initializeModel();
			initializeController();
		}

		/**
		 * Help to remove all commands, mediator, proxies from the facade
		 *
		 */
		public function dispose() : void
		{
			var i:int =0;

			for(i=0; i<_commandNameArray.length; i++)
				this.removeCommand( _commandNameArray[i] );

			for(i=0; i<_mediatorNameArray.length; i++)
				this.removeMediator( _mediatorNameArray[i] );

			for(i=0; i<_proxyNameArray.length; i++)
				this.removeProxy( _proxyNameArray[i] );

			_commandNameArray = new Array();
			_mediatorNameArray = new Array();
			_proxyNameArray = new Array();
		}

		/**
		 * after registartion add the notification name to a
		 * @param notificationName
		 * @param commandClassRef
		 *
		 */
		override public function registerCommand(notificationName:String, commandClassRef:Class):void
		{
			super.registerCommand(notificationName, commandClassRef);

			//save the notification name so we can delete it later
			_commandNameArray.push( notificationName );
		}

		override public function registerMediator(mediator:IMediator):void
		{
			super.registerMediator(mediator);

			//save the mediator name so we can delete it later
			_mediatorNameArray.push( mediator.getMediatorName() );
		}

		override public function registerProxy(proxy:IProxy):void
		{
			bindObject[proxy.getProxyName()] = proxy.getData();

			super.registerProxy(proxy);

			//save the proxy name so we can delete it later
			_proxyNameArray.push( proxy.getProxyName() );
		}

		/**
		 * add notification observer for a given mediator
		 * @param notification the notification to listen for
		 * @param notificationHandler handler to be called
		 * @param mediator
		 *
		 */
		public function addNotificationInterest(notification:String, notificationHandler:Function, mediator:IMediator):void {
			(view as KView).addNotificationInterest(notification, notificationHandler, mediator);
		}

		public function get app () : DisplayObject
		{
			return _app;
		}

		public function set app (disObj : DisplayObject) : void
		{
			_app = disObj;
		}

	}
}

package com.kaltura.kdpfl
{
	import com.kaltura.kdpfl.controller.InitMacroCommand;
	import com.kaltura.kdpfl.controller.LayoutReadyCommand;
	import com.kaltura.kdpfl.controller.PlaybackCompleteCommand;
	import com.kaltura.kdpfl.controller.SequenceItemPlayEndCommand;
	import com.kaltura.kdpfl.controller.SequenceSkipNextCommand;
	import com.kaltura.kdpfl.controller.StartupCommand;
	import com.kaltura.kdpfl.controller.media.InitChangeMediaMacroCommand;
	import com.kaltura.kdpfl.controller.media.LiveStreamCommand;
	import com.kaltura.kdpfl.controller.media.MediaReadyCommand;
	import com.kaltura.kdpfl.events.DynamicEvent;
	import com.kaltura.kdpfl.model.ExternalInterfaceProxy;
	import com.kaltura.kdpfl.model.type.DebugLevel;
	import com.kaltura.kdpfl.model.type.NotificationType;
	import com.kaltura.kdpfl.view.controls.KTrace;
	import com.kaltura.kdpfl.view.media.KMediaPlayerMediator;
	import com.kaltura.puremvc.as3.core.KView;

	import flash.display.DisplayObject;

	import mx.utils.ObjectProxy;

	import org.osmf.media.MediaPlayerState;
	import org.puremvc.as3.interfaces.IFacade;
	import org.puremvc.as3.interfaces.IMediator;
	import org.puremvc.as3.interfaces.IProxy;
	import org.puremvc.as3.patterns.facade.Facade;

	public class ApplicationFacade extends Facade implements IFacade
	{
		/**
		 * The current version of the KDP.
		 */
		public var kdpVersion : String = "v3.6.18";

		/**
		 * save any mediator name that is registered to this array in order to delete at any time
		 * (the pure mvc don't support it as built-in function)
		 */
		private var _mediatorNameArray : Array = new Array();
		/**
		 * save any proxy name that is registered to this array in order to delete at any time
		 * (the pure mvc don't support it as built-in function)
		 */
		private var _proxyNameArray : Array = new Array();
		/**
		 * save any notification that create a command name that is registered to this array in order to delete at any time
		 * (the pure mvc don't support it as built-in function)
		 */
		private var _commandNameArray : Array = new Array();

		/**
		 * The bindObject create dynamicly all attributes that need to be binded on it
		 */
		public var bindObject:ObjectProxy = new ObjectProxy();
		/**
		 * a reference to KDP3 main application
		 */
		private var _app : DisplayObject;

		/**
		 * the url of the kdp
		 */
		public var appFolder : String;
		public var debugMode : Boolean = false;
		/**
		 *
		 * will affect the traces that will be sent. See DebugLevel enum
		 */
		public var debugLevel:int;

		private var externalInterface : ExternalInterfaceProxy;

		/**
		 * return the one and only instance of the ApplicationFacade,
		 * if not exist it will be created.
		 * @return
		 *
		 */
		public static function getInstance() : ApplicationFacade
		{
			if (instance == null) instance = new ApplicationFacade();
			return instance as ApplicationFacade;
		}

		/**
		 * All this simply does is fire a notification which is routed to
		 * "StartupCommand" via the "registerCommand" handlers
		 * @param app
		 *
		 */
		public function start(app:DisplayObject):void
		{
			CONFIG::isSDK46 {
				kdpVersion += ".sdk46";
			}

			_app = app;
			appFolder = app.root.loaderInfo.url;
			appFolder = appFolder.substr(0, appFolder.lastIndexOf('/') + 1);

			sendNotification(NotificationType.STARTUP, app);
			externalInterface = retrieveProxy(ExternalInterfaceProxy.NAME) as ExternalInterfaceProxy;
		}

		/**
		 * Created to trace all notifications for debug
		 * @param notificationName
		 * @param body
		 * @param type
		 *
		 */
		override public function sendNotification(notificationName:String, body:Object = null, type:String = null):void {
			if (debugMode) {
				var s:String;
				if ((notificationName == NotificationType.BYTES_DOWNLOADED_CHANGE && debugLevel == DebugLevel.HIGH) ||
					(notificationName == NotificationType.PLAYER_UPDATE_PLAYHEAD && (debugLevel == DebugLevel.HIGH || debugLevel == DebugLevel.MEDIUM)) ||
					(notificationName != NotificationType.PLAYER_UPDATE_PLAYHEAD && notificationName != NotificationType.BYTES_DOWNLOADED_CHANGE))
				 {
					if (notificationName == NotificationType.PLAYER_STATE_CHANGE)
						s = 'Sent ' + notificationName + ' ==> ' + body.toString();
					else {
						s = 'Sent ' + notificationName;
						if (body) {
							var found:Boolean = false;
							for (var o:* in body) {
								s += ", " + o + ":" + body[o];
								found = true;
							}
							if (!found) {
								s += ", " + body.toString();
							}
						}
					}
				}

				if (s && s != "null") {
					var curTime:Number = 0;
					var kmediaPlayerMediator:KMediaPlayerMediator = retrieveMediator(KMediaPlayerMediator.NAME) as KMediaPlayerMediator;
					if (kmediaPlayerMediator &&
						kmediaPlayerMediator.player &&
						kmediaPlayerMediator.player.state!=MediaPlayerState.LOADING &&
						kmediaPlayerMediator.player.state!=MediaPlayerState.UNINITIALIZED &&
						kmediaPlayerMediator.player.state!=MediaPlayerState.PLAYBACK_ERROR)
					{
						curTime = kmediaPlayerMediator.getCurrentTime();
					}
					var date:Date = new Date();

					KTrace.getInstance().log(date.toTimeString(), ":", s, ", playhead position:", curTime);
				}

			}

			super.sendNotification(notificationName, body, type);
			//For external Flash/Flex application application listening to the KDP events
			_app.dispatchEvent(new DynamicEvent(notificationName, body));

			//For external Javascript application listening to the KDP events
			if (externalInterface)
				externalInterface.notifyJs(notificationName, body);

		}

		/**
		 * controls the routing of notifications to our controllers,
		 * we all know them as commands
		 *
		 */
		override protected function initializeController():void
		{
			super.initializeController();
			registerCommand(NotificationType.STARTUP, StartupCommand);

			// we do both init start KDP life cycle, and start to load the entry simultaneously
			registerCommand(NotificationType.INITIATE_APP, InitMacroCommand);

			//There are several things that need to be done as soon as the layout of the kdp is ready.
			registerCommand(NotificationType.LAYOUT_READY, LayoutReadyCommand );
			//when one call change media we fire the load media command again
			registerCommand(NotificationType.CHANGE_MEDIA, InitChangeMediaMacroCommand);

			registerCommand (NotificationType.LIVE_ENTRY, LiveStreamCommand );

			registerCommand (NotificationType.MEDIA_LOADED, MediaReadyCommand );

			registerCommand (NotificationType.PLAYBACK_COMPLETE, PlaybackCompleteCommand);

			registerCommand(NotificationType.SEQUENCE_ITEM_PLAY_END, SequenceItemPlayEndCommand);

			registerCommand(NotificationType.SEQUENCE_SKIP_NEXT, SequenceSkipNextCommand);
		}

		override protected function initializeView():void
		{
			if ( view != null ) return;
			view = KView.getInstance();
		}

		override protected function initializeFacade():void
		{
			initializeView();
			initializeModel();
			initializeController();
		}

		/**
		 * Help to remove all commands, mediator, proxies from the facade
		 *
		 */
		public function dispose() : void
		{
			var i:int =0;

			for(i=0; i<_commandNameArray.length; i++)
				this.removeCommand( _commandNameArray[i] );

			for(i=0; i<_mediatorNameArray.length; i++)
				this.removeMediator( _mediatorNameArray[i] );

			for(i=0; i<_proxyNameArray.length; i++)
				this.removeProxy( _proxyNameArray[i] );

			_commandNameArray = new Array();
			_mediatorNameArray = new Array();
			_proxyNameArray = new Array();
		}

		/**
		 * after registartion add the notification name to a
		 * @param notificationName
		 * @param commandClassRef
		 *
		 */
		override public function registerCommand(notificationName:String, commandClassRef:Class):void
		{
			super.registerCommand(notificationName, commandClassRef);

			//save the notification name so we can delete it later
			_commandNameArray.push( notificationName );
		}

		override public function registerMediator(mediator:IMediator):void
		{
			super.registerMediator(mediator);

			//save the mediator name so we can delete it later
			_mediatorNameArray.push( mediator.getMediatorName() );
		}

		override public function registerProxy(proxy:IProxy):void
		{
			bindObject[proxy.getProxyName()] = proxy.getData();

			super.registerProxy(proxy);

			//save the proxy name so we can delete it later
			_proxyNameArray.push( proxy.getProxyName() );
		}

		/**
		 * add notification observer for a given mediator
		 * @param notification the notification to listen for
		 * @param notificationHandler handler to be called
		 * @param mediator
		 *
		 */
		public function addNotificationInterest(notification:String, notificationHandler:Function, mediator:IMediator):void {
			(view as KView).addNotificationInterest(notification, notificationHandler, mediator);
		}

		public function get app () : DisplayObject
		{
			return _app;
		}

		public function set app (disObj : DisplayObject) : void
		{
			_app = disObj;
		}

	}
}

update kdp version to v3.6.18

update kdp version to v3.6.18


////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package org.apache.flex.core
{
	import flash.text.TextField;
	import flash.text.TextFormat;

	import org.apache.flex.core.ValuesManager;

    /**
     *  The CSSTextField class implements CSS text styles in a TextField.
     *  Not every CSS text style is currently supported.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
     */
	public class CSSTextField extends TextField
	{
        /**
         *  Constructor.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function CSSTextField()
		{
			super();
		}

        /**
         *  @private
         *  The styleParent property is set if the CSSTextField
         *  is used in a SimpleButton-based instance because
         *  the parent property is null, defeating CSS lookup.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public var styleParent:Object;

        /**
         *  @private
         */
		override public function set text(value:String):void
		{
			var sp:Object = parent;
			if (!sp)
				sp = styleParent;

			var tf: TextFormat = new TextFormat();
			tf.font = ValuesManager.valuesImpl.getValue(sp, "fontFamily") as String;
			tf.size = ValuesManager.valuesImpl.getValue(sp, "fontSize");
			tf.bold = ValuesManager.valuesImpl.getValue(sp, "fontWeight") == "bold";
			tf.color = ValuesManager.valuesImpl.getValue(sp, "color");
			var padding:Object = ValuesManager.valuesImpl.getValue(sp, "padding");
			if (padding == null) padding = 0;
			var paddingLeft:Object = ValuesManager.valuesImpl.getValue(sp,"padding-left");
			if (paddingLeft == null) paddingLeft = padding;
			var paddingRight:Object = ValuesManager.valuesImpl.getValue(sp,"padding-right");
			if (paddingRight == null) paddingRight = padding;
			tf.leftMargin = paddingLeft;
			tf.rightMargin = paddingRight;

			defaultTextFormat = tf;
			super.text = value;
		}
	}
}

////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package org.apache.flex.core
{
	import flash.text.TextField;
	import flash.text.TextFormat;

	import org.apache.flex.core.ValuesManager;

    /**
     *  The CSSTextField class implements CSS text styles in a TextField.
     *  Not every CSS text style is currently supported.
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
     */
	public class CSSTextField extends TextField
	{
        /**
         *  Constructor.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function CSSTextField()
		{
			super();
		}

        /**
         *  @private
         *  The styleParent property is set if the CSSTextField
         *  is used in a SimpleButton-based instance because
         *  the parent property is null, defeating CSS lookup.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public var styleParent:Object;

        /**
         *  @private
         */
		override public function set text(value:String):void
		{
			var sp:Object = parent;
			if (!sp)
				sp = styleParent;

			var tf: TextFormat = new TextFormat();
			tf.font = ValuesManager.valuesImpl.getValue(sp, "fontFamily") as String;
			tf.size = ValuesManager.valuesImpl.getValue(sp, "fontSize");
			tf.bold = ValuesManager.valuesImpl.getValue(sp, "fontWeight") == "bold";
			tf.color = ValuesManager.valuesImpl.getValue(sp, "color");
			var padding:Object = ValuesManager.valuesImpl.getValue(sp, "padding");
			if (padding == null) padding = 0;
			var paddingLeft:Object = ValuesManager.valuesImpl.getValue(sp,"padding-left");
			if (paddingLeft == null) paddingLeft = padding;
			var paddingRight:Object = ValuesManager.valuesImpl.getValue(sp,"padding-right");
			if (paddingRight == null) paddingRight = padding;
			tf.leftMargin = paddingLeft;
			tf.rightMargin = paddingRight;
            var align:Object = ValuesManager.valuesImpl.getValue(sp, "text-align");
            if (align == "center")
                tf.align = "center";
            else if (align == "right")
                tf.align = "right";

			defaultTextFormat = tf;
			super.text = value;
		}
	}
}

handle text-align

handle text-align


////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2008-2013 Esri. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
////////////////////////////////////////////////////////////////////////////////
package com.esri.builder.controllers
{

import com.esri.builder.eventbus.AppEvent;
import com.esri.builder.model.LocaleModel;
import com.esri.builder.model.Model;
import com.esri.builder.supportClasses.LogUtil;

import mx.core.FlexGlobals;
import mx.logging.ILogger;
import mx.logging.Log;
import mx.resources.ResourceManager;
import mx.styles.CSSStyleDeclaration;
import mx.styles.IStyleManager2;
import mx.styles.StyleManager;

public class LocaleController
{
    private static const LOG:ILogger = LogUtil.createLogger(LocaleController);

    public function LocaleController()
    {
        AppEvent.addListener(AppEvent.SETTINGS_SAVED, settingsChangeHandler, false, 500); //high priority to prevent app using outdated locale settings
    }

    private function settingsChangeHandler(event:AppEvent):void
    {
        updateApplicationLocale();
    }

    private function updateApplicationLocale():void
    {
        var selectedLocale:String = Model.instance.locale;
        var localeChain:Array = ResourceManager.getInstance().localeChain;

        var selectedLocaleIndex:int = localeChain.indexOf(selectedLocale);
        localeChain.splice(selectedLocaleIndex, 1);
        localeChain.unshift(selectedLocale);

        if (Log.isDebug())
        {
            LOG.debug("Updating application locale: {0}", selectedLocale);
        }

        ResourceManager.getInstance().update();
        applyLocaleLayoutDirection(selectedLocale);
        setPreferredLocaleFonts(selectedLocale);
        setEmphasisText(selectedLocale);
    }

    private function applyLocaleLayoutDirection(selectedLocale:String):void
    {
        var currentLayoutDirection:String = FlexGlobals.topLevelApplication.getStyle('layoutDirection');
        var localeLayoutDirection:String = LocaleModel.getInstance().getLocaleLayoutDirection(selectedLocale);
        if (localeLayoutDirection != currentLayoutDirection)
        {
            FlexGlobals.topLevelApplication.setStyle('direction', localeLayoutDirection);
            FlexGlobals.topLevelApplication.setStyle('layoutDirection', localeLayoutDirection);
        }

        var currentLocale:String = FlexGlobals.topLevelApplication.getStyle('locale');
        if (selectedLocale != currentLocale)
        {
            FlexGlobals.topLevelApplication.setStyle('locale', selectedLocale);
        }
    }

    private function setPreferredLocaleFonts(selectedLocale:String):void
    {
        if (selectedLocale == 'ar')
        {
            FlexGlobals.topLevelApplication.setStyle('fontFamily', LocaleModel.ARABIC_FONT_FAMILY);
        }
        else if (selectedLocale == 'ja_JP')
        {
            FlexGlobals.topLevelApplication.setStyle('fontFamily', LocaleModel.JAPANESE_FONT_FAMILY);
        }
        else if (selectedLocale == 'ko_KR')
        {
            FlexGlobals.topLevelApplication.setStyle('fontFamily', LocaleModel.KOREAN_FONT_FAMILY);
        }
        else if (selectedLocale == 'zh_CN')
        {
            FlexGlobals.topLevelApplication.setStyle('fontFamily', LocaleModel.CHINESE_FONT_FAMILY);
        }
        else
        {
            FlexGlobals.topLevelApplication.setStyle('fontFamily', undefined);
        }
    }

    private function setEmphasisText(locale:String):void
    {
        var topLevelStyleManager:IStyleManager2 = StyleManager.getStyleManager(null);
        var emphasisStyle:CSSStyleDeclaration = topLevelStyleManager.getStyleDeclaration(".emphasisText");

        var isItalicInappropriateLocale:Boolean =
            locale == 'ja_JP' || locale == 'ko_KR' || locale == 'zh_CN'
            || locale == 'ar' || locale == 'he_IL';
        var emphasisFontStyle:String = isItalicInappropriateLocale ? "normal" : "italic";
        emphasisStyle.setStyle("fontStyle", emphasisFontStyle);
    }
}
}

////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2008-2013 Esri. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
////////////////////////////////////////////////////////////////////////////////
package com.esri.builder.controllers
{

import com.esri.builder.eventbus.AppEvent;
import com.esri.builder.model.LocaleModel;
import com.esri.builder.model.Model;
import com.esri.builder.model.WidgetTypeRegistryModel;
import com.esri.builder.supportClasses.LogUtil;

import mx.core.FlexGlobals;
import mx.logging.ILogger;
import mx.logging.Log;
import mx.resources.ResourceManager;
import mx.styles.CSSStyleDeclaration;
import mx.styles.IStyleManager2;
import mx.styles.StyleManager;

public class LocaleController
{
    private static const LOG:ILogger = LogUtil.createLogger(LocaleController);

    public function LocaleController()
    {
        AppEvent.addListener(AppEvent.SETTINGS_SAVED, settingsChangeHandler, false, 500); //high priority to prevent app using outdated locale settings
    }

    private function settingsChangeHandler(event:AppEvent):void
    {
        updateApplicationLocale();
    }

    private function updateApplicationLocale():void
    {
        var selectedLocale:String = Model.instance.locale;
        var localeChain:Array = ResourceManager.getInstance().localeChain;

        var selectedLocaleIndex:int = localeChain.indexOf(selectedLocale);
        localeChain.splice(selectedLocaleIndex, 1);
        localeChain.unshift(selectedLocale);

        if (Log.isDebug())
        {
            LOG.debug("Updating application locale: {0}", selectedLocale);
        }

        ResourceManager.getInstance().update();
        applyLocaleLayoutDirection(selectedLocale);
        setPreferredLocaleFonts(selectedLocale);
        setEmphasisText(selectedLocale);
    }

    private function applyLocaleLayoutDirection(selectedLocale:String):void
    {
        var currentLayoutDirection:String = FlexGlobals.topLevelApplication.getStyle('layoutDirection');
        var localeLayoutDirection:String = LocaleModel.getInstance().getLocaleLayoutDirection(selectedLocale);
        if (localeLayoutDirection != currentLayoutDirection)
        {
            FlexGlobals.topLevelApplication.setStyle('direction', localeLayoutDirection);
            FlexGlobals.topLevelApplication.setStyle('layoutDirection', localeLayoutDirection);
        }

        var currentLocale:String = FlexGlobals.topLevelApplication.getStyle('locale');
        if (selectedLocale != currentLocale)
        {
            FlexGlobals.topLevelApplication.setStyle('locale', selectedLocale);
            WidgetTypeRegistryModel.getInstance().widgetTypeRegistry.sort();
        }
    }

    private function setPreferredLocaleFonts(selectedLocale:String):void
    {
        if (selectedLocale == 'ar')
        {
            FlexGlobals.topLevelApplication.setStyle('fontFamily', LocaleModel.ARABIC_FONT_FAMILY);
        }
        else if (selectedLocale == 'ja_JP')
        {
            FlexGlobals.topLevelApplication.setStyle('fontFamily', LocaleModel.JAPANESE_FONT_FAMILY);
        }
        else if (selectedLocale == 'ko_KR')
        {
            FlexGlobals.topLevelApplication.setStyle('fontFamily', LocaleModel.KOREAN_FONT_FAMILY);
        }
        else if (selectedLocale == 'zh_CN')
        {
            FlexGlobals.topLevelApplication.setStyle('fontFamily', LocaleModel.CHINESE_FONT_FAMILY);
        }
        else
        {
            FlexGlobals.topLevelApplication.setStyle('fontFamily', undefined);
        }
    }

    private function setEmphasisText(locale:String):void
    {
        var topLevelStyleManager:IStyleManager2 = StyleManager.getStyleManager(null);
        var emphasisStyle:CSSStyleDeclaration = topLevelStyleManager.getStyleDeclaration(".emphasisText");

        var isItalicInappropriateLocale:Boolean =
            locale == 'ja_JP' || locale == 'ko_KR' || locale == 'zh_CN'
            || locale == 'ar' || locale == 'he_IL';
        var emphasisFontStyle:String = isItalicInappropriateLocale ? "normal" : "italic";
        emphasisStyle.setStyle("fontStyle", emphasisFontStyle);
    }
}
}

Sort widget modules on locale change.

Sort widget modules on locale change.


// vim: tabstop=4 shiftwidth=4

// Copyright (c) 2010 , 杨博 (Yang Bo) All rights reserved.
//
//         pop.atry@gmail.com
//
// Use, modification and distribution are subject to the "New BSD License"
// as listed at <url: http://www.opensource.org/licenses/bsd-license.php >.

package com.netease.protobuf {
	import flash.utils.*
	public final class WriteUtils {
		public static function writeTag(output:IDataOutput,
				wireType:uint, number:uint):void {
			const varint:VarintWriter = new VarintWriter;
			varint.write(wireType, 3);
			varint.write(number, 32);
			varint.end()
			output.writeBytes(varint)
		}
		public static function write_TYPE_DOUBLE(output:IDataOutput, value:Number):void {
			output.writeDouble(value)
		}
		public static function write_TYPE_FLOAT(output:IDataOutput, value:Number):void {
			output.writeFloat(value)
		}
		public static function write_TYPE_INT64(output:IDataOutput, value:Int64):void {
			const varint:VarintWriter = new VarintWriter;
			varint.write(value.low, 32);
			varint.write(value.high, 32);
			varint.end()
			output.writeBytes(varint)
		}
		public static function write_TYPE_UINT64(output:IDataOutput, value:UInt64):void {
			const varint:VarintWriter = new VarintWriter;
			varint.write(value.low, 32);
			varint.write(value.high, 32);
			varint.end()
			output.writeBytes(varint)
		}
		public static function write_TYPE_INT32(output:IDataOutput, value:int):void {
			write_TYPE_UINT32(output, value)
		}
		public static function write_TYPE_FIXED64(output:IDataOutput, value:Int64):void {
			output.endian = Endian.LITTLE_ENDIAN
			output.writeUnsignedInt(value.low)
			output.writeInt(value.high)
		}
		public static function write_TYPE_FIXED32(output:IDataOutput, value:int):void {
			output.endian = Endian.LITTLE_ENDIAN
			output.writeInt(value)
		}
		public static function write_TYPE_BOOL(output:IDataOutput, value:Boolean):void {
			output.writeByte(value ? 1 : 0)
		}
		public static function write_TYPE_STRING(output:IDataOutput, value:String):void {
			var plb:PostposeLengthBuffer = output as PostposeLengthBuffer
			if (plb == null) {
				plb = new PostposeLengthBuffer
			}
			const i:uint = plb.beginBlock()
			plb.writeUTF(value)
			plb.endBlock(i)
			if (plb != output) {
				plb.toNormal(output)
			}
		}
		public static function write_TYPE_BYTES(output:IDataOutput, value:ByteArray):void {
			write_TYPE_UINT32(output, value.length)
			output.writeBytes(value)
		}
		public static function write_TYPE_UINT32(output:IDataOutput, value:uint):void {
			const varint:VarintWriter = new VarintWriter;
			varint.write(value, 32);
			varint.end()
			output.writeBytes(varint)
		}
		public static function write_TYPE_ENUM(output:IDataOutput, value:int):void {
			write_TYPE_INT32(output, value)
		}
		public static function write_TYPE_SFIXED32(output:IDataOutput, value:int):void {
			write_TYPE_FIXED32(output, (value >>> 31) ^ (value << 1))
		}
		public static function write_TYPE_SFIXED64(output:IDataOutput, value:Int64):void {
			output.endian = Endian.LITTLE_ENDIAN
			output.writeUnsignedInt((value.high >>> 31) ^ (value.low << 1))
			output.writeUnsignedInt((value.low >>> 31) ^ (value.high << 1))
		}
		public static function write_TYPE_SINT32(output:IDataOutput, value:int):void {
			write_TYPE_UINT32(output, (value >>> 31) ^ (value << 1))
		}
		public static function write_TYPE_SINT64(output:IDataOutput, value:Int64):void {
			const varint:VarintWriter = new VarintWriter;
			varint.write((value.high >>> 31) ^ (value.low << 1), 32);
			varint.write((value.low >>> 31) ^ (value.high << 1), 32);
			varint.end()
			output.writeBytes(varint)
		}
		public static function write_TYPE_MESSAGE(output:IDataOutput, value:IExternalizable):void {
			var plb:PostposeLengthBuffer = output as PostposeLengthBuffer
			if (plb == null) {
				plb = new PostposeLengthBuffer
			}
			const i:uint = plb.beginBlock()
			value.writeExternal(plb)
			plb.endBlock(i)
			if (plb != output) {
				plb.toNormal(output)
			}
		}
		public static function writePackedRepeated(output:IDataOutput,
				writeFunction:Function, value:Array):void {
			var plb:PostposeLengthBuffer = output as PostposeLengthBuffer
			if (plb == null) {
				plb = new PostposeLengthBuffer
			}
			const i:uint = plb.beginBlock()
			for each (var element:* in value) {
				writeFunction(plb, element)
			}
			plb.endBlock(i)
			if (plb != output) {
				plb.toNormal(output)
			}
		}
	}
}

// vim: tabstop=4 shiftwidth=4

// Copyright (c) 2010 , 杨博 (Yang Bo) All rights reserved.
//
//         pop.atry@gmail.com
//
// Use, modification and distribution are subject to the "New BSD License"
// as listed at <url: http://www.opensource.org/licenses/bsd-license.php >.

package com.netease.protobuf {
	import flash.utils.*
	public final class WriteUtils {
		public static function writeTag(output:IDataOutput,
				wireType:uint, number:uint):void {
			const varint:VarintWriter = new VarintWriter;
			varint.write(wireType, 3);
			varint.write(number, 32);
			varint.end()
			output.writeBytes(varint)
		}
		public static function write_TYPE_DOUBLE(output:IDataOutput, value:Number):void {
			output.writeDouble(value)
		}
		public static function write_TYPE_FLOAT(output:IDataOutput, value:Number):void {
			output.writeFloat(value)
		}
		public static function write_TYPE_INT64(output:IDataOutput, value:Int64):void {
			const varint:VarintWriter = new VarintWriter;
			varint.write(value.low, 32);
			varint.write(value.high, 32);
			varint.end()
			output.writeBytes(varint)
		}
		public static function write_TYPE_UINT64(output:IDataOutput, value:UInt64):void {
			const varint:VarintWriter = new VarintWriter;
			varint.write(value.low, 32);
			varint.write(value.high, 32);
			varint.end()
			output.writeBytes(varint)
		}
		public static function write_TYPE_INT32(output:IDataOutput, value:int):void {
			write_TYPE_UINT32(output, value)
		}
		public static function write_TYPE_FIXED64(output:IDataOutput, value:Int64):void {
			output.endian = Endian.LITTLE_ENDIAN
			output.writeUnsignedInt(value.low)
			output.writeInt(value.high)
		}
		public static function write_TYPE_FIXED32(output:IDataOutput, value:int):void {
			output.endian = Endian.LITTLE_ENDIAN
			output.writeInt(value)
		}
		public static function write_TYPE_BOOL(output:IDataOutput, value:Boolean):void {
			output.writeByte(value ? 1 : 0)
		}
		public static function write_TYPE_STRING(output:IDataOutput, value:String):void {
			var plb:PostposeLengthBuffer = output as PostposeLengthBuffer
			if (plb == null) {
				plb = new PostposeLengthBuffer
			}
			const i:uint = plb.beginBlock()
			plb.writeUTFBytes(value)
			plb.endBlock(i)
			if (plb != output) {
				plb.toNormal(output)
			}
		}
		public static function write_TYPE_BYTES(output:IDataOutput, value:ByteArray):void {
			write_TYPE_UINT32(output, value.length)
			output.writeBytes(value)
		}
		public static function write_TYPE_UINT32(output:IDataOutput, value:uint):void {
			const varint:VarintWriter = new VarintWriter;
			varint.write(value, 32);
			varint.end()
			output.writeBytes(varint)
		}
		public static function write_TYPE_ENUM(output:IDataOutput, value:int):void {
			write_TYPE_INT32(output, value)
		}
		public static function write_TYPE_SFIXED32(output:IDataOutput, value:int):void {
			write_TYPE_FIXED32(output, (value >>> 31) ^ (value << 1))
		}
		public static function write_TYPE_SFIXED64(output:IDataOutput, value:Int64):void {
			output.endian = Endian.LITTLE_ENDIAN
			output.writeUnsignedInt((value.high >>> 31) ^ (value.low << 1))
			output.writeUnsignedInt((value.low >>> 31) ^ (value.high << 1))
		}
		public static function write_TYPE_SINT32(output:IDataOutput, value:int):void {
			write_TYPE_UINT32(output, (value >>> 31) ^ (value << 1))
		}
		public static function write_TYPE_SINT64(output:IDataOutput, value:Int64):void {
			const varint:VarintWriter = new VarintWriter;
			varint.write((value.high >>> 31) ^ (value.low << 1), 32);
			varint.write((value.low >>> 31) ^ (value.high << 1), 32);
			varint.end()
			output.writeBytes(varint)
		}
		public static function write_TYPE_MESSAGE(output:IDataOutput, value:IExternalizable):void {
			var plb:PostposeLengthBuffer = output as PostposeLengthBuffer
			if (plb == null) {
				plb = new PostposeLengthBuffer
			}
			const i:uint = plb.beginBlock()
			value.writeExternal(plb)
			plb.endBlock(i)
			if (plb != output) {
				plb.toNormal(output)
			}
		}
		public static function writePackedRepeated(output:IDataOutput,
				writeFunction:Function, value:Array):void {
			var plb:PostposeLengthBuffer = output as PostposeLengthBuffer
			if (plb == null) {
				plb = new PostposeLengthBuffer
			}
			const i:uint = plb.beginBlock()
			for each (var element:* in value) {
				writeFunction(plb, element)
			}
			plb.endBlock(i)
			if (plb != output) {
				plb.toNormal(output)
			}
		}
	}
}

修复发送字符串时多发了前缀的 bug

修复发送字符串时多发了前缀的 bug


package aerys.minko.render.resource
{
	import flash.display.BitmapData;
	import flash.display3D.Context3D;
	import flash.display3D.IndexBuffer3D;
	import flash.display3D.Program3D;
	import flash.display3D.VertexBuffer3D;
	import flash.display3D.textures.CubeTexture;
	import flash.display3D.textures.Texture;
	import flash.display3D.textures.TextureBase;
	import flash.geom.Rectangle;

	public final class Context3DResource
	{
		private var _context				: Context3D					= null;

		private var _enableErrorChecking	: Boolean					= false;

		private var _rttTarget				: TextureBase				= null;
		private var _rttDepthAndStencil		: Boolean					= false;
		private var _rttAntiAliasing		: int						= 0;
		private var _rttSurfaceSelector		: int						= 0;
		private var _rectangle				: Rectangle					= null;

		private var _depthMask				: Boolean					= false;
		private var _passCompareMode		: String					= null;

		private var _program				: Program3D					= null;

		private var _blendingSource			: String					= null;
		private var _blendingDestination	: String					= null;

		private var _triangleCulling		: String					= null;

		private var _vertexBuffers			: Vector.<VertexBuffer3D>	= new Vector.<VertexBuffer3D>(8, true);
		private var _vertexBuffersOffsets	: Vector.<int>				= new Vector.<int>(8, true);
		private var _vertexBuffersFormats	: Vector.<String>			= new Vector.<String>(8, true);
		private var _textures				: Vector.<TextureBase>		= new Vector.<TextureBase>(8, true);

		private var _colorMaskRed			: Boolean					= false;
		private var _colorMaskGreen			: Boolean					= false;
		private var _colorMaskBlue			: Boolean					= false;
		private var _colorMaskAlpha			: Boolean					= false;

		public function get enabledErrorChecking() : Boolean
		{
			return _enableErrorChecking;
		}
		public function set enableErrorChecking(value : Boolean) : void
		{
			if (value != _enableErrorChecking)
			{
				_enableErrorChecking = value;
				_context.enableErrorChecking = value;
			}
		}

		public function Context3DResource(context : Context3D)
		{
			_context = context;
		}

		public function clear(red		: Number	= 0.0,
							  green		: Number	= 0.0,
							  blue		: Number	= 0.0,
							  alpha		: Number	= 1.0,
							  depth		: Number	= 1.0,
							  stencil	: uint		= 0,
							  mask		: uint		= 0xffffffff) : void
		{
			_context.clear(red, green, blue, alpha, depth, stencil, mask);
		}

		public function configureBackBuffer(width					: int,
											height					: int,
											antiAlias				: int,
											enabledDepthAndStencil	: Boolean) : Context3DResource
		{
			_context.configureBackBuffer(width, height, antiAlias, enabledDepthAndStencil);

			return this;
		}

		public function createCubeTexture(size							: int,
										  format						: String,
										  optimizeForRenderToTexture	: Boolean) : CubeTexture
		{
			return _context.createCubeTexture(size, format, optimizeForRenderToTexture);
		}

		public function createIndexBuffer(numIndices : int) : IndexBuffer3D
		{
			return _context.createIndexBuffer(numIndices);
		}

		public function createProgram() : Program3D
		{
			return _context.createProgram();
		}

		public function createTexture(width							: int,
									  height						: int,
									  format						: String,
									  optimizeForRenderToTexture	: Boolean) : Texture
		{
			return _context.createTexture(width, height, format, optimizeForRenderToTexture);
		}

		public function createVertexBuffer(numVertices : int, data32PerVertex : int) : VertexBuffer3D
		{
			return _context.createVertexBuffer(numVertices, data32PerVertex);
		}

		public function dispose() : void
		{
			_context.dispose();
		}

		public function drawToBitmapData(destination : BitmapData) : Context3DResource
		{
			_context.drawToBitmapData(destination);

			return this;
		}

		public function drawTriangles(indexBuffer	: IndexBuffer3D,
									  firstIndex	: int	= 0,
									  numTriangles	: int	= -1) : Context3DResource
		{
			_context.drawTriangles(indexBuffer, firstIndex, numTriangles);

			return this;
		}

		public function present() : Context3DResource
		{
			_context.present();

			return this;
		}

		public function setBlendFactors(source : String, destination : String) : Context3DResource
		{
			if (source != _blendingSource || destination != _blendingDestination)
			{
				_blendingSource = source;
				_blendingDestination = destination;
				_context.setBlendFactors(_blendingSource, _blendingDestination);
			}

			return this;
		}

		public function setColorMask(red 	: Boolean,
									 green 	: Boolean,
									 blue 	: Boolean,
									 alpha 	: Boolean) : Context3DResource
		{
			if (red != _colorMaskRed || green != _colorMaskGreen
				|| blue != _colorMaskBlue || alpha != _colorMaskAlpha)
			{
				_colorMaskRed = red;
				_colorMaskGreen = green;
				_colorMaskBlue = blue;
				_colorMaskAlpha = alpha;
				_context.setColorMask(
					_colorMaskRed,
					_colorMaskGreen,
					_colorMaskBlue,
					_colorMaskAlpha
				);
			}

			return this;
		}

		public function setCulling(triangleCulling : String) : Context3DResource
		{
			if (triangleCulling != _triangleCulling)
			{
				_triangleCulling = triangleCulling;
				_context.setCulling(triangleCulling);
			}

			return this;
		}

		public function setDepthTest(depthMask : Boolean, passCompareMode : String) : Context3DResource
		{
			if (depthMask != _depthMask || passCompareMode != _passCompareMode)
			{
				_depthMask = depthMask;
				_passCompareMode = passCompareMode;
				_context.setDepthTest(_depthMask, _passCompareMode);
			}

			return this;
		}

		public function setProgram(program : Program3D) : Context3DResource
		{
			if (_program != program)
			{
				_program = program;
				_context.setProgram(program);
			}

			return this;
		}

		public function setProgramConstantsFromVector(programeType	: String,
													  offset		: uint,
													  values		: Vector.<Number>,
													  numRegisters	: int	= -1) : Context3DResource
		{
			_context.setProgramConstantsFromVector(programeType, offset, values, numRegisters);

			return this;
		}

		public function setRenderToBackBuffer() : Context3DResource
		{
			if (_rttTarget != null)
			{
				_rttTarget = null;
				_context.setRenderToBackBuffer();
			}

			return this;
		}

		public function setRenderToTexture(texture					: TextureBase,
										   enableDepthAndStencil	: Boolean	= false,
										   antiAlias				: int		= 0,
										   surfaceSelector			: int		= 0) : Context3DResource
		{
			if (texture != _rttTarget || enableDepthAndStencil != _rttDepthAndStencil
				|| antiAlias != _rttAntiAliasing || surfaceSelector != _rttSurfaceSelector)
			{
				_rttTarget = texture;
				_rttDepthAndStencil = enableDepthAndStencil;
				_rttAntiAliasing = antiAlias;
				_rttSurfaceSelector = surfaceSelector;
				_context.setRenderToTexture(
					texture,
					enableDepthAndStencil,
					antiAlias,
					surfaceSelector
				);
			}

			return this;
		}

		public function setScissorRectangle(rectangle : Rectangle) : Context3DResource
		{
			if (_rectangle != rectangle)
			{
				_rectangle = rectangle;
				_context.setScissorRectangle(_rectangle);
			}

			return this;
		}

		public function setTextureAt(sampler	: uint,
									 texture	: TextureBase) : Context3DResource
		{
			if (_textures[sampler] != texture)
			{
				_textures[sampler] = texture;
				_context.setTextureAt(sampler, texture);
			}

			return this;
		}

		public function setVertexBufferAt(index			: int,
										  vertexBuffer	: VertexBuffer3D,
										  bufferOffset	: int		= 0,
										  format		: String	= 'float4') : Context3DResource
		{
			if (_vertexBuffers[index] != vertexBuffer
				|| _vertexBuffersOffsets[index] != bufferOffset
				|| _vertexBuffersFormats[index] != format)
			{
				_vertexBuffers[index] = vertexBuffer;
				_vertexBuffersOffsets[index] = bufferOffset;
				_vertexBuffersFormats[index] = format;

				_context.setVertexBufferAt(
					index,
					vertexBuffer,
					bufferOffset,
					format
				);
			}

			return this;
		}

		public function setStencilReferenceValue(refNum		: uint 	= 0,
												 readMask	: uint 	= 255,
												 writeMask	: uint 	= 255) : Context3DResource
		{
			_context.setStencilReferenceValue(refNum, readMask, writeMask);

			return this;
		}

		public function setStencilActions(triangleFace					: String = 'frontAndBack',
										  compareMode					: String = 'always',
										  actionOnBothPass				: String = 'keep',
										  actionOnDepthFail				: String = 'keep',
										  actionOnDepthPassStencilFail	: String = 'keep') : Context3DResource
		{
			_context.setStencilActions(
				triangleFace,
				compareMode,
				actionOnBothPass,
				actionOnDepthFail,
				actionOnDepthPassStencilFail
			);

			return this;
		}

	}
}

package aerys.minko.render.resource
{
	import flash.display.BitmapData;
	import flash.display3D.Context3D;
	import flash.display3D.IndexBuffer3D;
	import flash.display3D.Program3D;
	import flash.display3D.VertexBuffer3D;
	import flash.display3D.textures.CubeTexture;
	import flash.display3D.textures.Texture;
	import flash.display3D.textures.TextureBase;
	import flash.geom.Rectangle;

	public final class Context3DResource
	{
		private var _context				                : Context3D;

		private var _enableErrorChecking	                : Boolean;

		private var _rttTarget			                	: TextureBase;
		private var _rttDepthAndStencil	                	: Boolean;
		private var _rttAntiAliasing	                	: int;
		private var _rttSurfaceSelector		                : int;
		private var _rectangle				                : Rectangle;

		private var _depthMask			                	: Boolean;
		private var _passCompareMode	                	: String;

		private var _program			                	: Program3D;

		private var _blendingSource		                	: String;
		private var _blendingDestination                	: String;

		private var _triangleCulling	                	: String;

		private var _vertexBuffers			                : Vector.<VertexBuffer3D>;
		private var _vertexBuffersOffsets	                : Vector.<int>;
		private var _vertexBuffersFormats	                : Vector.<String>;
		private var _textures				                : Vector.<TextureBase>;

		private var _colorMaskRed			                : Boolean;
		private var _colorMaskGreen			                : Boolean;
		private var _colorMaskBlue			                : Boolean;
		private var _colorMaskAlpha	                		: Boolean;

        private var _stencilRefNum                          : uint;
        private var _stencilReadMask                        : uint;
        private var _stencilWriteMask                       : uint;
        private var _stencilTriangleFace                    : String;
        private var _stencilCompareMode                     : String;
        private var _stencilActionOnBothPass                : String;
        private var _stencilActionOnDepthFail               : String;
        private var _stencilActionOnDepthPassStencilFail    : String;

		public function get enabledErrorChecking() : Boolean
		{
			return _enableErrorChecking;
		}
		public function set enableErrorChecking(value : Boolean) : void
		{
			if (value != _enableErrorChecking)
			{
				_enableErrorChecking = value;
				_context.enableErrorChecking = value;
			}
		}

		public function Context3DResource(context : Context3D)
		{
			_context = context;

            initialize();
		}

        private function initialize() : void
        {
            _vertexBuffers = new Vector.<VertexBuffer3D>(8, true);
            _vertexBuffersOffsets = new Vector.<int>(8, true);
            _vertexBuffersFormats = new Vector.<String>(8, true);
            _textures = new Vector.<TextureBase>(8, true);
        }

		public function clear(red		: Number	= 0.0,
							  green		: Number	= 0.0,
							  blue		: Number	= 0.0,
							  alpha		: Number	= 1.0,
							  depth		: Number	= 1.0,
							  stencil	: uint		= 0,
							  mask		: uint		= 0xffffffff) : void
		{
			_context.clear(red, green, blue, alpha, depth, stencil, mask);
		}

		public function configureBackBuffer(width					: int,
											height					: int,
											antiAlias				: int,
											enabledDepthAndStencil	: Boolean) : Context3DResource
		{
			_context.configureBackBuffer(width, height, antiAlias, enabledDepthAndStencil);

			return this;
		}

		public function createCubeTexture(size							: int,
										  format						: String,
										  optimizeForRenderToTexture	: Boolean) : CubeTexture
		{
			return _context.createCubeTexture(size, format, optimizeForRenderToTexture);
		}

		public function createIndexBuffer(numIndices : int) : IndexBuffer3D
		{
			return _context.createIndexBuffer(numIndices);
		}

		public function createProgram() : Program3D
		{
			return _context.createProgram();
		}

		public function createTexture(width							: int,
									  height						: int,
									  format						: String,
									  optimizeForRenderToTexture	: Boolean) : Texture
		{
			return _context.createTexture(width, height, format, optimizeForRenderToTexture);
		}

		public function createVertexBuffer(numVertices : int, data32PerVertex : int) : VertexBuffer3D
		{
			return _context.createVertexBuffer(numVertices, data32PerVertex);
		}

		public function dispose() : void
		{
			_context.dispose();
		}

		public function drawToBitmapData(destination : BitmapData) : Context3DResource
		{
			_context.drawToBitmapData(destination);

			return this;
		}

		public function drawTriangles(indexBuffer	: IndexBuffer3D,
									  firstIndex	: int	= 0,
									  numTriangles	: int	= -1) : Context3DResource
		{
			_context.drawTriangles(indexBuffer, firstIndex, numTriangles);

			return this;
		}

		public function present() : Context3DResource
		{
			_context.present();

			return this;
		}

		public function setBlendFactors(source : String, destination : String) : Context3DResource
		{
			if (source != _blendingSource || destination != _blendingDestination)
			{
				_blendingSource = source;
				_blendingDestination = destination;
				_context.setBlendFactors(_blendingSource, _blendingDestination);
			}

			return this;
		}

		public function setColorMask(red 	: Boolean,
									 green 	: Boolean,
									 blue 	: Boolean,
									 alpha 	: Boolean) : Context3DResource
		{
			if (red != _colorMaskRed || green != _colorMaskGreen
				|| blue != _colorMaskBlue || alpha != _colorMaskAlpha)
			{
				_colorMaskRed = red;
				_colorMaskGreen = green;
				_colorMaskBlue = blue;
				_colorMaskAlpha = alpha;
				_context.setColorMask(
					_colorMaskRed,
					_colorMaskGreen,
					_colorMaskBlue,
					_colorMaskAlpha
				);
			}

			return this;
		}

		public function setCulling(triangleCulling : String) : Context3DResource
		{
			if (triangleCulling != _triangleCulling)
			{
				_triangleCulling = triangleCulling;
				_context.setCulling(triangleCulling);
			}

			return this;
		}

		public function setDepthTest(depthMask : Boolean, passCompareMode : String) : Context3DResource
		{
			if (depthMask != _depthMask || passCompareMode != _passCompareMode)
			{
				_depthMask = depthMask;
				_passCompareMode = passCompareMode;
				_context.setDepthTest(_depthMask, _passCompareMode);
			}

			return this;
		}

		public function setProgram(program : Program3D) : Context3DResource
		{
			if (_program != program)
			{
				_program = program;
				_context.setProgram(program);
			}

			return this;
		}

		public function setProgramConstantsFromVector(programeType	: String,
													  offset		: uint,
													  values		: Vector.<Number>,
													  numRegisters	: int	= -1) : Context3DResource
		{
			_context.setProgramConstantsFromVector(programeType, offset, values, numRegisters);

			return this;
		}

		public function setRenderToBackBuffer() : Context3DResource
		{
			if (_rttTarget != null)
			{
				_rttTarget = null;
				_context.setRenderToBackBuffer();
			}

			return this;
		}

		public function setRenderToTexture(texture					: TextureBase,
										   enableDepthAndStencil	: Boolean	= false,
										   antiAlias				: int		= 0,
										   surfaceSelector			: int		= 0) : Context3DResource
		{
			if (texture != _rttTarget || enableDepthAndStencil != _rttDepthAndStencil
				|| antiAlias != _rttAntiAliasing || surfaceSelector != _rttSurfaceSelector)
			{
				_rttTarget = texture;
				_rttDepthAndStencil = enableDepthAndStencil;
				_rttAntiAliasing = antiAlias;
				_rttSurfaceSelector = surfaceSelector;
				_context.setRenderToTexture(
					texture,
					enableDepthAndStencil,
					antiAlias,
					surfaceSelector
				);
			}

			return this;
		}

		public function setScissorRectangle(rectangle : Rectangle) : Context3DResource
		{
			if (_rectangle != rectangle)
			{
				_rectangle = rectangle;
				_context.setScissorRectangle(_rectangle);
			}

			return this;
		}

		public function setTextureAt(sampler	: uint,
									 texture	: TextureBase) : Context3DResource
		{
			if (_textures[sampler] != texture)
			{
				_textures[sampler] = texture;
				_context.setTextureAt(sampler, texture);
			}

			return this;
		}

		public function setVertexBufferAt(index			: int,
										  vertexBuffer	: VertexBuffer3D,
										  bufferOffset	: int		= 0,
										  format		: String	= 'float4') : Context3DResource
		{
			if (_vertexBuffers[index] != vertexBuffer
				|| _vertexBuffersOffsets[index] != bufferOffset
				|| _vertexBuffersFormats[index] != format)
			{
				_vertexBuffers[index] = vertexBuffer;
				_vertexBuffersOffsets[index] = bufferOffset;
				_vertexBuffersFormats[index] = format;

				_context.setVertexBufferAt(
					index,
					vertexBuffer,
					bufferOffset,
					format
				);
			}

			return this;
		}

		public function setStencilReferenceValue(refNum		: uint 	= 0,
												 readMask	: uint 	= 255,
												 writeMask	: uint 	= 255) : Context3DResource
		{
            if (refNum != _stencilRefNum
                || readMask != _stencilReadMask
                || writeMask != _stencilWriteMask
                )
            {
                _context.setStencilReferenceValue(refNum, readMask, writeMask);

                _stencilRefNum = refNum;
                _stencilReadMask = readMask;
                _stencilWriteMask = writeMask;
            }

			return this;
		}

		public function setStencilActions(triangleFace					: String = 'frontAndBack',
										  compareMode					: String = 'always',
										  actionOnBothPass				: String = 'keep',
										  actionOnDepthFail				: String = 'keep',
										  actionOnDepthPassStencilFail	: String = 'keep') : Context3DResource
		{
            if (triangleFace != _stencilTriangleFace
                || compareMode != _stencilCompareMode
                || actionOnBothPass != _stencilActionOnBothPass
                || actionOnDepthFail != _stencilActionOnDepthFail
                || actionOnDepthPassStencilFail != _stencilActionOnDepthPassStencilFail
            )
            {
    			_context.setStencilActions(
    				triangleFace,
    				compareMode,
    				actionOnBothPass,
    				actionOnDepthFail,
    				actionOnDepthPassStencilFail
    			);

                _stencilTriangleFace = triangleFace;
                _stencilCompareMode = compareMode;
                _stencilActionOnBothPass = actionOnBothPass;
                _stencilActionOnDepthFail = actionOnDepthFail;
                _stencilActionOnDepthPassStencilFail = actionOnDepthPassStencilFail;
            }

			return this;
		}

	}
}

handle stencil related GPU render states properly