package justpinegames.Logi
{
	import feathers.controls.List;
	import feathers.controls.renderers.IListItemRenderer;
    import feathers.controls.text.BitmapFontTextRenderer;
    import feathers.core.FeathersControl;
	import feathers.text.BitmapFontTextFormat;
	import org.osflash.signals.ISignal;
	import org.osflash.signals.Signal;
	import starling.events.Event;
	import starling.text.BitmapFont;
	import starling.textures.TextureSmoothing;

	internal class ConsoleItemRenderer extends FeathersControl implements IListItemRenderer
	{
		private static var _format:BitmapFontTextFormat = null;
		private static var _formatHighlight:BitmapFontTextFormat = null;

		private var _onChange:Signal = new Signal(ConsoleItemRenderer);

		private var _data:Object;
		private var _index:int;
		private var _owner:List;
		private var _isSelected:Boolean;

		private var _label:BitmapFontTextRenderer;

		public function ConsoleItemRenderer(labelColor:int, labelColorHighlight:int)
		{
			_format = _format ? _format : new BitmapFontTextFormat(new BitmapFont(), 16, labelColor);
			_formatHighlight = _formatHighlight ? _formatHighlight : new BitmapFontTextFormat(new BitmapFont(), 16, labelColorHighlight);
			_label = new BitmapFontTextRenderer();
			_label.addEventListener(Event.ADDED, function(e:Event):void
			{
				_label.textFormat = _format;
			});
			_label.smoothing = TextureSmoothing.NONE;
			this.addChild(_label);
		}

		public function get data():Object
		{
			return _data;
		}

		public function set data(value:Object):void
		{
			if (value == null)
			{
				return;
			}

			_label.text = value.label;
			_data = value;
		}

		public function get index():int
		{
			return _index;
		}

		public function set index(value:int):void
		{
			_index = value;
		}

		public function get owner():List
		{
			return _owner;
		}

		public function set owner(value:List):void
		{
			_owner = value;
		}

		public function get isSelected():Boolean
		{
			return _isSelected;
		}

		public function set isSelected(value:Boolean):void
		{
			if (_isSelected == value)
			{
				return;
			}

			if (value)
			{
				_label.textFormat = _formatHighlight;
			}
			else
			{
				_label.textFormat = _format;
			}

			_isSelected = value;
			_onChange.dispatch(this);
		}

		public function get onChange():ISignal
		{
			return this._onChange;
		}
	}
}

package justpinegames.Logi
{
	import feathers.controls.List;
	import feathers.controls.renderers.IListItemRenderer;
    import feathers.controls.text.BitmapFontTextRenderer;
    import feathers.core.FeathersControl;
	import feathers.text.BitmapFontTextFormat;
	import starling.events.Event;
	import starling.text.BitmapFont;
	import starling.textures.TextureSmoothing;

	internal class ConsoleItemRenderer extends FeathersControl implements IListItemRenderer
	{
		private static var _format:BitmapFontTextFormat = null;
		private static var _formatHighlight:BitmapFontTextFormat = null;

		private var _data:Object;
		private var _index:int;
		private var _owner:List;
		private var _isSelected:Boolean;

		private var _label:BitmapFontTextRenderer;

		[Event(name="change",type="starling.events.Event")]

		public function ConsoleItemRenderer(labelColor:int, labelColorHighlight:int)
		{
			_format = _format ? _format : new BitmapFontTextFormat(new BitmapFont(), 16, labelColor);
			_formatHighlight = _formatHighlight ? _formatHighlight : new BitmapFontTextFormat(new BitmapFont(), 16, labelColorHighlight);
			_label = new BitmapFontTextRenderer();
			_label.addEventListener(Event.ADDED, function(e:Event):void
			{
				_label.textFormat = _format;
			});
			_label.smoothing = TextureSmoothing.NONE;
			this.addChild(_label);
		}

		public function get data():Object
		{
			return _data;
		}

		public function set data(value:Object):void
		{
			if (value == null)
			{
				return;
			}

			_label.text = value.label;
			_data = value;
		}

		public function get index():int
		{
			return _index;
		}

		public function set index(value:int):void
		{
			_index = value;
		}

		public function get owner():List
		{
			return _owner;
		}

		public function set owner(value:List):void
		{
			_owner = value;
		}

		public function get isSelected():Boolean
		{
			return _isSelected;
		}

		public function set isSelected(value:Boolean):void
		{
			if (_isSelected == value)
			{
				return;
			}

			if (value)
			{
				_label.textFormat = _formatHighlight;
			}
			else
			{
				_label.textFormat = _format;
			}

			_isSelected = value;
			dispatchEventWith(Event.CHANGE);
		}

	}
}

Update src/justpinegames/Logi/ConsoleItemRenderer.as

Removed Signals dependency bringing this library in line with Feathers


package com.kaltura.delegates {
	import com.kaltura.commands.MultiRequest;
	import com.kaltura.commands.QueuedRequest;
	import com.kaltura.config.KalturaConfig;
	import com.kaltura.errors.KalturaError;
	import com.kaltura.net.KalturaCall;

	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;

	public class QueuedRequestDelegate extends WebDelegateBase {

		public function QueuedRequestDelegate(call:KalturaCall = null, config:KalturaConfig = null) {
			super(call, config);
		}

		override public function parse( result : XML ) : *
		{
			var resArr : Array = new Array();
			var resInd:int = 0;	// index for scanning result
			for ( var i:int=0; i<(call as QueuedRequest).calls.length; i++ )
			{
				var callClassName : String = getQualifiedClassName( (call as QueuedRequest).calls[i] );
				var commandName : String = callClassName.split("::")[1];
				var packageArr : Array =  (callClassName.split("::")[0]).split(".");
				var importFrom : String = packageArr[packageArr.length-1];

				var clsName : String ;
				var cls : Class;
				var myInst : Object;

				if (commandName == "MultiRequest") {
					clsName = "com.kaltura.delegates.MultiRequestDelegate";
					cls = getDefinitionByName( clsName ) as Class;
					myInst = new cls(null , null);
					// set the call after the constructor, so we don't fire execute()
					myInst.call = (call as QueuedRequest).calls[i];
				}
				else {
					clsName = "com.kaltura.delegates."+importFrom+"."+ commandName +"Delegate"; //'com.kaltura.delegates.session.SessionStartDelegate'
					cls = getDefinitionByName( clsName ) as Class;//(') as Class;
					myInst = new cls(null , null);
				}

				//build the result as a regular result
				var xml : String = "<result><result>";
				if (commandName == "MultiRequest") {
					// add as many items as the multirequest had
					var nActions:int = ((call as QueuedRequest).calls[i] as MultiRequest).actions.length;
					for (var j:int = 0; j<nActions ; j++) {
						xml += result.result.item[j + resInd].toXMLString();
					}
					// skip to the result of the next call that wasn't part of the MR:
					resInd+= nActions;
				}
				else {
					xml += result.result.item[resInd].children().toString();
					resInd++;
				}
				xml +="</result></result>";

				// add the item or a matching error:
				var kErr:KalturaError = validateKalturaResponse(xml);

				if (kErr == null) {
					var res : XML = new XML(xml);
					try {
						var obj : Object = (myInst as WebDelegateBase).parse( res );
						resArr.push( obj );
					} catch (e:Error) {
						kErr = new KalturaError();
						kErr.errorCode = String(e.errorID);
						kErr.errorMsg = e.message;
						resArr.push( kErr );
					}
				}
				else {
					resArr.push(kErr);
				}
			}

			return resArr;
		}

	}
}

package com.kaltura.delegates {
	import com.kaltura.commands.MultiRequest;
	import com.kaltura.commands.QueuedRequest;
	import com.kaltura.config.KalturaConfig;
	import com.kaltura.errors.KalturaError;
	import com.kaltura.net.KalturaCall;

	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;

	public class QueuedRequestDelegate extends WebDelegateBase {

		public function QueuedRequestDelegate(call:KalturaCall = null, config:KalturaConfig = null) {
			super(call, config);
		}

		override public function parse( result : XML ) : *
		{
			var resArr : Array = new Array();
			var resInd:int = 0;	// index for scanning result
			for ( var i:int=0; i<(call as QueuedRequest).calls.length; i++ )
			{
				var callClassName : String = getQualifiedClassName( (call as QueuedRequest).calls[i] );
				var commandName : String = callClassName.split("::")[1];
				var packageArr : Array =  (callClassName.split("::")[0]).split(".");
				var importFrom : String = packageArr[packageArr.length-1];

				var clsName : String ;
				var cls : Class;
				var myInst : Object;

				if (commandName == "MultiRequest") {
					clsName = "com.kaltura.delegates.MultiRequestDelegate";
					cls = getDefinitionByName( clsName ) as Class;
					myInst = new cls(null , null);
					// set the call after the constructor, so we don't fire execute()
					myInst.call = (call as QueuedRequest).calls[i];
				}
				else {
					clsName = "com.kaltura.delegates."+importFrom+"."+ commandName +"Delegate"; //'com.kaltura.delegates.session.SessionStartDelegate'
					cls = getDefinitionByName( clsName ) as Class;//(') as Class;
					myInst = new cls(null , null);
				}

				//build the result as a regular result
				var xml : String = "<result><result>";
				if (commandName == "MultiRequest") {
					// add as many items as the multirequest had
					var nActions:int = ((call as QueuedRequest).calls[i] as MultiRequest).actions.length;
					for (var j:int = 0; j<nActions ; j++) {
						xml += result.result.item[j + resInd].toXMLString();
					}
					// skip to the result of the next call that wasn't part of the MR:
					resInd+= nActions;
				}
				else {
					xml += result.result.item[resInd].children().toXMLString();
					resInd++;
				}
				xml +="</result></result>";

				// add the item or a matching error:
				var kErr:KalturaError = validateKalturaResponse(xml);

				if (kErr == null) {
					var res : XML = new XML(xml);
					try {
						var obj : Object = (myInst as WebDelegateBase).parse( res );
						resArr.push( obj );
					} catch (e:Error) {
						kErr = new KalturaError();
						kErr.errorCode = String(e.errorID);
						kErr.errorMsg = e.message;
						resArr.push( kErr );
					}
				}
				else {
					resArr.push(kErr);
				}
			}

			return resArr;
		}

	}
}

fix for report service

fix for report service

git-svn-id: 8a2ccb88241e16c78017770bc38d91d6d5396a5a@60459 6b8eccd3-e8c5-4e7d-8186-e12b5326b719


/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mangui.hls.controller {
    import org.mangui.hls.constant.HLSLoaderTypes;
    import org.mangui.hls.constant.HLSMaxLevelCappingMode;
    import org.mangui.hls.event.HLSEvent;
    import org.mangui.hls.event.HLSLoadMetrics;
    import org.mangui.hls.HLS;
    import org.mangui.hls.HLSSettings;
    import org.mangui.hls.model.Level;

    CONFIG::LOGGING {
        import org.mangui.hls.utils.Log;
    }
    /** Class that manages auto level selection
     *
     * this is an implementation based on Serial segment fetching method from
     * http://www.cs.tut.fi/~moncef/publications/rate-adaptation-IC-2011.pdf
     */
    public class LevelController {
        /** Reference to the HLS controller. **/
        private var _hls : HLS;
        /** switch up threshold **/
        private var _switchup : Vector.<Number> = null;
        /** switch down threshold **/
        private var _switchdown : Vector.<Number> = null;
        /** bitrate array **/
        private var _bitrate : Vector.<Number> = null;
        /** vector of levels with unique dimension with highest bandwidth **/
        private var _maxUniqueLevels : Vector.<Level> = null;
        /** nb level **/
        private var _nbLevel : int = 0;
        private var _lastSegmentDuration : Number;
        private var _lastFetchDuration : Number;
        private var  lastBandwidth : Number;
        private var  _autoLevelCapping : int = -1;
        private var  _startLevel : int = -1;
        private var  _fpsController : FPSController;

        /** Create the loader. **/
        public function LevelController(hls : HLS) : void {
            _hls = hls;
            _fpsController = new FPSController(hls);
            _hls.addEventListener(HLSEvent.MANIFEST_PARSED, _manifestParsedHandler);
            _hls.addEventListener(HLSEvent.MANIFEST_LOADED, _manifestLoadedHandler);
            _hls.addEventListener(HLSEvent.FRAGMENT_LOADED, _fragmentLoadedHandler);
        }
        ;

        public function dispose() : void {
            _fpsController.dispose();
            _fpsController = null;
            _hls.removeEventListener(HLSEvent.MANIFEST_PARSED, _manifestParsedHandler);
            _hls.removeEventListener(HLSEvent.MANIFEST_LOADED, _manifestLoadedHandler);
            _hls.removeEventListener(HLSEvent.FRAGMENT_LOADED, _fragmentLoadedHandler);
        }

        private function _fragmentLoadedHandler(event : HLSEvent) : void {
            var metrics : HLSLoadMetrics = event.loadMetrics;
            // only monitor main fragment metrics for level switching
            if(metrics.type == HLSLoaderTypes.FRAGMENT_MAIN) {
                lastBandwidth = metrics.bandwidth;
                _lastSegmentDuration = metrics.duration;
                _lastFetchDuration = metrics.processing_duration;
            }
        }

        private function _manifestParsedHandler(event : HLSEvent) : void {
            // upon manifest parsed event, trigger a level switch to load startLevel playlist
            _hls.dispatchEvent(new HLSEvent(HLSEvent.LEVEL_SWITCH, _hls.startLevel));
        }

        private function _manifestLoadedHandler(event : HLSEvent) : void {
            var levels : Vector.<Level> = event.levels;
            var maxswitchup : Number = 0;
            var minswitchdwown : Number = Number.MAX_VALUE;
            _nbLevel = levels.length;
            _bitrate = new Vector.<Number>(_nbLevel, true);
            _switchup = new Vector.<Number>(_nbLevel, true);
            _switchdown = new Vector.<Number>(_nbLevel, true);
            _lastSegmentDuration = 0;
            _lastFetchDuration = 0;
            lastBandwidth = 0;

            var i : int;

            for (i = 0; i < _nbLevel; i++) {
                _bitrate[i] = levels[i].bitrate;
            }

            for (i = 0; i < _nbLevel - 1; i++) {
                _switchup[i] = (_bitrate[i + 1] - _bitrate[i]) / _bitrate[i];
                maxswitchup = Math.max(maxswitchup, _switchup[i]);
            }
            for (i = 0; i < _nbLevel - 1; i++) {
                _switchup[i] = Math.min(maxswitchup, 2 * _switchup[i]);

                CONFIG::LOGGING {
                    Log.debug("_switchup[" + i + "]=" + _switchup[i]);
                }
            }

            for (i = 1; i < _nbLevel; i++) {
                _switchdown[i] = (_bitrate[i] - _bitrate[i - 1]) / _bitrate[i];
                minswitchdwown = Math.min(minswitchdwown, _switchdown[i]);
            }
            for (i = 1; i < _nbLevel; i++) {
                _switchdown[i] = Math.max(2 * minswitchdwown, _switchdown[i]);

                CONFIG::LOGGING {
                    Log.debug("_switchdown[" + i + "]=" + _switchdown[i]);
                }
            }

            if (HLSSettings.capLevelToStage) {
                _maxUniqueLevels = _maxLevelsWithUniqueDimensions;
            }
        }
        ;

        public function getbestlevel(downloadBandwidth : Number) : int {
            var max_level : int = _maxLevel;
            for (var i : int = max_level; i >= 0; i--) {
                if (_bitrate[i] <= downloadBandwidth) {
                    return i;
                }
            }
            return 0;
        }

        private function get _maxLevelsWithUniqueDimensions() : Vector.<Level> {
            var filter : Function = function(l : Level, i : int, v : Vector.<Level>) : Boolean {
                if (l.width > 0 && l.height > 0) {
                    if (i + 1 < v.length) {
                        var nextLevel : Level = v[i + 1];
                        if (l.width != nextLevel.width && l.height != nextLevel.height) {
                            return true;
                        }
                    } else {
                        return true;
                    }
                }
                return false;
            };

            return _hls.levels.filter(filter);
        }

        /** Return the capping/max level value that could be used by automatic level selection algorithm **/
        public function get autoLevelCapping() : int {
            return _autoLevelCapping;
        }

        /** set the capping/max level value that could be used by automatic level selection algorithm **/
        public function set autoLevelCapping(newLevel : int) : void {
            _autoLevelCapping = newLevel;
        }

        private function get _maxLevel() : int {
            // if set, _autoLevelCapping takes precedence
            if(_autoLevelCapping >= 0) {
                return Math.min(_nbLevel - 1, _autoLevelCapping);
            } else if (HLSSettings.capLevelToStage) {
                var maxLevelsCount : int = _maxUniqueLevels.length;

                if (_hls.stage && maxLevelsCount) {
                    var maxLevel : Level = this._maxUniqueLevels[0], maxLevelIdx : int = maxLevel.index, sWidth : Number = this._hls.stage.stageWidth, sHeight : Number = this._hls.stage.stageHeight, lWidth : int, lHeight : int, i : int;

                    switch (HLSSettings.maxLevelCappingMode) {
                        case HLSMaxLevelCappingMode.UPSCALE:
                            for (i = maxLevelsCount - 1; i >= 0; i--) {
                                maxLevel = this._maxUniqueLevels[i];
                                maxLevelIdx = maxLevel.index;
                                lWidth = maxLevel.width;
                                lHeight = maxLevel.height;
                                CONFIG::LOGGING {
                                    Log.debug("stage size: " + sWidth + "x" + sHeight + " ,level" + maxLevelIdx + " size: " + lWidth + "x" + lHeight);
                                }
                                if (sWidth >= lWidth || sHeight >= lHeight) {
                                    break;
                                    // from for loop
                                }
                            }
                            break;
                        case HLSMaxLevelCappingMode.DOWNSCALE:
                            for (i = 0; i < maxLevelsCount; i++) {
                                maxLevel = this._maxUniqueLevels[i];
                                maxLevelIdx = maxLevel.index;
                                lWidth = maxLevel.width;
                                lHeight = maxLevel.height;
                                CONFIG::LOGGING {
                                    Log.debug("stage size: " + sWidth + "x" + sHeight + " ,level" + maxLevelIdx + " size: " + lWidth + "x" + lHeight);
                                }
                                if (sWidth <= lWidth || sHeight <= lHeight) {
                                    break;
                                    // from for loop
                                }
                            }
                            break;
                    }
                    CONFIG::LOGGING {
                        Log.debug("max capped level idx: " + maxLevelIdx);
                    }
                }
                return maxLevelIdx;
            } else {
                return _nbLevel - 1;
            }
        }

        /** Update the quality level for the next fragment load. **/
        public function getnextlevel(current_level : int, buffer : Number) : int {
            if (_lastFetchDuration == 0 || _lastSegmentDuration == 0) {
                return 0;
            }

            /* rsft : remaining segment fetch time : available time to fetch next segment
            it depends on the current playback timestamp , the timestamp of the first frame of the next segment
            and TBMT, indicating a desired latency between the time instant to receive the last byte of a
            segment to the playback of the first media frame of a segment
            buffer is start time of next segment
            TBMT is the buffer size we need to ensure (we need at least 2 segments buffered */
            var rsft : Number = 1000 * buffer - 2 * _lastFetchDuration;
            var sftm : Number = Math.min(_lastSegmentDuration, rsft) / _lastFetchDuration;
            var max_level : Number = _maxLevel;
            var switch_to_level : int = current_level;
            // CONFIG::LOGGING {
            // Log.info("rsft:" + rsft);
            // Log.info("sftm:" + sftm);
            // }
            // }
            /* to switch level up :
            rsft should be greater than switch up condition
             */
            if ((current_level < max_level) && (sftm > (1 + _switchup[current_level]))) {
                CONFIG::LOGGING {
                    Log.debug("sftm:> 1+_switchup[_level]=" + (1 + _switchup[current_level]));
                }
                switch_to_level = current_level + 1;
            }

            /* to switch level down :
            rsft should be smaller than switch up condition,
            or the current level is greater than max level
             */ else if ((current_level > max_level && current_level > 0) || (current_level > 0 && (sftm < 1 - _switchdown[current_level]))) {
                CONFIG::LOGGING {
                    Log.debug("sftm < 1-_switchdown[current_level]=" + _switchdown[current_level]);
                }
                var bufferratio : Number = 1000 * buffer / _lastSegmentDuration;
                /* find suitable level matching current bandwidth, starting from current level
                when switching level down, we also need to consider that we might need to load two fragments.
                the condition (bufferratio > 2*_levels[j].bitrate/_lastBandwidth)
                ensures that buffer time is bigger than than the time to download 2 fragments from level j, if we keep same bandwidth.
                 */

                for (var j : int = current_level - 1; j >= 0; j--) {
                    if (_bitrate[j] <= lastBandwidth && (bufferratio > 2 * _bitrate[j] / lastBandwidth)) {
                        switch_to_level = j;
                        break;
                    }
                    if (j == 0) {
                        switch_to_level = 0;
                    }
                }
            }

            // Then we should check if selected level is higher than max_level if so, than take the min of those two
            switch_to_level = Math.min(max_level, switch_to_level);

            CONFIG::LOGGING {
                if (switch_to_level != current_level) {
                    Log.debug("switch to level " + switch_to_level);
                }
            }

            return switch_to_level;
        }

        // get level index of first level appearing in the manifest
        public function get firstLevel() : int {
            var levels : Vector.<Level> = _hls.levels;
            for (var i : int = 0; i < levels.length; i++) {
                if (levels[i].manifest_index == 0) {
                    return i;
                }
            }
            return 0;
        }

        /*  set the quality level used when starting a fresh playback */
        public function set startLevel(level : int) : void {
            _startLevel = level;
        };

        public function get startLevel() : int {
            var start_level : int = -1;
            var levels : Vector.<Level> = _hls.levels;
            if (levels) {
                // if set, _startLevel takes precedence
                if(_startLevel >=0) {
                    return Math.min(levels.length-1,_startLevel);
                } else if (HLSSettings.startFromLevel === -2) {
                    // playback will start from the first level appearing in Manifest (not sorted by bitrate)
                    return firstLevel;
                } else if (HLSSettings.startFromLevel === -1 && HLSSettings.startFromBitrate === -1) {
                    /* if startFromLevel is set to -1, it means that effective startup level
                     * will be determined from first segment download bandwidth
                     * let's use lowest bitrate for this download bandwidth assessment
                     * this should speed up playback start time
                     */
                    return 0;
                } else {
                    // set up start level as being the lowest non-audio level.
                    for (var i : int = 0; i < levels.length; i++) {
                        if (!levels[i].audio) {
                            start_level = i;
                            break;
                        }
                    }
                    // in case of audio only playlist, force startLevel to 0
                    if (start_level == -1) {
                        CONFIG::LOGGING {
                            Log.info("playlist is audio-only");
                        }
                        start_level = 0;
                    } else {
                        if (HLSSettings.startFromBitrate > 0) {
                            start_level = findIndexOfClosestLevel(HLSSettings.startFromBitrate);
                        } else if (HLSSettings.startFromLevel > 0) {
                            // adjust start level using a rule by 3
                            start_level += Math.round(HLSSettings.startFromLevel * (levels.length - start_level - 1));
                        }
                    }
                }
                CONFIG::LOGGING {
                    Log.debug("start level :" + start_level);
                }
            }
            return start_level;
        }

        /**
         * @param desiredBitrate
         * @return The index of the level that has a bitrate closest to the desired bitrate.
         */
        private function findIndexOfClosestLevel(desiredBitrate : Number) : int {
            var levelIndex : int = -1;
            var minDistance : Number = Number.MAX_VALUE;
            var levels : Vector.<Level> = _hls.levels;

            for (var index : int = 0; index < levels.length; index++) {
                var level : Level = levels[index];

                var distance : Number = Math.abs(desiredBitrate - level.bitrate);

                if (distance < minDistance) {
                    levelIndex = index;
                    minDistance = distance;
                }
            }
            return levelIndex;
        }

        public function get seekLevel() : int {
            var seek_level : int = -1;
            var levels : Vector.<Level> = _hls.levels;
            if (HLSSettings.seekFromLevel == -1) {
                // keep last level
                return _hls.loadLevel;
            }

            // set up seek level as being the lowest non-audio level.
            for (var i : int = 0; i < levels.length; i++) {
                if (!levels[i].audio) {
                    seek_level = i;
                    break;
                }
            }
            // in case of audio only playlist, force seek_level to 0
            if (seek_level == -1) {
                seek_level = 0;
            } else {
                if (HLSSettings.seekFromLevel > 0) {
                    // adjust start level using a rule by 3
                    seek_level += Math.round(HLSSettings.seekFromLevel * (levels.length - seek_level - 1));
                }
            }
            CONFIG::LOGGING {
                Log.debug("seek level :" + seek_level);
            }
            return seek_level;
        }
    }
}

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mangui.hls.controller {
    import org.mangui.hls.constant.HLSLoaderTypes;
    import org.mangui.hls.constant.HLSMaxLevelCappingMode;
    import org.mangui.hls.event.HLSEvent;
    import org.mangui.hls.event.HLSLoadMetrics;
    import org.mangui.hls.HLS;
    import org.mangui.hls.HLSSettings;
    import org.mangui.hls.model.Level;

    CONFIG::LOGGING {
        import org.mangui.hls.utils.Log;
    }
    /** Class that manages auto level selection
     *
     * this is an implementation based on Serial segment fetching method from
     * http://www.cs.tut.fi/~moncef/publications/rate-adaptation-IC-2011.pdf
     */
    public class LevelController {
        /** Reference to the HLS controller. **/
        private var _hls : HLS;
        /** switch up threshold **/
        private var _switchup : Vector.<Number> = null;
        /** switch down threshold **/
        private var _switchdown : Vector.<Number> = null;
        /** bitrate array **/
        private var _bitrate : Vector.<Number> = null;
        /** vector of levels with unique dimension with highest bandwidth **/
        private var _maxUniqueLevels : Vector.<Level> = null;
        /** nb level **/
        private var _nbLevel : int = 0;
        private var _lastSegmentDuration : Number;
        private var _lastFetchDuration : Number;
        private var  lastBandwidth : Number;
        private var  _autoLevelCapping : int;
        private var  _startLevel : int = -1;
        private var  _fpsController : FPSController;

        /** Create the loader. **/
        public function LevelController(hls : HLS) : void {
            _hls = hls;
            _fpsController = new FPSController(hls);
            _hls.addEventListener(HLSEvent.MANIFEST_PARSED, _manifestParsedHandler);
            _hls.addEventListener(HLSEvent.MANIFEST_LOADED, _manifestLoadedHandler);
            _hls.addEventListener(HLSEvent.FRAGMENT_LOADED, _fragmentLoadedHandler);
        }
        ;

        public function dispose() : void {
            _fpsController.dispose();
            _fpsController = null;
            _hls.removeEventListener(HLSEvent.MANIFEST_PARSED, _manifestParsedHandler);
            _hls.removeEventListener(HLSEvent.MANIFEST_LOADED, _manifestLoadedHandler);
            _hls.removeEventListener(HLSEvent.FRAGMENT_LOADED, _fragmentLoadedHandler);
        }

        private function _fragmentLoadedHandler(event : HLSEvent) : void {
            var metrics : HLSLoadMetrics = event.loadMetrics;
            // only monitor main fragment metrics for level switching
            if(metrics.type == HLSLoaderTypes.FRAGMENT_MAIN) {
                lastBandwidth = metrics.bandwidth;
                _lastSegmentDuration = metrics.duration;
                _lastFetchDuration = metrics.processing_duration;
            }
        }

        private function _manifestParsedHandler(event : HLSEvent) : void {
            // upon manifest parsed event, trigger a level switch to load startLevel playlist
            _hls.dispatchEvent(new HLSEvent(HLSEvent.LEVEL_SWITCH, _hls.startLevel));
        }

        private function _manifestLoadedHandler(event : HLSEvent) : void {
            var levels : Vector.<Level> = event.levels;
            var maxswitchup : Number = 0;
            var minswitchdwown : Number = Number.MAX_VALUE;
            _nbLevel = levels.length;
            _bitrate = new Vector.<Number>(_nbLevel, true);
            _switchup = new Vector.<Number>(_nbLevel, true);
            _switchdown = new Vector.<Number>(_nbLevel, true);
            _autoLevelCapping = -1;
            _lastSegmentDuration = 0;
            _lastFetchDuration = 0;
            lastBandwidth = 0;

            var i : int;

            for (i = 0; i < _nbLevel; i++) {
                _bitrate[i] = levels[i].bitrate;
            }

            for (i = 0; i < _nbLevel - 1; i++) {
                _switchup[i] = (_bitrate[i + 1] - _bitrate[i]) / _bitrate[i];
                maxswitchup = Math.max(maxswitchup, _switchup[i]);
            }
            for (i = 0; i < _nbLevel - 1; i++) {
                _switchup[i] = Math.min(maxswitchup, 2 * _switchup[i]);

                CONFIG::LOGGING {
                    Log.debug("_switchup[" + i + "]=" + _switchup[i]);
                }
            }

            for (i = 1; i < _nbLevel; i++) {
                _switchdown[i] = (_bitrate[i] - _bitrate[i - 1]) / _bitrate[i];
                minswitchdwown = Math.min(minswitchdwown, _switchdown[i]);
            }
            for (i = 1; i < _nbLevel; i++) {
                _switchdown[i] = Math.max(2 * minswitchdwown, _switchdown[i]);

                CONFIG::LOGGING {
                    Log.debug("_switchdown[" + i + "]=" + _switchdown[i]);
                }
            }

            if (HLSSettings.capLevelToStage) {
                _maxUniqueLevels = _maxLevelsWithUniqueDimensions;
            }
        }
        ;

        public function getbestlevel(downloadBandwidth : Number) : int {
            var max_level : int = _maxLevel;
            for (var i : int = max_level; i >= 0; i--) {
                if (_bitrate[i] <= downloadBandwidth) {
                    return i;
                }
            }
            return 0;
        }

        private function get _maxLevelsWithUniqueDimensions() : Vector.<Level> {
            var filter : Function = function(l : Level, i : int, v : Vector.<Level>) : Boolean {
                if (l.width > 0 && l.height > 0) {
                    if (i + 1 < v.length) {
                        var nextLevel : Level = v[i + 1];
                        if (l.width != nextLevel.width && l.height != nextLevel.height) {
                            return true;
                        }
                    } else {
                        return true;
                    }
                }
                return false;
            };

            return _hls.levels.filter(filter);
        }

        /** Return the capping/max level value that could be used by automatic level selection algorithm **/
        public function get autoLevelCapping() : int {
            return _autoLevelCapping;
        }

        /** set the capping/max level value that could be used by automatic level selection algorithm **/
        public function set autoLevelCapping(newLevel : int) : void {
            _autoLevelCapping = newLevel;
        }

        private function get _maxLevel() : int {
            // if set, _autoLevelCapping takes precedence
            if(_autoLevelCapping >= 0) {
                return Math.min(_nbLevel - 1, _autoLevelCapping);
            } else if (HLSSettings.capLevelToStage) {
                var maxLevelsCount : int = _maxUniqueLevels.length;

                if (_hls.stage && maxLevelsCount) {
                    var maxLevel : Level = this._maxUniqueLevels[0], maxLevelIdx : int = maxLevel.index, sWidth : Number = this._hls.stage.stageWidth, sHeight : Number = this._hls.stage.stageHeight, lWidth : int, lHeight : int, i : int;

                    switch (HLSSettings.maxLevelCappingMode) {
                        case HLSMaxLevelCappingMode.UPSCALE:
                            for (i = maxLevelsCount - 1; i >= 0; i--) {
                                maxLevel = this._maxUniqueLevels[i];
                                maxLevelIdx = maxLevel.index;
                                lWidth = maxLevel.width;
                                lHeight = maxLevel.height;
                                CONFIG::LOGGING {
                                    Log.debug("stage size: " + sWidth + "x" + sHeight + " ,level" + maxLevelIdx + " size: " + lWidth + "x" + lHeight);
                                }
                                if (sWidth >= lWidth || sHeight >= lHeight) {
                                    break;
                                    // from for loop
                                }
                            }
                            break;
                        case HLSMaxLevelCappingMode.DOWNSCALE:
                            for (i = 0; i < maxLevelsCount; i++) {
                                maxLevel = this._maxUniqueLevels[i];
                                maxLevelIdx = maxLevel.index;
                                lWidth = maxLevel.width;
                                lHeight = maxLevel.height;
                                CONFIG::LOGGING {
                                    Log.debug("stage size: " + sWidth + "x" + sHeight + " ,level" + maxLevelIdx + " size: " + lWidth + "x" + lHeight);
                                }
                                if (sWidth <= lWidth || sHeight <= lHeight) {
                                    break;
                                    // from for loop
                                }
                            }
                            break;
                    }
                    CONFIG::LOGGING {
                        Log.debug("max capped level idx: " + maxLevelIdx);
                    }
                }
                return maxLevelIdx;
            } else {
                return _nbLevel - 1;
            }
        }

        /** Update the quality level for the next fragment load. **/
        public function getnextlevel(current_level : int, buffer : Number) : int {
            if (_lastFetchDuration == 0 || _lastSegmentDuration == 0) {
                return 0;
            }

            /* rsft : remaining segment fetch time : available time to fetch next segment
            it depends on the current playback timestamp , the timestamp of the first frame of the next segment
            and TBMT, indicating a desired latency between the time instant to receive the last byte of a
            segment to the playback of the first media frame of a segment
            buffer is start time of next segment
            TBMT is the buffer size we need to ensure (we need at least 2 segments buffered */
            var rsft : Number = 1000 * buffer - 2 * _lastFetchDuration;
            var sftm : Number = Math.min(_lastSegmentDuration, rsft) / _lastFetchDuration;
            var max_level : Number = _maxLevel;
            var switch_to_level : int = current_level;
            // CONFIG::LOGGING {
            // Log.info("rsft:" + rsft);
            // Log.info("sftm:" + sftm);
            // }
            // }
            /* to switch level up :
            rsft should be greater than switch up condition
             */
            if ((current_level < max_level) && (sftm > (1 + _switchup[current_level]))) {
                CONFIG::LOGGING {
                    Log.debug("sftm:> 1+_switchup[_level]=" + (1 + _switchup[current_level]));
                }
                switch_to_level = current_level + 1;
            }

            /* to switch level down :
            rsft should be smaller than switch up condition,
            or the current level is greater than max level
             */ else if ((current_level > max_level && current_level > 0) || (current_level > 0 && (sftm < 1 - _switchdown[current_level]))) {
                CONFIG::LOGGING {
                    Log.debug("sftm < 1-_switchdown[current_level]=" + _switchdown[current_level]);
                }
                var bufferratio : Number = 1000 * buffer / _lastSegmentDuration;
                /* find suitable level matching current bandwidth, starting from current level
                when switching level down, we also need to consider that we might need to load two fragments.
                the condition (bufferratio > 2*_levels[j].bitrate/_lastBandwidth)
                ensures that buffer time is bigger than than the time to download 2 fragments from level j, if we keep same bandwidth.
                 */

                for (var j : int = current_level - 1; j >= 0; j--) {
                    if (_bitrate[j] <= lastBandwidth && (bufferratio > 2 * _bitrate[j] / lastBandwidth)) {
                        switch_to_level = j;
                        break;
                    }
                    if (j == 0) {
                        switch_to_level = 0;
                    }
                }
            }

            // Then we should check if selected level is higher than max_level if so, than take the min of those two
            switch_to_level = Math.min(max_level, switch_to_level);

            CONFIG::LOGGING {
                if (switch_to_level != current_level) {
                    Log.debug("switch to level " + switch_to_level);
                }
            }

            return switch_to_level;
        }

        // get level index of first level appearing in the manifest
        public function get firstLevel() : int {
            var levels : Vector.<Level> = _hls.levels;
            for (var i : int = 0; i < levels.length; i++) {
                if (levels[i].manifest_index == 0) {
                    return i;
                }
            }
            return 0;
        }

        /*  set the quality level used when starting a fresh playback */
        public function set startLevel(level : int) : void {
            _startLevel = level;
        };

        public function get startLevel() : int {
            var start_level : int = -1;
            var levels : Vector.<Level> = _hls.levels;
            if (levels) {
                // if set, _startLevel takes precedence
                if(_startLevel >=0) {
                    return Math.min(levels.length-1,_startLevel);
                } else if (HLSSettings.startFromLevel === -2) {
                    // playback will start from the first level appearing in Manifest (not sorted by bitrate)
                    return firstLevel;
                } else if (HLSSettings.startFromLevel === -1 && HLSSettings.startFromBitrate === -1) {
                    /* if startFromLevel is set to -1, it means that effective startup level
                     * will be determined from first segment download bandwidth
                     * let's use lowest bitrate for this download bandwidth assessment
                     * this should speed up playback start time
                     */
                    return 0;
                } else {
                    // set up start level as being the lowest non-audio level.
                    for (var i : int = 0; i < levels.length; i++) {
                        if (!levels[i].audio) {
                            start_level = i;
                            break;
                        }
                    }
                    // in case of audio only playlist, force startLevel to 0
                    if (start_level == -1) {
                        CONFIG::LOGGING {
                            Log.info("playlist is audio-only");
                        }
                        start_level = 0;
                    } else {
                        if (HLSSettings.startFromBitrate > 0) {
                            start_level = findIndexOfClosestLevel(HLSSettings.startFromBitrate);
                        } else if (HLSSettings.startFromLevel > 0) {
                            // adjust start level using a rule by 3
                            start_level += Math.round(HLSSettings.startFromLevel * (levels.length - start_level - 1));
                        }
                    }
                }
                CONFIG::LOGGING {
                    Log.debug("start level :" + start_level);
                }
            }
            return start_level;
        }

        /**
         * @param desiredBitrate
         * @return The index of the level that has a bitrate closest to the desired bitrate.
         */
        private function findIndexOfClosestLevel(desiredBitrate : Number) : int {
            var levelIndex : int = -1;
            var minDistance : Number = Number.MAX_VALUE;
            var levels : Vector.<Level> = _hls.levels;

            for (var index : int = 0; index < levels.length; index++) {
                var level : Level = levels[index];

                var distance : Number = Math.abs(desiredBitrate - level.bitrate);

                if (distance < minDistance) {
                    levelIndex = index;
                    minDistance = distance;
                }
            }
            return levelIndex;
        }

        public function get seekLevel() : int {
            var seek_level : int = -1;
            var levels : Vector.<Level> = _hls.levels;
            if (HLSSettings.seekFromLevel == -1) {
                // keep last level
                return _hls.loadLevel;
            }

            // set up seek level as being the lowest non-audio level.
            for (var i : int = 0; i < levels.length; i++) {
                if (!levels[i].audio) {
                    seek_level = i;
                    break;
                }
            }
            // in case of audio only playlist, force seek_level to 0
            if (seek_level == -1) {
                seek_level = 0;
            } else {
                if (HLSSettings.seekFromLevel > 0) {
                    // adjust start level using a rule by 3
                    seek_level += Math.round(HLSSettings.seekFromLevel * (levels.length - seek_level - 1));
                }
            }
            CONFIG::LOGGING {
                Log.debug("seek level :" + seek_level);
            }
            return seek_level;
        }
    }
}

remove forced level capping on new manifest load


/*
 *  FRESteamWorks.h
 *  This file is part of FRESteamWorks.
 *
 *  Created by David ´Oldes´ Oliva on 3/29/12.
 *  Contributors: Ventero <http://github.com/Ventero>
 *  Copyright (c) 2012 Amanita Design. All rights reserved.
 *  Copyright (c) 2012-2013 Level Up Labs, LLC. All rights reserved.
 */

package
{
	import com.amanitadesign.steam.FRESteamWorks;
	import com.amanitadesign.steam.SteamConstants;
	import com.amanitadesign.steam.SteamEvent;
	import com.amanitadesign.steam.WorkshopConstants;

	import flash.desktop.NativeApplication;
	import flash.display.SimpleButton;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.utils.ByteArray;

	public class FRESteamWorksTest extends Sprite
	{
		public var Steamworks:FRESteamWorks = new FRESteamWorks();
		public var tf:TextField;

		private var _buttonPos:int = 5;

		public function FRESteamWorksTest()
		{
			tf = new TextField();
			tf.x = 160;
			tf.width = stage.stageWidth - tf.x;
			tf.height = stage.stageHeight;
			addChild(tf);

			addButton("Check stats/achievements", checkAchievements);
			addButton("Toggle achievement", toggleAchievement);
			addButton("Toggle cloud enabled", toggleCloudEnabled);
			addButton("Toggle file", toggleFile);
			addButton("Publish file", publishFile);
			addButton("Show Friends overlay", activateOverlay);

			Steamworks.addEventListener(SteamEvent.STEAM_RESPONSE, onSteamResponse);
			NativeApplication.nativeApplication.addEventListener(Event.EXITING, onExit);
			try {
				Steamworks.useCrashHandler(480, "1.0", "Feb 20 2013", "21:42:20");
				if(!Steamworks.init()){
					log("STEAMWORKS API is NOT available");
					return;
				}

				log("STEAMWORKS API is available\n");
				log("User ID: " + Steamworks.getUserID());
				log("Persona name: " + Steamworks.getPersonaName());
				log("isCloudEnabledForApp() == "+Steamworks.isCloudEnabledForApp() );
				log("getFileCount() == "+Steamworks.getFileCount() );
				log("fileExists('test.txt') == "+Steamworks.fileExists('test.txt') );

				Steamworks.resetAllStats(true);
			} catch(e:Error) {
				log("*** ERROR ***");
				log(e.message);
				log(e.getStackTrace());
			}

		}
		private function log(value:String):void{
			tf.appendText(value+"\n");
			tf.scrollV = tf.maxScrollV;
		}

		public function writeFileToCloud(fileName:String, data:String):Boolean {
			var dataOut:ByteArray = new ByteArray();
			dataOut.writeUTFBytes(data);
			return Steamworks.fileWrite(fileName, dataOut);
		}

		public function readFileFromCloud(fileName:String):String {
			var dataIn:ByteArray = new ByteArray();
			var result:String;
			dataIn.position = 0;
			dataIn.length = Steamworks.getFileSize(fileName);

			if(dataIn.length>0 && Steamworks.fileRead(fileName,dataIn)){
				result = dataIn.readUTFBytes(dataIn.length);
			}
			return result;
		}

		private function checkAchievements(e:Event = null):void {
			if(!Steamworks.isReady) return;

			// current stats and achievement ids are from steam example app
			log("isAchievement('ACH_WIN_ONE_GAME') == "+Steamworks.isAchievement("ACH_WIN_ONE_GAME"));
			log("isAchievement('ACH_TRAVEL_FAR_SINGLE') == "+Steamworks.isAchievement("ACH_TRAVEL_FAR_SINGLE"));
			log("setStatFloat('FeetTraveled') == "+Steamworks.setStatFloat('FeetTraveled', 21.3));
			log("setStatInt('NumGames', 2) == "+Steamworks.setStatInt('NumGames', 2));
			Steamworks.storeStats();
			log("getStatInt('NumGames') == "+Steamworks.getStatInt('NumGames'));
			log("getStatFloat('FeetTraveled') == "+Steamworks.getStatFloat('FeetTraveled'));
		}

		private function toggleAchievement(e:Event = null):void{
			if(!Steamworks.isReady) return;

			var result:Boolean = Steamworks.isAchievement("ACH_WIN_ONE_GAME");
			log("isAchievement('ACH_WIN_ONE_GAME') == " + result);
			if(!result) {
				log("setAchievement('ACH_WIN_ONE_GAME') == "+Steamworks.setAchievement("ACH_WIN_ONE_GAME"));
			} else {
				log("clearAchievement('ACH_WIN_ONE_GAME') == "+Steamworks.clearAchievement("ACH_WIN_ONE_GAME"));
			}
		}

		private function toggleCloudEnabled(e:Event = null):void {
			if(!Steamworks.isReady) return;

			var enabled:Boolean = Steamworks.isCloudEnabledForApp();
			log("isCloudEnabledForApp() == " + enabled);
			log("setCloudEnabledForApp(" + !enabled + ") == " + Steamworks.setCloudEnabledForApp(!enabled));
			log("isCloudEnabledForApp() == " + Steamworks.isCloudEnabledForApp());
		}

		private function toggleFile(e:Event = null):void {
			if(!Steamworks.isReady) return;

			var result:Boolean = Steamworks.fileExists('test.txt');
			log("fileExists('test.txt') == " + result);
			if(result){
				log("readFileFromCloud('test.txt') == "+readFileFromCloud('test.txt') );
				log("fileDelete('test.txt') == "+Steamworks.fileDelete('test.txt'));
			} else {
				log("writeFileToCloud('test.txt','click') == "+writeFileToCloud('test.txt','click'));
			}
		}

		private function publishFile(e:Event = null):void {
			if(!Steamworks.isReady) return;

			var res:Boolean = Steamworks.publishWorkshopFile("test.txt", "", 480,
				"Test.txt", "Test.txt", WorkshopConstants.VISIBILITY_Private,
				["TestTag"], WorkshopConstants.FILETYPE_Community);
			log("publishWorkshopFile('test.txt' ...) == " + res);
		}

		private function activateOverlay(e:Event = null):void {
			if(!Steamworks.isReady) return;

			log("activateGameOverlay('Friends') == " + Steamworks.activateGameOverlay("Friends"));
		}

		private function onSteamResponse(e:SteamEvent):void{
			switch(e.req_type){
				case SteamConstants.RESPONSE_OnUserStatsStored:
					log("RESPONSE_OnUserStatsStored: "+e.response);
					break;
				case SteamConstants.RESPONSE_OnUserStatsReceived:
					log("RESPONSE_OnUserStatsReceived: "+e.response);
					break;
				case SteamConstants.RESPONSE_OnAchievementStored:
					log("RESPONSE_OnAchievementStored: "+e.response);
					break;
				default:
					log("STEAMresponse type:"+e.req_type+" response:"+e.response);
			}
		}

		private function onExit(e:Event):void{
			log("Exiting application, cleaning up");
			Steamworks.dispose();
		}

		private function addButton(label:String, callback:Function):void {
			var button:Sprite = new Sprite();
			button.graphics.beginFill(0xaaaaaa);
			button.graphics.drawRoundRect(0, 0, 150, 30, 5, 5);
			button.graphics.endFill();
			button.buttonMode = true;
			button.useHandCursor = true;
			button.addEventListener(MouseEvent.CLICK, callback);
			button.x = 5;
			button.y = _buttonPos;
			_buttonPos += button.height + 5;

			var text:TextField = new TextField();
			text.text = label;
			text.width = 140;
			text.height = 25;
			text.x = 5;
			text.y = 5;
			text.mouseEnabled = false;

			button.addChild(text);
			addChild(button);
		}
	}
}

/*
 *  FRESteamWorks.h
 *  This file is part of FRESteamWorks.
 *
 *  Created by David ´Oldes´ Oliva on 3/29/12.
 *  Contributors: Ventero <http://github.com/Ventero>
 *  Copyright (c) 2012 Amanita Design. All rights reserved.
 *  Copyright (c) 2012-2013 Level Up Labs, LLC. All rights reserved.
 */

package
{
	import com.amanitadesign.steam.FRESteamWorks;
	import com.amanitadesign.steam.SteamConstants;
	import com.amanitadesign.steam.SteamEvent;
	import com.amanitadesign.steam.WorkshopConstants;

	import flash.desktop.NativeApplication;
	import flash.display.SimpleButton;
	import flash.display.Sprite;
	import flash.display.StageDisplayState;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.utils.ByteArray;

	public class FRESteamWorksTest extends Sprite
	{
		public var Steamworks:FRESteamWorks = new FRESteamWorks();
		public var tf:TextField;

		private var _buttonPos:int = 5;

		public function FRESteamWorksTest()
		{
			tf = new TextField();
			tf.x = 160;
			tf.width = stage.stageWidth - tf.x;
			tf.height = stage.stageHeight;
			addChild(tf);

			addButton("Check stats/achievements", checkAchievements);
			addButton("Toggle achievement", toggleAchievement);
			addButton("Toggle cloud enabled", toggleCloudEnabled);
			addButton("Toggle file", toggleFile);
			addButton("Publish file", publishFile);
			addButton("Toggle fullscreen", toggleFullscreen);
			addButton("Show Friends overlay", activateOverlay);

			Steamworks.addEventListener(SteamEvent.STEAM_RESPONSE, onSteamResponse);
			NativeApplication.nativeApplication.addEventListener(Event.EXITING, onExit);
			try {
				Steamworks.useCrashHandler(480, "1.0", "Feb 20 2013", "21:42:20");
				if(!Steamworks.init()){
					log("STEAMWORKS API is NOT available");
					return;
				}

				log("STEAMWORKS API is available\n");
				log("User ID: " + Steamworks.getUserID());
				log("Persona name: " + Steamworks.getPersonaName());
				log("isCloudEnabledForApp() == "+Steamworks.isCloudEnabledForApp() );
				log("getFileCount() == "+Steamworks.getFileCount() );
				log("fileExists('test.txt') == "+Steamworks.fileExists('test.txt') );

				Steamworks.resetAllStats(true);
			} catch(e:Error) {
				log("*** ERROR ***");
				log(e.message);
				log(e.getStackTrace());
			}

		}
		private function log(value:String):void{
			tf.appendText(value+"\n");
			tf.scrollV = tf.maxScrollV;
		}

		public function writeFileToCloud(fileName:String, data:String):Boolean {
			var dataOut:ByteArray = new ByteArray();
			dataOut.writeUTFBytes(data);
			return Steamworks.fileWrite(fileName, dataOut);
		}

		public function readFileFromCloud(fileName:String):String {
			var dataIn:ByteArray = new ByteArray();
			var result:String;
			dataIn.position = 0;
			dataIn.length = Steamworks.getFileSize(fileName);

			if(dataIn.length>0 && Steamworks.fileRead(fileName,dataIn)){
				result = dataIn.readUTFBytes(dataIn.length);
			}
			return result;
		}

		private function checkAchievements(e:Event = null):void {
			if(!Steamworks.isReady) return;

			// current stats and achievement ids are from steam example app
			log("isAchievement('ACH_WIN_ONE_GAME') == "+Steamworks.isAchievement("ACH_WIN_ONE_GAME"));
			log("isAchievement('ACH_TRAVEL_FAR_SINGLE') == "+Steamworks.isAchievement("ACH_TRAVEL_FAR_SINGLE"));
			log("setStatFloat('FeetTraveled') == "+Steamworks.setStatFloat('FeetTraveled', 21.3));
			log("setStatInt('NumGames', 2) == "+Steamworks.setStatInt('NumGames', 2));
			Steamworks.storeStats();
			log("getStatInt('NumGames') == "+Steamworks.getStatInt('NumGames'));
			log("getStatFloat('FeetTraveled') == "+Steamworks.getStatFloat('FeetTraveled'));
		}

		private function toggleAchievement(e:Event = null):void{
			if(!Steamworks.isReady) return;

			var result:Boolean = Steamworks.isAchievement("ACH_WIN_ONE_GAME");
			log("isAchievement('ACH_WIN_ONE_GAME') == " + result);
			if(!result) {
				log("setAchievement('ACH_WIN_ONE_GAME') == "+Steamworks.setAchievement("ACH_WIN_ONE_GAME"));
			} else {
				log("clearAchievement('ACH_WIN_ONE_GAME') == "+Steamworks.clearAchievement("ACH_WIN_ONE_GAME"));
			}
		}

		private function toggleCloudEnabled(e:Event = null):void {
			if(!Steamworks.isReady) return;

			var enabled:Boolean = Steamworks.isCloudEnabledForApp();
			log("isCloudEnabledForApp() == " + enabled);
			log("setCloudEnabledForApp(" + !enabled + ") == " + Steamworks.setCloudEnabledForApp(!enabled));
			log("isCloudEnabledForApp() == " + Steamworks.isCloudEnabledForApp());
		}

		private function toggleFile(e:Event = null):void {
			if(!Steamworks.isReady) return;

			var result:Boolean = Steamworks.fileExists('test.txt');
			log("fileExists('test.txt') == " + result);
			if(result){
				log("readFileFromCloud('test.txt') == "+readFileFromCloud('test.txt') );
				log("fileDelete('test.txt') == "+Steamworks.fileDelete('test.txt'));
			} else {
				log("writeFileToCloud('test.txt','click') == "+writeFileToCloud('test.txt','click'));
			}
		}

		private function publishFile(e:Event = null):void {
			if(!Steamworks.isReady) return;

			var res:Boolean = Steamworks.publishWorkshopFile("test.txt", "", 480,
				"Test.txt", "Test.txt", WorkshopConstants.VISIBILITY_Private,
				["TestTag"], WorkshopConstants.FILETYPE_Community);
			log("publishWorkshopFile('test.txt' ...) == " + res);
		}

		private function toggleFullscreen(e:Event = null):void {
			if(stage.displayState == StageDisplayState.NORMAL)
				stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
			else
				stage.displayState = StageDisplayState.NORMAL;
		}

		private function activateOverlay(e:Event = null):void {
			if(!Steamworks.isReady) return;

			log("activateGameOverlay('Friends') == " + Steamworks.activateGameOverlay("Friends"));
		}

		private function onSteamResponse(e:SteamEvent):void{
			switch(e.req_type){
				case SteamConstants.RESPONSE_OnUserStatsStored:
					log("RESPONSE_OnUserStatsStored: "+e.response);
					break;
				case SteamConstants.RESPONSE_OnUserStatsReceived:
					log("RESPONSE_OnUserStatsReceived: "+e.response);
					break;
				case SteamConstants.RESPONSE_OnAchievementStored:
					log("RESPONSE_OnAchievementStored: "+e.response);
					break;
				default:
					log("STEAMresponse type:"+e.req_type+" response:"+e.response);
			}
		}

		private function onExit(e:Event):void{
			log("Exiting application, cleaning up");
			Steamworks.dispose();
		}

		private function addButton(label:String, callback:Function):void {
			var button:Sprite = new Sprite();
			button.graphics.beginFill(0xaaaaaa);
			button.graphics.drawRoundRect(0, 0, 150, 30, 5, 5);
			button.graphics.endFill();
			button.buttonMode = true;
			button.useHandCursor = true;
			button.addEventListener(MouseEvent.CLICK, callback);
			button.x = 5;
			button.y = _buttonPos;
			_buttonPos += button.height + 5;

			var text:TextField = new TextField();
			text.text = label;
			text.width = 140;
			text.height = 25;
			text.x = 5;
			text.y = 5;
			text.mouseEnabled = false;

			button.addChild(text);
			addChild(button);
		}
	}
}

Add fullscreen toggle button to test app


/*
 * Copyright (c) 2014 castLabs GmbH
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

package com.castlabs.dash.utils {
import flash.events.TimerEvent;
import flash.external.ExternalInterface;
import flash.utils.Timer;

public class Console {
    private static const ERROR:String = "error";
    private static const WARN:String = "warn";
    private static const INFO:String = "info";
    private static const DEBUG:String = "debug";

    private var enabled:Boolean = false;
    private var events:Array = [];

    public function Console() {
    }

    public function enable():void {
        enabled = true;

        var timer:Timer = new Timer(2000); // 2 second
        timer.addEventListener(TimerEvent.TIMER, send);
        timer.start();
    }

    private function send(event:TimerEvent):void {
        if (events.length == 0) {
            return;
        }

        ExternalInterface.call("handleEvents", events);

        while (events.length > 0) {
            events.pop();
        }
    }

    public function error(message:String):void {
        log(ERROR, message);
    }

    public function warn(message:String):void {
        log(WARN, message);
    }

    public function info(message:String):void {
        log(INFO, message);
    }

    public function debug(message:String):void {
        log(DEBUG, message);
    }

    public function logAndBuildError(message:String):Error {
        log(ERROR, message);
        return new Error(message);
    }

    public function log(level:String, message:String):void {
        if (!enabled) {
            return;
        }

        trace(message);

        events.push({
            id: "log",
            level: level,
            message: message
        });
    }

    public function appendRealUserBandwidth(bandwidth:Number):void {
        appendUserBandwidth("real", bandwidth);
    }

    public function appendAverageUserBandwidth(bandwidth:Number):void {
        appendUserBandwidth("average", bandwidth);
    }

    public function appendUserBandwidth(type:String, bandwidth:Number):void {
        if (!enabled) {
            return;
        }

        events.push({
            id: "appendUserBandwidth",
            dataset: type,
            bandwidth: bandwidth
        });
    }

    public function appendVideoBandwidth(bandwidth:Number):void {
        appendMediaBandwidth("video", bandwidth);
    }

    public function appendAudioBandwidth(bandwidth:Number):void {
        appendMediaBandwidth("audio", bandwidth);
    }

    public function appendMediaBandwidth(type:String, bandwidth:Number):void {
        if (!enabled) {
            return;
        }

        events.push({
            id: "appendMediaBandwidth",
            dataset: type,
            bandwidth: bandwidth
        });
    }
}
}

/*
 * Copyright (c) 2014 castLabs GmbH
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

package com.castlabs.dash.utils {
import flash.events.TimerEvent;
import flash.external.ExternalInterface;
import flash.utils.Timer;

public class Console {
    private static const ERROR:String = "error";
    private static const WARN:String = "warn";
    private static const INFO:String = "info";
    private static const DEBUG:String = "debug";

    private var enabled:Boolean = false;
    private var events:Array = [];

    public function Console() {
    }

    public function enable():void {
        enabled = true;

        var timer:Timer = new Timer(2000); // 2 second
        timer.addEventListener(TimerEvent.TIMER, send);
        timer.start();
    }

    private function send(event:TimerEvent):void {
        if (events.length == 0) {
            return;
        }

		if (ExternalInterface.available)
			ExternalInterface.call("handleEvents", events);

        while (events.length > 0) {
            events.pop();
        }
    }

    public function error(message:String):void {
        log(ERROR, message);
    }

    public function warn(message:String):void {
        log(WARN, message);
    }

    public function info(message:String):void {
        log(INFO, message);
    }

    public function debug(message:String):void {
        log(DEBUG, message);
    }

    public function logAndBuildError(message:String):Error {
        log(ERROR, message);
        return new Error(message);
    }

    public function log(level:String, message:String):void {
        if (!enabled) {
            return;
        }

        trace(message);

        events.push({
            id: "log",
            level: level,
            message: message
        });
    }

    public function appendRealUserBandwidth(bandwidth:Number):void {
        appendUserBandwidth("real", bandwidth);
    }

    public function appendAverageUserBandwidth(bandwidth:Number):void {
        appendUserBandwidth("average", bandwidth);
    }

    public function appendUserBandwidth(type:String, bandwidth:Number):void {
        if (!enabled) {
            return;
        }

        events.push({
            id: "appendUserBandwidth",
            dataset: type,
            bandwidth: bandwidth
        });
    }

    public function appendVideoBandwidth(bandwidth:Number):void {
        appendMediaBandwidth("video", bandwidth);
    }

    public function appendAudioBandwidth(bandwidth:Number):void {
        appendMediaBandwidth("audio", bandwidth);
    }

    public function appendMediaBandwidth(type:String, bandwidth:Number):void {
        if (!enabled) {
            return;
        }

        events.push({
            id: "appendMediaBandwidth",
            dataset: type,
            bandwidth: bandwidth
        });
    }
}
}

Check ExternalInterface availability

Check ExternalInterface availability


/*
 *  SteamConstants.as
 *  This file is part of FRESteamWorks.
 *
 *  Created by David ´Oldes´ Oliva on 3/29/12.
 *  Contributors: Ventero <http://github.com/Ventero>
 *  Copyright (c) 2012 Amanita Design. All rights reserved.
 *  Copyright (c) 2012-2013 Level Up Labs, LLC. All rights reserved.
 */

package com.amanitadesign.steam
{
	public class SteamConstants
	{
		/* response values */
		public static const RESPONSE_OK:int = 0;
		public static const RESPONSE_FAILED:int = 1;

		/* response types */
		public static const RESPONSE_OnUserStatsReceived:int = 0;
		public static const RESPONSE_OnUserStatsStored:int = 1;
		public static const RESPONSE_OnAchievementStored:int = 2;
		public static const RESPONSE_OnGameOverlayActivated:int = 3;
		public static const RESPONSE_OnFileShared:int = 4;
		public static const RESPONSE_OnUGCDownload:int = 5;
		public static const RESPONSE_OnPublishWorkshopFile:int = 6;
		public static const RESPONSE_OnDeletePublishedFile:int = 7;
		public static const RESPONSE_OnGetPublishedFileDetails:int = 8;
		public static const RESPONSE_OnEnumerateUserPublishedFiles:int = 9;
		public static const RESPONSE_OnEnumeratePublishedWorkshopFiles:int = 10;
		public static const RESPONSE_OnEnumerateUserSubscribedFiles:int = 11;
		public static const RESPONSE_OnEnumerateUserSharedWorkshopFiles:int = 12;
		public static const RESPONSE_OnEnumeratePublishedFilesByUserAction:int = 13;
		public static const RESPONSE_OnCommitPublishedFileUpdate:int = 14;
		public static const RESPONSE_OnSubscribePublishedFile:int = 15;
		public static const RESPONSE_OnUnsubscribePublishedFile:int = 16;
		public static const RESPONSE_OnGetPublishedItemVoteDetails:int = 17;
		public static const RESPONSE_OnUpdateUserPublishedItemVote:int = 18;
		public static const RESPONSE_OnSetUserPublishedFileActio:int = 19;
	}

}

/*
 *  SteamConstants.as
 *  This file is part of FRESteamWorks.
 *
 *  Created by David ´Oldes´ Oliva on 3/29/12.
 *  Contributors: Ventero <http://github.com/Ventero>
 *  Copyright (c) 2012 Amanita Design. All rights reserved.
 *  Copyright (c) 2012-2013 Level Up Labs, LLC. All rights reserved.
 */

package com.amanitadesign.steam
{
	public class SteamConstants
	{
		/* response values */
		public static const RESPONSE_OK:int = 0;
		public static const RESPONSE_FAILED:int = 1;

		/* response types */
		public static const RESPONSE_OnUserStatsReceived:int = 0;
		public static const RESPONSE_OnUserStatsStored:int = 1;
		public static const RESPONSE_OnAchievementStored:int = 2;
		public static const RESPONSE_OnGameOverlayActivated:int = 3;
		public static const RESPONSE_OnFileShared:int = 4;
		public static const RESPONSE_OnUGCDownload:int = 5;
		public static const RESPONSE_OnPublishWorkshopFile:int = 6;
		public static const RESPONSE_OnDeletePublishedFile:int = 7;
		public static const RESPONSE_OnGetPublishedFileDetails:int = 8;
		public static const RESPONSE_OnEnumerateUserPublishedFiles:int = 9;
		public static const RESPONSE_OnEnumeratePublishedWorkshopFiles:int = 10;
		public static const RESPONSE_OnEnumerateUserSubscribedFiles:int = 11;
		public static const RESPONSE_OnEnumerateUserSharedWorkshopFiles:int = 12;
		public static const RESPONSE_OnEnumeratePublishedFilesByUserAction:int = 13;
		public static const RESPONSE_OnCommitPublishedFileUpdate:int = 14;
		public static const RESPONSE_OnSubscribePublishedFile:int = 15;
		public static const RESPONSE_OnUnsubscribePublishedFile:int = 16;
		public static const RESPONSE_OnGetPublishedItemVoteDetails:int = 17;
		public static const RESPONSE_OnUpdateUserPublishedItemVote:int = 18;
		public static const RESPONSE_OnSetUserPublishedFileAction:int = 19;
	}

}

Fix typo

[lib] Fix typo


//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// 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.util {

import flash.net.ObjectEncoding;

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

import flash.system.ApplicationDomain;

import flash.utils.ByteArray;
import flash.utils.Endian;
import flash.utils.IExternalizable;
import flash.utils.getQualifiedSuperclassName; // function import

import com.threerings.io.TypedArray;

/**
 * Utility methods for transforming flash objects into byte[].
 */
public class ObjectMarshaller
{
    /**
     * Encode the specified object as either a byte[] or a byte[][] (see below).
     * The specific mechanism of encoding is not important,
     * as long as decode returns a clone of the original object.
     *
     * No validation is done to verify that the object can be serialized.
     *
     * Currently, cycles in the object graph are preserved on the other end.
     *
     * @param encodeArrayElements if true and the obj is an Array, each element is
     * encoded separately, returning a byte[][] instead of a byte[].
     */
    public static function encode (
        obj :Object, encodeArrayElements :Boolean = false) :Object
    {
        if (obj == null) {
            return null;
        }
        if (encodeArrayElements && obj is Array) {
            var src :Array = (obj as Array);
            var dest :TypedArray = TypedArray.create(ByteArray);
            for (var ii :int = 0; ii < src.length; ii++) {
                dest.push(encode(src[ii], false));
            }
            return dest;
        }

        // TODO: Our own encoding, that takes into account
        // the ApplicationDomain.. ACK
        var bytes :ByteArray = new ByteArray();
        bytes.endian = Endian.BIG_ENDIAN;
        bytes.objectEncoding = ObjectEncoding.AMF3;
        bytes.writeObject(obj);
        return bytes;
    }

    /**
     * Validate the value and encode it. Arrays are not broken-up.
     */
    public static function validateAndEncode (obj :Object) :ByteArray
    {
        validateValue(obj);
        return encode(obj, false) as ByteArray;
    }

    /**
     * Decode the specified byte[] or byte[][] back into a flash Object.
     */
    public static function decode (encoded :Object) :Object
    {
        if (encoded == null) {
            return null;
        }
        if (encoded is TypedArray) {
            var src :TypedArray = (encoded as TypedArray);
            var dest :Array = [];
            for (var ii :int = 0; ii < src.length; ii++) {
                dest.push(decode(src[ii] as ByteArray));
            }
            return dest;
        }
        var bytes :ByteArray = (encoded as ByteArray);
        // re-set the position in case we're decoding the actual same byte
        // array used to encode (and not a network reconstruction)
        bytes.position = 0;

        // TODO: Our own decoding, that takes into account
        // the ApplicationDomain.. ACK
        bytes.endian = Endian.BIG_ENDIAN;
        bytes.objectEncoding = ObjectEncoding.AMF3;
        return bytes.readObject();
    }

    /**
     * Validate that the value is kosher for encoding, or throw an ArgumentError if it's not.
     */
    public static function validateValue (value :Object) :void
        // throws ArgumentError
    {
        var s :String = getValidationError(value);
        if (s != null) {
            throw new ArgumentError(s);
        }
    }

    /**
     * Get the String reason why this value is not encodable, or null if no error.
     */
    public static function getValidationError (value :Object) :String
    {
        if (value == null) {
            return null;

        } else if (value is IExternalizable) {
            return "IExternalizable is not yet supported";

        } else if (value is Array) {
            if (ClassUtil.getClassName(value) != "Array") {
                // We can't allow arrays to be serialized as IExternalizables
                // because we need to know element values (opaquely) on the
                // server. Also, we don't allow other types because we wouldn't
                // create the right class on the other side.
                return "Custom array subclasses are not supported";
            }
            // then, continue on with the sub-properties check (below)

        } else {
            var type :String = typeof(value);
            if (type == "number" || type == "string" || type == "boolean" ) {
                return null; // kosher!
            }
            if (-1 != VALID_CLASSES.indexOf(ClassUtil.getClass(value))) {
                return null; // kosher
            }
            if (!Util.isPlainObject(value)) {
                return "Non-simple properties may not be set.";
            }
            // fall through and verify the plain object's sub-properties
        }

        // check sub-properties (of arrays and objects)
        for each (var arrValue :Object in value) {
            var s :String = getValidationError(arrValue);
            if (s != null) {
                return s;
            }
        }

        return null; // it all checks out!
    }

    /** Non-simple classes that we allow, as long as they are not subclassed. */
    protected static const VALID_CLASSES :Array = [ ByteArray, Point, Rectangle ];
}
}

//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// 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.util {

import flash.net.ObjectEncoding;

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

import flash.system.ApplicationDomain;

import flash.utils.ByteArray;
import flash.utils.Dictionary;
import flash.utils.Endian;
import flash.utils.IExternalizable;
import flash.utils.getQualifiedSuperclassName; // function import

import com.threerings.io.TypedArray;

/**
 * Utility methods for transforming flash objects into byte[].
 */
public class ObjectMarshaller
{
    /**
     * Encode the specified object as either a byte[] or a byte[][] (see below).
     * The specific mechanism of encoding is not important,
     * as long as decode returns a clone of the original object.
     *
     * No validation is done to verify that the object can be serialized.
     *
     * Currently, cycles in the object graph are preserved on the other end.
     *
     * @param encodeArrayElements if true and the obj is an Array, each element is
     * encoded separately, returning a byte[][] instead of a byte[].
     */
    public static function encode (
        obj :Object, encodeArrayElements :Boolean = false) :Object
    {
        if (obj == null) {
            return null;
        }
        if (encodeArrayElements && obj is Array) {
            var src :Array = (obj as Array);
            var dest :TypedArray = TypedArray.create(ByteArray);
            for (var ii :int = 0; ii < src.length; ii++) {
                dest.push(encode(src[ii], false));
            }
            return dest;
        }

        // TODO: Our own encoding, that takes into account
        // the ApplicationDomain.. ACK
        var bytes :ByteArray = new ByteArray();
        bytes.endian = Endian.BIG_ENDIAN;
        bytes.objectEncoding = ObjectEncoding.AMF3;
        bytes.writeObject(obj);
        return bytes;
    }

    /**
     * Validate the value and encode it. Arrays are not broken-up.
     */
    public static function validateAndEncode (obj :Object) :ByteArray
    {
        validateValue(obj);
        return encode(obj, false) as ByteArray;
    }

    /**
     * Decode the specified byte[] or byte[][] back into a flash Object.
     */
    public static function decode (encoded :Object) :Object
    {
        if (encoded == null) {
            return null;
        }
        if (encoded is TypedArray) {
            var src :TypedArray = (encoded as TypedArray);
            var dest :Array = [];
            for (var ii :int = 0; ii < src.length; ii++) {
                dest.push(decode(src[ii] as ByteArray));
            }
            return dest;
        }
        var bytes :ByteArray = (encoded as ByteArray);
        // re-set the position in case we're decoding the actual same byte
        // array used to encode (and not a network reconstruction)
        bytes.position = 0;

        // TODO: Our own decoding, that takes into account
        // the ApplicationDomain.. ACK
        bytes.endian = Endian.BIG_ENDIAN;
        bytes.objectEncoding = ObjectEncoding.AMF3;
        return bytes.readObject();
    }

    /**
     * Validate that the value is kosher for encoding, or throw an ArgumentError if it's not.
     */
    public static function validateValue (value :Object) :void
        // throws ArgumentError
    {
        var s :String = getValidationError(value);
        if (s != null) {
            throw new ArgumentError(s);
        }
    }

    /**
     * Get the String reason why this value is not encodable, or null if no error.
     */
    public static function getValidationError (value :Object) :String
    {
        if (value == null) {
            return null;

        } else if (value is IExternalizable) {
            return "IExternalizable is not yet supported";

        } else if (value is Array) {
            if (ClassUtil.getClassName(value) != "Array") {
                // We can't allow arrays to be serialized as IExternalizables
                // because we need to know element values (opaquely) on the
                // server. Also, we don't allow other types because we wouldn't
                // create the right class on the other side.
                return "Custom array subclasses are not supported";
            }
            // then, continue on with the sub-properties check (below)

        } else if (value is Dictionary) {
            if (ClassUtil.getClassName(value) != "flash.utils.Dictionary") {
                return "Custom Dictionary subclasses are not supported";
            }
            // check all the keys
            for (var key :* in value) {
                var se :String = getValidationError(key);
                if (se != null) {
                    return se;
                }
            }
            // then, continue on with sub-property check (below)

        } else {
            var type :String = typeof(value);
            if (type == "number" || type == "string" || type == "boolean" ) {
                return null; // kosher!
            }
            if (-1 != VALID_CLASSES.indexOf(ClassUtil.getClass(value))) {
                return null; // kosher
            }
            if (!Util.isPlainObject(value)) {
                return "Non-simple properties may not be set.";
            }
            // fall through and verify the plain object's sub-properties
        }

        // check sub-properties (of arrays and objects)
        for each (var arrValue :Object in value) {
            var s :String = getValidationError(arrValue);
            if (s != null) {
                return s;
            }
        }

        return null; // it all checks out!
    }

    /** Non-simple classes that we allow, as long as they are not subclassed. */
    protected static const VALID_CLASSES :Array = [ ByteArray, Point, Rectangle ];
}
}

Support Dictionary, too.

Support Dictionary, too.

git-svn-id: a1a4b28b82a3276cc491891159dd9963a0a72fae@4972 542714f4-19e9-0310-aa3c-eee0fc999fb1


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

package com.google.analytics.core
{

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

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

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

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

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

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

         *
- You want to disable tracking across hosts.

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

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

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

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

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

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

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

    }
}

fix comment for asdoc

fix comment for asdoc


package
{
	import flash.display.MovieClip;

	public class ComponentMultimeter extends MovieClip
	{
		public var expandOnFocus:ExpandOnFocus;
		private var startX:Number;
		private var startY:Number;
		private var hitAreaMC:MovieClip = null;

		public function ComponentMultimeter() {
			super();
			trace('ENTER ComponentMultimeter');
			//trace('component breadboard ' +stage.this.x+' '+stage.this.y);
			expandOnFocus = new ExpandOnFocus(this,2.1,10,-10, this.hitAreaMC);	// give breadboard rollover behavior
			this.visible = true;
		}

		public function putOnStage(value1:Number,value2:Number) {
			this.startX=value1;
			this.startY=value2;

		}

		public function setStartX(value:Number) {
			this.startX = value;
		}
		public function setStartY(value:Number) {
			this.startY = value;
		}
		public function getVisibility() {
			return this.visible;
		}
		public function setHitArea(target:MovieClip):void {
			this.hitAreaMC = target;
		}

		//visibility can be set from the javascript as follows:
		//flash.sendCommand('set_multimeter_visiblity','true');
		//
		//or in flash with
		//circuit.getMultimeter().setVisibility('true');

		public function setVisibility(statStr:String) {
			switch((statStr).toLowerCase()) {
 		    	case "true":
				case "1":
				case "yes":
				default:
				this.visible = true;
				break;
				case "false":
				case "0":
				case "no":
				this.visible = false;
			}
		}

	}
}

package
{
	import flash.display.MovieClip;

	public class ComponentMultimeter extends MovieClip
	{
		public var expandOnFocus:ExpandOnFocus;
		private var startX:Number;
		private var startY:Number;
		private var hitAreaMC:MovieClip = null;

		public function ComponentMultimeter() {
			super();
			trace('ENTER ComponentMultimeter');
			//trace('component breadboard ' +stage.this.x+' '+stage.this.y);
			expandOnFocus = new ExpandOnFocus(this,2.1,10,-10, this.hitAreaMC);	// give breadboard rollover behavior
			this.visible = true;
		}

		public function putOnStage(value1:Number,value2:Number) {
			this.startX=value1;
			this.startY=value2;

		}

		public function setStartX(value:Number) {
			this.startX = value;
		}
		public function setStartY(value:Number) {
			this.startY = value;
		}
		public function getVisibility() {
			return this.visible;
		}
		public function setHitArea(target:MovieClip):void {
			this.hitAreaMC = target;
		}

		//visibility can be set from the javascript as follows:
		//flash.sendCommand('set_multimeter_visibility','true');
		//
		//or in flash with
		//circuit.getMultimeter().setVisibility('true');

		public function setVisibility(statStr:String) {
			switch((statStr).toLowerCase()) {
 		    	case "true":
				case "1":
				case "yes":
				default:
				this.visible = true;
				break;
				case "false":
				case "0":
				case "no":
				this.visible = false;
			}
		}

	}
}

correct typo for word "visibility" in a comment