////////////////////////////////////////////////////////////////////////////////
//
//  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.utils
{

	[ExcludeClass]
	COMPILE::AS3
	public class Language {}

    COMPILE::JS
    {
        import goog.bind;
        import goog.global;
    }

    /**
     * @flexjsignoreimport goog.bind
     * @flexjsignoreimport goog.global
     */
    COMPILE::JS
	public class Language
	{

		//--------------------------------------
		//   Static Property
		//--------------------------------------

		/**
		 * Helper var for sortOn
		 */
		static private var sortNames:Array;
		static private var sortNamesOne:Array = [];
		static private var muler:Number;
		static private var zeroStr:String = String.fromCharCode(0);

		//--------------------------------------
		//   Static Function
		//--------------------------------------

		/**
		 * as()
		 *
		 * @param leftOperand The lefthand operand of the
		 * binary as operator in AS3.
		 * @param rightOperand The righthand operand of the
		 * binary operator in AS3.
		 * @param coercion The cast is a coercion,
		 * throw exception if it fails.
		 * @return Returns the lefthand operand if it is of the
		 * type of the righthand operand, otherwise null.
		 */
		static public function as(leftOperand:Object, rightOperand:Object, coercion:* = null):Object
		{
			var error:Error, itIs:Boolean, message:String;

			coercion = (coercion !== undefined) ? coercion : false;

			itIs = Language.is(leftOperand, rightOperand);

			if (!itIs && coercion)
			{
				message = 'Type Coercion failed';

				if (TypeError)
				{
					error = new TypeError(message);
				}
				else
				{
					error = new Error(message);
				}
				throw error;
			}

			return (itIs) ? leftOperand : null;
		}

		/**
		 * int()
		 *
		 * @param value The value to be cast.
		 * @return {number}
		 */
		static public function _int(value:Number):Number
		{
			return value >> 0;
		}

		/**
		 * is()
		 *
		 * @param leftOperand The lefthand operand of the
		 * binary as operator in AS3.
		 * @param rightOperand The righthand operand of the
		 * binary operator in AS3.
		 * @return {boolean}
		 */
		static public function is(leftOperand:Object, rightOperand:Object):Boolean
		{
			var superClass:Object;

			if (leftOperand == null || rightOperand == null)
				return false;

            if (leftOperand instanceof rightOperand)
                return true;
            if (rightOperand === Object)
                return true; // every value is an Object in ActionScript except null and undefined (caught above)

			if (typeof leftOperand === 'string')
				return rightOperand === String;

			if (typeof leftOperand === 'number')
				return rightOperand === Number;

            if (typeof leftOperand === 'boolean')
                return rightOperand === Boolean;
            if (rightOperand === Array)
                return Array.isArray(leftOperand);

			if (leftOperand.FLEXJS_CLASS_INFO === undefined)
				return false; // could be a function but not an instance

			if (leftOperand.FLEXJS_CLASS_INFO.interfaces)
			{
				if (checkInterfaces(leftOperand, rightOperand))
				{
					return true;
				}
			}

			superClass = leftOperand.constructor;
            superClass = superClass.superClass_;

			if (superClass)
			{
				while (superClass && superClass.FLEXJS_CLASS_INFO)
				{
					if (superClass.FLEXJS_CLASS_INFO.interfaces)
					{
						if (checkInterfaces(superClass, rightOperand))
						{
							return true;
						}
					}
					superClass = superClass.constructor;
                    superClass = superClass.superClass_;
				}
			}

			return false;
		}

        /**
         * Helper function for is()
         */
        private static function checkInterfaces(leftOperand:*, rightOperand:*):Boolean
        {
            var i:int, interfaces:Array;

            interfaces = leftOperand.FLEXJS_CLASS_INFO.interfaces;
            for (i = interfaces.length - 1; i > -1; i--) {
                if (interfaces[i] === rightOperand) {
                    return true;
                }

                if (interfaces[i].prototype.FLEXJS_CLASS_INFO.interfaces) {
                    var isit:Boolean = checkInterfaces(interfaces[i].prototype, rightOperand);
                    if (isit) return true;
                }
            }

            return false;
        }

        /**
         * Implementation of "classDef is Class"
         */
        public function isClass(classDef:*):Boolean
        {
            return typeof classDef === 'function'
                   && classDef.prototype
                   && classDef.prototype.constructor === classDef;
        }

        /**
         * Implementation of "classDef as Class"
         */
        public function asClass(classDef:*):Class
        {
            return isClass(classDef) ? classDef : null;
        }

		/**
		 * postdecrement handles foo--
		 *
		 * @param obj The object with the getter/setter.
		 * @param prop The name of a property.
		 * @return {number}
		 */
		static public function postdecrement(obj:Object, prop:String):int
		{
			var value:int = obj[prop];
			obj[prop] = value - 1;
			return value;
		}

		/**
		 * postincrement handles foo++
		 *
		 * @param obj The object with the getter/setter.
		 * @param prop The name of a property.
		 * @return {number}
		 */
		static public function postincrement(obj:Object, prop:String):int
		{
			var value:int = obj[prop];
			obj[prop] = value + 1;
			return value;
		}

		/**
		 * predecrement handles --foo
		 *
		 * @param obj The object with the getter/setter.
		 * @param prop The name of a property.
		 * @return {number}
		 */
		static public function predecrement(obj:Object, prop:String):int
		{
			var value:int = obj[prop] - 1;
			obj[prop] = value;
			return value;
		}

		/**
		 * preincrement handles ++foo
		 *
		 * @param obj The object with the getter/setter.
		 * @param prop The name of a property.
		 * @return {number}
		 */
		static public function preincrement(obj:Object, prop:String):int
		{
			var value:int = obj[prop] + 1;
			obj[prop] = value;
			return value;
		}

		/**
		 * superGetter calls the getter on the given class' superclass.
		 *
		 * @param clazz The class.
		 * @param pthis The this pointer.
		 * @param prop The name of the getter.
		 * @return {Object}
		 */
		static public function superGetter(clazz:Object, pthis:Object, prop:String):Object
		{
			var superClass:Object = clazz.superClass_;
			var superdesc:Object = Object.getOwnPropertyDescriptor(superClass, prop);

			while (superdesc == null)
			{
				superClass = superClass.constructor;
                superClass = superClass.superClass_;
				superdesc = Object.getOwnPropertyDescriptor(superClass, prop);
			}
			return superdesc.get.call(pthis);
		}

		/**
		 * superSetter calls the setter on the given class' superclass.
		 *
		 * @param clazz The class.
		 * @param pthis The this pointer.
		 * @param prop The name of the getter.
		 * @param value The value.
		 */
		static public function superSetter(clazz:Object, pthis:Object, prop:String, value:Object):void
		{
			var superClass:Object = clazz.superClass_;
			var superdesc:Object = Object.getOwnPropertyDescriptor(superClass, prop);

			while (superdesc == null)
			{
				superClass = superClass.constructor;
                superClass = superClass.superClass_;
				superdesc = Object.getOwnPropertyDescriptor(superClass, prop);
			}
			superdesc.set.apply(pthis, [value]);
		}

		static public function trace(...rest):void
		{
			var theConsole:*;

			theConsole = goog.global.console;

			if (theConsole === undefined)
			{
				if(typeof window !== "undefined")
				{
					theConsole = window.console;
				}
				else if(typeof console !== "undefined")
				{
					theConsole = console;
				}
			}

			try
			{
				if (theConsole && theConsole.log)
				{
					theConsole.log.apply(theConsole, rest);
				}
			}
			catch (e:Error)
			{
				// ignore; at least we tried ;-)
			}
		}

		/**
		 * uint()
		 *
		 * @param value The value to be cast.
		 * @return {number}
		 */
		static public function uint(value:Number):Number
		{
			return value >>> 0;
		}

        /**
         * caches closures and returns the one closure
         *
         * @param fn The method on the instance.
         * @param object The instance.
         * @param boundMethodName The name to use to cache the closure.
         * @return The closure.
         */
        static public function closure(fn:Function, object:Object, boundMethodName:String):Function {
            if (object.hasOwnProperty(boundMethodName)) {
                return object[boundMethodName];
            }
            var boundMethod:Function = goog.bind(fn, object);
            Object.defineProperty(object, boundMethodName, {
                value: boundMethod
            });
            return boundMethod;
        };

		/**
		 * @author lizhi
		 * @param	arr
		 * @param	names
		 * @param	opt
		 */
		public static function sortOn(arr:Array,names:Object,opt:Object=0):void{
			if (names is Array){
				sortNames = names as Array;
			}else{
				sortNamesOne[0] = names;
				sortNames = sortNamesOne;
			}
			if (opt is Array){
				var opt2:int = 0;
				for each(var o:int in opt){
					opt2 = opt2 | o;
				}
			}else{
				opt2 = opt as int;
			}
			muler = (Array.DESCENDING & opt2) > 0?-1: 1;
			if(opt2&Array.NUMERIC){
				arr.sort(compareNumber);
			}else if (opt2&Array.CASEINSENSITIVE){
				arr.sort(compareStringCaseinsensitive);
			}else{
				arr.sort(compareString);
			}
		}
		private static function compareStringCaseinsensitive(a:Object, b:Object):int{
			for each(var n:String in sortNames){
				var v:int = (a[n]||zeroStr).toString().toLowerCase().localeCompare((b[n]||zeroStr).toString().toLowerCase());
				if (v != 0){
					return v*muler;
				}
			}
			return 0;
		}
		private static function compareString(a:Object, b:Object):int{
			for each(var n:String in sortNames){
				var v:int = (a[n]||zeroStr).toString().localeCompare((b[n]||zeroStr).toString());
				if (v != 0){
					return v*muler;
				}
			}
			return 0;
		}

		private static function compareNumber(a:Object, b:Object):int{
			for each(var n:String in sortNames){
				if (a[n]>b[n]){
					return muler;
				}else if (a[n]<b[n]){
					return -muler;
				}
			}
			return 0;
		}
	}
}

////////////////////////////////////////////////////////////////////////////////
//
//  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.utils
{

	[ExcludeClass]
	COMPILE::AS3
	public class Language {}

    COMPILE::JS
    {
        import goog.bind;
        import goog.global;
    }

    /**
     * @flexjsignoreimport goog.bind
     * @flexjsignoreimport goog.global
     */
    COMPILE::JS
	public class Language
	{

		//--------------------------------------
		//   Static Property
		//--------------------------------------

		/**
		 * Helper var for sortOn
		 */
		static private var sortNames:Array;
		static private var sortNamesOne:Array = [];
		static private var muler:Number;
		static private var zeroStr:String = String.fromCharCode(0);

		//--------------------------------------
		//   Static Function
		//--------------------------------------

		/**
		 * as()
		 *
		 * @param leftOperand The lefthand operand of the
		 * binary as operator in AS3.
		 * @param rightOperand The righthand operand of the
		 * binary operator in AS3.
		 * @param coercion The cast is a coercion,
		 * throw exception if it fails.
		 * @return Returns the lefthand operand if it is of the
		 * type of the righthand operand, otherwise null.
		 */
		static public function as(leftOperand:Object, rightOperand:Object, coercion:* = null):Object
		{
			var error:Error, itIs:Boolean, message:String;

			coercion = (coercion !== undefined) ? coercion : false;

			itIs = Language.is(leftOperand, rightOperand);

			if (!itIs && coercion)
			{
				message = 'Type Coercion failed';

				if (TypeError)
				{
					error = new TypeError(message);
				}
				else
				{
					error = new Error(message);
				}
				throw error;
			}

			return (itIs) ? leftOperand : null;
		}

		/**
		 * int()
		 *
		 * @param value The value to be cast.
		 * @return {number}
		 */
		static public function _int(value:Number):Number
		{
			return value >> 0;
		}

		/**
		 * is()
		 *
		 * @param leftOperand The lefthand operand of the
		 * binary as operator in AS3.
		 * @param rightOperand The righthand operand of the
		 * binary operator in AS3.
		 * @return {boolean}
		 */
		static public function is(leftOperand:Object, rightOperand:Object):Boolean
		{
			var superClass:Object;

			if (leftOperand == null || rightOperand == null)
				return false;

            if (leftOperand instanceof rightOperand)
                return true;
            if (rightOperand === Object)
                return true; // every value is an Object in ActionScript except null and undefined (caught above)

			if (typeof leftOperand === 'string')
				return rightOperand === String;

			if (typeof leftOperand === 'number')
				return rightOperand === Number;

            if (typeof leftOperand === 'boolean')
                return rightOperand === Boolean;
            if (rightOperand === Array)
                return Array.isArray(leftOperand);

			if (leftOperand.FLEXJS_CLASS_INFO === undefined)
				return false; // could be a function but not an instance

			if (leftOperand.FLEXJS_CLASS_INFO.interfaces)
			{
				if (checkInterfaces(leftOperand, rightOperand))
				{
					return true;
				}
			}

			superClass = leftOperand.constructor;
            superClass = superClass.superClass_;

			if (superClass)
			{
				while (superClass && superClass.FLEXJS_CLASS_INFO)
				{
					if (superClass.FLEXJS_CLASS_INFO.interfaces)
					{
						if (checkInterfaces(superClass, rightOperand))
						{
							return true;
						}
					}
					superClass = superClass.constructor;
                    superClass = superClass.superClass_;
				}
			}

			return false;
		}

        /**
         * Helper function for is()
         */
        private static function checkInterfaces(leftOperand:*, rightOperand:*):Boolean
        {
            var i:int, interfaces:Array;

            interfaces = leftOperand.FLEXJS_CLASS_INFO.interfaces;
            for (i = interfaces.length - 1; i > -1; i--) {
                if (interfaces[i] === rightOperand) {
                    return true;
                }

                if (interfaces[i].prototype.FLEXJS_CLASS_INFO.interfaces) {
                    var isit:Boolean = checkInterfaces(interfaces[i].prototype, rightOperand);
                    if (isit) return true;
                }
            }

            return false;
        }

        /**
         * Implementation of "classDef is Class"
         */
        public function isClass(classDef:*):Boolean
        {
            return typeof classDef === 'function'
                   && classDef.prototype
                   && classDef.prototype.constructor === classDef;
        }

        /**
         * Implementation of "classDef as Class"
         */
        public function asClass(classDef:*):Class
        {
            return isClass(classDef) ? classDef : null;
        }

		/**
		 * postdecrement handles foo--
		 *
		 * @param obj The object with the getter/setter.
		 * @param prop The name of a property.
		 * @return {number}
		 */
		static public function postdecrement(obj:Object, prop:String):int
		{
			var value:int = obj[prop];
			obj[prop] = value - 1;
			return value;
		}

		/**
		 * postincrement handles foo++
		 *
		 * @param obj The object with the getter/setter.
		 * @param prop The name of a property.
		 * @return {number}
		 */
		static public function postincrement(obj:Object, prop:String):int
		{
			var value:int = obj[prop];
			obj[prop] = value + 1;
			return value;
		}

		/**
		 * predecrement handles --foo
		 *
		 * @param obj The object with the getter/setter.
		 * @param prop The name of a property.
		 * @return {number}
		 */
		static public function predecrement(obj:Object, prop:String):int
		{
			var value:int = obj[prop] - 1;
			obj[prop] = value;
			return value;
		}

		/**
		 * preincrement handles ++foo
		 *
		 * @param obj The object with the getter/setter.
		 * @param prop The name of a property.
		 * @return {number}
		 */
		static public function preincrement(obj:Object, prop:String):int
		{
			var value:int = obj[prop] + 1;
			obj[prop] = value;
			return value;
		}

		/**
		 * superGetter calls the getter on the given class' superclass.
		 *
		 * @param clazz The class.
		 * @param pthis The this pointer.
		 * @param prop The name of the getter.
		 * @return {Object}
		 */
		static public function superGetter(clazz:Object, pthis:Object, prop:String):Object
		{
			var superClass:Object = clazz.superClass_;
			var superdesc:Object = Object.getOwnPropertyDescriptor(superClass, prop);

			while (superdesc == null)
			{
				superClass = superClass.constructor;
                superClass = superClass.superClass_;
				superdesc = Object.getOwnPropertyDescriptor(superClass, prop);
			}
			return superdesc.get.call(pthis);
		}

		/**
		 * superSetter calls the setter on the given class' superclass.
		 *
		 * @param clazz The class.
		 * @param pthis The this pointer.
		 * @param prop The name of the getter.
		 * @param value The value.
		 */
		static public function superSetter(clazz:Object, pthis:Object, prop:String, value:Object):void
		{
			var superClass:Object = clazz.superClass_;
			var superdesc:Object = Object.getOwnPropertyDescriptor(superClass, prop);

			while (superdesc == null)
			{
				superClass = superClass.constructor;
                superClass = superClass.superClass_;
				superdesc = Object.getOwnPropertyDescriptor(superClass, prop);
			}
			superdesc.set.apply(pthis, [value]);
		}

		static public function trace(...rest):void
		{
			var theConsole:*;

			theConsole = goog.global.console;

			if (theConsole === undefined)
			{
				if(typeof window !== "undefined")
				{
					theConsole = window.console;
				}
				else if(typeof console !== "undefined")
				{
					theConsole = console;
				}
			}

			try
			{
				if (theConsole && theConsole.log)
				{
					theConsole.log.apply(theConsole, rest);
				}
			}
			catch (e:Error)
			{
				// ignore; at least we tried ;-)
			}
		}

		/**
		 * uint()
		 *
		 * @param value The value to be cast.
		 * @return {number}
		 */
		static public function uint(value:Number):Number
		{
			return value >>> 0;
		}

        /**
         * caches closures and returns the one closure
         *
         * @param fn The method on the instance.
         * @param object The instance.
         * @param boundMethodName The name to use to cache the closure.
         * @return The closure.
         */
        static public function closure(fn:Function, object:Object, boundMethodName:String):Function {
            if (object.hasOwnProperty(boundMethodName)) {
                return object[boundMethodName];
            }
            var boundMethod:Function = goog.bind(fn, object);
            Object.defineProperty(object, boundMethodName, {
                value: boundMethod
            });
            return boundMethod;
        };

		/**
		 * @param	arr
		 * @param	names
		 * @param	opt
		 */
		public static function sortOn(arr:Array,names:Object,opt:Object=0):void{
			if (names is Array){
				sortNames = names as Array;
			}else{
				sortNamesOne[0] = names;
				sortNames = sortNamesOne;
			}
			if (opt is Array){
				var opt2:int = 0;
				for each(var o:int in opt){
					opt2 = opt2 | o;
				}
			}else{
				opt2 = opt as int;
			}
			muler = (Array.DESCENDING & opt2) > 0?-1: 1;
			if(opt2&Array.NUMERIC){
				arr.sort(compareNumber);
			}else if (opt2&Array.CASEINSENSITIVE){
				arr.sort(compareStringCaseinsensitive);
			}else{
				arr.sort(compareString);
			}
		}
		private static function compareStringCaseinsensitive(a:Object, b:Object):int{
			for each(var n:String in sortNames){
				var v:int = (a[n]||zeroStr).toString().toLowerCase().localeCompare((b[n]||zeroStr).toString().toLowerCase());
				if (v != 0){
					return v*muler;
				}
			}
			return 0;
		}
		private static function compareString(a:Object, b:Object):int{
			for each(var n:String in sortNames){
				var v:int = (a[n]||zeroStr).toString().localeCompare((b[n]||zeroStr).toString());
				if (v != 0){
					return v*muler;
				}
			}
			return 0;
		}

		private static function compareNumber(a:Object, b:Object):int{
			for each(var n:String in sortNames){
				if (a[n]>b[n]){
					return muler;
				}else if (a[n]<b[n]){
					return -muler;
				}
			}
			return 0;
		}
	}
}

remove tag

remove tag


package htmlelements
{
	import flash.display.Sprite;
	import flash.events.*;
	import flash.net.NetConnection;
	import flash.net.NetStream;
	import flash.media.Video;
	import flash.media.SoundTransform;
	import flash.utils.Timer;

	import FlashMediaElement;
	import HtmlMediaEvent;

	public class VideoElement extends Sprite implements IMediaElement
	{
		private var _currentUrl:String = "";
		private var _autoplay:Boolean = true;
		private var _preload:String = "";
		private var _isPreloading:Boolean = false;

		private var _connection:NetConnection;
		private var _stream:NetStream;
		private var _video:Video;
		private var _element:FlashMediaElement;
		private var _soundTransform;
		private var _oldVolume:Number = 1;

		// event values
		private var _duration:Number = 0;
		private var _framerate:Number;
		private var _isPaused:Boolean = true;
		private var _isEnded:Boolean = false;
		private var _volume:Number = 1;
		private var _isMuted:Boolean = false;

		private var _bytesLoaded:Number = 0;
		private var _bytesTotal:Number = 0;
		private var _bufferedTime:Number = 0;
		private var _bufferEmpty:Boolean = false;

		private var _videoWidth:Number = -1;
		private var _videoHeight:Number = -1;

		private var _timer:Timer;

		private var _isRTMP:Boolean = false;
		private var _isConnected:Boolean = false;
		private var _playWhenConnected:Boolean = false;
		private var _hasStartedPlaying:Boolean = false;

		private var _parentReference:Object;

		public function setReference(arg:Object):void {
			_parentReference = arg;
		}

		public function setSize(width:Number, height:Number):void {
			_video.width = width;
			_video.height = height;
		}

		public function get video():Video {
			return _video;
		}

		public function get videoHeight():Number {
			return _videoHeight;
		}

		public function get videoWidth():Number {
			return _videoWidth;
		}

		public function duration():Number {
			return _duration;
		}

		public function currentProgress():Number {
			if(_stream != null) {
				return Math.round(_stream.bytesLoaded/_stream.bytesTotal*100);
			} else {
				return 0;
			}
		}

		public function currentTime():Number {
			if (_stream != null) {
				return _stream.time;
			} else {
				return 0;
			}
		}

		// (1) load()
		// calls _connection.connect();
		// waits for NetConnection.Connect.Success
		// _stream gets created

		public function VideoElement(element:FlashMediaElement, autoplay:Boolean, preload:String, timerRate:Number, startVolume:Number)
		{
			_element = element;
			_autoplay = autoplay;
			_volume = startVolume;
			_preload = preload;

			_video = new Video();
			addChild(_video);

			_connection = new NetConnection();
			_connection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
			_connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
			//_connection.connect(null);

			_timer = new Timer(timerRate);
			_timer.addEventListener("timer", timerHandler);

		}

		private function timerHandler(e:TimerEvent) {

			_bytesLoaded = _stream.bytesLoaded;
			_bytesTotal = _stream.bytesTotal;

			if (!_isPaused)
				sendEvent(HtmlMediaEvent.TIMEUPDATE);

			//trace("bytes", _bytesLoaded, _bytesTotal);

			if (_bytesLoaded < _bytesTotal)
				sendEvent(HtmlMediaEvent.PROGRESS);
		}

		// internal events
		private function netStatusHandler(event:NetStatusEvent):void {
			trace("netStatus", event.info.code);

			switch (event.info.code) {

				case "NetStream.Buffer.Empty":
					_bufferEmpty = true;
					_isEnded ? sendEvent(HtmlMediaEvent.ENDED) : null;
					break;

				case "NetStream.Buffer.Full":
					_bytesLoaded = _stream.bytesLoaded;
					_bytesTotal = _stream.bytesTotal;
					_bufferEmpty = false;

					sendEvent(HtmlMediaEvent.PROGRESS);
					break;

				case "NetConnection.Connect.Success":
					connectStream();
					break;
				case "NetStream.Play.StreamNotFound":
					trace("Unable to locate video");
					break;

				// STREAM
				case "NetStream.Play.Start":

					_isPaused = false;
					sendEvent(HtmlMediaEvent.LOADEDDATA);
					sendEvent(HtmlMediaEvent.CANPLAY);

					if (!_isPreloading) {

						sendEvent(HtmlMediaEvent.PLAY);
						sendEvent(HtmlMediaEvent.PLAYING);

					}

					_timer.start();

					break;

				case "NetStream.Seek.Notify":
					sendEvent(HtmlMediaEvent.SEEKED);
					break;

				case "NetStream.Pause.Notify":
					_isPaused = true;
					sendEvent(HtmlMediaEvent.PAUSE);
					break;

				case "NetStream.Play.Stop":
					_isEnded = true;
					_isPaused = false;
					_timer.stop();
					_bufferEmpty ? sendEvent(HtmlMediaEvent.ENDED) : null;
					break;

			}
		}

		private function securityErrorHandler(event:SecurityErrorEvent):void {
			trace("securityErrorHandler: " + event);
		}

		private function asyncErrorHandler(event:AsyncErrorEvent):void {
			// ignore AsyncErrorEvent events.
		}

		private function onMetaDataHandler(info:Object):void {
			_duration = info.duration;
			_framerate = info.framerate;
			_videoWidth = info.width;
			_videoHeight = info.height;

			// set size?

			sendEvent(HtmlMediaEvent.LOADEDMETADATA);

			if (_isPreloading) {

				_stream.pause();
				_isPaused = true;
				_isPreloading = false;

				sendEvent(HtmlMediaEvent.PROGRESS);
				sendEvent(HtmlMediaEvent.TIMEUPDATE);

			}
		}

		// interface members
		public function setSrc(url:String):void {
			if (_isConnected && _stream) {
				// stop and restart
				_stream.pause();
			}

			_currentUrl = url;
			_isRTMP = !!_currentUrl.match(/^rtmp(s|t|e|te)?\:\/\//);
			_isConnected = false;
			_hasStartedPlaying = false;
		}

		public function load():void {
			// disconnect existing stream and connection
			if (_isConnected && _stream) {
				_stream.pause();
				_stream.close();
				_connection.close();
			}
			_isConnected = false;
			_isPreloading = false;

			_isEnded = false;
			_bufferEmpty = false;

			// start new connection
			if (_isRTMP) {
				var rtmpInfo:Object = parseRTMP(_currentUrl);
				_connection.connect(rtmpInfo.server);
			} else {
				_connection.connect(null);
			}

			// in a few moments the "NetConnection.Connect.Success" event will fire
			// and call createConnection which finishes the "load" sequence
			sendEvent(HtmlMediaEvent.LOADSTART);
		}

		private function connectStream():void {
			trace("connectStream");
			_stream = new NetStream(_connection);

			// explicitly set the sound since it could have come before the connection was made
			_soundTransform = new SoundTransform(_volume);
			_stream.soundTransform = _soundTransform;

			_stream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler); // same event as connection
			_stream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);

			var customClient:Object = new Object();
			customClient.onMetaData = onMetaDataHandler;
			_stream.client = customClient;

			_video.attachNetStream(_stream);

			// start downloading without playing )based on preload and play() hasn't been called)
			// I wish flash had a load() command to make this less awkward
			if (_preload != "none" && !_playWhenConnected) {
				_isPaused = true;
				//stream.bufferTime = 20;
				_stream.play(_currentUrl, 0, 0);
				_stream.pause();

				_isPreloading = true;

				//_stream.pause();
				//
				//sendEvent(HtmlMediaEvent.PAUSE); // have to send this because the "playing" event gets sent via event handlers
			}

			_isConnected = true;

			if (_playWhenConnected && !_hasStartedPlaying) {
				play();
				_playWhenConnected = false;
			}

		}

		public function play():void {

			if (!_hasStartedPlaying && !_isConnected) {
				_playWhenConnected = true;
				load();
				return;
			}

			if (_hasStartedPlaying) {
				if (_isPaused) {
					_stream.resume();
					_timer.start();
					_isPaused = false;
					sendEvent(HtmlMediaEvent.PLAY);
					sendEvent(HtmlMediaEvent.PLAYING);
				}
			} else {

				if (_isRTMP) {
					var rtmpInfo:Object = parseRTMP(_currentUrl);
					_stream.play(rtmpInfo.stream);
				} else {
					_stream.play(_currentUrl);
				}
				_timer.start();
				_isPaused = false;
				_hasStartedPlaying = true;

				// don't toss play/playing events here, because we haven't sent a
				// canplay / loadeddata event yet. that'll be handled in the net
				// event listener
			}

		}

		public function pause():void {
			if (_stream == null)
				return;

			_stream.pause();
			_isPaused = true;

			if (_bytesLoaded == _bytesTotal) {
				_timer.stop();
			}

			_isPaused = true;
			sendEvent(HtmlMediaEvent.PAUSE);
		}

		public function stop():void {
			if (_stream == null)
				return;

			_stream.close();
			_isPaused = false;
			_timer.stop();
			sendEvent(HtmlMediaEvent.STOP);
		}

		public function setCurrentTime(pos:Number):void {
			if (_stream == null)
				return;

			sendEvent(HtmlMediaEvent.SEEKING);
			_stream.seek(pos);
			sendEvent(HtmlMediaEvent.TIMEUPDATE);
		}

		public function setVolume(volume:Number):void {
			if (_stream != null) {
				_soundTransform = new SoundTransform(volume);
				_stream.soundTransform = _soundTransform;
			}

			_volume = volume;

			_isMuted = (_volume == 0);

			sendEvent(HtmlMediaEvent.VOLUMECHANGE);
		}

		public function getVolume():Number {
			if(_isMuted) {
				return 0;
			} else {
				return _volume;
			}
		}

		public function setMuted(muted:Boolean):void {

			if (_isMuted == muted)
				return;

			if (muted) {
				_oldVolume = (_stream == null) ? _oldVolume : _stream.soundTransform.volume;
				setVolume(0);
			} else {
				setVolume(_oldVolume);
			}

			_isMuted = muted;
		}

		private function sendEvent(eventName:String) {

			// calculate this to mimic HTML5
			_bufferedTime = _bytesLoaded / _bytesTotal * _duration;

			// build JSON
			var values:String =
							"duration:" + _duration +
							",framerate:" + _framerate +
							",currentTime:" + (_stream != null ? _stream.time : 0) +
							",muted:" + _isMuted +
							",paused:" + _isPaused +
							",ended:" + _isEnded +
							",volume:" + _volume +
							",src:\"" + _currentUrl + "\"" +
							",bytesTotal:" + _bytesTotal +
							",bufferedBytes:" + _bytesLoaded +
							",bufferedTime:" + _bufferedTime +
							",videoWidth:" + _videoWidth +
							",videoHeight:" + _videoHeight +
							"";

			_element.sendEvent(eventName, values);
		}

		private function parseRTMP(url:String) {
			var match:Array = url.match(/(.*)\/((flv|mp4|mp3):.*)/);
			var rtmpInfo:Object = {
				server: null,
				stream: null
			};

			if (match) {
				rtmpInfo.server = match[1];
				rtmpInfo.stream = match[2];
			}
			else {
				rtmpInfo.server = url.replace(/\/[^\/]+$/,"/");
				rtmpInfo.stream = url.split("/").pop();
			}

			trace("parseRTMP - server: " + rtmpInfo.server + " stream: " + rtmpInfo.stream);

			return rtmpInfo;
		}
	}
}

package htmlelements
{
	import flash.display.Sprite;
	import flash.events.*;
	import flash.net.NetConnection;
	import flash.net.NetStream;
	import flash.media.Video;
	import flash.media.SoundTransform;
	import flash.utils.Timer;

	import FlashMediaElement;
	import HtmlMediaEvent;

	public class VideoElement extends Sprite implements IMediaElement
	{
		private var _currentUrl:String = "";
		private var _autoplay:Boolean = true;
		private var _preload:String = "";
		private var _isPreloading:Boolean = false;

		private var _connection:NetConnection;
		private var _stream:NetStream;
		private var _video:Video;
		private var _element:FlashMediaElement;
		private var _soundTransform;
		private var _oldVolume:Number = 1;

		// event values
		private var _duration:Number = 0;
		private var _framerate:Number;
		private var _isPaused:Boolean = true;
		private var _isEnded:Boolean = false;
		private var _volume:Number = 1;
		private var _isMuted:Boolean = false;

		private var _bytesLoaded:Number = 0;
		private var _bytesTotal:Number = 0;
		private var _bufferedTime:Number = 0;
		private var _bufferEmpty:Boolean = false;

		private var _videoWidth:Number = -1;
		private var _videoHeight:Number = -1;

		private var _timer:Timer;

		private var _isRTMP:Boolean = false;
		private var _isConnected:Boolean = false;
		private var _playWhenConnected:Boolean = false;
		private var _hasStartedPlaying:Boolean = false;

		private var _parentReference:Object;

		public function setReference(arg:Object):void {
			_parentReference = arg;
		}

		public function setSize(width:Number, height:Number):void {
			_video.width = width;
			_video.height = height;
		}

		public function get video():Video {
			return _video;
		}

		public function get videoHeight():Number {
			return _videoHeight;
		}

		public function get videoWidth():Number {
			return _videoWidth;
		}

		public function duration():Number {
			return _duration;
		}

		public function currentProgress():Number {
			if(_stream != null) {
				return Math.round(_stream.bytesLoaded/_stream.bytesTotal*100);
			} else {
				return 0;
			}
		}

		public function currentTime():Number {
			if (_stream != null) {
				return _stream.time;
			} else {
				return 0;
			}
		}

		// (1) load()
		// calls _connection.connect();
		// waits for NetConnection.Connect.Success
		// _stream gets created

		public function VideoElement(element:FlashMediaElement, autoplay:Boolean, preload:String, timerRate:Number, startVolume:Number)
		{
			_element = element;
			_autoplay = autoplay;
			_volume = startVolume;
			_preload = preload;

			_video = new Video();
			addChild(_video);

			_connection = new NetConnection();
			_connection.client = { onBWDone: function():void{} };
			_connection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
			_connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
			//_connection.connect(null);

			_timer = new Timer(timerRate);
			_timer.addEventListener("timer", timerHandler);

		}

		private function timerHandler(e:TimerEvent) {

			_bytesLoaded = _stream.bytesLoaded;
			_bytesTotal = _stream.bytesTotal;

			if (!_isPaused)
				sendEvent(HtmlMediaEvent.TIMEUPDATE);

			//trace("bytes", _bytesLoaded, _bytesTotal);

			if (_bytesLoaded < _bytesTotal)
				sendEvent(HtmlMediaEvent.PROGRESS);
		}

		// internal events
		private function netStatusHandler(event:NetStatusEvent):void {
			trace("netStatus", event.info.code);

			switch (event.info.code) {

				case "NetStream.Buffer.Empty":
					_bufferEmpty = true;
					_isEnded ? sendEvent(HtmlMediaEvent.ENDED) : null;
					break;

				case "NetStream.Buffer.Full":
					_bytesLoaded = _stream.bytesLoaded;
					_bytesTotal = _stream.bytesTotal;
					_bufferEmpty = false;

					sendEvent(HtmlMediaEvent.PROGRESS);
					break;

				case "NetConnection.Connect.Success":
					connectStream();
					break;
				case "NetStream.Play.StreamNotFound":
					trace("Unable to locate video");
					break;

				// STREAM
				case "NetStream.Play.Start":

					_isPaused = false;
					sendEvent(HtmlMediaEvent.LOADEDDATA);
					sendEvent(HtmlMediaEvent.CANPLAY);

					if (!_isPreloading) {

						sendEvent(HtmlMediaEvent.PLAY);
						sendEvent(HtmlMediaEvent.PLAYING);

					}

					_timer.start();

					break;

				case "NetStream.Seek.Notify":
					sendEvent(HtmlMediaEvent.SEEKED);
					break;

				case "NetStream.Pause.Notify":
					_isPaused = true;
					sendEvent(HtmlMediaEvent.PAUSE);
					break;

				case "NetStream.Play.Stop":
					_isEnded = true;
					_isPaused = false;
					_timer.stop();
					_bufferEmpty ? sendEvent(HtmlMediaEvent.ENDED) : null;
					break;

			}
		}

		private function securityErrorHandler(event:SecurityErrorEvent):void {
			trace("securityErrorHandler: " + event);
		}

		private function asyncErrorHandler(event:AsyncErrorEvent):void {
			// ignore AsyncErrorEvent events.
		}

		private function onMetaDataHandler(info:Object):void {
			_duration = info.duration;
			_framerate = info.framerate;
			_videoWidth = info.width;
			_videoHeight = info.height;

			// set size?

			sendEvent(HtmlMediaEvent.LOADEDMETADATA);

			if (_isPreloading) {

				_stream.pause();
				_isPaused = true;
				_isPreloading = false;

				sendEvent(HtmlMediaEvent.PROGRESS);
				sendEvent(HtmlMediaEvent.TIMEUPDATE);

			}
		}

		// interface members
		public function setSrc(url:String):void {
			if (_isConnected && _stream) {
				// stop and restart
				_stream.pause();
			}

			_currentUrl = url;
			_isRTMP = !!_currentUrl.match(/^rtmp(s|t|e|te)?\:\/\//);
			_isConnected = false;
			_hasStartedPlaying = false;
		}

		public function load():void {
			// disconnect existing stream and connection
			if (_isConnected && _stream) {
				_stream.pause();
				_stream.close();
				_connection.close();
			}
			_isConnected = false;
			_isPreloading = false;

			_isEnded = false;
			_bufferEmpty = false;

			// start new connection
			if (_isRTMP) {
				var rtmpInfo:Object = parseRTMP(_currentUrl);
				_connection.connect(rtmpInfo.server);
			} else {
				_connection.connect(null);
			}

			// in a few moments the "NetConnection.Connect.Success" event will fire
			// and call createConnection which finishes the "load" sequence
			sendEvent(HtmlMediaEvent.LOADSTART);
		}

		private function connectStream():void {
			trace("connectStream");
			_stream = new NetStream(_connection);

			// explicitly set the sound since it could have come before the connection was made
			_soundTransform = new SoundTransform(_volume);
			_stream.soundTransform = _soundTransform;

			_stream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler); // same event as connection
			_stream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);

			var customClient:Object = new Object();
			customClient.onMetaData = onMetaDataHandler;
			_stream.client = customClient;

			_video.attachNetStream(_stream);

			// start downloading without playing )based on preload and play() hasn't been called)
			// I wish flash had a load() command to make this less awkward
			if (_preload != "none" && !_playWhenConnected) {
				_isPaused = true;
				//stream.bufferTime = 20;
				_stream.play(_currentUrl, 0, 0);
				_stream.pause();

				_isPreloading = true;

				//_stream.pause();
				//
				//sendEvent(HtmlMediaEvent.PAUSE); // have to send this because the "playing" event gets sent via event handlers
			}

			_isConnected = true;

			if (_playWhenConnected && !_hasStartedPlaying) {
				play();
				_playWhenConnected = false;
			}

		}

		public function play():void {

			if (!_hasStartedPlaying && !_isConnected) {
				_playWhenConnected = true;
				load();
				return;
			}

			if (_hasStartedPlaying) {
				if (_isPaused) {
					_stream.resume();
					_timer.start();
					_isPaused = false;
					sendEvent(HtmlMediaEvent.PLAY);
					sendEvent(HtmlMediaEvent.PLAYING);
				}
			} else {

				if (_isRTMP) {
					var rtmpInfo:Object = parseRTMP(_currentUrl);
					_stream.play(rtmpInfo.stream);
				} else {
					_stream.play(_currentUrl);
				}
				_timer.start();
				_isPaused = false;
				_hasStartedPlaying = true;

				// don't toss play/playing events here, because we haven't sent a
				// canplay / loadeddata event yet. that'll be handled in the net
				// event listener
			}

		}

		public function pause():void {
			if (_stream == null)
				return;

			_stream.pause();
			_isPaused = true;

			if (_bytesLoaded == _bytesTotal) {
				_timer.stop();
			}

			_isPaused = true;
			sendEvent(HtmlMediaEvent.PAUSE);
		}

		public function stop():void {
			if (_stream == null)
				return;

			_stream.close();
			_isPaused = false;
			_timer.stop();
			sendEvent(HtmlMediaEvent.STOP);
		}

		public function setCurrentTime(pos:Number):void {
			if (_stream == null)
				return;

			sendEvent(HtmlMediaEvent.SEEKING);
			_stream.seek(pos);
			sendEvent(HtmlMediaEvent.TIMEUPDATE);
		}

		public function setVolume(volume:Number):void {
			if (_stream != null) {
				_soundTransform = new SoundTransform(volume);
				_stream.soundTransform = _soundTransform;
			}

			_volume = volume;

			_isMuted = (_volume == 0);

			sendEvent(HtmlMediaEvent.VOLUMECHANGE);
		}

		public function getVolume():Number {
			if(_isMuted) {
				return 0;
			} else {
				return _volume;
			}
		}

		public function setMuted(muted:Boolean):void {

			if (_isMuted == muted)
				return;

			if (muted) {
				_oldVolume = (_stream == null) ? _oldVolume : _stream.soundTransform.volume;
				setVolume(0);
			} else {
				setVolume(_oldVolume);
			}

			_isMuted = muted;
		}

		private function sendEvent(eventName:String) {

			// calculate this to mimic HTML5
			_bufferedTime = _bytesLoaded / _bytesTotal * _duration;

			// build JSON
			var values:String =
							"duration:" + _duration +
							",framerate:" + _framerate +
							",currentTime:" + (_stream != null ? _stream.time : 0) +
							",muted:" + _isMuted +
							",paused:" + _isPaused +
							",ended:" + _isEnded +
							",volume:" + _volume +
							",src:\"" + _currentUrl + "\"" +
							",bytesTotal:" + _bytesTotal +
							",bufferedBytes:" + _bytesLoaded +
							",bufferedTime:" + _bufferedTime +
							",videoWidth:" + _videoWidth +
							",videoHeight:" + _videoHeight +
							"";

			_element.sendEvent(eventName, values);
		}

		private function parseRTMP(url:String) {
			var match:Array = url.match(/(.*)\/((flv|mp4|mp3):.*)/);
			var rtmpInfo:Object = {
				server: null,
				stream: null
			};

			if (match) {
				rtmpInfo.server = match[1];
				rtmpInfo.stream = match[2];
			}
			else {
				rtmpInfo.server = url.replace(/\/[^\/]+$/,"/");
				rtmpInfo.stream = url.split("/").pop();
			}

			trace("parseRTMP - server: " + rtmpInfo.server + " stream: " + rtmpInfo.stream);

			return rtmpInfo;
		}
	}
}

Add onBWDone handler to remove errors. See http://stackoverflow.com/questions/2296822/flash-as3-streaming-player-onbwdone


/**
 * Created by newkrok on 08/04/16.
 */
package ageofai.home.view
{
<<<<<<< HEAD
    import ageofai.home.event.HomeEvent;
    import ageofai.home.view.event.HomeViewEvent;

    import common.mvc.view.base.ABaseMediator;

    public class HomeMediator extends ABaseMediator
    {
        [Inject]
        public var view:HomeView;

        override public function initialize():void
        {
            this.addContextListener( HomeEvent.REQUEST_TO_CREATE_VILLAGER, this.villagerCredatedEventHandler );
            this.addContextListener( HomeEvent.VILLAGER_CREATION_IN_PROGRESS, this.villagerCreatingInProgressEventHandler );
            this.addContextListener( HomeEvent.FOOD_AMOUNT_UPDATED, this.foodAmountUpdatedHandler );
            this.addContextListener( HomeEvent.WOOD_AMOUNT_UPDATED, this.woodAmountUpdatedHandler );

            this.addViewListener( HomeViewEvent.VILLAGER_VIEW_CREATED, this.villageViewCreatedHandler );
        }

        private function villageViewCreatedHandler( e:HomeViewEvent ):void
        {
            var homeEvent:HomeEvent = new HomeEvent( HomeEvent.VILLAGER_VIEW_CREATED );
            homeEvent.villagerView = e.villagerView;
            homeEvent.homeVO = e.homeVO;

            this.dispatch( homeEvent );
        }

        private function villagerCredatedEventHandler( e:HomeEvent ):void
        {
            this.view.createVillagerView( e.homeVO );
        }

        private function villagerCreatingInProgressEventHandler( e:HomeEvent ):void
        {
            this.view.showProgressValue( e.progressPercentage / 100 );
        }

        private function foodAmountUpdatedHandler( event:HomeEvent ):void
        {
            this.view.updateFoodAmount( event.homeVO.food );
        }

        private function woodAmountUpdatedHandler( event:HomeEvent ):void
        {
            this.view.updateWoodAmount( event.homeVO.wood );
        }
    }
=======
	import ageofai.home.event.HomeEvent;
	import ageofai.home.view.event.HomeViewEvent;
	import ageofai.home.vo.HomeVO;

	import common.mvc.view.base.ABaseMediator;

	public class HomeMediator extends ABaseMediator
	{
		[Inject]
		public var view:HomeView;

		override public function initialize():void
		{
			this.addContextListener( HomeEvent.REQUEST_TO_CREATE_VILLAGER, this.villagerCredatedEventHandler );
			this.addContextListener( HomeEvent.VILLAGER_CREATION_IN_PROGRESS, this.villagerCreatingInProgressEventHandler );
			this.addContextListener( HomeEvent.FOOD_AMOUNT_UPDATED, this.foodAmountUpdatedHandler );
			this.addContextListener( HomeEvent.WOOD_AMOUNT_UPDATED, this.woodAmountUpdatedHandler );

			this.addViewListener( HomeViewEvent.VILLAGER_VIEW_CREATED, this.villagerViewCreatedHandler );
		}

		private function villagerViewCreatedHandler( e:HomeViewEvent ):void
		{
            if (e.homeVO.id != this.view.id) return;

			var homeEvent:HomeEvent = new HomeEvent( HomeEvent.VILLAGER_VIEW_CREATED );
			homeEvent.villagerView = e.villagerView;
			homeEvent.homeVO = e.homeVO;

			this.dispatch( homeEvent );
		}

		private function villagerCredatedEventHandler( e:HomeEvent ):void
		{
            if (e.homeVO.id != this.view.id) return;

			this.view.createVillagerView( e.homeVO );
		}

		private function villagerCreatingInProgressEventHandler( e:HomeEvent ):void
		{
            if (e.homeVO.id != this.view.id) return;

			this.view.showProgressValue( e.progressPercentage / 100 );
		}

		private function foodAmountUpdatedHandler( home:HomeVO ):void
		{
			this.view.updateFoodAmount( home.food );
		}

		private function woodAmountUpdatedHandler( home:HomeVO ):void
		{
			this.view.updateWoodAmount( home.wood );
		}
	}
>>>>>>> origin/master
}

/**
 * Created by newkrok on 08/04/16.
 */
package ageofai.home.view
{
	import ageofai.home.event.HomeEvent;
	import ageofai.home.view.event.HomeViewEvent;
	import ageofai.home.vo.HomeVO;

	import common.mvc.view.base.ABaseMediator;

	public class HomeMediator extends ABaseMediator
	{
		[Inject]
		public var view:HomeView;

		override public function initialize():void
		{
			this.addContextListener( HomeEvent.REQUEST_TO_CREATE_VILLAGER, this.villagerCredatedEventHandler );
			this.addContextListener( HomeEvent.VILLAGER_CREATION_IN_PROGRESS, this.villagerCreatingInProgressEventHandler );
			this.addContextListener( HomeEvent.FOOD_AMOUNT_UPDATED, this.foodAmountUpdatedHandler );
			this.addContextListener( HomeEvent.WOOD_AMOUNT_UPDATED, this.woodAmountUpdatedHandler );

			this.addViewListener( HomeViewEvent.VILLAGER_VIEW_CREATED, this.villagerViewCreatedHandler );
		}

		private function villagerViewCreatedHandler( e:HomeViewEvent ):void
		{
            if (e.homeVO.id != this.view.id) return;

			var homeEvent:HomeEvent = new HomeEvent( HomeEvent.VILLAGER_VIEW_CREATED );
			homeEvent.villagerView = e.villagerView;
			homeEvent.homeVO = e.homeVO;

			this.dispatch( homeEvent );
		}

		private function villagerCredatedEventHandler( e:HomeEvent ):void
		{
            if (e.homeVO.id != this.view.id) return;

			this.view.createVillagerView( e.homeVO );
		}

		private function villagerCreatingInProgressEventHandler( e:HomeEvent ):void
		{
            if (e.homeVO.id != this.view.id) return;

			this.view.showProgressValue( e.progressPercentage / 100 );
		}

        private function foodAmountUpdatedHandler( event:HomeEvent ):void
        {
            if (event.homeVO.id != this.view.id) return;

            this.view.updateFoodAmount( event.homeVO.food );
        }

        private function woodAmountUpdatedHandler( event:HomeEvent ):void
        {
            if (event.homeVO.id != this.view.id) return;

            this.view.updateWoodAmount( event.homeVO.wood );
        }
    }
}

Fix merge conflict

Fix merge conflict


/*
* Copyright (c) 2015 Snowplow Analytics Ltd. All rights reserved.
*
* This program is licensed to you under the Apache License Version 2.0,
* and you may not use this file except in compliance with the Apache License Version 2.0.
* You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the Apache License Version 2.0 is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
*/

package com.snowplowanalytics.snowplow.tracker.emitter
{
	import com.adobe.net.URI;
	import com.snowplowanalytics.snowplow.tracker.Constants;
	import com.snowplowanalytics.snowplow.tracker.Util;
	import com.snowplowanalytics.snowplow.tracker.event.EmitterEvent;
	import com.snowplowanalytics.snowplow.tracker.payload.IPayload;
	import com.snowplowanalytics.snowplow.tracker.payload.SchemaPayload;

	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.net.URLRequestMethod;

	public class Emitter extends EventDispatcher
	{
		private var _uri:URI;
		private var _buffer:Array = [];

		protected var bufferSize:int = BufferOption.DEFAULT;
		protected var httpMethod:String = URLRequestMethod.GET;

		/**
		 * Create an Emitter instance with a collector URL and HttpMethod to send requests.
		 * @param URI The collector URL. Don't include "http://" - this is done automatically.
		 * @param httpMethod The HTTP request method. If GET, BufferOption is set to Instant.
		 * @param successCallback The callback function to handle success cases when sending events.
		 * @param errorCallback The callback function to handle error cases when sending events.
		 */
		public function Emitter(uri:String, httpMethod:String = URLRequestMethod.GET) {
			if (httpMethod == URLRequestMethod.GET) {
				_uri = new URI("http://" + uri + "/i");
			} else { // POST
				_uri = new URI("http://" + uri + "/" + Constants.PROTOCOL_VENDOR + "/" + Constants.PROTOCOL_VERSION);
			}

			this.httpMethod = httpMethod;
		}

		/**
		 * Sets whether the buffer should send events instantly or after the buffer has reached
		 * it's limit. By default, this is set to BufferOption Default.
		 * @param option Set the BufferOption enum to Instant send events upon creation.
		 */
		public function setBufferSize(option:int):void {
			this.bufferSize = option;
		}

		/**
		 * Add event payloads to the emitter's buffer
		 * @param payload Payload to be added
		 */
		public function addToBuffer(payload:IPayload):void {
			_buffer.push(payload);
			if (_buffer.length == bufferSize)
				flushBuffer();
		}

		/**
		 * Sends all events in the buffer to the collector.
		 */
		public function checkBufferComplete(successCount:int, totalCount:int, totalPayloads:int, unsentPayloads:Array):void {
			if (totalCount == totalPayloads)
			{
				if (unsentPayloads.length == 0)
				{
					dispatchEvent(new EmitterEvent(EmitterEvent.SUCCESS, successCount));
				}
				else
				{
					dispatchEvent(new EmitterEvent(EmitterEvent.FAILURE, successCount, unsentPayloads, "Not all items in buffer were sent"));
				}
			}
		}

		/**
		 * Sends all events in the buffer to the collector.
		 */
		public function flushBuffer():void {
			if (_buffer.length == 0) {
				trace("Buffer is empty, exiting flush operation.");
				return;
			}

			if (httpMethod == URLRequestMethod.GET) {
				var successCount:int = 0;
				var totalCount:int = 0;
				var totalPayloads:int = _buffer.length;
				var unsentPayloads:Array = [];

				for each (var getPayload:IPayload in _buffer) {
					sendGetData(getPayload,
						function onGetSuccess (data:*):void {
							successCount++;
							totalCount++;
							checkBufferComplete(successCount, totalCount, totalPayloads, unsentPayloads);
						},
						function onGetError ():void {
							totalCount++;
							unsentPayloads.push(payload);
							checkBufferComplete(successCount, totalCount, totalPayloads, unsentPayloads);
						}
					);
				}
			} else if (httpMethod == URLRequestMethod.POST) {
				var unsentPayload:Array = [];

				var postPayload:SchemaPayload = new SchemaPayload();
				postPayload.setSchema(Constants.SCHEMA_PAYLOAD_DATA);

				var eventMaps:Array = [];
				for each (var payload:IPayload in _buffer) {
					eventMaps.push(payload.getMap());
				}

				postPayload.setData(eventMaps);

				sendPostData(postPayload,
					function onPostSuccess (data:*):void
					{
						dispatchEvent(new EmitterEvent(EmitterEvent.SUCCESS, _buffer.length));
					},
					function onPostError (event:Event):void
					{
						unsentPayload.push(postPayload);
						dispatchEvent(new EmitterEvent(EmitterEvent.FAILURE, 0, unsentPayloads, event.toString()));
					}
				);
			}

			// Empties current buffer
			Util.clearArray(_buffer);
		}

		protected function sendPostData(payload:IPayload, successCallback:Function, errorCallback:Function):void
		{
			Util.getResponse(_uri.toString(),
				successCallback,
				errorCallback,
				URLRequestMethod.POST,
				payload.toString());
		}

		protected function sendGetData(payload:IPayload, successCallback:Function, errorCallback:Function):void
		{
			var hashMap:Object = payload.getMap();
			_uri.setQueryByMap(hashMap);

			Util.getResponse(_uri.toString(),
				successCallback,
				errorCallback);
		}
	}
}

/*
* Copyright (c) 2015 Snowplow Analytics Ltd. All rights reserved.
*
* This program is licensed to you under the Apache License Version 2.0,
* and you may not use this file except in compliance with the Apache License Version 2.0.
* You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the Apache License Version 2.0 is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
*/

package com.snowplowanalytics.snowplow.tracker.emitter
{
	import com.adobe.net.URI;
	import com.snowplowanalytics.snowplow.tracker.Constants;
	import com.snowplowanalytics.snowplow.tracker.Util;
	import com.snowplowanalytics.snowplow.tracker.event.EmitterEvent;
	import com.snowplowanalytics.snowplow.tracker.payload.IPayload;
	import com.snowplowanalytics.snowplow.tracker.payload.SchemaPayload;

	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.net.URLRequestMethod;

	public class Emitter extends EventDispatcher
	{
		private var _uri:URI;
		private var _buffer:Array = [];

		protected var bufferSize:int = BufferOption.DEFAULT;
		protected var httpMethod:String = URLRequestMethod.GET;

		/**
		 * Create an Emitter instance with a collector URL and HttpMethod to send requests.
		 * @param URI The collector URL. Don't include "http://" - this is done automatically.
		 * @param httpMethod The HTTP request method. If GET, BufferOption is set to Instant.
		 * @param protocol The protocol for the call. Either http or https. Defaults to https.
		 */
		public function Emitter(uri:String, httpMethod:String = URLRequestMethod.GET, protocol:String = "https") {

			if (httpMethod == URLRequestMethod.GET) {
				_uri = new URI(protocol + "://" + uri + "/i");
			} else { // POST
				_uri = new URI(protocol + "://" + uri + "/" + Constants.PROTOCOL_VENDOR + "/" + Constants.PROTOCOL_VERSION);
			}

			this.httpMethod = httpMethod;
		}

		/**
		 * Sets whether the buffer should send events instantly or after the buffer has reached
		 * it's limit. By default, this is set to BufferOption Default.
		 * @param option Set the BufferOption enum to Instant send events upon creation.
		 */
		public function setBufferSize(option:int):void {
			this.bufferSize = option;
		}

		/**
		 * Add event payloads to the emitter's buffer
		 * @param payload Payload to be added
		 */
		public function addToBuffer(payload:IPayload):void {
			_buffer.push(payload);
			if (_buffer.length == bufferSize)
				flushBuffer();
		}

		/**
		 * Sends all events in the buffer to the collector.
		 */
		public function checkBufferComplete(successCount:int, totalCount:int, totalPayloads:int, unsentPayloads:Array):void {
			if (totalCount == totalPayloads)
			{
				if (unsentPayloads.length == 0)
				{
					dispatchEvent(new EmitterEvent(EmitterEvent.SUCCESS, successCount));
				}
				else
				{
					dispatchEvent(new EmitterEvent(EmitterEvent.FAILURE, successCount, unsentPayloads, "Not all items in buffer were sent"));
				}
			}
		}

		/**
		 * Sends all events in the buffer to the collector.
		 */
		public function flushBuffer():void {
			if (_buffer.length == 0) {
				trace("Buffer is empty, exiting flush operation.");
				return;
			}

			if (httpMethod == URLRequestMethod.GET) {
				var successCount:int = 0;
				var totalCount:int = 0;
				var totalPayloads:int = _buffer.length;
				var unsentPayloads:Array = [];

				for each (var getPayload:IPayload in _buffer) {
					sendGetData(getPayload,
						function onGetSuccess (data:*):void {
							successCount++;
							totalCount++;
							checkBufferComplete(successCount, totalCount, totalPayloads, unsentPayloads);
						},
						function onGetError ():void {
							totalCount++;
							unsentPayloads.push(payload);
							checkBufferComplete(successCount, totalCount, totalPayloads, unsentPayloads);
						}
					);
				}
			} else if (httpMethod == URLRequestMethod.POST) {
				var unsentPayload:Array = [];

				var postPayload:SchemaPayload = new SchemaPayload();
				postPayload.setSchema(Constants.SCHEMA_PAYLOAD_DATA);

				var eventMaps:Array = [];
				for each (var payload:IPayload in _buffer) {
					eventMaps.push(payload.getMap());
				}

				postPayload.setData(eventMaps);

				sendPostData(postPayload,
					function onPostSuccess (data:*):void
					{
						dispatchEvent(new EmitterEvent(EmitterEvent.SUCCESS, _buffer.length));
					},
					function onPostError (event:Event):void
					{
						unsentPayload.push(postPayload);
						dispatchEvent(new EmitterEvent(EmitterEvent.FAILURE, 0, unsentPayloads, event.toString()));
					}
				);
			}

			// Empties current buffer
			Util.clearArray(_buffer);
		}

		protected function sendPostData(payload:IPayload, successCallback:Function, errorCallback:Function):void
		{
			Util.getResponse(_uri.toString(),
				successCallback,
				errorCallback,
				URLRequestMethod.POST,
				payload.toString());
		}

		protected function sendGetData(payload:IPayload, successCallback:Function, errorCallback:Function):void
		{
			var hashMap:Object = payload.getMap();
			_uri.setQueryByMap(hashMap);

			Util.getResponse(_uri.toString(),
				successCallback,
				errorCallback);
		}
	}
}

Add ability to choose HTTP protocol for Emitter. Change default to HTTPS.


/*
 * This class is used as a special renderer for CBio nodes where details about a node
 * can be displayed using 3 different disc segments around the node.
 **/
package org.cytoscapeweb.view.render
{
	import flare.util.Shapes;
	import flare.vis.data.DataSprite;
	import flare.vis.data.NodeSprite;

	import flash.display.*;
	import flash.display.BitmapData;
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.geom.Matrix;
	import flash.geom.Rectangle;
	import flash.ui.Mouse;
	import flash.utils.setTimeout;

	import mx.utils.StringUtil;

	import org.alivepdf.display.Display;
	import org.cytoscapeweb.util.GraphUtils;
	import org.cytoscapeweb.util.NodeShapes;

	public class CBioNodeRenderer extends NodeRenderer
	{
		private static var _instance:CBioNodeRenderer =
			new CBioNodeRenderer();

		private var _imgCache:ImageCache = ImageCache.instance;

		private var _detailFlag:Boolean = false;

		public static function get instance() : CBioNodeRenderer
		{
			return _instance;
		}

		public function get detailFlag() : Boolean
		{
			return this._detailFlag;
		}

		public function set detailFlag(value:Boolean) : void
		{
			this._detailFlag = value;
		}

		public function CBioNodeRenderer(defaultSize:Number=6)
		{
			super(defaultSize);
		}

		/** @inheritDoc */
		public override function render(d:DataSprite):void {trace("RENDER NODE: " + d.data.id);
			var lineAlpha:Number = d.lineAlpha;
			var fillAlpha:Number = d.fillAlpha;
			var size:Number = d.size * defaultSize;

			var g:Graphics = d.graphics;
			g.clear();

			if (lineAlpha > 0 && d.lineWidth > 0)
			{
				var pixelHinting:Boolean = d.shape === NodeShapes.ROUND_RECTANGLE;
				g.lineStyle(d.lineWidth, d.lineColor, lineAlpha, pixelHinting);
			}

			if (fillAlpha > 0)
			{
				// 1. Draw the background color:
				// Using a bit mask to avoid transparent mdes when fillcolor=0xffffffff.
				// See https://sourceforge.net/forum/message.php?msg_id=7393265
				g.beginFill(0xffffff & d.fillColor, fillAlpha);
				drawShape(d, d.shape, null);
				g.endFill();

				// 2. Draw an image on top:
				drawImage(d,0,0);
			}
		}

		// Draws the corresponding shape on given sprite
		protected override function drawShape(st:Sprite, shape:String, bounds:Rectangle):void
		{
			var d:DataSprite = st as DataSprite;
			var g:Graphics = d.graphics;
			var size:Number = d.size*defaultSize;

			switch (shape) {
				case null:
					break;
				case NodeShapes.RECTANGLE:
					g.drawRect(-size/2, -size/2, size, size);
					break;
				case NodeShapes.TRIANGLE:
				case NodeShapes.DIAMOND:
				case NodeShapes.HEXAGON:
				case NodeShapes.OCTAGON:
				case NodeShapes.PARALLELOGRAM:
				case NodeShapes.V:
					var r:Rectangle = new Rectangle(-size/2, -size/2, size, size);
					var points:Array = NodeShapes.getDrawPoints(r, shape);
					Shapes.drawPolygon(g, points);
					break;
				case NodeShapes.ROUND_RECTANGLE:
					g.drawRoundRect(-size/2, -size/2, size, size, size/2, size/2);
					break;
				case NodeShapes.ELLIPSE:
				default:
					if (this._detailFlag || Boolean(d.props.detailFlag))
					{
						// Draws the disc containing details
						drawDetails(d, size/2);
					}

					// Genes are colored according to total alteration percentage
					var total:Number = Number(d.data.PERCENT_ALTERED) * 100;

					g.beginFill(getNodeColorRW(total), 50);

					// Seeded genes (IN_QUERY = true) are drawn with thicker borders
					var inQuery:String = d.data.IN_QUERY;

					if (inQuery == "false")
					{
						g.lineStyle(1, 0x000000, 1);
					}
					else
					{
						g.lineStyle(5, 0x000000, 1);
					}

					g.drawCircle(0, 0, size/2);
			}
		}

		protected override function drawImage(d:DataSprite, w:Number, h:Number):void
		{
			var url:String = d.props.imageUrl;
			var size:Number = d.size*defaultSize;

			if (size > 0 && url != null && StringUtil.trim(url).length > 0) {
				// Load the image into the cache first?
				if (!_imgCache.contains(url)) {trace("Will load IMAGE...");
					_imgCache.loadImage(url);
				}
				if (_imgCache.isLoaded(url)) {trace(" .LOADED :-)");
					draw();
				} else {trace(" .NOT loaded :-(");
					drawWhenLoaded();
				}

				function drawWhenLoaded():void {
					setTimeout(function():void {trace(" .TIMEOUT: Checking again...");
						if (_imgCache.isLoaded(url)) draw();
						else if (!_imgCache.isBroken(url)) drawWhenLoaded();
					}, 50);
				}

				function draw():void {trace("Will draw: " + d.data.id);
					// Get the image from cache:
					var bd:BitmapData = _imgCache.getImage(url);

					if (bd != null) {
						var bmpSize:Number = Math.min(bd.height, bd.width);
						var scale:Number = size/bmpSize;

						var m:Matrix = new Matrix();
						m.scale(scale, scale);
						m.translate(-(bd.width*scale)/2, -(bd.height*scale)/2);

						d.graphics.beginBitmapFill(bd, m, false, true);
						drawShape(d, d.shape, null);
						d.graphics.endFill();
					}
				}
			}
		}

		// Draws the details of the node around the node circle
		private function drawDetails(d:DataSprite, RADIUS:int):void
		{
			var g:Graphics = d.graphics;

			// Flags represent whether a disc part will be drawn or not
			var topFlag:Boolean = false;
			var rightFlag:Boolean = false;
			var leftFlag:Boolean = false;

			var thickness:int = 16; // Thickness of the detail disc
			var smoothness:int = 90; // Determines how smooth the ars are drawn
			var circleMargin:int = 0; // Margin between the discs and the node
			var insideMargin:Number = 1.0; // Inner margins for the percentage slices (should be half the border thickness!)

			// These variables are used for the gradient color for unused disc parts
			var fillType:String = "linear"
			var colors:Array = [0xDCDCDC, 0xFFFFFF];
			var alphas:Array = [100, 100];
			var ratios:Array = [0x00, 0xFF];
			var matrix:Matrix = new Matrix();
			matrix.createGradientBox(3, 3, 0, 0, 0);
			matrix.rotate(90/360);
			var spreadMethod:String = "repeat";

			g.lineStyle(0,0x000000,1);

			// Following part looks at available data and sets percentages if data is available

			// Top disc
			if (d.data.PERCENT_CNA_HEMIZYGOUSLY_DELETED != null ||
				d.data.PERCENT_CNA_AMPLIFIED != null ||
				d.data.PERCENT_CNA_HOMOZYGOUSLY_DELETED != null ||
				d.data.PERCENT_CNA_GAINED != null)
			{
				var hemizygousDeletion:Number = Number(d.data.PERCENT_CNA_HEMIZYGOUSLY_DELETED) * 100;
				var amplification:Number = Number(d.data.PERCENT_CNA_AMPLIFIED) * 100;
				var homozygousDeletion:Number = Number(d.data.PERCENT_CNA_HOMOZYGOUSLY_DELETED) * 100;
				var gain:Number = Number(d.data.PERCENT_CNA_GAINED) * 100;
				topFlag = true;
			}

			// Right disc
			if (d.data.PERCENT_MUTATED != null)
			{
				var mutation:Number = Number(d.data.PERCENT_MUTATED) * 100;
				rightFlag = true;
			}

			// Left disc
			if (d.data.PERCENT_MRNA_WAY_UP != null ||
				d.data.PERCENT_MRNA_WAY_DOWN != null)
			{
				var upRegulation:Number = Number(d.data.PERCENT_MRNA_WAY_UP) * 100;
				var downRegulation:Number = Number(d.data.PERCENT_MRNA_WAY_DOWN) * 100;
				leftFlag = true;
			}

			/* Following part draws the disc slice if associated flag is on, 3 disc parts are drawn in such a
			 * way that there are 20 degrees empty space between each part and the parts themselves have a
			 * 100 degrees space each, adding up to 360 degrees. The gray backgrounds are drawn first and the
			 * corresponing colored percentages are filled using the data about the node.
			 */

			// Don't draw anything if none is available
			if (!(topFlag || rightFlag || leftFlag))
			{
				return;
			}

			var innerRadius:Number;
			var outerRadius:Number;

			// Draws the top arc if its flag is on
			if (topFlag == true)
			{
				innerRadius = RADIUS + circleMargin;
				outerRadius = RADIUS + thickness;

				// The gray back part is drawn
				g.lineStyle(2, 0xDCDCDC, 1);
				g.beginFill(0xFFFFFF, 50);
				drawSolidArc(0, 0, innerRadius, outerRadius, 218/360, 104/360, smoothness, g);

				innerRadius += insideMargin;
				outerRadius -= insideMargin;

				g.lineStyle(0, 0xFFFFFF, 0);

				var amplificationArc:int = amplification;
				g.beginFill(0xFF2500, 50);
				drawSolidArc (0, 0, innerRadius, outerRadius, 220/360, (amplificationArc/360), smoothness, g);

				var homozygousDeletionArc:int = homozygousDeletion;
				g.beginFill(0x0332FF, 50);
				drawSolidArc (0, 0, innerRadius, outerRadius, 220/360 + (amplificationArc/360), (homozygousDeletionArc/360), smoothness,g);

				var gainArc:int = gain;
				g.beginFill(0xFFC5CC, 50);
				drawSolidArc (0, 0, innerRadius, outerRadius, 220/360 + ((amplificationArc+homozygousDeletionArc)/360), (gainArc/360), smoothness,g);

				var hemizygousDeletionArc:int = hemizygousDeletion;
				g.beginFill(0x9EDFE0, 50);
				drawSolidArc (0, 0, innerRadius, outerRadius, 220/360 + ((amplificationArc+homozygousDeletionArc+gainArc)/360), (hemizygousDeletionArc/360), smoothness,g);

				g.lineStyle(1, 0x000000, 1);
			}
			else
			{
				g.lineStyle(1, 0xDCDCDC, 0.5);
				g.beginGradientFill(fillType, colors, alphas, ratios, matrix, spreadMethod);
				drawSolidArc(0, 0, RADIUS+circleMargin, RADIUS+thickness, 219/360, 102/360, smoothness, g);
				g.endFill();
			}

			if (rightFlag == true)
			{
				innerRadius = RADIUS + circleMargin;
				outerRadius = RADIUS + thickness;

				g.lineStyle(2, 0xDCDCDC, 1);
				g.beginFill(0xFFFFFF, 50);
				drawSolidArc(0, 0, innerRadius, outerRadius, -22/360, 104/360, smoothness, g);

				innerRadius += insideMargin;
				outerRadius -= insideMargin;

				g.lineStyle(0,0xDCDCDC,0);

				var mutationArc:int = mutation;
				g.beginFill(0x008F00, 50);
				drawSolidArc (0, 0, innerRadius, outerRadius, -20/360, (mutationArc/360), smoothness,g);

				g.lineStyle(1, 0x000000, 1);
			}
			else
			{
				g.lineStyle(1, 0xDCDCDC, 0.5);
				g.beginGradientFill(fillType, colors, alphas, ratios, matrix, spreadMethod);
				drawSolidArc(0, 0, RADIUS+circleMargin, RADIUS+thickness, -21/360, 102/360, smoothness, g);
				g.endFill();
			}

			if (leftFlag == true)
			{
				innerRadius = RADIUS + circleMargin;
				outerRadius = RADIUS + thickness;

				g.lineStyle(2, 0xDCDCDC, 1);
				g.beginFill(0xFFFFFF, 50);
				drawSolidArc (0, 0, innerRadius, outerRadius, 202/360, -(104/360), smoothness,g);

				innerRadius += insideMargin;
				outerRadius -= insideMargin;

				g.lineStyle(0, 0xDCDCDC, 0);

				var upRegulationArc:int = upRegulation;
				g.beginFill(0xFFACA9, 50);
				drawSolidArc (0, 0, innerRadius, outerRadius, 200/360, -(upRegulationArc/360), smoothness,g);

				var downRegulationArc:int = downRegulation;
				g.beginFill(0x78AAD6, 50);
				drawSolidArc (0, 0, innerRadius, outerRadius, 200/360 - (upRegulationArc/360), -(downRegulationArc/360), smoothness,g);

				// When only borders are to be drawn (like in the OncoPrint)
//				g.endFill();
//				var upRegulationArc:int = upRegulation;
//				g.lineStyle(1.5,0xFFACA9,1);
//				drawSolidArc (0, 0, RADIUS+circleMargin+1.5, RADIUS+thickness-1.5, 201/360-4/360, -(upRegulationArc/360), smoothness,g);
//
//				var downRegulationArc:int = downRegulation;
//				g.lineStyle(1.5,0x78AAD6,1);
//				drawSolidArc (0, 0, RADIUS+circleMargin+1.5, RADIUS+thickness-1.5, 201/360 - (upRegulationArc/360)-8/360, -(downRegulationArc/360), smoothness,g);

				g.lineStyle(1, 0x000000, 1);
			}
			else
			{
				g.lineStyle(1, 0xDCDCDC, 0.5);
				g.beginGradientFill(fillType, colors, alphas, ratios, matrix, spreadMethod);
				drawSolidArc (0, 0, RADIUS+circleMargin, RADIUS+thickness, 201/360, -(102/360), smoothness,g);
				g.endFill();
			}

			g.lineStyle(1, 0x000000, 1);
		}

		/**
		 * Draws a solid arc part using the given parameters
		 *
		 * @param centerX	X-axis of the center of the shape
		 * @param centerY	Y-axis of the center of the shape
		 * @param innerRadius	radius of the inner circle
		 * @param outerRadius	radius of the outer circle
		 * @param startAngle	starting angle of the arc
		 * @param arcAngle	the angle that arc fills
		 * @param steps		determines how smooth the curve of the arc is
		 * @param g			graphics object to draw on it
		 * Reference: http://www.pixelwit.com/blog/2008/12/drawing-closed-arc-shape/
		 * */
		private function drawSolidArc (centerX:Number, centerY:Number, innerRadius:Number, outerRadius:Number, startAngle:Number, arcAngle:Number, steps:Number, g:Graphics):void{
			var twoPI:Number = 2 * Math.PI;
			var angleStep:Number = arcAngle/steps;
			var angle:Number, i:Number, endAngle:Number;

			var xx:Number = centerX + Math.cos(startAngle * twoPI) * innerRadius;
			var yy:Number = centerY + Math.sin(startAngle * twoPI) * innerRadius;

			var startPoint:Object = {x:xx, y:yy};
			g.moveTo(xx, yy);

			for(i=1; i<=steps; i++){
				angle = (startAngle + i * angleStep) * twoPI;
				xx = centerX + Math.cos(angle) * innerRadius;
				yy = centerY + Math.sin(angle) * innerRadius;
				g.lineTo(xx, yy);
			}

			endAngle = startAngle + arcAngle;

			for(i=0; i<=steps; i++){
				angle = (endAngle - i * angleStep) * twoPI;
				xx = centerX + Math.cos(angle) * outerRadius;
				yy = centerY + Math.sin(angle) * outerRadius;
				g.lineTo(xx, yy);
			}

			g.lineTo(startPoint.x, startPoint.y);
		}

		// Returns the color between Red and White using the given value as a ratio
		private function getNodeColorRW(value:int):Number
		{
			var high:int = 100;
			var low:int = 0;

			var highCRed:int = 255;
			var highCGreen:int = 0;
			var highCBlue:int = 0;

			var lowCRed:int = 255;
			var lowCGreen:int = 255;
			var lowCBlue:int = 255;

			// transform percentage value by using the formula:
			// y = 0.000166377 x^3  +  -0.0380704 x^2  +  3.14277x
			// instead of linear scaling, we use polynomial scaling to better
			// emphasize lower alteration frequencies
			value = (0.000166377 * value * value * value) -
				(0.0380704 * value * value) +
				(3.14277 * value);

			// check boundary values
			if (value > 100)
			{
				value = 100;
			}
			else if (value < 0)
			{
				value = 0;
			}

			if (value >= high)
			{
				return rgb2hex(highCRed, highCGreen, highCBlue);
			}
			else if (value > low)
			{
				return rgb2hex( getValueByRatio(value, low, high, lowCRed, highCRed),
					getValueByRatio(value, low, high, lowCGreen, highCGreen),
					getValueByRatio(value, low, high, lowCBlue, highCBlue)
				);
			}
			else
			{
				return rgb2hex(lowCRed, lowCGreen, lowCBlue);
			}
		}

		// used in getNodeColorRW to calculate a color number according to the ratio given
		private function getValueByRatio(num:Number,
				numLow:Number, numHigh:Number, colorNum1:int, colorNum2:int):int
		{
			return ((((num - numLow) / (numHigh - numLow)) * (colorNum2 - colorNum1)) + colorNum1)
		}

		// bitwise conversion of rgb color to a hex value
		private function rgb2hex(r:int, g:int, b:int):Number {
			return(r<<16 | g<<8 | b);
		}
	}
}

fix for CBioNodeRenderer.as

fix for CBioNodeRenderer.as


package htmlelements
{
	import flash.display.Sprite;
	import flash.events.*;
	import flash.net.NetConnection;
	import flash.net.NetStream;
	import flash.media.Video;
	import flash.media.SoundTransform;
	import flash.utils.Timer;

	import FlashMediaElement;
	import HtmlMediaEvent;

	public class VideoElement extends Sprite implements IMediaElement
	{
		private var _currentUrl:String = "";
		private var _autoplay:Boolean = true;

		private var _connection:NetConnection;
		private var _stream:NetStream;
		private var _video:Video;
		private var _element:FlashMediaElement;
		private var _soundTransform;
		private var _oldVolume:Number = 1;

		// event values
		private var _duration:Number = 0;
		private var _framerate:Number;
		private var _isPaused:Boolean = true;
		private var _isEnded:Boolean = false;
		private var _volume:Number = 1;
		private var _isMuted:Boolean = false;

		private var _bytesLoaded:Number = 0;
		private var _bytesTotal:Number = 0;
		private var _bufferedTime:Number = 0;

		private var _videoWidth:Number = -1;
		private var _videoHeight:Number = -1;

		private var _timer:Timer;

		private var _isRTMP:Boolean = false;
		private var _isConnected:Boolean = false;
		private var _playWhenConnected:Boolean = false;
		private var _hasStartedPlaying:Boolean = false;

		public function get video():Video {
			return _video;
		}

		public function get videoHeight():Number {
			return _videoHeight;
		}

		public function get videoWidth():Number {
			return _videoWidth;
		}

		public function duration():Number {
			return _duration;
		}

		public function currentTime():Number {
			if (_stream != null) {
				return _stream.time;
			} else {
				return 0;
			}
		}

		// (1) load()
		// calls _connection.connect();
		// waits for NetConnection.Connect.Success
		// _stream gets created

		public function VideoElement(element:FlashMediaElement, autoplay:Boolean, timerRate:Number)
		{
			_element = element;
			_autoplay = autoplay;

			_video = new Video();
			addChild(_video);

			_connection = new NetConnection();
			_connection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
			_connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
			//_connection.connect(null);

			_timer = new Timer(timerRate);
			_timer.addEventListener("timer", timerHandler);

		}

		private function timerHandler(e:TimerEvent) {

			_bytesLoaded = _stream.bytesLoaded;
			_bytesTotal = _stream.bytesTotal;

			sendEvent(HtmlMediaEvent.TIMEUPDATE);

			trace("bytes", _bytesLoaded, _bytesTotal);

			if (_bytesLoaded < _bytesTotal)
				sendEvent(HtmlMediaEvent.PROGRESS);
		}

		// internal events
		private function netStatusHandler(event:NetStatusEvent):void {
			trace("netStatus", event.info.code);

			switch (event.info.code) {

				case "NetStream.Buffer.Empty":
				case "NetStream.Buffer.Full":
					_bytesLoaded = _stream.bytesLoaded;
					_bytesTotal = _stream.bytesTotal;

					sendEvent(HtmlMediaEvent.PROGRESS);
					break;

				case "NetConnection.Connect.Success":
					connectStream();
					break;
				case "NetStream.Play.StreamNotFound":
					trace("Unable to locate video");
					break;

				// STREAM
				case "NetStream.Play.Start":
					_isPaused = false;
					sendEvent(HtmlMediaEvent.CANPLAY);
					sendEvent(HtmlMediaEvent.PLAY);
					sendEvent(HtmlMediaEvent.PLAYING);
					_timer.start();
					break;

				case "NetStream.Seek.Notify":
					sendEvent(HtmlMediaEvent.SEEKED);
					break;

				case "NetStream.Pause.Notify":
					_isPaused = true;
					sendEvent(HtmlMediaEvent.PAUSE);
					break;

				case "NetStream.Play.Stop":
					_isPaused = false;
					_timer.stop();
					sendEvent(HtmlMediaEvent.ENDED);
					break;

			}
		}

		private function connectStream():void {
			trace("connectStream");
			_stream = new NetStream(_connection);

			// explicitly set the sound since it could have come before the connection was made
			_soundTransform = new SoundTransform(_volume);
			_stream.soundTransform = _soundTransform;

			_stream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler); // same event as connection
			_stream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);

			var customClient:Object = new Object();
			customClient.onMetaData = onMetaDataHandler;
			_stream.client = customClient;

			_video.attachNetStream(_stream);

			_isConnected = true;

			if (_playWhenConnected && !_hasStartedPlaying) {
				play();
				_playWhenConnected = false;
			}

		}

		private function securityErrorHandler(event:SecurityErrorEvent):void {
			trace("securityErrorHandler: " + event);
		}

		private function asyncErrorHandler(event:AsyncErrorEvent):void {
			// ignore AsyncErrorEvent events.
		}

		private function onMetaDataHandler(info:Object):void {
			_duration = info.duration;
			_framerate = info.framerate;
			_videoWidth = info.width;
			_videoHeight = info.height;

			// set size?

			sendEvent(HtmlMediaEvent.LOADEDMETADATA);
		}

		// interface members
		public function setSrc(url:String):void {
			if (_isConnected && _stream) {
				// stop and restart
				_stream.pause();
			}

			_currentUrl = url;
			_isRTMP = !!_currentUrl.match(/^rtmp(s|t|e|te)?\:\/\//);
			_isConnected = false;
			_hasStartedPlaying = false;
		}

		public function load():void {
			// as far as I know there is no way to start downloading a file without playing it (preload="auto" in HTML5)
			// so this "load" just begins a Flash connection
			if (_isConnected && _stream) {
				_stream.pause();
			}
			_isConnected = false;

			if (_isRTMP) {
				_connection.connect(_currentUrl.replace(/\/[^\/]+$/,"/"));
			} else {
				_connection.connect(null);
			}
			// in a few moments the "NetConnection.Connect.Success" event will fire
			// and call createConnection which finishes the "load" sequence

			sendEvent(HtmlMediaEvent.LOADSTART);
		}

		public function play():void {

			if (!_hasStartedPlaying && !_isConnected) {
				_playWhenConnected = true;
				load();
				return;
			}

			if (_hasStartedPlaying) {
				if (_isPaused) {
					_stream.resume();
					_timer.start();
					_isPaused = false;
					sendEvent(HtmlMediaEvent.PLAY);
					sendEvent(HtmlMediaEvent.PLAYING);
				}
			} else {

				if (_isRTMP) {
					_stream.play(_currentUrl.split("/").pop());
				} else {
					_stream.play(_currentUrl);
				}
				_timer.start();
				_isPaused = false;
				sendEvent(HtmlMediaEvent.PLAY);
				sendEvent(HtmlMediaEvent.PLAYING);
				_hasStartedPlaying = true;
			}

		}

		public function pause():void {
			if (_stream == null)
				return;

			_stream.pause();
			_isPaused = true;
			_timer.stop();

			_isPaused = true;
			sendEvent(HtmlMediaEvent.PAUSE);
		}

		public function stop():void {
			if (_stream == null)
				return;

			_stream.close();
			_isPaused = false;
			_timer.stop();
			sendEvent(HtmlMediaEvent.STOP);
		}

		public function setCurrentTime(pos:Number):void {
			if (_stream == null)
				return;

			_stream.seek(pos);
			sendEvent(HtmlMediaEvent.TIMEUPDATE);
			sendEvent(HtmlMediaEvent.SEEKED);
		}

		public function setVolume(volume:Number):void {
			if (_stream != null) {
				_soundTransform = new SoundTransform(volume);
				_stream.soundTransform = _soundTransform;
			}

			_volume = volume;

			_isMuted = (_volume == 0);

			sendEvent(HtmlMediaEvent.VOLUMECHANGE);
		}

		public function setMuted(muted:Boolean):void {

			if (_isMuted == muted)
				return;

			if (muted) {
				_oldVolume = _stream.soundTransform.volume;
				setVolume(0);
			} else {
				setVolume(_oldVolume);
			}

			_isMuted = muted;
		}

		private function sendEvent(eventName:String) {

			// calculate this to mimic HTML5
			_bufferedTime = _bytesLoaded / _bytesTotal + _duration;

			// build JSON
			var values:String =
							"{duration:" + _duration +
							",framerate:" + _framerate +
							",currentTime:" + (_stream != null ? _stream.time : 0) +
							",muted:" + _isMuted +
							",paused:" + _isPaused +
							",ended:" + _isEnded +
							",volume:" + _volume +
							",src:\"" + _currentUrl + "\"" +
							",bytesTotal:" + _bytesTotal +
							",bufferedBytes:" + _bytesLoaded +
							",bufferedTime:" + _bufferedTime +
							",videoWidth:" + _videoWidth +
							",videoHeight:" + _videoHeight +
							"}";

			_element.sendEvent(eventName, values);
		}
	}
}

package htmlelements
{
	import flash.display.Sprite;
	import flash.events.*;
	import flash.net.NetConnection;
	import flash.net.NetStream;
	import flash.media.Video;
	import flash.media.SoundTransform;
	import flash.utils.Timer;

	import FlashMediaElement;
	import HtmlMediaEvent;

	public class VideoElement extends Sprite implements IMediaElement
	{
		private var _currentUrl:String = "";
		private var _autoplay:Boolean = true;

		private var _connection:NetConnection;
		private var _stream:NetStream;
		private var _video:Video;
		private var _element:FlashMediaElement;
		private var _soundTransform;
		private var _oldVolume:Number = 1;

		// event values
		private var _duration:Number = 0;
		private var _framerate:Number;
		private var _isPaused:Boolean = true;
		private var _isEnded:Boolean = false;
		private var _volume:Number = 1;
		private var _isMuted:Boolean = false;

		private var _bytesLoaded:Number = 0;
		private var _bytesTotal:Number = 0;
		private var _bufferedTime:Number = 0;

		private var _videoWidth:Number = -1;
		private var _videoHeight:Number = -1;

		private var _timer:Timer;

		private var _isRTMP:Boolean = false;
		private var _isConnected:Boolean = false;
		private var _playWhenConnected:Boolean = false;
		private var _hasStartedPlaying:Boolean = false;

		public function get video():Video {
			return _video;
		}

		public function get videoHeight():Number {
			return _videoHeight;
		}

		public function get videoWidth():Number {
			return _videoWidth;
		}

		public function duration():Number {
			return _duration;
		}

		public function currentTime():Number {
			if (_stream != null) {
				return _stream.time;
			} else {
				return 0;
			}
		}

		// (1) load()
		// calls _connection.connect();
		// waits for NetConnection.Connect.Success
		// _stream gets created

		public function VideoElement(element:FlashMediaElement, autoplay:Boolean, timerRate:Number)
		{
			_element = element;
			_autoplay = autoplay;

			_video = new Video();
			addChild(_video);

			_connection = new NetConnection();
			_connection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
			_connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
			//_connection.connect(null);

			_timer = new Timer(timerRate);
			_timer.addEventListener("timer", timerHandler);

		}

		private function timerHandler(e:TimerEvent) {

			_bytesLoaded = _stream.bytesLoaded;
			_bytesTotal = _stream.bytesTotal;

			sendEvent(HtmlMediaEvent.TIMEUPDATE);

			trace("bytes", _bytesLoaded, _bytesTotal);

			if (_bytesLoaded < _bytesTotal)
				sendEvent(HtmlMediaEvent.PROGRESS);
		}

		// internal events
		private function netStatusHandler(event:NetStatusEvent):void {
			trace("netStatus", event.info.code);

			switch (event.info.code) {

				case "NetStream.Buffer.Empty":
					_isEnded ? sendEvent(HtmlMediaEvent.ENDED) : null;
					break;

				case "NetStream.Buffer.Full":
					_bytesLoaded = _stream.bytesLoaded;
					_bytesTotal = _stream.bytesTotal;

					sendEvent(HtmlMediaEvent.PROGRESS);
					break;

				case "NetConnection.Connect.Success":
					connectStream();
					break;
				case "NetStream.Play.StreamNotFound":
					trace("Unable to locate video");
					break;

				// STREAM
				case "NetStream.Play.Start":
					_isPaused = false;
					sendEvent(HtmlMediaEvent.CANPLAY);
					sendEvent(HtmlMediaEvent.PLAY);
					sendEvent(HtmlMediaEvent.PLAYING);
					_timer.start();
					break;

				case "NetStream.Seek.Notify":
					sendEvent(HtmlMediaEvent.SEEKED);
					break;

				case "NetStream.Pause.Notify":
					_isPaused = true;
					sendEvent(HtmlMediaEvent.PAUSE);
					break;

				case "NetStream.Play.Stop":
					_isEnded = true;
					_isPaused = false;
					_timer.stop();
					_bufferEmpty ? sendEvent(HtmlMediaEvent.ENDED) : null;
					break;

			}
		}

		private function connectStream():void {
			trace("connectStream");
			_stream = new NetStream(_connection);

			// explicitly set the sound since it could have come before the connection was made
			_soundTransform = new SoundTransform(_volume);
			_stream.soundTransform = _soundTransform;

			_stream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler); // same event as connection
			_stream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);

			var customClient:Object = new Object();
			customClient.onMetaData = onMetaDataHandler;
			_stream.client = customClient;

			_video.attachNetStream(_stream);

			_isConnected = true;

			if (_playWhenConnected && !_hasStartedPlaying) {
				play();
				_playWhenConnected = false;
			}

		}

		private function securityErrorHandler(event:SecurityErrorEvent):void {
			trace("securityErrorHandler: " + event);
		}

		private function asyncErrorHandler(event:AsyncErrorEvent):void {
			// ignore AsyncErrorEvent events.
		}

		private function onMetaDataHandler(info:Object):void {
			_duration = info.duration;
			_framerate = info.framerate;
			_videoWidth = info.width;
			_videoHeight = info.height;

			// set size?

			sendEvent(HtmlMediaEvent.LOADEDMETADATA);
		}

		// interface members
		public function setSrc(url:String):void {
			if (_isConnected && _stream) {
				// stop and restart
				_stream.pause();
			}

			_currentUrl = url;
			_isRTMP = !!_currentUrl.match(/^rtmp(s|t|e|te)?\:\/\//);
			_isConnected = false;
			_hasStartedPlaying = false;
		}

		public function load():void {
			// as far as I know there is no way to start downloading a file without playing it (preload="auto" in HTML5)
			// so this "load" just begins a Flash connection
			if (_isConnected && _stream) {
				_stream.pause();
			}
			_isConnected = false;

			if (_isRTMP) {
				_connection.connect(_currentUrl.replace(/\/[^\/]+$/,"/"));
			} else {
				_connection.connect(null);
			}
			// in a few moments the "NetConnection.Connect.Success" event will fire
			// and call createConnection which finishes the "load" sequence

			sendEvent(HtmlMediaEvent.LOADSTART);
		}

		public function play():void {

			if (!_hasStartedPlaying && !_isConnected) {
				_playWhenConnected = true;
				load();
				return;
			}

			if (_hasStartedPlaying) {
				if (_isPaused) {
					_stream.resume();
					_timer.start();
					_isPaused = false;
					sendEvent(HtmlMediaEvent.PLAY);
					sendEvent(HtmlMediaEvent.PLAYING);
				}
			} else {

				if (_isRTMP) {
					_stream.play(_currentUrl.split("/").pop());
				} else {
					_stream.play(_currentUrl);
				}
				_timer.start();
				_isPaused = false;
				sendEvent(HtmlMediaEvent.PLAY);
				sendEvent(HtmlMediaEvent.PLAYING);
				_hasStartedPlaying = true;
			}

		}

		public function pause():void {
			if (_stream == null)
				return;

			_stream.pause();
			_isPaused = true;
			_timer.stop();

			_isPaused = true;
			sendEvent(HtmlMediaEvent.PAUSE);
		}

		public function stop():void {
			if (_stream == null)
				return;

			_stream.close();
			_isPaused = false;
			_timer.stop();
			sendEvent(HtmlMediaEvent.STOP);
		}

		public function setCurrentTime(pos:Number):void {
			if (_stream == null)
				return;

			_stream.seek(pos);
			sendEvent(HtmlMediaEvent.TIMEUPDATE);
			sendEvent(HtmlMediaEvent.SEEKED);
		}

		public function setVolume(volume:Number):void {
			if (_stream != null) {
				_soundTransform = new SoundTransform(volume);
				_stream.soundTransform = _soundTransform;
			}

			_volume = volume;

			_isMuted = (_volume == 0);

			sendEvent(HtmlMediaEvent.VOLUMECHANGE);
		}

		public function setMuted(muted:Boolean):void {

			if (_isMuted == muted)
				return;

			if (muted) {
				_oldVolume = _stream.soundTransform.volume;
				setVolume(0);
			} else {
				setVolume(_oldVolume);
			}

			_isMuted = muted;
		}

		private function sendEvent(eventName:String) {

			// calculate this to mimic HTML5
			_bufferedTime = _bytesLoaded / _bytesTotal + _duration;

			// build JSON
			var values:String =
							"{duration:" + _duration +
							",framerate:" + _framerate +
							",currentTime:" + (_stream != null ? _stream.time : 0) +
							",muted:" + _isMuted +
							",paused:" + _isPaused +
							",ended:" + _isEnded +
							",volume:" + _volume +
							",src:\"" + _currentUrl + "\"" +
							",bytesTotal:" + _bytesTotal +
							",bufferedBytes:" + _bytesLoaded +
							",bufferedTime:" + _bufferedTime +
							",videoWidth:" + _videoWidth +
							",videoHeight:" + _videoHeight +
							"}";

			_element.sendEvent(eventName, values);
		}
	}
}

fix for issue #49 - "ended" event firing before actual stream end