/**
 * Copyright 2017 FreshPlanet
 * 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.freshplanet.ane.AirInAppPurchase {

	import flash.events.EventDispatcher;
	import flash.events.StatusEvent;
	import flash.external.ExtensionContext;
	import flash.system.Capabilities;

    /**
     *
     */
	public class InAppPurchase extends EventDispatcher {

        // --------------------------------------------------------------------------------------//
        //																						 //
        // 									   PUBLIC API										 //
        // 																						 //
        // --------------------------------------------------------------------------------------//

        /**
         * If true, logs will be displayed at the ActionScript level.
         */
        public static var logEnabled:Boolean = false;

        /**
         *
         */
        public static function get isSupported():Boolean {
            return _isIOSOrMacOS() || _isAndroid();
        }

        /**
         *
         */
        public static function get instance():InAppPurchase {
            return _instance ? _instance : new InAppPurchase();
        }

        /**
         * INIT_SUCCESSFUL
         * INIT_ERROR
         * @param googlePlayKey
         * @param debug
         */
        public function init(googlePlayKey:String, debug:Boolean = false):void {

            if (!isSupported)
                _dispatchEvent(InAppPurchaseEvent.INIT_ERROR, "InAppPurchase not supported");
            else
                _context.call("initLib", googlePlayKey, debug);
        }

        /**
         * PURCHASE_SUCCESSFUL
         * PURCHASE_ERROR
         * @param productId
         */
        public function makePurchase(productId:String):void {

            if (!isSupported)
                _dispatchEvent(InAppPurchaseEvent.PURCHASE_ERROR, "InAppPurchase not supported");
            else
                _context.call("makePurchase", productId);
        }

        /**
         * PURCHASE_SUCCESSFUL
         * PURCHASE_ERROR
         * @param productId
         * @param oldProductId used on Android when upgrading/downgrading subscription - pass in the productId of current user subscription
         * @param prorationMode used on Android when upgrading/downgrading subscription
         * @param oldSubscriptionPurchaseToken used on Android when upgrading/downgrading subscription
         * @param appleDiscountData used on iOS/MacOS when purchasing a subscription with a promotional offer (discount)
         */
        public function makeSubscription(productId:String, oldProductId:String = null, prorationMode:InAppPurchaseProrationMode = null, oldSubscriptionPurchaseToken:String = null, appleDiscountData:Object = null):void {

            if (!isSupported)
                _dispatchEvent(InAppPurchaseEvent.PURCHASE_ERROR, "InAppPurchase not supported");
            else
                _context.call("makeSubscription", productId, oldProductId ? oldProductId : "", prorationMode ? prorationMode.value : -1, oldSubscriptionPurchaseToken ? oldSubscriptionPurchaseToken : "", appleDiscountData ? JSON.stringify(appleDiscountData) : "");
        }

        /**
         * CONSUME_SUCCESSFUL
         * CONSUME_ERROR
         * @param productId
         * @param receipt
         */
        public function removePurchaseFromQueue(productId:String, receipt:String):void {

            if (!isSupported)
                _dispatchEvent(InAppPurchaseEvent.CONSUME_ERROR, "InAppPurchase not supported");
            else {

                _context.call("removePurchaseFromQueue", productId, receipt);

                if (_isIOSOrMacOS()) {

                    var filterPurchase:Function = function(jsonPurchase:String, index:int, purchases:Vector.<Object>):Boolean {

                        try {

                            var purchase:Object = JSON.parse(jsonPurchase);
                            return JSON.stringify(purchase.receipt) != receipt;
                        }
                        catch (error:Error) {
                            _log("ERROR", "couldn't parse purchase: " + jsonPurchase);
                        }

                        return false;
                    };

                    _iosPendingPurchases = _iosPendingPurchases.filter(filterPurchase);
                }
            }
        }

        /**
         * PRODUCT_INFO_RECEIVED
         * PRODUCT_INFO_ERROR
         * @param productsIds
         * @param subscriptionIds
         */
        public function getProductsInfo(productsIds:Array, subscriptionIds:Array):void {

            if (!isSupported)
                _dispatchEvent(InAppPurchaseEvent.PRODUCT_INFO_ERROR, "InAppPurchase not supported");
            else {

                productsIds ||= [];
                subscriptionIds ||= [];
                _context.call("getProductsInfo", productsIds, subscriptionIds);
            }
        }

        /**
         * RESTORE_INFO_RECEIVED
         * RESTORE_INFO_ERROR
         */
        public function restoreTransactions(restoreIOSHistory:Boolean=false):void {

            if (!isSupported)
                _dispatchEvent(InAppPurchaseEvent.RESTORE_INFO_ERROR, "InAppPurchase not supported");
            else if (_isAndroid() || restoreIOSHistory) {
                _context.call("restoreTransaction", restoreIOSHistory);
            }
            else if (_isIOSOrMacOS()) {

                var jsonPurchases:String = "[" + _iosPendingPurchases.join(",") + "]";
                var jsonData:String = "{ \"purchases\": " + jsonPurchases + "}";

                _dispatchEvent(InAppPurchaseEvent.RESTORE_INFO_RECEIVED, jsonData);
            }
        }

        public function clearTransactions():void
        {
            _iosPendingPurchases = new Vector.<Object>();
            if (!isSupported || _isAndroid()) {
                _dispatchEvent("CLEAR_TRANSACTIONS_ERROR", "clear transactions not supported");
            } else if (_isIOSOrMacOS()) {
                _context.call("clearTransactions");
            }
        }

        public function getPendingAppStorePurchase():String {
            if (_isIOSOrMacOS()) {
                return _context.call("getPendingAppStorePurchase") as String;
            }

            return null;
        }

        // --------------------------------------------------------------------------------------//
        //																						 //
        // 									 	PRIVATE API										 //
        // 																						 //
        // --------------------------------------------------------------------------------------//

        private static const EXTENSION_ID:String = "com.freshplanet.ane.AirInAppPurchase";
        private static var _instance:InAppPurchase = null;
		private var _context:ExtensionContext = null;

        private var _iosPendingPurchases:Vector.<Object> = new Vector.<Object>();

        /**
         * "private" singleton constructor
         */
		public function InAppPurchase() {

            super();

            if (_instance)
                throw Error("This is a singleton, use getInstance(), do not call the constructor directly.");

            _instance = this;

            _context = ExtensionContext.createExtensionContext(EXTENSION_ID, null);

            if (!_context)
                _log("ERROR", "Extension context is null. Please check if extension.xml is setup correctly.");
            else
                _context.addEventListener(StatusEvent.STATUS, _onStatus);
		}

        /**
         *
         * @param type
         * @param eventData
         */
        private function _dispatchEvent(type:String, eventData:String):void {
            this.dispatchEvent(new InAppPurchaseEvent(type, eventData))
        }

        /**
         *
         * @param event
         */
		private function _onStatus(event:StatusEvent):void {

            if (event.code == InAppPurchaseEvent.PURCHASE_SUCCESSFUL && _isIOSOrMacOS())
                _iosPendingPurchases.push(event.level);
            else if(event.code == "DEBUG")
                _log("DEBUG", event.level);
            else if(event.code == "log")
                trace(event.level);

            _dispatchEvent(event.code, event.level);
		}

        /**
         *
         * @param strings
         */
        private function _log(...strings):void {

            if (logEnabled) {

                strings.unshift(EXTENSION_ID);
                trace.apply(null, strings);
            }
        }

        /**
         *
         * @return
         */
        private static function _isIOSOrMacOS():Boolean {
			return Capabilities.os.indexOf("Mac OS") > -1 || (Capabilities.manufacturer.indexOf("iOS") > -1 && Capabilities.os.indexOf("x86_64") < 0 && Capabilities.os.indexOf("i386") < 0);
        }

        /**
         *
         * @return
         */
        private static function _isAndroid():Boolean {
            return Capabilities.manufacturer.indexOf("Android") > -1;
        }
	}
}

/**
 * Copyright 2017 FreshPlanet
 * 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.freshplanet.ane.AirInAppPurchase {

	import flash.events.EventDispatcher;
	import flash.events.StatusEvent;
	import flash.external.ExtensionContext;
	import flash.system.Capabilities;

    /**
     *
     */
	public class InAppPurchase extends EventDispatcher {

        // --------------------------------------------------------------------------------------//
        //																						 //
        // 									   PUBLIC API										 //
        // 																						 //
        // --------------------------------------------------------------------------------------//

        /**
         * If true, logs will be displayed at the ActionScript level.
         */
        public static var logEnabled:Boolean = false;

        /**
         *
         */
        public static function get isSupported():Boolean {
            return _isIOSOrMacOS() || _isAndroid();
        }

        /**
         *
         */
        public static function get instance():InAppPurchase {
            return _instance ? _instance : new InAppPurchase();
        }

        /**
         * INIT_SUCCESSFUL
         * INIT_ERROR
         * @param googlePlayKey
         * @param debug
         */
        public function init(googlePlayKey:String, debug:Boolean = false):void {

            if (!isSupported)
                _dispatchEvent(InAppPurchaseEvent.INIT_ERROR, "InAppPurchase not supported");
            else
                _context.call("initLib", googlePlayKey, debug);
        }

        /**
         * PURCHASE_SUCCESSFUL
         * PURCHASE_ERROR
         * @param productId
         */
        public function makePurchase(productId:String):void {

            if (!isSupported)
                _dispatchEvent(InAppPurchaseEvent.PURCHASE_ERROR, "InAppPurchase not supported");
            else
                _context.call("makePurchase", productId);
        }

        /**
         * PURCHASE_SUCCESSFUL
         * PURCHASE_ERROR
         * @param productId
         * @param oldProductId used on Android when upgrading/downgrading subscription - pass in the productId of current user subscription
         * @param prorationMode used on Android when upgrading/downgrading subscription
         * @param appleDiscountData used on iOS/MacOS when purchasing a subscription with a promotional offer (discount)
         */
        public function makeSubscription(productId:String, oldProductId:String = null, prorationMode:InAppPurchaseProrationMode = null, appleDiscountData:Object = null):void {

            if (!isSupported)
                _dispatchEvent(InAppPurchaseEvent.PURCHASE_ERROR, "InAppPurchase not supported");
            else
                _context.call("makeSubscription", productId, oldProductId ? oldProductId : "", prorationMode ? prorationMode.value : -1, "", appleDiscountData ? JSON.stringify(appleDiscountData) : "");
        }

        /**
         * CONSUME_SUCCESSFUL
         * CONSUME_ERROR
         * @param productId
         * @param receipt
         */
        public function removePurchaseFromQueue(productId:String, receipt:String):void {

            if (!isSupported)
                _dispatchEvent(InAppPurchaseEvent.CONSUME_ERROR, "InAppPurchase not supported");
            else {

                _context.call("removePurchaseFromQueue", productId, receipt);

                if (_isIOSOrMacOS()) {

                    var filterPurchase:Function = function(jsonPurchase:String, index:int, purchases:Vector.<Object>):Boolean {

                        try {

                            var purchase:Object = JSON.parse(jsonPurchase);
                            return JSON.stringify(purchase.receipt) != receipt;
                        }
                        catch (error:Error) {
                            _log("ERROR", "couldn't parse purchase: " + jsonPurchase);
                        }

                        return false;
                    };

                    _iosPendingPurchases = _iosPendingPurchases.filter(filterPurchase);
                }
            }
        }

        /**
         * PRODUCT_INFO_RECEIVED
         * PRODUCT_INFO_ERROR
         * @param productsIds
         * @param subscriptionIds
         */
        public function getProductsInfo(productsIds:Array, subscriptionIds:Array):void {

            if (!isSupported)
                _dispatchEvent(InAppPurchaseEvent.PRODUCT_INFO_ERROR, "InAppPurchase not supported");
            else {

                productsIds ||= [];
                subscriptionIds ||= [];
                _context.call("getProductsInfo", productsIds, subscriptionIds);
            }
        }

        /**
         * RESTORE_INFO_RECEIVED
         * RESTORE_INFO_ERROR
         */
        public function restoreTransactions(restoreIOSHistory:Boolean=false):void {

            if (!isSupported)
                _dispatchEvent(InAppPurchaseEvent.RESTORE_INFO_ERROR, "InAppPurchase not supported");
            else if (_isAndroid() || restoreIOSHistory) {
                _context.call("restoreTransaction", restoreIOSHistory);
            }
            else if (_isIOSOrMacOS()) {

                var jsonPurchases:String = "[" + _iosPendingPurchases.join(",") + "]";
                var jsonData:String = "{ \"purchases\": " + jsonPurchases + "}";

                _dispatchEvent(InAppPurchaseEvent.RESTORE_INFO_RECEIVED, jsonData);
            }
        }

        public function clearTransactions():void
        {
            _iosPendingPurchases = new Vector.<Object>();
            if (!isSupported || _isAndroid()) {
                _dispatchEvent("CLEAR_TRANSACTIONS_ERROR", "clear transactions not supported");
            } else if (_isIOSOrMacOS()) {
                _context.call("clearTransactions");
            }
        }

        public function getPendingAppStorePurchase():String {
            if (_isIOSOrMacOS()) {
                return _context.call("getPendingAppStorePurchase") as String;
            }

            return null;
        }

        // --------------------------------------------------------------------------------------//
        //																						 //
        // 									 	PRIVATE API										 //
        // 																						 //
        // --------------------------------------------------------------------------------------//

        private static const EXTENSION_ID:String = "com.freshplanet.ane.AirInAppPurchase";
        private static var _instance:InAppPurchase = null;
		private var _context:ExtensionContext = null;

        private var _iosPendingPurchases:Vector.<Object> = new Vector.<Object>();

        /**
         * "private" singleton constructor
         */
		public function InAppPurchase() {

            super();

            if (_instance)
                throw Error("This is a singleton, use getInstance(), do not call the constructor directly.");

            _instance = this;

            _context = ExtensionContext.createExtensionContext(EXTENSION_ID, null);

            if (!_context)
                _log("ERROR", "Extension context is null. Please check if extension.xml is setup correctly.");
            else
                _context.addEventListener(StatusEvent.STATUS, _onStatus);
		}

        /**
         *
         * @param type
         * @param eventData
         */
        private function _dispatchEvent(type:String, eventData:String):void {
            this.dispatchEvent(new InAppPurchaseEvent(type, eventData))
        }

        /**
         *
         * @param event
         */
		private function _onStatus(event:StatusEvent):void {

            if (event.code == InAppPurchaseEvent.PURCHASE_SUCCESSFUL && _isIOSOrMacOS())
                _iosPendingPurchases.push(event.level);
            else if(event.code == "DEBUG")
                _log("DEBUG", event.level);
            else if(event.code == "log")
                trace(event.level);

            _dispatchEvent(event.code, event.level);
		}

        /**
         *
         * @param strings
         */
        private function _log(...strings):void {

            if (logEnabled) {

                strings.unshift(EXTENSION_ID);
                trace.apply(null, strings);
            }
        }

        /**
         *
         * @return
         */
        private static function _isIOSOrMacOS():Boolean {
			return Capabilities.os.indexOf("Mac OS") > -1 || (Capabilities.manufacturer.indexOf("iOS") > -1 && Capabilities.os.indexOf("x86_64") < 0 && Capabilities.os.indexOf("i386") < 0);
        }

        /**
         *
         * @return
         */
        private static function _isAndroid():Boolean {
            return Capabilities.manufacturer.indexOf("Android") > -1;
        }
	}
}

remove old subscription token param

remove old subscription token param


/*
Copyright (c) 2014, Mesmotronic Limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this
  list of conditions and the following disclaimer in the documentation and/or
  other materials provided with the distribution.

* Neither the name of the {organization} nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package com.mesmotronic.ane
{
	import flash.external.ExtensionContext;

	public class AndroidFullScreen
	{
		// Static initializer
		{
			init();
		}

		static private function init():void
		{
			context = ExtensionContext.createExtensionContext('com.mesmotronic.ane.fullscreen', '');
		}

		static private var context:ExtensionContext;

		static public function get isSupported():Boolean
		{
			return !!context;
		}

		/**
		 * Hides the system status and navigation bars
		 * @return		Boolean		false if unsuccessful or not supported, otherwise true
		 */
		static public function hideSystemUI():Boolean
		{
			if (!context) return false;
			return context.call("hideSystemUI");
		}

		/**
		 * Puts your app into full screen immersive mode, hiding the system and
		 * navigation bars. Users can show them by swiping from the top of the screen.
		 *
		 * @return		Boolean		false if unsuccessful or not supported, otherwise true
		 */
		static public function immersiveMode(sticky:Boolean=true):Boolean
		{
			if (!context) return false;
			return context.call("immersiveMode", sticky);
		}

		/**
		 * Is immersive mode supported on this device?
		 *
		 * @return		Boolean		false if unsuccessful or not supported, otherwise true
		 */
		static public function get isImmersiveModeSupported():Boolean
		{
			if (!context) return false;
			return context.call("immersiveModeSupported");
		}

		/**
		 * Show the system status and navigation bars
		 * @return		Boolean		false if unsuccessful or not supported, otherwise true
		 */
		static public function showSystemUI():Boolean
		{
			if (!context) return false;
			return context.call("showSystemUI");
		}

		/**
		 * Extends your app underneath the status and navigation bar
		 * @return		Boolean		false if unsuccessful or not supported, otherwise true
		 */
		static public function showUnderSystemUI():Boolean
		{
			if (!context) return false;
			return context.call("showUnderSystemUI");
		}
	}
}

/*
Copyright (c) 2014, Mesmotronic Limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this
  list of conditions and the following disclaimer in the documentation and/or
  other materials provided with the distribution.

* Neither the name of the {organization} nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package com.mesmotronic.ane
{
	import flash.external.ExtensionContext;

	public class AndroidFullScreen
	{
		// Static initializer
		{
			init();
		}

		static private function init():void
		{
			context = ExtensionContext.createExtensionContext('com.mesmotronic.ane.fullscreen', '');
		}

		static private var context:ExtensionContext;

		static public function get isSupported():Boolean
		{
			return !!context;
		}

		/**
		 * Hides the system status and navigation bars
		 * @return		Boolean		false if unsuccessful or not supported, otherwise true
		 */
		static public function hideSystemUI():Boolean
		{
			if (!context) return false;
			return context.call("hideSystemUI");
		}

		/**
		 * Puts your app into full screen immersive mode, hiding the system and
		 * navigation bars. Users can show them by swiping from the top of the screen.
		 *
		 * @return		Boolean		false if unsuccessful or not supported, otherwise true
		 */
		static public function immersiveMode(sticky:Boolean=true):Boolean
		{
			if (!context) return false;
			return context.call("immersiveMode", sticky);
		}

		/**
		 * Is immersive mode supported on this device?
		 *
		 * @return		Boolean		false if unsuccessful or not supported, otherwise true
		 */
		static public function get isImmersiveModeSupported():Boolean
		{
			if (!context) return false;
			return context.call("isImmersiveModeSupported");
		}

		/**
		 * Show the system status and navigation bars
		 * @return		Boolean		false if unsuccessful or not supported, otherwise true
		 */
		static public function showSystemUI():Boolean
		{
			if (!context) return false;
			return context.call("showSystemUI");
		}

		/**
		 * Extends your app underneath the status and navigation bar
		 * @return		Boolean		false if unsuccessful or not supported, otherwise true
		 */
		static public function showUnderSystemUI():Boolean
		{
			if (!context) return false;
			return context.call("showUnderSystemUI");
		}
	}
}

Update AndroidFullScreen.as

Update AndroidFullScreen.as

A little mistake. In FullScreenContext.java function name is isImmersiveModeSupported.


package com.kaltura.kdpfl.view
{
	import com.kaltura.kdpfl.model.ConfigProxy;
	import com.kaltura.kdpfl.model.MediaProxy;
	import com.kaltura.kdpfl.model.SequenceProxy;
	import com.kaltura.kdpfl.model.type.AdsNotificationTypes;
	import com.kaltura.kdpfl.model.type.NotificationType;
	import com.kaltura.kdpfl.model.type.SequenceContextType;
	import com.kaltura.types.KalturaAdType;
	import com.kaltura.vo.KalturaAdCuePoint;

	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.external.ExternalInterface;
	import flash.net.URLLoader;
	import flash.net.URLRequest;

	import org.puremvc.as3.interfaces.INotification;
	import org.puremvc.as3.patterns.mediator.Mediator;

	public class ComscoreMediator extends Mediator
	{
		public static const NAME : String = "comscoreMediator";

		public static const VIDEO_TYPE : String = "1";
		public static const PREROLL_AD_CONTENT_TYPE : String = "09";
		public static const POSTROLL_AD_CONTENT_TYPE : String = "10";
		public static const MIDROLL_AD_CONTENT_TYPE : String = "11";
		public static const IN_BANNER_VIDEO_AD : String = "12";

		protected var _playerPlayedFired : Boolean = false;
		protected var cParams : Object = new Object();
		protected var _flashvars : Object;
		protected var view:ComscorePluginCode;

		//total number of segments, determined by number of ad cue points
		private var _numOfSegments:int = 1;
		//current playing segment
		private var _currentSegment:int = 1;
		//array containing all ad cue points start time, to calculate current segment
		private var _startTimeArray:Array = new Array();

		private var _shoudSendBeacon:Boolean = false;
		private var _sendOnSequnceEnd:Boolean = false;

		private static const CPARAMS_LENGTH:int = 6;
		private var _sequenceProxy:SequenceProxy;

		public function ComscoreMediator(mediatorName:String=null, viewComponent:Object=null)
		{
			super(NAME, viewComponent);
			view = viewComponent as ComscorePluginCode;
		}

		override public function onRegister():void
		{
			_sequenceProxy = (facade.retrieveProxy(SequenceProxy.NAME) as SequenceProxy);
			super.onRegister();
		}

		override public function listNotificationInterests():Array
		{
			var arr : Array = [
				NotificationType.PLAYER_PLAYED,
				AdsNotificationTypes.AD_START,
				NotificationType.ENTRY_READY,
				NotificationType.LAYOUT_READY,
				NotificationType.CUE_POINTS_RECEIVED,
				NotificationType.AD_OPPORTUNITY,
				NotificationType.PLAYER_UPDATE_PLAYHEAD,
				NotificationType.MID_SEQUENCE_COMPLETE]
			return arr;
		}

		override public function handleNotification(notification:INotification):void
		{
			switch (notification.getName() )
			{
				case NotificationType.LAYOUT_READY:
					_flashvars = (facade.retrieveProxy(ConfigProxy.NAME) as ConfigProxy).vo.flashvars;
					break;

				case NotificationType.ENTRY_READY:
					createCParams();
					_playerPlayedFired = false;
					break;

				case NotificationType.PLAYER_PLAYED:
					if (!_playerPlayedFired)
					{
						if (!_sequenceProxy.vo.isInSequence)
						{
							cParams["c5"] = view.c5;
							comscoreBeacon();
							_playerPlayedFired = true;
						}
					}
					break;

				case AdsNotificationTypes.AD_START:
					switch (_sequenceProxy.sequenceContext)
					{
						case SequenceContextType.PRE:
							cParams["c5"] = PREROLL_AD_CONTENT_TYPE;
							break;
						case SequenceContextType.POST:
							cParams["c5"] = POSTROLL_AD_CONTENT_TYPE;
							break;
						case SequenceContextType.MID:
							cParams["c5"] = MIDROLL_AD_CONTENT_TYPE ;
							_sendOnSequnceEnd = true;
							break;
					}
					comscoreBeacon();
					_shoudSendBeacon = false;
					break;

				case NotificationType.CUE_POINTS_RECEIVED:
					var cuePointsMap:Object = notification.getBody();
					_startTimeArray = new Array();
					var entryMSDuration:int = (facade.retrieveProxy(MediaProxy.NAME) as MediaProxy).vo.entry.msDuration;
					for (var inTime:String in cuePointsMap) {
						if (parseInt(inTime)!=0 && parseInt(inTime)!=entryMSDuration) {
							var cpArray:Array = cuePointsMap[inTime];
							//whether this start time was already saved to _startTimeArray
							var startTimeSaved:Boolean = false;
							for (var i:int = 0; i<cpArray.length; i++) {
								if (cpArray[i] is KalturaAdCuePoint) {
									var curCp:KalturaAdCuePoint = cpArray[i] as KalturaAdCuePoint;
									if (curCp.adType == KalturaAdType.VIDEO && !startTimeSaved) {
										_startTimeArray.push(inTime);
										startTimeSaved = true;
										_numOfSegments++;
									}
								}
							}

						}
					}
					_startTimeArray.sort(Array.NUMERIC);
					break;

				case NotificationType.AD_OPPORTUNITY:
					var msDuration:int = (facade.retrieveProxy(MediaProxy.NAME) as MediaProxy).vo.entry.msDuration;
					var cp:KalturaAdCuePoint = notification.getBody().cuePoint as KalturaAdCuePoint;
					if (cp.startTime!=0 && cp.startTime!=msDuration && cp.adType == KalturaAdType.VIDEO) {
						for (var j:int =0 ; j<_startTimeArray.length; j++) {
							if (_startTimeArray[j]==cp.startTime) {
								//add 1 since array is zero based and segment is 1 based,
								//add another one because we passed the cue point
								_currentSegment = j + 2;
								break;
							}
						}

						_shoudSendBeacon = true;
					}
					break;

				case NotificationType.PLAYER_UPDATE_PLAYHEAD:
					if (_shoudSendBeacon) {
						cParams["c5"] = view.c5;
						comscoreBeacon();
						_shoudSendBeacon = false;
					}
					break;

				case NotificationType.MID_SEQUENCE_COMPLETE:
					if (_sendOnSequnceEnd) {
						cParams["c5"] = view.c5;
						comscoreBeacon();
						_sendOnSequnceEnd = false;
					}
					break;
			}
		}

		protected function comscoreBeacon () : void
		{
			var loadUrl : String;
			var referrer : String = "";
			var page : String = "";
			var title : String = "";

			try {
				if(_flashvars.referer)
				{
					referrer = ExternalInterface.call( "function() { return document.referrer; }").toString();
				}
			} catch (e : Error)
			{
				referrer = _flashvars.referer;
			}
			try {
				if(_flashvars.referer)
				{
					page = ExternalInterface.call( "function () { return document.location.href; } ").toString();
				}
			} catch (e : Error)
			{
				page = _flashvars.referer;
			}
			try {
				if(_flashvars.referer)
				{
					title = ExternalInterface.call( "function () { return document.title; } ").toString();
				}
			} catch (e : Error)
			{
				title = _flashvars.referer;
			}

			if (page.indexOf("https") != -1 ) {
				loadUrl = "https://sb.";
			}  else {
				loadUrl = "http://b."
			}
			loadUrl += "scorecardresearch.com/p?";

			createCParams();

			//concat cParams, by their order
			for (var i:int = 0; i < CPARAMS_LENGTH; i++)
			{
				var curC:String = "c" + (i + 1);
				if (cParams[curC] && cParams[curC]!='')
				{
					loadUrl += curC+"="+cParams[curC]+"&";
				}
			}

			if (page && page != "") {
				loadUrl += "c7=" + page +"&";
			}

			if (title && title != "") {
				loadUrl += "c8=" + title +"&";
			}

			if (referrer && referrer != "") {
				loadUrl += "c9=" + referrer +"&";
			}

			loadUrl += "c10=" + _currentSegment + "-" + _numOfSegments + "&";
			loadUrl += "rn=" + Math.random().toString() + "&";
			loadUrl +="cv=" + view.comscoreVersion + "&";
			if (view.cs_eidr)
				loadUrl +="cs_eidr="+view.cs_eidr + "&";
			if (_sequenceProxy.vo.isInSequence && view.cs_adid)
				loadUrl += "cs_adid="+view.cs_adid;

			var loader : URLLoader = new URLLoader();
			var urlRequest : URLRequest = new URLRequest(loadUrl);
			loader.addEventListener(Event.COMPLETE, onComscoreBeaconSuccess);
			loader.addEventListener(IOErrorEvent.IO_ERROR, onComscoreBeaconFailed);
			loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onComscoreBeaconFailed);
			loader.load(urlRequest);
		}

		protected function onComscoreBeaconSuccess (e : Event) : void
		{
		}

		protected function onComscoreBeaconFailed (e : Event) : void
		{
		}

		protected function createCParams() : void
		{
			cParams["c1"] = view.c1 ? view.c1 : VIDEO_TYPE;
			cParams["c2"] = view.c2;
			cParams["c3"] = view.c3;
			cParams["c4"] = view.c4;
			cParams["c6"] = view.c6;
		}
	}
}

package com.kaltura.kdpfl.view
{
	import com.kaltura.kdpfl.model.ConfigProxy;
	import com.kaltura.kdpfl.model.MediaProxy;
	import com.kaltura.kdpfl.model.SequenceProxy;
	import com.kaltura.kdpfl.model.type.AdsNotificationTypes;
	import com.kaltura.kdpfl.model.type.NotificationType;
	import com.kaltura.kdpfl.model.type.SequenceContextType;
	import com.kaltura.types.KalturaAdType;
	import com.kaltura.vo.KalturaAdCuePoint;

	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.external.ExternalInterface;
	import flash.net.URLLoader;
	import flash.net.URLRequest;

	import org.puremvc.as3.interfaces.INotification;
	import org.puremvc.as3.patterns.mediator.Mediator;

	public class ComscoreMediator extends Mediator
	{
		public static const NAME : String = "comscoreMediator";

		public static const VIDEO_TYPE : String = "1";
		public static const PREROLL_AD_CONTENT_TYPE : String = "09";
		public static const POSTROLL_AD_CONTENT_TYPE : String = "10";
		public static const MIDROLL_AD_CONTENT_TYPE : String = "11";
		public static const IN_BANNER_VIDEO_AD : String = "12";

		protected var _playerPlayedFired : Boolean = false;
		protected var cParams : Object = new Object();
		protected var _flashvars : Object;
		protected var view:ComscorePluginCode;

		//total number of segments, determined by number of ad cue points
		private var _numOfSegments:int = 1;
		//current playing segment
		private var _currentSegment:int = 1;
		//array containing all ad cue points start time, to calculate current segment
		private var _startTimeArray:Array = new Array();

		private var _shoudSendBeacon:Boolean = false;
		private var _sendOnSequnceEnd:Boolean = false;

		private static const CPARAMS_LENGTH:int = 6;
		private var _sequenceProxy:SequenceProxy;

		public function ComscoreMediator(mediatorName:String=null, viewComponent:Object=null)
		{
			super(NAME, viewComponent);
			view = viewComponent as ComscorePluginCode;
		}

		override public function onRegister():void
		{
			_sequenceProxy = (facade.retrieveProxy(SequenceProxy.NAME) as SequenceProxy);
			super.onRegister();
		}

		override public function listNotificationInterests():Array
		{
			var arr : Array = [
				NotificationType.PLAYER_PLAYED,
				AdsNotificationTypes.AD_START,
				NotificationType.ENTRY_READY,
				NotificationType.LAYOUT_READY,
				NotificationType.CUE_POINTS_RECEIVED,
				NotificationType.AD_OPPORTUNITY,
				NotificationType.PLAYER_UPDATE_PLAYHEAD,
				NotificationType.MID_SEQUENCE_COMPLETE,
				NotificationType.CHANGE_MEDIA]
			return arr;
		}

		override public function handleNotification(notification:INotification):void
		{
			switch (notification.getName() )
			{
				case NotificationType.LAYOUT_READY:
					_flashvars = (facade.retrieveProxy(ConfigProxy.NAME) as ConfigProxy).vo.flashvars;
					break;

				case NotificationType.ENTRY_READY:
					createCParams();
					_playerPlayedFired = false;
					break;

				case NotificationType.PLAYER_PLAYED:
					if (!_playerPlayedFired)
					{
						if (!_sequenceProxy.vo.isInSequence)
						{
							cParams["c5"] = view.c5;
							comscoreBeacon();
							_playerPlayedFired = true;
						}
					}
					break;

				case AdsNotificationTypes.AD_START:
					switch (_sequenceProxy.sequenceContext)
					{
						case SequenceContextType.PRE:
							cParams["c5"] = PREROLL_AD_CONTENT_TYPE;
							break;
						case SequenceContextType.POST:
							cParams["c5"] = POSTROLL_AD_CONTENT_TYPE;
							break;
						case SequenceContextType.MID:
							cParams["c5"] = MIDROLL_AD_CONTENT_TYPE ;
							_sendOnSequnceEnd = true;
							break;
					}
					comscoreBeacon();
					_shoudSendBeacon = false;
					break;

				case NotificationType.CUE_POINTS_RECEIVED:
					var cuePointsMap:Object = notification.getBody();
					_startTimeArray = new Array();
					var entryMSDuration:int = (facade.retrieveProxy(MediaProxy.NAME) as MediaProxy).vo.entry.msDuration;
					for (var inTime:String in cuePointsMap) {
						if (parseInt(inTime)!=0 && parseInt(inTime)!=entryMSDuration) {
							var cpArray:Array = cuePointsMap[inTime];
							//whether this start time was already saved to _startTimeArray
							var startTimeSaved:Boolean = false;
							for (var i:int = 0; i<cpArray.length; i++) {
								if (cpArray[i] is KalturaAdCuePoint) {
									var curCp:KalturaAdCuePoint = cpArray[i] as KalturaAdCuePoint;
									if (curCp.adType == KalturaAdType.VIDEO && !startTimeSaved) {
										_startTimeArray.push(inTime);
										startTimeSaved = true;
										_numOfSegments++;
									}
								}
							}

						}
					}
					_startTimeArray.sort(Array.NUMERIC);
					break;

				case NotificationType.AD_OPPORTUNITY:
					var msDuration:int = (facade.retrieveProxy(MediaProxy.NAME) as MediaProxy).vo.entry.msDuration;
					var cp:KalturaAdCuePoint = notification.getBody().cuePoint as KalturaAdCuePoint;
					if (cp.startTime!=0 && cp.startTime!=msDuration && cp.adType == KalturaAdType.VIDEO) {
						for (var j:int =0 ; j<_startTimeArray.length; j++) {
							if (_startTimeArray[j]==cp.startTime) {
								//add 1 since array is zero based and segment is 1 based,
								//add another one because we passed the cue point
								_currentSegment = j + 2;
								break;
							}
						}

						_shoudSendBeacon = true;
					}
					break;

				case NotificationType.PLAYER_UPDATE_PLAYHEAD:
					if (_shoudSendBeacon) {
						cParams["c5"] = view.c5;
						comscoreBeacon();
						_shoudSendBeacon = false;
					}
					break;

				case NotificationType.MID_SEQUENCE_COMPLETE:
					if (_sendOnSequnceEnd) {
						cParams["c5"] = view.c5;
						comscoreBeacon();
						_sendOnSequnceEnd = false;
					}
					break;

				case NotificationType.CHANGE_MEDIA:
					_numOfSegments = 1;
			}
		}

		protected function comscoreBeacon () : void
		{
			var loadUrl : String;
			var referrer : String = "";
			var page : String = "";
			var title : String = "";

			try {
				if(_flashvars.referer)
				{
					referrer = ExternalInterface.call( "function() { return document.referrer; }").toString();
				}
			} catch (e : Error)
			{
				referrer = _flashvars.referer;
			}
			try {
				if(_flashvars.referer)
				{
					page = ExternalInterface.call( "function () { return document.location.href; } ").toString();
				}
			} catch (e : Error)
			{
				page = _flashvars.referer;
			}
			try {
				if(_flashvars.referer)
				{
					title = ExternalInterface.call( "function () { return document.title; } ").toString();
				}
			} catch (e : Error)
			{
				title = _flashvars.referer;
			}

			if (page.indexOf("https") != -1 ) {
				loadUrl = "https://sb.";
			}  else {
				loadUrl = "http://b."
			}
			loadUrl += "scorecardresearch.com/p?";

			createCParams();

			//concat cParams, by their order
			for (var i:int = 0; i < CPARAMS_LENGTH; i++)
			{
				var curC:String = "c" + (i + 1);
				if (cParams[curC] && cParams[curC]!='')
				{
					loadUrl += curC+"="+cParams[curC]+"&";
				}
			}

			if (page && page != "") {
				loadUrl += "c7=" + page +"&";
			}

			if (title && title != "") {
				loadUrl += "c8=" + title +"&";
			}

			if (referrer && referrer != "") {
				loadUrl += "c9=" + referrer +"&";
			}

			loadUrl += "c10=" + _currentSegment + "-" + _numOfSegments + "&";
			loadUrl += "rn=" + Math.random().toString() + "&";
			loadUrl +="cv=" + view.comscoreVersion + "&";
			if (view.cs_eidr)
				loadUrl +="cs_eidr="+view.cs_eidr + "&";
			if (_sequenceProxy.vo.isInSequence && view.cs_adid)
				loadUrl += "cs_adid="+view.cs_adid;

			var loader : URLLoader = new URLLoader();
			var urlRequest : URLRequest = new URLRequest(loadUrl);
			loader.addEventListener(Event.COMPLETE, onComscoreBeaconSuccess);
			loader.addEventListener(IOErrorEvent.IO_ERROR, onComscoreBeaconFailed);
			loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onComscoreBeaconFailed);
			loader.load(urlRequest);
		}

		protected function onComscoreBeaconSuccess (e : Event) : void
		{
		}

		protected function onComscoreBeaconFailed (e : Event) : void
		{
		}

		protected function createCParams() : void
		{
			cParams["c1"] = view.c1 ? view.c1 : VIDEO_TYPE;
			cParams["c2"] = view.c2;
			cParams["c3"] = view.c3;
			cParams["c4"] = view.c4;
			cParams["c6"] = view.c6;
		}
	}
}

reset segments count on change media

qnd: reset segments count on change media

git-svn-id: 3f608e5a9a704dd448217c0a64c508e7f145cfa1@92241 6b8eccd3-e8c5-4e7d-8186-e12b5326b719


////////////////////////////////////////////////////////////////////////////////
//
//  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.TextFieldAutoSize;
	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")
			{
				autoSize = TextFieldAutoSize.NONE;
                tf.align = "center";
			}
            else if (align == "right")
			{
                tf.align = "right";
				autoSize = TextFieldAutoSize.NONE;
			}
            var backgroundColor:Object = ValuesManager.valuesImpl.getValue(sp, "background-color");
            if (backgroundColor != null)
            {
                this.background = true;
                if (backgroundColor is String)
                {
                    backgroundColor = backgroundColor.replace("#", "0x");
                    backgroundColor = uint(backgroundColor);
                }
                this.backgroundColor = backgroundColor as uint;
            }
			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.TextFieldAutoSize;
	import flash.text.TextFormat;

	import org.apache.flex.core.ValuesManager;
    import org.apache.flex.events.Event;

    /**
     *  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;
			sp.addEventListener("classNameChanged", updateStyles);

			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")
			{
				autoSize = TextFieldAutoSize.NONE;
                tf.align = "center";
			}
            else if (align == "right")
			{
                tf.align = "right";
				autoSize = TextFieldAutoSize.NONE;
			}
            var backgroundColor:Object = ValuesManager.valuesImpl.getValue(sp, "background-color");
            if (backgroundColor != null)
            {
                this.background = true;
                if (backgroundColor is String)
                {
                    backgroundColor = backgroundColor.replace("#", "0x");
                    backgroundColor = uint(backgroundColor);
                }
                this.backgroundColor = backgroundColor as uint;
            }
			defaultTextFormat = tf;
			super.text = value;
		}

        private function updateStyles(event:Event):void
        {
            // force styles to be re-calculated
            this.text = text;
        }
	}
}

handle classname changes

handle classname changes


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

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

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

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

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

		private var _data				: DataProvider;

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

		public function get frustumCulling() : uint
		{
			return _frustumCulling;
		}
		public function set frustumCulling(value : uint) : void
		{
			if (value != _frustumCulling)
			{
				_frustumCulling = value;
				if (value == FrustumCulling.DISABLED)
				{
					_data.computedVisibility = true;
					if (_mesh.localToWorldTransformChanged.hasCallback(meshLocalToWorldChangedHandler))
					{
						_mesh.localToWorldTransformChanged.remove(meshLocalToWorldChangedHandler);
					}
				}
				else if (_mesh && _mesh.scene)
				{
					_mesh.localToWorldTransformChanged.add(meshLocalToWorldChangedHandler);
	            	testCulling();
				}
			}
		}

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

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

		public function MeshVisibilityController()
		{
			super(Mesh);

			initialize();
		}

		private function initialize() : void
		{
			_data = new DataProvider(
				{ computedVisibility : true },
				'MeshVisibilityDataProvider',
				DataProviderUsage.EXCLUSIVE
			);

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

            _state = STATE_UNDEFINED;

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

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

			_mesh = target;

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

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

			if (_frustumCulling)
				testCulling();
		}

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

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

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

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

			if (!scene)
				return ;

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

			if (_frustumCulling)
			{
	            meshLocalToWorldChangedHandler(mesh, mesh.getLocalToWorldTransform());
				mesh.localToWorldTransformChanged.add(meshLocalToWorldChangedHandler);
			}

            mesh.computedVisibilityChanged.add(computedVisiblityChangedHandler);
            mesh.bindings.addProvider(_data);
		}

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

			if (!scene)
				return ;

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

			if (_frustumCulling)
				mesh.localToWorldTransformChanged.remove(meshLocalToWorldChangedHandler);

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

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

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

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

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

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

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

				_boundingSphere.update(center, radius);
			}

			testCulling();
		}

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

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

				if (!camera)
					return ;

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

				var inside : Boolean = _lastTest == -1;

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

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

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

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

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

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

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

		private var _data				: DataProvider;

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

		public function get frustumCulling() : uint
		{
			return _frustumCulling;
		}
		public function set frustumCulling(value : uint) : void
		{
			if (value != _frustumCulling)
			{
				_frustumCulling = value;
				if (value == FrustumCulling.DISABLED)
				{
					_data.computedVisibility = true;
					if (_mesh.localToWorldTransformChanged.hasCallback(meshLocalToWorldChangedHandler))
						_mesh.localToWorldTransformChanged.remove(meshLocalToWorldChangedHandler);
				}
				else if (_mesh && _mesh.scene)
				{
					_mesh.localToWorldTransformChanged.add(meshLocalToWorldChangedHandler);
	            	testCulling();
				}
			}
		}

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

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

		public function MeshVisibilityController()
		{
			super(Mesh);

			initialize();
		}

		private function initialize() : void
		{
			_data = new DataProvider(
				{ computedVisibility : true },
				'MeshVisibilityDataProvider',
				DataProviderUsage.EXCLUSIVE
			);

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

            _state = STATE_UNDEFINED;

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

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

			_mesh = target;

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

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

			if (_frustumCulling)
				testCulling();
		}

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

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

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

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

			if (!scene)
				return ;

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

			if (_frustumCulling)
			{
	            meshLocalToWorldChangedHandler(mesh, mesh.getLocalToWorldTransform());
				mesh.localToWorldTransformChanged.add(meshLocalToWorldChangedHandler);
			}

            mesh.computedVisibilityChanged.add(computedVisiblityChangedHandler);
            mesh.bindings.addProvider(_data);
		}

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

			if (!scene)
				return ;

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

			if (_frustumCulling)
				mesh.localToWorldTransformChanged.remove(meshLocalToWorldChangedHandler);

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

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

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

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

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

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

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

				_boundingSphere.update(center, radius);
			}

			testCulling();
		}

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

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

				if (!camera)
					return ;

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

				var inside : Boolean = _lastTest == -1;

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

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

remove useless brackets

remove useless brackets


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

package com.threerings.flash {

import flash.display.DisplayObject;

import flash.filters.BevelFilter;
import flash.filters.BitmapFilter;
import flash.filters.BlurFilter;
import flash.filters.ColorMatrixFilter;
import flash.filters.ConvolutionFilter;
import flash.filters.DisplacementMapFilter;
import flash.filters.DropShadowFilter;
import flash.filters.GlowFilter;
import flash.filters.GradientBevelFilter;
import flash.filters.GradientGlowFilter;

import com.threerings.util.ArrayUtil;
import com.threerings.util.ClassUtil;

/**
 * Useful utility methods that wouldn't be needed if the flash API were not so retarded.
 */
public class FilterUtil
{
    /**
     * Add the specified filter to the DisplayObject.
     */
    public static function addFilter (disp :DisplayObject, filter :BitmapFilter) :void
    {
        checkArgs(disp, filter);
        var filts :Array = disp.filters;
        if (filts == null) {
            filts = [];
        }
        filts.push(filter);
        disp.filters = filts;
    }

    /**
     * Remove the specified filter from the DisplayObject.
     * Note that the filter set in the DisplayObject is a clone, so the values
     * of the specified filter are used to find a match.
     */
    public static function removeFilter (disp :DisplayObject, filter :BitmapFilter) :void
    {
        checkArgs(disp, filter);
        var filts :Array = disp.filters;
        if (filts != null) {
            for (var ii :int = filts.length - 1; ii >= 0; ii--) {
                var oldFilter :BitmapFilter = (filts[ii] as BitmapFilter);
                if (equals(oldFilter, filter)) {
                    filts.splice(ii, 1);
                    if (filts.length == 0) {
                        filts = null;
                    }
                    disp.filters = filts;
                    return; // SUCCESS
                }
            }
        }
    }

    /**
     * Are the two filters equals?
     */
    public static function equals (f1 :BitmapFilter, f2 :BitmapFilter) :Boolean
    {
        if (f1 === f2) { // catch same instance, or both null
            return true;

        } else if (f1 == null || f2 == null) { // otherwise nulls are no good
            return false;
        }

        var c1 :Class = ClassUtil.getClass(f1);
        if (c1 !== ClassUtil.getClass(f2)) {
            return false;
        }

        // when we have two filters of the same class, figure it out by hand...
        switch (c1) {
        case BevelFilter:
            var bf1 :BevelFilter = (f1 as BevelFilter);
            var bf2 :BevelFilter = (f2 as BevelFilter);
            return (bf1.angle == bf2.angle) && (bf1.blurX == bf2.blurX) &&
                (bf1.blurY == bf2.blurY) && (bf1.distance == bf2.distance) &&
                (bf1.highlightAlpha == bf2.highlightAlpha) &&
                (bf1.highlightColor == bf2.highlightColor) && (bf1.knockout == bf2.knockout) &&
                (bf1.quality == bf2.quality) && (bf1.shadowAlpha == bf2.shadowAlpha) &&
                (bf1.shadowColor == bf2.shadowColor) && (bf1.strength == bf2.strength) &&
                (bf1.type == bf2.type);

        case BlurFilter:
            var blur1 :BlurFilter = (f1 as BlurFilter);
            var blur2 :BlurFilter = (f2 as BlurFilter);
            return (blur1.blurX == blur2.blurX) && (blur1.blurY == blur2.blurY) &&
                (blur1.quality == blur2.quality);

        case ColorMatrixFilter:
            var cmf1 :ColorMatrixFilter = (f1 as ColorMatrixFilter);
            var cmf2 :ColorMatrixFilter = (f2 as ColorMatrixFilter);
            return ArrayUtil.equals(cmf1.matrix, cmf2.matrix);

        case ConvolutionFilter:
            var cf1 :ConvolutionFilter = (f1 as ConvolutionFilter);
            var cf2 :ConvolutionFilter = (f2 as ConvolutionFilter);
            return (cf1.alpha == cf2.alpha) && (cf1.bias == cf2.bias) && (cf1.clamp == cf2.clamp) &&
                (cf1.color == cf2.color) && (cf1.divisor == cf2.divisor) &&
                ArrayUtil.equals(cf1.matrix, cf2.matrix) && (cf1.matrixX == cf2.matrixX) &&
                (cf1.matrixY == cf2.matrixY) && (cf1.preserveAlpha == cf2.preserveAlpha);

        case DisplacementMapFilter:
            var dmf1 :DisplacementMapFilter = (f1 as DisplacementMapFilter);
            var dmf2 :DisplacementMapFilter = (f2 as DisplacementMapFilter);
            return (dmf1.alpha == dmf2.alpha) && (dmf1.color == dmf2.color) &&
                (dmf1.componentX == dmf2.componentX) && (dmf1.componentY == dmf2.componentY) &&
                (dmf1.mapBitmap == dmf2.mapBitmap) && dmf1.mapPoint.equals(dmf2.mapPoint) &&
                (dmf1.mode == dmf2.mode) && (dmf1.scaleX == dmf2.scaleX) &&
                (dmf1.scaleY == dmf2.scaleY);

        case DropShadowFilter:
            var dsf1 :DropShadowFilter = (f1 as DropShadowFilter);
            var dsf2 :DropShadowFilter = (f2 as DropShadowFilter);
            return (dsf1.alpha == dsf2.alpha) && (dsf1.angle = dsf2.angle) &&
                (dsf1.blurX = dsf2.blurX) && (dsf1.blurY = dsf2.blurY) &&
                (dsf1.color = dsf2.color) && (dsf1.distance = dsf2.distance) &&
                (dsf1.hideObject = dsf2.hideObject) && (dsf1.inner = dsf2.inner) &&
                (dsf1.knockout = dsf2.knockout) && (dsf1.quality = dsf2.quality) &&
                (dsf1.strength = dsf2.strength);

        case GlowFilter:
            var gf1 :GlowFilter = (f1 as GlowFilter);
            var gf2 :GlowFilter = (f2 as GlowFilter);
            return (gf1.alpha == gf2.alpha) && (gf1.blurX == gf2.blurX) &&
                (gf1.blurY == gf2.blurY) && (gf1.color == gf2.color) && (gf1.inner == gf2.inner) &&
                (gf1.knockout == gf2.knockout) && (gf1.quality == gf2.quality) &&
                (gf1.strength == gf2.strength);

        case GradientBevelFilter:
            var gbf1 :GradientBevelFilter = (f1 as GradientBevelFilter);
            var gbf2 :GradientBevelFilter = (f2 as GradientBevelFilter);
            return ArrayUtil.equals(gbf1.alphas, gbf2.alphas) && (gbf1.angle == gbf2.angle) &&
                (gbf1.blurX == gbf2.blurX) && (gbf1.blurY == gbf2.blurY) &&
                ArrayUtil.equals(gbf1.colors, gbf2.colors) && (gbf1.distance == gbf2.distance) &&
                (gbf1.knockout == gbf2.knockout) && (gbf1.quality == gbf2.quality) &&
                ArrayUtil.equals(gbf1.ratios, gbf2.ratios) && (gbf1.strength == gbf2.strength) &&
                (gbf1.type == gbf2.type);

        case GradientGlowFilter:
            var ggf1 :GradientGlowFilter = (f1 as GradientGlowFilter);
            var ggf2 :GradientGlowFilter = (f2 as GradientGlowFilter);
            return ArrayUtil.equals(ggf1.alphas, ggf2.alphas) && (ggf1.angle == ggf2.angle) &&
                (ggf1.blurX == ggf2.blurX) && (ggf1.blurY == ggf2.blurY) &&
                ArrayUtil.equals(ggf1.colors, ggf2.colors) && (ggf1.distance == ggf2.distance) &&
                (ggf1.knockout == ggf2.knockout) && (ggf1.quality == ggf2.quality) &&
                ArrayUtil.equals(ggf1.ratios, ggf2.ratios) && (ggf1.strength == ggf2.strength) &&
                (ggf1.type == ggf2.type);

        default:
            throw new ArgumentError("OMG! Unknown filter type: " + c1);
        }
    }

    /**
     * Create a filter that, if applied to a DisplayObject, will shift the hue of that object
     * by the given value.
     */
    public static function createHueShift (hue :int) :ColorMatrixFilter
    {
        return shiftHueBy(null, hue);
    }

    /**
    * Shift the color matrix filter by the given amount.  This is adapted from the code found at
    * http://www.kirupa.com/forum/showthread.php?t=230706
    */
    public static function shiftHueBy (original :ColorMatrixFilter,
        hueShift :int) :ColorMatrixFilter
    {
        var cosMatrix :Array = [ 0.787, -0.715, -0.072,
                                -0.212, 0.285, -0.072,
                                -0.213, -0.715, 0.928 ];
        var sinMatrix :Array = [-0.213, -0.715, 0.928,
                                0.143, 0.140, -0.283,
                                -0.787, 0.715, 0.072 ];
        var multiplier :Array = [];
        var cos :Number = Math.cos(hueShift * Math.PI / 180);
        var sin :Number = Math.sin(hueShift * Math.PI / 180);
        for (var ii :int = 0; ii < 9; ii++) {
            multiplier.push([ 0.213, 0.715, 0.072 ][ii%3] + cosMatrix[ii] * cos +
                sinMatrix[ii] * sin);
        }

        var originalMatrix :Array;
        if (original == null || original.matrix == null) {
            // thats the identity matrix for this filter
            originalMatrix = [ 1, 0, 0, 0, 0,
                               0, 1, 0, 0, 0,
                               0, 0, 1, 0, 0,
                               0, 0, 0, 1, 0 ];
        } else {
            originalMatrix = original.matrix;
        }

        // this loop compresses a massive, wacky concatination function that was used in the code
        // from the site listed above
        var matrix :Array = [];
        for (ii = 0; ii < 20; ii++) {
            if ((ii % 5) > 2) {
                matrix.push(originalMatrix[ii]);
            } else {
                var base :int = Math.floor(ii / 5) * 5;
                matrix.push((originalMatrix[base] * multiplier[ii%5]) +
                            (originalMatrix[base+1] * multiplier[(ii%5)+3]) +
                            (originalMatrix[base+2] * multiplier[(ii%5)+6]));
            }
        }

        return new ColorMatrixFilter(matrix);
    }

    protected static function checkArgs (disp :DisplayObject, filter :BitmapFilter) :void
    {
        if (disp == null || filter == null) {
            throw new ArgumentError("args may not be null");
        }
    }
}
}

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

package com.threerings.flash {

import flash.display.DisplayObject;

import flash.filters.BevelFilter;
import flash.filters.BitmapFilter;
import flash.filters.BlurFilter;
import flash.filters.ColorMatrixFilter;
import flash.filters.ConvolutionFilter;
import flash.filters.DisplacementMapFilter;
import flash.filters.DropShadowFilter;
import flash.filters.GlowFilter;
import flash.filters.GradientBevelFilter;
import flash.filters.GradientGlowFilter;

import com.threerings.util.ArrayUtil;
import com.threerings.util.ClassUtil;

/**
 * Useful utility methods that wouldn't be needed if the flash API were not so retarded.
 */
public class FilterUtil
{
    /**
     * Add the specified filter to the DisplayObject.
     */
    public static function addFilter (disp :DisplayObject, filter :BitmapFilter) :void
    {
        checkArgs(disp, filter);
        var filts :Array = disp.filters;
        if (filts == null) {
            filts = [];
        }
        filts.push(filter);
        disp.filters = filts;
    }

    /**
     * Remove the specified filter from the DisplayObject.
     * Note that the filter set in the DisplayObject is a clone, so the values
     * of the specified filter are used to find a match.
     */
    public static function removeFilter (disp :DisplayObject, filter :BitmapFilter) :void
    {
        checkArgs(disp, filter);
        var filts :Array = disp.filters;
        if (filts != null) {
            for (var ii :int = filts.length - 1; ii >= 0; ii--) {
                var oldFilter :BitmapFilter = (filts[ii] as BitmapFilter);
                if (equals(oldFilter, filter)) {
                    filts.splice(ii, 1);
                    if (filts.length == 0) {
                        filts = null;
                    }
                    disp.filters = filts;
                    return; // SUCCESS
                }
            }
        }
    }

    /**
     * Are the two filters equals?
     */
    public static function equals (f1 :BitmapFilter, f2 :BitmapFilter) :Boolean
    {
        if (f1 === f2) { // catch same instance, or both null
            return true;

        } else if (f1 == null || f2 == null) { // otherwise nulls are no good
            return false;
        }

        var c1 :Class = ClassUtil.getClass(f1);
        if (c1 !== ClassUtil.getClass(f2)) {
            return false;
        }

        // when we have two filters of the same class, figure it out by hand...
        switch (c1) {
        case BevelFilter:
            var bf1 :BevelFilter = (f1 as BevelFilter);
            var bf2 :BevelFilter = (f2 as BevelFilter);
            return (bf1.angle == bf2.angle) && (bf1.blurX == bf2.blurX) &&
                (bf1.blurY == bf2.blurY) && (bf1.distance == bf2.distance) &&
                (bf1.highlightAlpha == bf2.highlightAlpha) &&
                (bf1.highlightColor == bf2.highlightColor) && (bf1.knockout == bf2.knockout) &&
                (bf1.quality == bf2.quality) && (bf1.shadowAlpha == bf2.shadowAlpha) &&
                (bf1.shadowColor == bf2.shadowColor) && (bf1.strength == bf2.strength) &&
                (bf1.type == bf2.type);

        case BlurFilter:
            var blur1 :BlurFilter = (f1 as BlurFilter);
            var blur2 :BlurFilter = (f2 as BlurFilter);
            return (blur1.blurX == blur2.blurX) && (blur1.blurY == blur2.blurY) &&
                (blur1.quality == blur2.quality);

        case ColorMatrixFilter:
            var cmf1 :ColorMatrixFilter = (f1 as ColorMatrixFilter);
            var cmf2 :ColorMatrixFilter = (f2 as ColorMatrixFilter);
            return ArrayUtil.equals(cmf1.matrix, cmf2.matrix);

        case ConvolutionFilter:
            var cf1 :ConvolutionFilter = (f1 as ConvolutionFilter);
            var cf2 :ConvolutionFilter = (f2 as ConvolutionFilter);
            return (cf1.alpha == cf2.alpha) && (cf1.bias == cf2.bias) && (cf1.clamp == cf2.clamp) &&
                (cf1.color == cf2.color) && (cf1.divisor == cf2.divisor) &&
                ArrayUtil.equals(cf1.matrix, cf2.matrix) && (cf1.matrixX == cf2.matrixX) &&
                (cf1.matrixY == cf2.matrixY) && (cf1.preserveAlpha == cf2.preserveAlpha);

        case DisplacementMapFilter:
            var dmf1 :DisplacementMapFilter = (f1 as DisplacementMapFilter);
            var dmf2 :DisplacementMapFilter = (f2 as DisplacementMapFilter);
            return (dmf1.alpha == dmf2.alpha) && (dmf1.color == dmf2.color) &&
                (dmf1.componentX == dmf2.componentX) && (dmf1.componentY == dmf2.componentY) &&
                (dmf1.mapBitmap == dmf2.mapBitmap) && dmf1.mapPoint.equals(dmf2.mapPoint) &&
                (dmf1.mode == dmf2.mode) && (dmf1.scaleX == dmf2.scaleX) &&
                (dmf1.scaleY == dmf2.scaleY);

        case DropShadowFilter:
            var dsf1 :DropShadowFilter = (f1 as DropShadowFilter);
            var dsf2 :DropShadowFilter = (f2 as DropShadowFilter);
            return (dsf1.alpha == dsf2.alpha) && (dsf1.angle = dsf2.angle) &&
                (dsf1.blurX = dsf2.blurX) && (dsf1.blurY = dsf2.blurY) &&
                (dsf1.color = dsf2.color) && (dsf1.distance = dsf2.distance) &&
                (dsf1.hideObject = dsf2.hideObject) && (dsf1.inner = dsf2.inner) &&
                (dsf1.knockout = dsf2.knockout) && (dsf1.quality = dsf2.quality) &&
                (dsf1.strength = dsf2.strength);

        case GlowFilter:
            var gf1 :GlowFilter = (f1 as GlowFilter);
            var gf2 :GlowFilter = (f2 as GlowFilter);
            return (gf1.alpha == gf2.alpha) && (gf1.blurX == gf2.blurX) &&
                (gf1.blurY == gf2.blurY) && (gf1.color == gf2.color) && (gf1.inner == gf2.inner) &&
                (gf1.knockout == gf2.knockout) && (gf1.quality == gf2.quality) &&
                (gf1.strength == gf2.strength);

        case GradientBevelFilter:
            var gbf1 :GradientBevelFilter = (f1 as GradientBevelFilter);
            var gbf2 :GradientBevelFilter = (f2 as GradientBevelFilter);
            return ArrayUtil.equals(gbf1.alphas, gbf2.alphas) && (gbf1.angle == gbf2.angle) &&
                (gbf1.blurX == gbf2.blurX) && (gbf1.blurY == gbf2.blurY) &&
                ArrayUtil.equals(gbf1.colors, gbf2.colors) && (gbf1.distance == gbf2.distance) &&
                (gbf1.knockout == gbf2.knockout) && (gbf1.quality == gbf2.quality) &&
                ArrayUtil.equals(gbf1.ratios, gbf2.ratios) && (gbf1.strength == gbf2.strength) &&
                (gbf1.type == gbf2.type);

        case GradientGlowFilter:
            var ggf1 :GradientGlowFilter = (f1 as GradientGlowFilter);
            var ggf2 :GradientGlowFilter = (f2 as GradientGlowFilter);
            return ArrayUtil.equals(ggf1.alphas, ggf2.alphas) && (ggf1.angle == ggf2.angle) &&
                (ggf1.blurX == ggf2.blurX) && (ggf1.blurY == ggf2.blurY) &&
                ArrayUtil.equals(ggf1.colors, ggf2.colors) && (ggf1.distance == ggf2.distance) &&
                (ggf1.knockout == ggf2.knockout) && (ggf1.quality == ggf2.quality) &&
                ArrayUtil.equals(ggf1.ratios, ggf2.ratios) && (ggf1.strength == ggf2.strength) &&
                (ggf1.type == ggf2.type);

        default:
            throw new ArgumentError("OMG! Unknown filter type: " + c1);
        }
    }

    /**
     * Create a filter that, if applied to a DisplayObject, will shift the hue of that object
     * by the given value.
     *
     * @param hueShift a value, in degrees, between -180 and 180.
     */
    public static function createHueShift (hue :int) :ColorMatrixFilter
    {
        return shiftHueBy(null, hue);
    }

    /**
    * Shift the color matrix filter by the given amount.  This is adapted from the code found at
    * http://www.kirupa.com/forum/showthread.php?t=230706
     *
     * @param hueShift a value, in degrees, between -180 and 180.
    */
    public static function shiftHueBy (original :ColorMatrixFilter,
        hueShift :int) :ColorMatrixFilter
    {
        var cosMatrix :Array = [ 0.787, -0.715, -0.072,
                                -0.212, 0.285, -0.072,
                                -0.213, -0.715, 0.928 ];
        var sinMatrix :Array = [-0.213, -0.715, 0.928,
                                0.143, 0.140, -0.283,
                                -0.787, 0.715, 0.072 ];
        var multiplier :Array = [];
        var cos :Number = Math.cos(hueShift * Math.PI / 180);
        var sin :Number = Math.sin(hueShift * Math.PI / 180);
        for (var ii :int = 0; ii < 9; ii++) {
            multiplier.push([ 0.213, 0.715, 0.072 ][ii%3] + cosMatrix[ii] * cos +
                sinMatrix[ii] * sin);
        }

        var originalMatrix :Array;
        if (original == null || original.matrix == null) {
            // thats the identity matrix for this filter
            originalMatrix = [ 1, 0, 0, 0, 0,
                               0, 1, 0, 0, 0,
                               0, 0, 1, 0, 0,
                               0, 0, 0, 1, 0 ];
        } else {
            originalMatrix = original.matrix;
        }

        // this loop compresses a massive, wacky concatination function that was used in the code
        // from the site listed above
        var matrix :Array = [];
        for (ii = 0; ii < 20; ii++) {
            if ((ii % 5) > 2) {
                matrix.push(originalMatrix[ii]);
            } else {
                var base :int = Math.floor(ii / 5) * 5;
                matrix.push((originalMatrix[base] * multiplier[ii%5]) +
                            (originalMatrix[base+1] * multiplier[(ii%5)+3]) +
                            (originalMatrix[base+2] * multiplier[(ii%5)+6]));
            }
        }

        return new ColorMatrixFilter(matrix);
    }

    protected static function checkArgs (disp :DisplayObject, filter :BitmapFilter) :void
    {
        if (disp == null || filter == null) {
            throw new ArgumentError("args may not be null");
        }
    }
}
}

Document the hueShift parameter.

Document the hueShift parameter.

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