<commit_before>gfxRessources = {
	createPlayerGfx: function(rsr) {
		return rsr.image("/img/rod-mand.png", 0, 0, 20, 10);
	},
	createPlayerGfx: function(paper, type) {

		var images = [
			"/img/rod-mand.png",
			"/img/blu-mand.png",
			"/img/blo-mand.png",
			"/img/redblonde.png",
			"/img/brownred.png",
			"/img/lightbluebrown.png",
			"/img/greybrown.png"];

		var image = images[type%images.length];

		return paper.image(image, 0, 0, 20, 10);
	},

	createBackgroundTile: function(tile) {
		return tile.image("/img/grass.png", 0, 0, 178, 178);
	},
	createHeart: function(tile) {
		return tile.image("/img/heart.png", 0, 0, 124, 109);
	},
	animateHeart: function (numAnimations, paper, x, y, image) {
		var it = this;

		if( image == null )
		{
			var iW = 124 /3;
			var iH = 108 /3;
			image = paper.image("img/heart.png", x - iW / 2, y - iH / 2, iW , iH);
			image.toFront();
		}

		image.animate({
			opacity: 0.3,
			transform: "s2.4"
		}, 300, "cubic-bezier(.26,1,.54,.56) ", function() {

			image.animate({
				opacity: 1,
				transform: "s1"
			}, 1000, "cubic-bezier(.26,1,.54,.56) ", function(){
				if(numAnimations>1)
					it.animateHeart(--numAnimations, paper, x, y, image);
				else
				{
					image.remove();
					image = null;
				}
			});
		});
	},
	animateDeath: function (numAnimations, paper, x, y, image) {
		var it = this;
		if( image == null ){
			var iW = 124 /3;
			var iH = 108 /3;
			image = paper.image("img/skull.png", x - iW / 2, y - iH / 2, iW , iH);
			image.toFront();
		}

		image.animate({
			opacity: 0.3,
			transform: "s2.4"
		}, 300, "cubic-bezier(.26,1,.54,.56) ", function() {

			image.animate({
				opacity: 1,
				transform: "s1"
			}, 1000, "cubic-bezier(.26,1,.54,.56) ", function(){
				if(numAnimations>1)
					it.animateDeath(--numAnimations, paper, x, y, image);
				else
				{
					image.remove();
					image = null;
				}
			});
		});
	}
};
<commit_msg>dfghjkl<commit_after>gfxRessources = {
	createPlayerGfx: function(rsr) {
		return rsr.image("/img/rod-mand.png", 0, 0, 20, 10);
	},
	createPlayerGfx: function(paper, type) {

		var images = [
			"/img/rod-mand.png",
			"/img/blu-mand.png",
			"/img/blo-mand.png",
			"/img/redblonde.png",
			"/img/brownred.png",
			"/img/lightbluebrown.png",
			"/img/greybrown.png"];

		var image = images[type%images.length];

		return paper.image(image, 0, 0, 20, 10);
	},

	createBackgroundTile: function(tile) {
		return tile.image("/img/grass.png", 0, 0, 178, 178);
	},
	createHeart: function(tile) {
		return tile.image("/img/heart.png", 0, 0, 124, 109);
	},
	animateHeart: function (numAnimations, paper, x, y, image) {
		var it = this;

		if( image == null )
		{
			var iW = 124 /3;
			var iH = 108 /3;
			image = paper.image("img/heart.png", x - iW / 2, y - iH / 2, iW , iH);
			image.toFront();
		}

		image.animate({
			opacity: 0.3,
			transform: "s2.4"
		}, 300, "cubic-bezier(.26,1,.54,.56) ", function() {

			image.animate({
				opacity: 1,
				transform: "s1"
			}, 1000, "cubic-bezier(.26,1,.54,.56) ", function(){
				if(numAnimations>1)
					it.animateHeart(--numAnimations, paper, x, y, image);
				else
				{
					image.remove();
					image = null;
				}
			});
		});
	},
	animateDeath: function (numAnimations, paper, x, y, image) {
		var it = this;
		if( image == null ){
			var iW = 124 /3;
			var iH = 108 /3;
			image = paper.image("img/skull.png", x - iW / 2, y - iH / 2, iW , iH);
			image.toFront();
		}

		image.animate({
			opacity: 0.3,
			transform: "s2.4"
		}, 300, "cubic-bezier(.26,1,.54,.56) ", function() {

			image.animate({
				opacity: 1,
				transform: "s1"
			}, 1000, "cubic-bezier(.26,1,.54,.56) ", function(){
				if(numAnimations>1)
					it.animateDeath(--numAnimations, paper, x, y, image);
				else
				{
					image.remove();
					image = null;
					it.animateBlood(paper, x, y, null);
				}
			});
		});
	},
	animateBlood: function (paper, x, y, image) {
		var it = this;
		if( image == null ){
			var iW = 124 /3;
			var iH = 108 /3;
			image = paper.image("img/blood_pool.png", x - iW / 2, y - iH / 2, iW , iH);
			image.toFront();
		}

		image.animate({
				opacity: 0.0,
				transform: "s2.4"
			},
			15000,
			"linear",
			function() {
				image.remove();
				image = null;
			}
		);
	}

};
<|endoftext|>


<commit_before>let firebase = require("@modules/core/firebase")
let serviceCore = require("@modules/core/service")

class CourseService extends firebase{

	get core() {
		return new serviceCore()
	}

	store( user, course) {
		return this.core.store('courses', course)
		.then((response)=>{
			if(response.status) {
				return this.core.storeSet('users/'+user+'/courses', response.data.o[1], {
					title: course.title,
					description: course.description
				})
			}
		})
		.catch((error)=>{
			return {
				status: false,
				data: error
			}
		})
	}

	delete( user, id ) {
		return this.core.delete( 'users/'+user+'/courses/', id )
	}

	update( user, newCourse, id) {
		return this.core.update('courses/', newCourse, id)
		.then( response =>{
			if(response.status) {
				return this.core.update(
					'users/'+user+'/courses/', {
					title: newCourse.title,
					description: newCourse.description},
					id
				)
			}
		})
		.catch((error)=>{
			return {
				status: false,
				data: error
			}
		})
	}

	getAll( user ) {
		return this.core.getAll('users/'+user+'/courses/')
	}

	getSingle( user, id ) {
		return this.core.getSingle('users/'+user+'/courses/', id)
	}
}
module.exports = CourseService <commit_msg>course delete done<commit_after>let firebase = require("@modules/core/firebase")
let serviceCore = require("@modules/core/service")

class CourseService extends firebase{

	get core() {
		return new serviceCore()
	}

	store( user, course) {
		return this.core.store('courses', course)
		.then((response)=>{
			if(response.status) {
				return this.core.storeSet('users/'+user+'/courses', response.data.o[1], {
					title: course.title,
					description: course.description
				})
			}
		})
		.catch((error)=>{
			return {
				status: false,
				data: error
			}
		})
	}

	delete( user, id ) {
		return this.core.delete( 'users/'+user+'/courses/', id )
		.then( response =>{
			if(response.status) {
				this.core.delete( 'courses/', id )
			}
		})
	}

	update( user, newCourse, id) {
		return this.core.update('courses/', newCourse, id)
		.then( response =>{
			if(response.status) {
				return this.core.update(
					'users/'+user+'/courses/', {
					title: newCourse.title,
					description: newCourse.description},
					id
				)
			}
		})
		.catch((error)=>{
			return {
				status: false,
				data: error
			}
		})
	}

	getAll( user ) {
		return this.core.getAll('users/'+user+'/courses/')
	}

	getSingle( user, id ) {
		return this.core.getSingle('courses/', id)
	}
}
module.exports = CourseService <|endoftext|>


<commit_before>( function( mw, $ ) {"use strict";

	mw.PluginManager.add( 'sourceSelector', mw.KBaseComponent.extend({

		defaultConfig: {
			"parent": "controlsContainer",
			"order": 61,
			"displayImportance": 'low',
			"align": "right",
			"showTooltip": true,
			"switchOnResize": false,
			"simpleFormat": true
		},

		isDisabled: false,
		inUpdateLayout:false,
		selectSourceTitle: gM( 'mwe-embedplayer-select_source' ),
		switchSourceTitle: gM( 'mwe-embedplayer-switch_source' ),
        AutoTitle: gM( 'mwe-embedplayer-auto_source' ),
		saveBackgroundColor: null, // used to save background color upon disable and rotate and return it when enabled again to prevent rotating box around the icon when custom style is applied

        sourcesList: [],
        firstPlay:false,

		setup: function(){
			var _this = this;

			this.bind( 'playerReady sourcesReplaced', function(){
				_this.buildMenu();
			});

            this.bind( 'firstPlay', function(){
                _this.firstPlay = true;
            });

			this.bind( 'SourceChange', function(){
				var selectedSrc = _this.getPlayer().mediaElement.selectedSource;
				var selectedId = selectedSrc.getAssetId();

				//if selected source is not part of the menu, show the source before it as the selected one
				//workaround when auto switch with kplayer occurred and the selected source is not part of the menu data provider
				if ( selectedSrc.skip ) {
					var sources = _this.getSources();
					for ( var i = 0; i< sources.length; i++ ) {
						//look for the closest flavor
						if ( selectedSrc.getSrc() == sources[i].getSrc() ) {
							if ( i == 0 && sources.length > 1 ) {
								selectedId = sources[i+1].getAssetId();
							} else {
								selectedId = sources[i-1].getAssetId();
							}
							break;
						}
					}
				}
				_this.getMenu().setActive({'key': 'id', 'val': selectedId});
				_this.onEnable();
			});

			this.bind( 'sourceSwitchingStarted', function(){
				_this.onDisable();
			});
			this.bind( 'sourceSwitchingEnd', function(newIndex){
                _this.onEnable();
			});
            this.bind( 'onHideControlBar', function(){
                if ( _this.getMenu().isOpen() )
                    _this.getMenu().close();
            });

			// Check for switch on resize option
			if( this.getConfig( 'switchOnResize' ) ){
				this.bind( 'updateLayout', function(){
					// workaround to avoid the amount of 'updateLayout' events
					// !seeking will avoid getting current time equal to 0
					if ( !_this.inUpdateLayout && !_this.embedPlayer.seeking ){
						_this.inUpdateLayout = true;
						_this.updateLayoutTimout = setTimeout(function() {
							_this.inUpdateLayout = false;
						},1000);
						//if we're working with kplayer - mp4 can't be seeked - so disable this feature
						//this only effect native for now
						if (_this.embedPlayer.instanceOf === "Native" && !_this.embedPlayer.isInSequence() ) {
							// TODO add additional logic for "auto" where multiple bitrates
							// exist at the same resolution.
							var selectedSource = _this.embedPlayer.mediaElement.autoSelectSource(_this.embedPlayer.supportsURLTimeEncoding(), _this.embedPlayer.startTime, _this.embedPlayer.pauseTime);
							if ( selectedSource ) { // source was found
								_this.embedPlayer.switchSrc( selectedSource );
							}
						} else {
							mw.log( "sourceSelector - switchOnResize is ignored - Can't switch source since not using native player or during ad playback");
						}
					}
				});
			}
		},
		getSources: function(){
			return this.getPlayer().getSources();
		},

		buildMenu: function(){
			var _this = this;

			// Destroy old menu
			this.getMenu().destroy();

			var sources = this.getSources().slice(0);

			if( ! sources.length ){
				_this.log("Error with getting sources");
				return ;
			}

            //add Auto for addaptive bitrate streams
            if ( !this.handleAdaptiveBitrateAndContinue() )
                return;

			if( sources.length == 1 ){
				// no need to do building menu logic.
				this.addSourceToMenu( sources[0], _this.getSourceTitle(sources[0]) );
				return ;
			}
			// sort by height then bitrate:
			sources.sort(function(a,b){
				var hdiff = b.getHeight() - a.getHeight();
				if( hdiff != 0 ){
					return hdiff;
				}
				return b.getBitrate() - a.getBitrate();
			});

			// if simple format don't include more then two sources per size in menu
			if( _this.getConfig( 'simpleFormat' ) ){
				var prevSource = null;
				var twice = false;
				$.each( sources, function( sourceIndex, source ) {
					if( ! prevSource ){
						prevSource = source;
						return true;
					}
					if( source.getHeight() != 0
						&&
						( _this.getSourceSizeName( prevSource )
							==
							_this.getSourceSizeName( source ) )
						){
						//if the selected source has the same height, skip this source
						var selectedSrc = _this.getPlayer().mediaElement.selectedSource;
						if ( selectedSrc
							&&
							!_this.isSourceSelected( source )
							&&
							!_this.isSourceSelected( prevSource )
							&&
							( _this.getSourceSizeName( source )
								==
								_this.getSourceSizeName( selectedSrc ) )
							){
							source.skip = true;
						}
						else if( twice ){
							// don't skip if this is the default source:
							if( !_this.isSourceSelected( source ) ){
								// skip this source
								source.skip = true;
							} else {
								source.skip = false;
							}
							prevSource = source;
							return true;
						}
						// set the first source as "HQ"
						prevSource.hq = true;
						twice = true;
					} else {
						twice = false;
					}
					// always update prevSource
					prevSource = source;
				});
			}

			var prevSource = null;
			$.each( sources, function( sourceIndex, source ) {
				if( source.skip ){
					return true;
				}
				// Output the player select code:
				var supportingPlayers = mw.EmbedTypes.getMediaPlayers().getMIMETypePlayers( source.getMIMEType() );
				for ( var i = 0; i < supportingPlayers.length ; i++ ) {
					if(
						(
							_this.getPlayer().selectedPlayer === undefined
								&&
								supportingPlayers[i].library == 'Native'
							)
							||
							(
								_this.getPlayer().selectedPlayer !== undefined
									&&
									supportingPlayers[i].library == _this.getPlayer().selectedPlayer.library
								)
						){
						_this.addSourceToMenu( source );
					}
				}
			});
		},
		isSourceSelected: function( source ){
			var _this = this;
			return ( _this.getPlayer().mediaElement.selectedSource && source.getSrc()
				==
				_this.getPlayer().mediaElement.selectedSource.getSrc()
				);
		},
        handleAdaptiveBitrateAndContinue: function (){
            //Silverlight smoothStream
            if( ( this.getPlayer().streamerType === "smoothStream" ) ){
                this.addAutoToMenu();
                return true;
            }

            //HLS, HDS
            if(  this.getPlayer().streamerType != "http" && !this.getPlayer().isPlaying() ){
                this.addAutoToMenu();
                return false;
            }

            if( this.getPlayer().streamerType != "http" && this.firstPlay ){ //add and select Auto for adaptive bitrate
                this.addAutoToMenu();
                this.firstPlay = false;
            }
            return true;
        },
        addAutoToMenu: function (){
            var _this = this;
            this.getMenu().addItem({
                'label': _this.AutoTitle,
                'callback': function () {
                    _this.getPlayer().switchSrc("-1");
                },
               'active': true
            });
        },
		addSourceToMenu: function( source ){
			var _this = this;

            var sourceLabel = this.getSourceTitle( source );
            if( $.inArray(sourceLabel, this.sourcesList) == -1 ) {

                this.sourcesList.push(sourceLabel);

                this.getMenu().addItem({
                    'label': sourceLabel,
                    'attributes': {
                        'id': source.getAssetId()
                    },
                    'callback': function () {
                        _this.getPlayer().switchSrc(source);
                    },
                    'active': _this.isSourceSelected(source)
                });
            }
		},
        getSourceSizeName: function( source ){
			if( source.getHeight() < 255 ){
				return '240P';
			} else if( source.getHeight() < 370 ){
				return '360P';
			} else if( source.getHeight() < 500 ){
				return '480P';
			} else if( source.getHeight() < 800 ){
				return '720P';
			} else {
				return '1080P';
			}
		},
		getSourceTitle: function( source ){
			// We should return "Auto" for Apple HLS
			if( source.getMIMEType() == 'application/vnd.apple.mpegurl' ) {
				return _this.AutoTitle;
			}
			var title = '';
			if( source.getHeight() ){
				title+= this.getSourceSizeName( source );
			} else if ( source.getBitrate() ) {
				var bits = ( Math.round( source.getBitrate() / 1024 * 10 ) / 10 ) + '';
				if( bits[0] == '0' ){
					bits = bits.substring(1);
				}
				title+= ' ' + bits + 'Mbs ';
			}
			if( this.getConfig( 'simpleFormat' ) ){
				if( source.hq ){
					title += ' HQ';
				}
			} else {
				// include type if not simple format
				title += ' ' + source.getMIMEType().replace('video/', '');
			}
			return title;
		},
		toggleMenu: function(){
			if ( this.isDisabled ) {
				return;
			}
			this.getMenu().toggle();
		},
		getComponent: function() {
			var _this = this;
			if( !this.$el ) {
				var $menu = $( '<ul />' );
				var $button = $( '<button />' )
					.addClass( 'btn icon-cog' )
					.attr('title', _this.selectSourceTitle)
					.click( function(e){
						_this.toggleMenu();
					});
				this.setAccessibility($button,_this.selectSourceTitle);
				this.$el = $( '<div />' )
					.addClass( 'dropup' + this.getCssClass() )
					.append( $button, $menu );
			}
			return this.$el;
		},
		getMenu: function(){
			if( !this.menu ) {
				this.menu = new mw.KMenu(this.getComponent().find('ul'), {
					tabIndex: this.getBtn().attr('tabindex')
				});
			}
			return this.menu;
		},
		getBtn: function(){
			return this.getComponent().find( 'button' );
		},
		onEnable: function(){
			this.isDisabled = false;
			this.updateTooltip( this.selectSourceTitle );
			this.getComponent().find('button').removeClass( 'rotate' );
			this.getBtn().removeClass( 'disabled' );
			if (this.saveBackgroundColor){
				this.getComponent().find('button').attr('style', 'background-color: ' + this.saveBackgroundColor + ' !important');
			}
		},
		onDisable: function(){
			this.isDisabled = true;
			this.updateTooltip( this.switchSourceTitle );
			this.getComponent().find('button').addClass( 'rotate' );
			this.saveBackgroundColor = this.getComponent().find('button').css("background-color");
			this.getComponent().find('button').attr('style', 'background-color: null !important');
			this.getComponent().removeClass( 'open' );
			this.getBtn().addClass( 'disabled' );
		}
	}));

} )( window.mw, window.jQuery );		<commit_msg>FEC-2412 Support configuration on flavor selector to display bitrate instead of size<commit_after>( function( mw, $ ) {"use strict";

	mw.PluginManager.add( 'sourceSelector', mw.KBaseComponent.extend({

		defaultConfig: {
			"parent": "controlsContainer",
			"order": 61,
			"displayImportance": 'low',
			"align": "right",
			"showTooltip": true,
			"switchOnResize": false,
			"simpleFormat": true,
            "dispalyMode": "size" //'size' – displays frame size ( default ), 'bitrate' – displays the bitrate, 'sizebitrate' displays size followed by bitrate
		},

		isDisabled: false,
		inUpdateLayout:false,
		selectSourceTitle: gM( 'mwe-embedplayer-select_source' ),
		switchSourceTitle: gM( 'mwe-embedplayer-switch_source' ),
        AutoTitle: gM( 'mwe-embedplayer-auto_source' ),
		saveBackgroundColor: null, // used to save background color upon disable and rotate and return it when enabled again to prevent rotating box around the icon when custom style is applied

        sourcesList: [],
        firstPlay:false,

		setup: function(){
			var _this = this;

			this.bind( 'playerReady sourcesReplaced', function(){
				_this.buildMenu();
			});

            this.bind( 'firstPlay', function(){
                _this.firstPlay = true;
            });

			this.bind( 'SourceChange', function(){
				var selectedSrc = _this.getPlayer().mediaElement.selectedSource;
				var selectedId = selectedSrc.getAssetId();

				//if selected source is not part of the menu, show the source before it as the selected one
				//workaround when auto switch with kplayer occurred and the selected source is not part of the menu data provider
				if ( selectedSrc.skip ) {
					var sources = _this.getSources();
					for ( var i = 0; i< sources.length; i++ ) {
						//look for the closest flavor
						if ( selectedSrc.getSrc() == sources[i].getSrc() ) {
							if ( i == 0 && sources.length > 1 ) {
								selectedId = sources[i+1].getAssetId();
							} else {
								selectedId = sources[i-1].getAssetId();
							}
							break;
						}
					}
				}
				_this.getMenu().setActive({'key': 'id', 'val': selectedId});
				_this.onEnable();
			});

			this.bind( 'sourceSwitchingStarted', function(){
				_this.onDisable();
			});
			this.bind( 'sourceSwitchingEnd', function(newIndex){
                _this.onEnable();
			});
            this.bind( 'onHideControlBar', function(){
                if ( _this.getMenu().isOpen() )
                    _this.getMenu().close();
            });

			// Check for switch on resize option
			if( this.getConfig( 'switchOnResize' ) ){
				this.bind( 'updateLayout', function(){
					// workaround to avoid the amount of 'updateLayout' events
					// !seeking will avoid getting current time equal to 0
					if ( !_this.inUpdateLayout && !_this.embedPlayer.seeking ){
						_this.inUpdateLayout = true;
						_this.updateLayoutTimout = setTimeout(function() {
							_this.inUpdateLayout = false;
						},1000);
						//if we're working with kplayer - mp4 can't be seeked - so disable this feature
						//this only effect native for now
						if (_this.embedPlayer.instanceOf === "Native" && !_this.embedPlayer.isInSequence() ) {
							// TODO add additional logic for "auto" where multiple bitrates
							// exist at the same resolution.
							var selectedSource = _this.embedPlayer.mediaElement.autoSelectSource(_this.embedPlayer.supportsURLTimeEncoding(), _this.embedPlayer.startTime, _this.embedPlayer.pauseTime);
							if ( selectedSource ) { // source was found
								_this.embedPlayer.switchSrc( selectedSource );
							}
						} else {
							mw.log( "sourceSelector - switchOnResize is ignored - Can't switch source since not using native player or during ad playback");
						}
					}
				});
			}
		},
		getSources: function(){
			return this.getPlayer().getSources();
		},

		buildMenu: function(){
			var _this = this;

			// Destroy old menu
			this.getMenu().destroy();

			var sources = this.getSources().slice(0);

			if( ! sources.length ){
				_this.log("Error with getting sources");
				return ;
			}

            //add Auto for addaptive bitrate streams
            if ( !this.handleAdaptiveBitrateAndContinue() )
                return;

			if( sources.length == 1 ){
				// no need to do building menu logic.
				this.addSourceToMenu( sources[0], _this.getSourceTitle(sources[0]) );
				return ;
			}
			// sort by height then bitrate:
			sources.sort(function(a,b){
				var hdiff = b.getHeight() - a.getHeight();
				if( hdiff != 0 ){
					return hdiff;
				}
				return b.getBitrate() - a.getBitrate();
			});

			// if simple format don't include more then two sources per size in menu
			if( _this.getConfig( 'simpleFormat' ) ){
				var prevSource = null;
				var twice = false;
				$.each( sources, function( sourceIndex, source ) {
					if( ! prevSource ){
						prevSource = source;
						return true;
					}
					if( source.getHeight() != 0
						&&
						( _this.getSourceSizeName( prevSource )
							==
							_this.getSourceSizeName( source ) )
						){
						//if the selected source has the same height, skip this source
						var selectedSrc = _this.getPlayer().mediaElement.selectedSource;
						if ( selectedSrc
							&&
							!_this.isSourceSelected( source )
							&&
							!_this.isSourceSelected( prevSource )
							&&
							( _this.getSourceSizeName( source )
								==
								_this.getSourceSizeName( selectedSrc ) )
							){
							source.skip = true;
						}
						else if( twice ){
							// don't skip if this is the default source:
							if( !_this.isSourceSelected( source ) ){
								// skip this source
								source.skip = true;
							} else {
								source.skip = false;
							}
							prevSource = source;
							return true;
						}
						// set the first source as "HQ"
						prevSource.hq = true;
						twice = true;
					} else {
						twice = false;
					}
					// always update prevSource
					prevSource = source;
				});
			}

			var prevSource = null;
			$.each( sources, function( sourceIndex, source ) {
				if( source.skip ){
					return true;
				}
				// Output the player select code:
				var supportingPlayers = mw.EmbedTypes.getMediaPlayers().getMIMETypePlayers( source.getMIMEType() );
				for ( var i = 0; i < supportingPlayers.length ; i++ ) {
					if(
						(
							_this.getPlayer().selectedPlayer === undefined
								&&
								supportingPlayers[i].library == 'Native'
							)
							||
							(
								_this.getPlayer().selectedPlayer !== undefined
									&&
									supportingPlayers[i].library == _this.getPlayer().selectedPlayer.library
								)
						){
						_this.addSourceToMenu( source );
					}
				}
			});
		},
		isSourceSelected: function( source ){
			var _this = this;
			return ( _this.getPlayer().mediaElement.selectedSource && source.getSrc()
				==
				_this.getPlayer().mediaElement.selectedSource.getSrc()
				);
		},
        handleAdaptiveBitrateAndContinue: function (){
            //Silverlight smoothStream
            if( ( this.getPlayer().streamerType === "smoothStream" ) ){
                this.addAutoToMenu();
                return true;
            }

            //HLS, HDS
            if(  this.getPlayer().streamerType != "http" && !this.getPlayer().isPlaying() ){
                this.addAutoToMenu();
                return false;
            }

            if( this.getPlayer().streamerType != "http" && this.firstPlay ){ //add and select Auto for adaptive bitrate
                this.addAutoToMenu();
                this.firstPlay = false;
            }
            return true;
        },
        addAutoToMenu: function (){
            var _this = this;
            this.getMenu().addItem({
                'label': _this.AutoTitle,
                'callback': function () {
                    _this.getPlayer().switchSrc("-1");
                },
               'active': true
            });
        },
		addSourceToMenu: function( source ){
			var _this = this;

            var sourceLabel = this.getSourceTitle( source );
            if( $.inArray(sourceLabel, this.sourcesList) == -1 ) {

                this.sourcesList.push(sourceLabel);

                this.getMenu().addItem({
                    'label': sourceLabel,
                    'attributes': {
                        'id': source.getAssetId()
                    },
                    'callback': function () {
                        _this.getPlayer().switchSrc(source);
                    },
                    'active': _this.isSourceSelected(source)
                });
            }
		},
        getSourceSizeName: function( source ){
			if( source.getHeight() < 255 ){
				return '240P';
			} else if( source.getHeight() < 370 ){
				return '360P';
			} else if( source.getHeight() < 500 ){
				return '480P';
			} else if( source.getHeight() < 800 ){
				return '720P';
			} else {
				return '1080P';
			}
		},
		getSourceTitle: function( source ){
			// We should return "Auto" for Apple HLS
			if( source.getMIMEType() == 'application/vnd.apple.mpegurl' ) {
				return _this.AutoTitle;
			}

            var title = '';
            switch( this.getConfig( 'dispalyMode' ) ){
                case 'size' :
                    title = this.getSourceTitleSize(source);
                    break;
                case 'bitrate' :
                    title = this.getSourceTitleBitrate(source);
                    break;
                case 'sizebitrate' :
                    title = this.getSourceTitleSizeBitrate(source);
                    break;
            }
            if( this.getConfig( 'simpleFormat' ) ){
                if( source.hq ){
                    title += ' HQ';
                }
            } else {
                // include type if not simple format
                title += ' ' + source.getMIMEType().replace('video/', '');
            }
            return title;
		},
        getSourceTitleSize: function( source ){
            var title = '';
            if( source.getHeight() ){
                title = this.getSourceSizeName( source );
            } else { //fallback for a case we don't have a frame size (height) for the source (for example HLS source)
                title = this.getSourceTitleBitrate(source);
            }
            return title;
        },
        getSourceTitleBitrate: function( source ){
            var title = '';
            if ( source.getBitrate() ) {
                var bits = ( Math.round( source.getBitrate() / 1024 * 10 ) / 10 ) + '';
                if( bits[0] == '0' ){
                    bits = bits.substring(1);
                }
                title+= ' ' + bits + 'Mbs ';
            }
            return title;
        },
        getSourceTitleSizeBitrate: function( source ){
            var title = '';
            if( source.getHeight() ){
                title = this.getSourceSizeName( source ) + ' ';
            }
            title += this.getSourceTitleBitrate(source);
            return title;
        },
		toggleMenu: function(){
			if ( this.isDisabled ) {
				return;
			}
			this.getMenu().toggle();
		},
		getComponent: function() {
			var _this = this;
			if( !this.$el ) {
				var $menu = $( '<ul />' );
				var $button = $( '<button />' )
					.addClass( 'btn icon-cog' )
					.attr('title', _this.selectSourceTitle)
					.click( function(e){
						_this.toggleMenu();
					});
				this.setAccessibility($button,_this.selectSourceTitle);
				this.$el = $( '<div />' )
					.addClass( 'dropup' + this.getCssClass() )
					.append( $button, $menu );
			}
			return this.$el;
		},
		getMenu: function(){
			if( !this.menu ) {
				this.menu = new mw.KMenu(this.getComponent().find('ul'), {
					tabIndex: this.getBtn().attr('tabindex')
				});
			}
			return this.menu;
		},
		getBtn: function(){
			return this.getComponent().find( 'button' );
		},
		onEnable: function(){
			this.isDisabled = false;
			this.updateTooltip( this.selectSourceTitle );
			this.getComponent().find('button').removeClass( 'rotate' );
			this.getBtn().removeClass( 'disabled' );
			if (this.saveBackgroundColor){
				this.getComponent().find('button').attr('style', 'background-color: ' + this.saveBackgroundColor + ' !important');
			}
		},
		onDisable: function(){
			this.isDisabled = true;
			this.updateTooltip( this.switchSourceTitle );
			this.getComponent().find('button').addClass( 'rotate' );
			this.saveBackgroundColor = this.getComponent().find('button').css("background-color");
			this.getComponent().find('button').attr('style', 'background-color: null !important');
			this.getComponent().removeClass( 'open' );
			this.getBtn().addClass( 'disabled' );
		}
	}));

} )( window.mw, window.jQuery );		<|endoftext|>


<commit_before>( function( mw, $ ) {"use strict";

	mw.PluginManager.add( 'sourceSelector', mw.KBaseComponent.extend({

		defaultConfig: {
			"parent": "controlsContainer",
			"order": 61,
			"displayImportance": 'low',
			"align": "right",
			"showTooltip": true,
			"switchOnResize": false,
			"simpleFormat": true
		},

		isDisabled: false,
		inUpdateLayout:false,
		selectSourceTitle: gM( 'mwe-embedplayer-select_source' ),
		switchSourceTitle: gM( 'mwe-embedplayer-switch_source' ),

		setup: function(){
			var _this = this;

			this.bind( 'playerReady sourcesReplaced', function(){
				_this.buildMenu();
			});

			this.bind( 'SourceChange', function(){
				var selectedSrc = _this.getPlayer().mediaElement.selectedSource;
				var selectedId = selectedSrc.getAssetId();

				//if selected source is not part of the menu, show the source before it as the selected one
				//workaround when auto switch with kplayer occurred and the selected source is not part of the menu data provider
				if ( selectedSrc.skip ) {
					var sources = _this.getSources();
					for ( var i = 0; i< sources.length; i++ ) {
						//look for the closest flavor
						 if ( selectedSrc.getSrc() == sources[i].getSrc() ) {
							if ( i == 0 && sources.length > 1 ) {
								selectedId = sources[i+1].getAssetId();
							} else {
								selectedId = sources[i-1].getAssetId();
							}
							 break;
						 }
					}
				}
				_this.getMenu().setActive({'key': 'id', 'val': selectedId});
				_this.onEnable();
			});

			this.bind( 'sourceSwitchingStarted', function(){
				_this.onDisable();
			});

			// Check for switch on resize option
			if( this.getConfig( 'switchOnResize' ) ){
				this.bind( 'updateLayout', function(){
					// workaround to avoid the amount of 'updateLayout' events
					// !seeking will avoid getting current time equal to 0
					if ( !_this.inUpdateLayout && !_this.embedPlayer.seeking ){
						_this.inUpdateLayout = true;
						_this.updateLayoutTimout = setTimeout(function() {
							_this.inUpdateLayout = false;
						},1000);
						//if we're working with kplayer - mp4 can't be seeked - so disable this feature
						//this only effect native for now
						if (_this.embedPlayer.instanceOf === "Native") {
							// TODO add additional logic for "auto" where multiple bitrates
							// exist at the same resolution.
							var selectedSource = _this.embedPlayer.mediaElement.autoSelectSource();
							if ( selectedSource ) { // source was found
								_this.embedPlayer.switchSrc( selectedSource );
							}
						} else {
							mw.log( "sourceSelector - switchOnResize is ignored - Can't switch source since not using native player");
						}
					}
				});
			}
		},
		getSources: function(){
			return this.getPlayer().mediaElement.getPlayableSources();
		},

		buildMenu: function(){
			var _this = this;

			// Destroy old menu
			this.getMenu().destroy();

			var sources = this.getSources();

			if( ! sources.length ){
				_this.log("Error with getting sources");
				return ;
			}

			if( sources.length == 1 ){
				// no need to do building menu logic.
				this.addSourceToMenu( sources[0], _this.getSourceTitle(sources[0]) );
				return ;
			}
			// sort by height then bitrate:
			sources.sort(function(a,b){
				var hdiff = b.getHeight() - a.getHeight();
				if( hdiff != 0 ){
					return hdiff;
				}
				return b.getBitrate() - a.getBitrate();
			});

			// if simple format don't include more then two sources per size in menu
			if( _this.getConfig( 'simpleFormat' ) ){
				var prevSource = null;
				var twice = false;
				$.each( sources, function( sourceIndex, source ) {
					if( ! prevSource ){
						prevSource = source;
						return true;
					}
					if( source.getHeight() != 0
						&&
						( _this.getSourceSizeName( prevSource )
							==
						_this.getSourceSizeName( source ) )
					){
						//if the selected source has the same height, skip this source
						var selectedSrc = _this.getPlayer().mediaElement.selectedSource;
						if ( selectedSrc
							&&
							!_this.isSourceSelected( source )
							&&
							!_this.isSourceSelected( prevSource )
							&&
							( _this.getSourceSizeName( source )
								==
							_this.getSourceSizeName( selectedSrc ) )
						){
							source.skip = true;
						}
						else if( twice ){
							// don't skip if this is the default source:
							if( !_this.isSourceSelected( source ) ){
								// skip this source
								source.skip = true;
							} else {
								source.skip = false;
							}
							prevSource = source;
							return true;
						}
						// set the first source as "HQ"
						prevSource.hq = true;
						twice = true;
					} else {
						twice = false;
					}
					// always update prevSource
					prevSource = source;
				});
			}

			var prevSource = null;
			$.each( sources, function( sourceIndex, source ) {
				if( source.skip ){
					return true;
				}
				// Output the player select code:
				var supportingPlayers = mw.EmbedTypes.getMediaPlayers().getMIMETypePlayers( source.getMIMEType() );
				for ( var i = 0; i < supportingPlayers.length ; i++ ) {
					if(
						(
							_this.getPlayer().selectedPlayer === undefined
							&&
							supportingPlayers[i].library == 'Native'
						)
							||
						(
							_this.getPlayer().selectedPlayer !== undefined
							&&
							supportingPlayers[i].library == _this.getPlayer().selectedPlayer.library
						)
					){
						_this.addSourceToMenu( source );
					}
				}
			});
		},
		isSourceSelected: function( source ){
			var _this = this;
			return ( _this.getPlayer().mediaElement.selectedSource && source.getSrc()
					==
					_this.getPlayer().mediaElement.selectedSource.getSrc()
				);
		},
		addSourceToMenu: function( source ){
			var _this = this;;
			this.getMenu().addItem({
				'label': this.getSourceTitle( source ),
				'attributes': {
					'id': source.getAssetId()
				},
				'callback': function(){
					_this.getPlayer().switchSrc( source );
				},
				'active': _this.isSourceSelected( source )
			});
		},
		getSourceSizeName: function( source ){
			if( source.getHeight() < 255 ){
				return '240P';
			} else if( source.getHeight() < 370 ){
				return '360P';
			} else if( source.getHeight() < 500 ){
				return '480P';
			} else if( source.getHeight() < 800 ){
				return '720P';
			} else {
				return '1080P';
			}
		},
		getSourceTitle: function( source ){
			// We should return "Auto" for Apple HLS
			if( source.getMIMEType() == 'application/vnd.apple.mpegurl' ) {
				return 'Auto';
			}
			var title = '';
			if( source.getHeight() ){
				title+= this.getSourceSizeName( source );
			} else if ( source.getBitrate() ) {
					var bits = ( Math.round( source.getBitrate() / 1024 * 10 ) / 10 ) + '';
					if( bits[0] == '0' ){
						bits = bits.substring(1);
					}
					title+= ' ' + bits + 'Mbs ';
			}
			if( this.getConfig( 'simpleFormat' ) ){
				if( source.hq ){
					title += ' HQ';
				}
			} else {
				// include type if not simple format
				title += ' ' + source.getMIMEType().replace('video/', '');
			}
			return title;
		},
		toggleMenu: function(){
			if ( this.isDisabled ) {
				return;
			}
			this.getMenu().toggle();
		},
		getComponent: function() {
			var _this = this;
			if( !this.$el ) {
				var $menu = $( '<ul />' );
				var $button = $( '<button />' )
								.addClass( 'btn icon-cog' )
								.attr('title', _this.selectSourceTitle)
								.click( function(e){
									_this.toggleMenu();
								});
                this.setAccessibility($button,_this.selectSourceTitle);
				this.$el = $( '<div />' )
								.addClass( 'dropup' + this.getCssClass() )
								.append( $button, $menu );
			}
			return this.$el;
		},
		getMenu: function(){
			if( !this.menu ) {
				this.menu = new mw.KMenu(this.getComponent().find('ul'), {
					tabIndex: this.getBtn().attr('tabindex')
				});
			}
			return this.menu;
		},
		getBtn: function(){
			return this.getComponent().find( 'button' );
		},
		onEnable: function(){
			this.isDisabled = false;
			this.updateTooltip( this.selectSourceTitle );
			this.getComponent().find('button').removeClass( 'rotate' );
			this.getBtn().removeClass( 'disabled' );
		},
		onDisable: function(){
			this.isDisabled = true;
			this.updateTooltip( this.switchSourceTitle );
			this.getComponent().find('button').addClass( 'rotate' );
			this.getComponent().removeClass( 'open' );
			this.getBtn().addClass( 'disabled' );
		}
	}));

} )( window.mw, window.jQuery );		<commit_msg>#issue-676 #time 1h #comment save background color upon disable and rotate and return it when enabled again to prevent rotating box around the icon when custom style is applied link to ticket: https://github.com/kaltura/mwEmbed/issues/676<commit_after>( function( mw, $ ) {"use strict";

	mw.PluginManager.add( 'sourceSelector', mw.KBaseComponent.extend({

		defaultConfig: {
			"parent": "controlsContainer",
			"order": 61,
			"displayImportance": 'low',
			"align": "right",
			"showTooltip": true,
			"switchOnResize": false,
			"simpleFormat": true
		},

		isDisabled: false,
		inUpdateLayout:false,
		selectSourceTitle: gM( 'mwe-embedplayer-select_source' ),
		switchSourceTitle: gM( 'mwe-embedplayer-switch_source' ),
		saveBackgroundColor: null, // used to save background color upon disable and rotate and return it when enabled again to prevent rotating box around the icon when custom style is applied

		setup: function(){
			var _this = this;

			this.bind( 'playerReady sourcesReplaced', function(){
				_this.buildMenu();
			});

			this.bind( 'SourceChange', function(){
				var selectedSrc = _this.getPlayer().mediaElement.selectedSource;
				var selectedId = selectedSrc.getAssetId();

				//if selected source is not part of the menu, show the source before it as the selected one
				//workaround when auto switch with kplayer occurred and the selected source is not part of the menu data provider
				if ( selectedSrc.skip ) {
					var sources = _this.getSources();
					for ( var i = 0; i< sources.length; i++ ) {
						//look for the closest flavor
						if ( selectedSrc.getSrc() == sources[i].getSrc() ) {
							if ( i == 0 && sources.length > 1 ) {
								selectedId = sources[i+1].getAssetId();
							} else {
								selectedId = sources[i-1].getAssetId();
							}
							break;
						}
					}
				}
				_this.getMenu().setActive({'key': 'id', 'val': selectedId});
				_this.onEnable();
			});

			this.bind( 'sourceSwitchingStarted', function(){
				_this.onDisable();
			});

			// Check for switch on resize option
			if( this.getConfig( 'switchOnResize' ) ){
				this.bind( 'updateLayout', function(){
					// workaround to avoid the amount of 'updateLayout' events
					// !seeking will avoid getting current time equal to 0
					if ( !_this.inUpdateLayout && !_this.embedPlayer.seeking ){
						_this.inUpdateLayout = true;
						_this.updateLayoutTimout = setTimeout(function() {
							_this.inUpdateLayout = false;
						},1000);
						//if we're working with kplayer - mp4 can't be seeked - so disable this feature
						//this only effect native for now
						if (_this.embedPlayer.instanceOf === "Native") {
							// TODO add additional logic for "auto" where multiple bitrates
							// exist at the same resolution.
							var selectedSource = _this.embedPlayer.mediaElement.autoSelectSource();
							if ( selectedSource ) { // source was found
								_this.embedPlayer.switchSrc( selectedSource );
							}
						} else {
							mw.log( "sourceSelector - switchOnResize is ignored - Can't switch source since not using native player");
						}
					}
				});
			}
		},
		getSources: function(){
			return this.getPlayer().mediaElement.getPlayableSources();
		},

		buildMenu: function(){
			var _this = this;

			// Destroy old menu
			this.getMenu().destroy();

			var sources = this.getSources();

			if( ! sources.length ){
				_this.log("Error with getting sources");
				return ;
			}

			if( sources.length == 1 ){
				// no need to do building menu logic.
				this.addSourceToMenu( sources[0], _this.getSourceTitle(sources[0]) );
				return ;
			}
			// sort by height then bitrate:
			sources.sort(function(a,b){
				var hdiff = b.getHeight() - a.getHeight();
				if( hdiff != 0 ){
					return hdiff;
				}
				return b.getBitrate() - a.getBitrate();
			});

			// if simple format don't include more then two sources per size in menu
			if( _this.getConfig( 'simpleFormat' ) ){
				var prevSource = null;
				var twice = false;
				$.each( sources, function( sourceIndex, source ) {
					if( ! prevSource ){
						prevSource = source;
						return true;
					}
					if( source.getHeight() != 0
						&&
						( _this.getSourceSizeName( prevSource )
							==
							_this.getSourceSizeName( source ) )
						){
						//if the selected source has the same height, skip this source
						var selectedSrc = _this.getPlayer().mediaElement.selectedSource;
						if ( selectedSrc
							&&
							!_this.isSourceSelected( source )
							&&
							!_this.isSourceSelected( prevSource )
							&&
							( _this.getSourceSizeName( source )
								==
								_this.getSourceSizeName( selectedSrc ) )
							){
							source.skip = true;
						}
						else if( twice ){
							// don't skip if this is the default source:
							if( !_this.isSourceSelected( source ) ){
								// skip this source
								source.skip = true;
							} else {
								source.skip = false;
							}
							prevSource = source;
							return true;
						}
						// set the first source as "HQ"
						prevSource.hq = true;
						twice = true;
					} else {
						twice = false;
					}
					// always update prevSource
					prevSource = source;
				});
			}

			var prevSource = null;
			$.each( sources, function( sourceIndex, source ) {
				if( source.skip ){
					return true;
				}
				// Output the player select code:
				var supportingPlayers = mw.EmbedTypes.getMediaPlayers().getMIMETypePlayers( source.getMIMEType() );
				for ( var i = 0; i < supportingPlayers.length ; i++ ) {
					if(
						(
							_this.getPlayer().selectedPlayer === undefined
								&&
								supportingPlayers[i].library == 'Native'
							)
							||
							(
								_this.getPlayer().selectedPlayer !== undefined
									&&
									supportingPlayers[i].library == _this.getPlayer().selectedPlayer.library
								)
						){
						_this.addSourceToMenu( source );
					}
				}
			});
		},
		isSourceSelected: function( source ){
			var _this = this;
			return ( _this.getPlayer().mediaElement.selectedSource && source.getSrc()
				==
				_this.getPlayer().mediaElement.selectedSource.getSrc()
				);
		},
		addSourceToMenu: function( source ){
			var _this = this;;
			this.getMenu().addItem({
				'label': this.getSourceTitle( source ),
				'attributes': {
					'id': source.getAssetId()
				},
				'callback': function(){
					_this.getPlayer().switchSrc( source );
				},
				'active': _this.isSourceSelected( source )
			});
		},
		getSourceSizeName: function( source ){
			if( source.getHeight() < 255 ){
				return '240P';
			} else if( source.getHeight() < 370 ){
				return '360P';
			} else if( source.getHeight() < 500 ){
				return '480P';
			} else if( source.getHeight() < 800 ){
				return '720P';
			} else {
				return '1080P';
			}
		},
		getSourceTitle: function( source ){
			// We should return "Auto" for Apple HLS
			if( source.getMIMEType() == 'application/vnd.apple.mpegurl' ) {
				return 'Auto';
			}
			var title = '';
			if( source.getHeight() ){
				title+= this.getSourceSizeName( source );
			} else if ( source.getBitrate() ) {
				var bits = ( Math.round( source.getBitrate() / 1024 * 10 ) / 10 ) + '';
				if( bits[0] == '0' ){
					bits = bits.substring(1);
				}
				title+= ' ' + bits + 'Mbs ';
			}
			if( this.getConfig( 'simpleFormat' ) ){
				if( source.hq ){
					title += ' HQ';
				}
			} else {
				// include type if not simple format
				title += ' ' + source.getMIMEType().replace('video/', '');
			}
			return title;
		},
		toggleMenu: function(){
			if ( this.isDisabled ) {
				return;
			}
			this.getMenu().toggle();
		},
		getComponent: function() {
			var _this = this;
			if( !this.$el ) {
				var $menu = $( '<ul />' );
				var $button = $( '<button />' )
					.addClass( 'btn icon-cog' )
					.attr('title', _this.selectSourceTitle)
					.click( function(e){
						_this.toggleMenu();
					});
				this.setAccessibility($button,_this.selectSourceTitle);
				this.$el = $( '<div />' )
					.addClass( 'dropup' + this.getCssClass() )
					.append( $button, $menu );
			}
			return this.$el;
		},
		getMenu: function(){
			if( !this.menu ) {
				this.menu = new mw.KMenu(this.getComponent().find('ul'), {
					tabIndex: this.getBtn().attr('tabindex')
				});
			}
			return this.menu;
		},
		getBtn: function(){
			return this.getComponent().find( 'button' );
		},
		onEnable: function(){
			this.isDisabled = false;
			this.updateTooltip( this.selectSourceTitle );
			this.getComponent().find('button').removeClass( 'rotate' );
			this.getBtn().removeClass( 'disabled' );
			if (this.saveBackgroundColor){
				this.getComponent().find('button').attr('style', 'background-color: ' + this.saveBackgroundColor + ' !important');
			}
		},
		onDisable: function(){
			this.isDisabled = true;
			this.updateTooltip( this.switchSourceTitle );
			this.getComponent().find('button').addClass( 'rotate' );
			this.saveBackgroundColor = this.getComponent().find('button').css("background-color");
			this.getComponent().find('button').attr('style', 'background-color: null !important');
			this.getComponent().removeClass( 'open' );
			this.getBtn().addClass( 'disabled' );
		}
	}));

} )( window.mw, window.jQuery );		<|endoftext|>


<commit_before>var assert = require("assert");
var sync = require('../src');

describe('Basic', function(){
  describe('return value', function(){
    it('should return value for key', function(){
      assert.equal('value', sync.key);
    })
  })
})
<commit_msg>Semicolons in test<commit_after>var assert = require("assert");
var sync = require('../src');

describe('Basic', function(){
  describe('return value', function(){
    it('should return value for key', function(){
      assert.equal('value', sync.key);
    });
  });
});
<|endoftext|>


<commit_before>import actionTypes from '../action-types';
import templates from '../templates';
import GuideProtocol from '../utilities/guide-protocol';
import { GUIDE_CONNECTED, GUIDE_ERRORED,
  GUIDE_HINT_RECEIVED, GUIDE_ALERT_RECEIVED } from '../modules/notifications';
import { requestRemediation } from '../modules/remediation';
import GeneticsUtils from '../utilities/genetics-utils';
import io from 'socket.io-client';
import AuthoringUtils from '../utilities/authoring-utils';
import { cloneDeep } from 'lodash';

var socket = null,
    session = "",
    sequence = 0,
    isConnectonEstablished = false,
    msgQueue = [];

export function initializeITSSocket(guideServer, socketPath, store) {
  socket = io(guideServer, {
    path: socketPath,
    reconnection: false
  });

  socket.on('connect', data =>
    store.dispatch({type: GUIDE_CONNECTED, data})
  );

  const receiveITSEvent = (data) => {
    var event = GuideProtocol.Event.fromJson(data);
    console.info(`%c Received from ITS: ${event.action} ${event.target}`, 'color: #f99a00', event);

    if (event.isMatch("ITS", "HINT", "USER")) {
      // TODO: Re-enable dispatch once ITS is fixed
      console.log("ITS provided hint to user:", event.context.dialog);
      //store.dispatch({type: GUIDE_HINT_RECEIVED, data: event});
    } else if (event.isMatch("ITS", "REMEDIATE", "USER")) {
      // TODO: Re-enable dispatch once ITS is fixed
      console.log("ITS spoke to user:", event.context.dialog);
      // store.dispatch(requestRemediation(event));
    } else if (event.isMatch("ITS", "SPOKETO", "USER")) {
      // do nothing with this
      console.log("ITS spoke to user:", event.context.dialog);
    } else if (event.isMatch("ITS", "ISSUED", "ALERT")) {
      // TODO: Re-enable dispatch once ITS is fixed
      console.log("ITS alerted user:", event.context.dialog);
      //store.dispatch({type: GUIDE_ALERT_RECEIVED, data: event});
    } else {
      console.log("%c Unhandled ITS message:", 'color: #f99a00', event.toString());
    }
  };

  socket.on(GuideProtocol.Event.Channel, receiveITSEvent);

  // for testing
  window.GV_TEST_receiveITSEvent = receiveITSEvent;

  socket.on('error', data =>
    store.dispatch({type: GUIDE_ERRORED, data})
  );
  socket.on('connect_error', data =>
    store.dispatch({type: GUIDE_ERRORED, data})
  );
  socket.on('reconnect_error', data =>
    store.dispatch({type: GUIDE_ERRORED, data})
  );

  return socket;
}

export default loggingMetadata => store => next => action => {

  let prevState = store.getState(),
      result = next(action),
      nextState = store.getState();

  if (action.type === actionTypes.SESSION_STARTED) {
    session = action.session;
  }

  switch(action.type) {
    case GUIDE_ERRORED: {
      console.log("%c Error connecting to ITS!", 'color: #f99a00');
      socket.close();
      break;
    }
    case GUIDE_CONNECTED: {
      console.log("%c ITS Connection Success!", 'color: #f99a00');
      if (msgQueue.length) {
        msgQueue.forEach((msg, index) => {
          // use setTimeout to stagger messages sent to ITS
          setTimeout(() => {
            console.log("%c Sending queued message to ITS:", 'color: #f99a00', msg);
            sendMessage(msg, socket);
          }, 10 * index);
        });
        msgQueue = [];
      }
      isConnectonEstablished = true;
      break;
    }
    case GUIDE_HINT_RECEIVED:
    case GUIDE_ALERT_RECEIVED: {
      break;
    }
    default: {
      // other action types - send to ITS
      if (action.meta && action.meta.itsLog){
        let message = createLogEntry(loggingMetadata, action, prevState, nextState);
        if (!isConnectonEstablished) {
          console.log("%c Queuing message for ITS:", 'color: #f99a00', message);
          msgQueue.push(message);
        }
        else {
          console.log("%c Sending message to ITS:", 'color: #f99a00', message, JSON.stringify(message));
          sendMessage(message, socket);
        }
      }
    }
  }

  return result;
};

function sendMessage(message, socket) {
  socket.emit(GuideProtocol.Event.Channel, JSON.stringify(message));
}

function getValue(obj, path) {
  for (let i=0, ii=path.length; i<ii; i++){
      obj = obj[path[i]];
  }
  return obj;
}

// exported for unit test purposes
export function makeMutable(obj) {
  if (!obj) return obj;
  if (obj.asMutable) {
    return obj.asMutable({deep: true});
  } else if (obj.isArray) {
    for (let item of obj) {
      item = makeMutable(item);
    }
  } else if (typeof obj === "object") {
    for (let key in obj) {
      obj[key] = makeMutable(obj[key]);
    }
  }
  return obj;
}

// exported for unit test purposes
export function changePropertyValues(obj, key, func) {
  if (!obj) return;
  if (obj.isArray) {
    for (let item of obj) {
      changePropertyValues(item, key, func);
    }
  } else for (let prop in obj) {
      if (prop === key) {
        obj[prop] = func(obj[prop]);
      } else if (typeof obj[prop] === "object") {
        changePropertyValues(obj[prop], key, func);
      }
    }
}

function getChallengeType(state) {
  if (state.location && state.location.id === "hatchery") {
    return "Hatchery";
  }
  if (state.challengeType && state.challengeType === "match-target") {
    if (state.template === "FVEggGame") {
      return "Breeding";
    }
    return "Sim";
  }
  if (state.challengeType && state.challengeType === "submit-parents") {
    return "Siblings";
  }
}

function getSelectableAttributes(nextState) {
  if ((nextState.template && nextState.template === "FVGenomeChallenge") ||
      (nextState.challengeType && nextState.challengeType === "submit-parents")) {
    return ["sex", ...nextState.userChangeableGenes];
  }
  if (nextState.template && nextState.template === "FVEggSortGame") {
    return ["sex", ...nextState.visibleGenes];
  }
}

function getTarget(nextState) {
  let targetIndex;
  if ((nextState.template && nextState.template === "FVGenomeChallenge") &&
      (nextState.challengeType && nextState.challengeType === "match-target")) {
    targetIndex = 1;
  } else {
    return;
  }
  let targetDrakeOrg = GeneticsUtils.convertDrakeToOrg(nextState.drakes[targetIndex]);
  return {
    sex: targetDrakeOrg.sex,
    phenotype: targetDrakeOrg.phenotype.characteristics
  };
}

function getSelected(action, nextState) {
  let userIndex;
  if (action.type === actionTypes.ALLELE_CHANGED &&
      (nextState.template && nextState.template === "FVGenomeChallenge") &&
      (nextState.challengeType && nextState.challengeType === "match-target")) {
    userIndex = 0;
  } else {
    return;
  }
  let userDrakeOrg = GeneticsUtils.convertDrakeToOrg(nextState.drakes[userIndex]);
  return {
    sex: userDrakeOrg.sex,
    alleles: userDrakeOrg.getAlleleString()
  };
}

function createLogEntry(loggingMetadata, action, prevState, nextState){
  let event = { ...action.meta.itsLog },
      context = { ...action },
      routeSpec = nextState.routeSpec;

  context.routeSpec = routeSpec;
  context.groupId = "Test-v3";
  context.challengeId = AuthoringUtils.getChallengeId(nextState.authoring, routeSpec);
  context.classId = loggingMetadata.classInfo;

  let challengeType = getChallengeType(prevState);
  if (challengeType) {
    context.challengeType = challengeType;
  }

  let selectableAttributes = getSelectableAttributes(nextState);
  if (selectableAttributes) {
    context.selectableAttributes = selectableAttributes;
  }

  let target = context.target || getTarget(prevState);
  if (target) {
    context.target = target;
  }

  let previous = context.selected || getSelected(action, prevState);
  if (previous) {
    context.previous = previous;
  }

  let selected = context.selected || getSelected(action, nextState);
  if (selected) {
    context.selected = selected;
  }

  if (action.meta.logNextState) {
    for (let prop in action.meta.logNextState) {
      context[prop] = getValue(nextState, action.meta.logNextState[prop]);
    }
  }
  if (action.meta.logTemplateState) {
    let Template = templates[nextState.template];
    if (Template.logState) {
      let templateState = Template.logState(nextState);
      context = {
        ...context,
        ...templateState
      };
    }
  }
  if (action.meta.dontLog) {
    for (let prop of action.meta.dontLog) {
      delete context[prop];
    }
  }

  delete context.type;
  delete context.meta;

  context = makeMutable(cloneDeep(context));

  let changeSexToString = sex => sex === 0 ? "male" : sex === 1 ? "female" : sex;
  changePropertyValues(context, "sex", changeSexToString);
  changePropertyValues(context, "newSex", changeSexToString);

  if (prevState.remediation) {
    context.remediation = true;
    context.challengeId = `${context.challengeId}-REMEDIATION`;
  }

  const message =
    {
      classInfo: loggingMetadata.classInfo,
      studentId: loggingMetadata.studentId,
      externalId: loggingMetadata.externalId,
      session: session,
      time: Date.now(),
      sequence: sequence,
      ...event,
      context: context
    };

  sequence++;
  return message;
}
<commit_msg>fix typo<commit_after>import actionTypes from '../action-types';
import templates from '../templates';
import GuideProtocol from '../utilities/guide-protocol';
import { GUIDE_CONNECTED, GUIDE_ERRORED,
  GUIDE_HINT_RECEIVED, GUIDE_ALERT_RECEIVED } from '../modules/notifications';
import { requestRemediation } from '../modules/remediation';
import GeneticsUtils from '../utilities/genetics-utils';
import io from 'socket.io-client';
import AuthoringUtils from '../utilities/authoring-utils';
import { cloneDeep } from 'lodash';

var socket = null,
    session = "",
    sequence = 0,
    isConnectonEstablished = false,
    msgQueue = [];

export function initializeITSSocket(guideServer, socketPath, store) {
  socket = io(guideServer, {
    path: socketPath,
    reconnection: false
  });

  socket.on('connect', data =>
    store.dispatch({type: GUIDE_CONNECTED, data})
  );

  const receiveITSEvent = (data) => {
    var event = GuideProtocol.Event.fromJson(data);
    console.info(`%c Received from ITS: ${event.action} ${event.target}`, 'color: #f99a00', event);

    if (event.isMatch("ITS", "HINT", "USER")) {
      // TODO: Re-enable dispatch once ITS is fixed
      console.log("ITS provided hint to user:", event.context.dialog);
      //store.dispatch({type: GUIDE_HINT_RECEIVED, data: event});
    } else if (event.isMatch("ITS", "REMEDIATE", "USER")) {
      // TODO: Re-enable dispatch once ITS is fixed
      console.log("ITS offered user remediation:", event.context.dialog);
      // store.dispatch(requestRemediation(event));
    } else if (event.isMatch("ITS", "SPOKETO", "USER")) {
      // do nothing with this
      console.log("ITS spoke to user:", event.context.dialog);
    } else if (event.isMatch("ITS", "ISSUED", "ALERT")) {
      // TODO: Re-enable dispatch once ITS is fixed
      console.log("ITS alerted user:", event.context.dialog);
      //store.dispatch({type: GUIDE_ALERT_RECEIVED, data: event});
    } else {
      console.log("%c Unhandled ITS message:", 'color: #f99a00', event.toString());
    }
  };

  socket.on(GuideProtocol.Event.Channel, receiveITSEvent);

  // for testing
  window.GV_TEST_receiveITSEvent = receiveITSEvent;

  socket.on('error', data =>
    store.dispatch({type: GUIDE_ERRORED, data})
  );
  socket.on('connect_error', data =>
    store.dispatch({type: GUIDE_ERRORED, data})
  );
  socket.on('reconnect_error', data =>
    store.dispatch({type: GUIDE_ERRORED, data})
  );

  return socket;
}

export default loggingMetadata => store => next => action => {

  let prevState = store.getState(),
      result = next(action),
      nextState = store.getState();

  if (action.type === actionTypes.SESSION_STARTED) {
    session = action.session;
  }

  switch(action.type) {
    case GUIDE_ERRORED: {
      console.log("%c Error connecting to ITS!", 'color: #f99a00');
      socket.close();
      break;
    }
    case GUIDE_CONNECTED: {
      console.log("%c ITS Connection Success!", 'color: #f99a00');
      if (msgQueue.length) {
        msgQueue.forEach((msg, index) => {
          // use setTimeout to stagger messages sent to ITS
          setTimeout(() => {
            console.log("%c Sending queued message to ITS:", 'color: #f99a00', msg);
            sendMessage(msg, socket);
          }, 10 * index);
        });
        msgQueue = [];
      }
      isConnectonEstablished = true;
      break;
    }
    case GUIDE_HINT_RECEIVED:
    case GUIDE_ALERT_RECEIVED: {
      break;
    }
    default: {
      // other action types - send to ITS
      if (action.meta && action.meta.itsLog){
        let message = createLogEntry(loggingMetadata, action, prevState, nextState);
        if (!isConnectonEstablished) {
          console.log("%c Queuing message for ITS:", 'color: #f99a00', message);
          msgQueue.push(message);
        }
        else {
          console.log("%c Sending message to ITS:", 'color: #f99a00', message, JSON.stringify(message));
          sendMessage(message, socket);
        }
      }
    }
  }

  return result;
};

function sendMessage(message, socket) {
  socket.emit(GuideProtocol.Event.Channel, JSON.stringify(message));
}

function getValue(obj, path) {
  for (let i=0, ii=path.length; i<ii; i++){
      obj = obj[path[i]];
  }
  return obj;
}

// exported for unit test purposes
export function makeMutable(obj) {
  if (!obj) return obj;
  if (obj.asMutable) {
    return obj.asMutable({deep: true});
  } else if (obj.isArray) {
    for (let item of obj) {
      item = makeMutable(item);
    }
  } else if (typeof obj === "object") {
    for (let key in obj) {
      obj[key] = makeMutable(obj[key]);
    }
  }
  return obj;
}

// exported for unit test purposes
export function changePropertyValues(obj, key, func) {
  if (!obj) return;
  if (obj.isArray) {
    for (let item of obj) {
      changePropertyValues(item, key, func);
    }
  } else for (let prop in obj) {
      if (prop === key) {
        obj[prop] = func(obj[prop]);
      } else if (typeof obj[prop] === "object") {
        changePropertyValues(obj[prop], key, func);
      }
    }
}

function getChallengeType(state) {
  if (state.location && state.location.id === "hatchery") {
    return "Hatchery";
  }
  if (state.challengeType && state.challengeType === "match-target") {
    if (state.template === "FVEggGame") {
      return "Breeding";
    }
    return "Sim";
  }
  if (state.challengeType && state.challengeType === "submit-parents") {
    return "Siblings";
  }
}

function getSelectableAttributes(nextState) {
  if ((nextState.template && nextState.template === "FVGenomeChallenge") ||
      (nextState.challengeType && nextState.challengeType === "submit-parents")) {
    return ["sex", ...nextState.userChangeableGenes];
  }
  if (nextState.template && nextState.template === "FVEggSortGame") {
    return ["sex", ...nextState.visibleGenes];
  }
}

function getTarget(nextState) {
  let targetIndex;
  if ((nextState.template && nextState.template === "FVGenomeChallenge") &&
      (nextState.challengeType && nextState.challengeType === "match-target")) {
    targetIndex = 1;
  } else {
    return;
  }
  let targetDrakeOrg = GeneticsUtils.convertDrakeToOrg(nextState.drakes[targetIndex]);
  return {
    sex: targetDrakeOrg.sex,
    phenotype: targetDrakeOrg.phenotype.characteristics
  };
}

function getSelected(action, nextState) {
  let userIndex;
  if (action.type === actionTypes.ALLELE_CHANGED &&
      (nextState.template && nextState.template === "FVGenomeChallenge") &&
      (nextState.challengeType && nextState.challengeType === "match-target")) {
    userIndex = 0;
  } else {
    return;
  }
  let userDrakeOrg = GeneticsUtils.convertDrakeToOrg(nextState.drakes[userIndex]);
  return {
    sex: userDrakeOrg.sex,
    alleles: userDrakeOrg.getAlleleString()
  };
}

function createLogEntry(loggingMetadata, action, prevState, nextState){
  let event = { ...action.meta.itsLog },
      context = { ...action },
      routeSpec = nextState.routeSpec;

  context.routeSpec = routeSpec;
  context.groupId = "Test-v3";
  context.challengeId = AuthoringUtils.getChallengeId(nextState.authoring, routeSpec);
  context.classId = loggingMetadata.classInfo;

  let challengeType = getChallengeType(prevState);
  if (challengeType) {
    context.challengeType = challengeType;
  }

  let selectableAttributes = getSelectableAttributes(nextState);
  if (selectableAttributes) {
    context.selectableAttributes = selectableAttributes;
  }

  let target = context.target || getTarget(prevState);
  if (target) {
    context.target = target;
  }

  let previous = context.selected || getSelected(action, prevState);
  if (previous) {
    context.previous = previous;
  }

  let selected = context.selected || getSelected(action, nextState);
  if (selected) {
    context.selected = selected;
  }

  if (action.meta.logNextState) {
    for (let prop in action.meta.logNextState) {
      context[prop] = getValue(nextState, action.meta.logNextState[prop]);
    }
  }
  if (action.meta.logTemplateState) {
    let Template = templates[nextState.template];
    if (Template.logState) {
      let templateState = Template.logState(nextState);
      context = {
        ...context,
        ...templateState
      };
    }
  }
  if (action.meta.dontLog) {
    for (let prop of action.meta.dontLog) {
      delete context[prop];
    }
  }

  delete context.type;
  delete context.meta;

  context = makeMutable(cloneDeep(context));

  let changeSexToString = sex => sex === 0 ? "male" : sex === 1 ? "female" : sex;
  changePropertyValues(context, "sex", changeSexToString);
  changePropertyValues(context, "newSex", changeSexToString);

  if (prevState.remediation) {
    context.remediation = true;
    context.challengeId = `${context.challengeId}-REMEDIATION`;
  }

  const message =
    {
      classInfo: loggingMetadata.classInfo,
      studentId: loggingMetadata.studentId,
      externalId: loggingMetadata.externalId,
      session: session,
      time: Date.now(),
      sequence: sequence,
      ...event,
      context: context
    };

  sequence++;
  return message;
}
<|endoftext|>


<commit_before>/**
 * ------------------------------------------
 * 播放器控件实现文件
 * @version  1.0
 * @author   genify(caijf@corp.netease.com)
 * ------------------------------------------
 */
var f = function() {
    // variable declaration
    var _  = NEJ.P,
        _e = _('nej.e'),
        _u = _('nej.u'),
        _t = _('nej.ut'),
        _n = _('nej.n'),
        _p = _('nej.cef.ut'),
        _player = _('player'),
        _proPlayer;
    /**
     * 播放器控件，单例模式使用
     *
     * @singleton
     * @class   {nej.cef.ut._$$Player}
     * @extends {nej.ut._$$Event}
     * @param   {Object} 配置参数
     * @config  {Number} step 音量调节步长，0-1之间，默认0.1
     *
     * [hr]
     * 播放状态变化触发事件，播放状态值说明
     * [ntb]
     *   状态值  |  说明
     *   ------------------
     *  -1    |  初始化阶段
     *   0    |  缓冲阶段，出loading提示
     *   1    |  播放状态
     *   2    |  暂停状态
     *   3    |  停止状态
     *   4    |  播放至结尾
     *   5    |  播放异常
     * [/ntb]
     * @event  {onstatechange}
     * @param  {Object} 状态信息
     * @config {Number} state 状态值，见说明表
     *
     * [hr]
     * 歌曲文件下载进度
     * @event  {onloading}
     * @param  {Object} 进度信息
     * @config {Number} loaded 已下载，如0.5
     * @config {Number} total  总数，为1
     *
     * [hr]
     * 播放位置变化触发事件
     * @event  {onpositionchange}
     * @param  {Object} 播放信息
     * @config {Float} current  当前位置
     * @config {Float} duration 音乐总时长
     *
     * [hr]
     * 音量变化触发事件
     * @event  {onvolumechange}
     * @param  {Object} 音量信息
     * @config {Float}  volume 当前音量值，0.0-1.0
     *
     * [hr]
     * 静音状态变化触发事件
     * @event  {onmutechange}
     * @param  {Object}  静音状态信息
     * @config {Boolean} mute 静音状态，true-静音，false-非静音
     *
     * [hr]
     * 歌曲变化触发事件
     * @event  {ontrackchange}
     * @param  {Object}  静音状态信息
     * @config {Boolean} flag 变化标识，-1-上一首，1-下一首
     *
     * [hr]
     * 播放模式变化触发事件，模式说明
     * [ntb]
     *   名称                       |  说明
     *   -----------------------
     *   playorder  |  顺序播放
     *   playcycle  |  循环播放
     *   playrandom |  随机播放
     * [/ntb]
     * @event  {onmodechange}
     * @param  {Object}  静音状态信息
     * @config {Boolean} mode 模式，见描述
     *
     * [hr]
     * 歌词更新触发事件
     * @event  {onlrcupdate}
     * @param  {Object}  歌词信息
     * @config {String}  id  歌曲ID
     * @config {String}  lrc 歌词内容
     *
     * [hr]
     * 请求切换到下一个模式
     * @event  {onnextmode}
     * @param  {Object} 模式信息
     */
    _p._$$Player = NEJ.C();
      _proPlayer = _p._$$Player._$extend(_t._$$Event);
    /**
     * 控件初始化
     * @return {Void}
     */
    _proPlayer.__init = function(){
        this.__nevt = [
            'playmodechange','error','playpre','loading',
            'volumechange','volumeupdate','notify','stop','dataloadfailed',
            'dataloaded','play','pause','ended','playmode','playnext',
            'timeupdate','lyricsupdate','buffering','action','cachefailed'
        ];
        this.__supInit();
    };
    /**
     * 控件重置
     * @param  {Object} 配置信息
     * @return {Void}
     */
    _proPlayer.__reset = (function(){
        var _mevent = {
            playing:'play',
            paused:'pause'
        };
        // add native event
        var _doAddEvent = function(_name){
            _player['on'+_name] = this.
                __onNativeEvent._$bind(this,_name);
        };
        return function(_options){
            this.__supReset(_options);
            this.__step = _options.step||0.1;
            _u._$forEach(
                this.__nevt,_doAddEvent,this
            );
            // sync player status
            var _status = _player.status||'pause';
            this.__onNativeEvent(
                _mevent[_status]||_status
            );
        };
    })();
    /**
     * 控件销毁
     * @return {Void}
     */
    _proPlayer.__destroy = (function(){
        var _doDelEvent = function(_name){
            delete _player['on'+_name];
        };
        return function(){
            this.__supDestroy();
            _u._$forEach(
                this.__nevt,_doDelEvent
            );
        };
    })();
    /**
     * 预加载歌曲
     * @param  {Object} 歌曲信息
     * @return {Void}
     */
    _proPlayer._$preload = function(_options){
        _n._$exec('player.preload',_options);
    };
    /**
     * 播放音乐
     * @param  {Object} 音乐信息
     * @return {Void}
     */
    _proPlayer._$play = function(_options){
        this.__load = !0;
        _n._$exec('player.load',_options);
        _n._$exec('player.setInfo',_options);
        this._$dispatchEvent('onstatechange',{
            state:-1
        });
    };
    /**
     * 恢复状态
     * @return {Void}
     */
    _proPlayer._$resume = function(){
        _n._$exec('player.play');
    };
    /**
     * 暂停播放
     * @return {Void}
     */
    _proPlayer._$pause = function(){
        _n._$exec('player.pause');
    };
    /**
     * 停止播放
     * @return {Void}
     */
    _proPlayer._$stop = function(){
        _n._$exec('player.stop');
    };
    /**
     * 设置静音
     * @param  {Boolean} 静音，true-静音，false-非静音
     * @return {Void}
     */
    _proPlayer._$setMute = function(_mute){
        _n._$exec('player.mute',!!_mute);
        this._$dispatchEvent('onmutechange',{
            mute:!!_mute
        });
    };
    /**
     * 设置模式
     * @param  {String} 播放模式
     * @return {Void}
     */
    _proPlayer._$setMode = function(_mode){
        _n._$exec('player.setPlayMode',_mode);
        this.__onNativeEvent('playmode',_mode);
    };
    /**
     * 设置音量
     * @param  {Float} 音量，范围：[0.0,1.0]
     * @return {Void}
     */
    _proPlayer._$setVolume = function(_volume){
        _n._$exec('player.setVolume',_volume);
        this._$setMute(_volume==0);
    };
    /**
     * 微调音量
     * @param  {Number} 调节标识, 1/-1
     * @return {Void}
     */
    _proPlayer._$stepVolume = function(_flag){
        var _vol = _n._$exec('player.getVolume')+(_flag||0)*this.__step;
        this._$setVolume(
            Math.max(0,Math.min(1,_u._$fixed(_vol,2)))
        );
    };
    /**
     * 设置播放位置
     * @param  {Float} 播放位置，百分比
     * @return {Void}
     */
    _proPlayer._$setPosition = function(_ratio){
        _n._$exec('player.setCurrentTime',_ratio*(_player.duration||0));
    };
    /**
     * 设置歌词
     * @param  {String} 歌词内容
     * @return {Void}
     */
    _proPlayer._$setLRC = function(_lrc){
        !_lrc ? _n._$exec('player.setLRCEmpty')
              : _n._$exec('player.setLRC',_lrc||'');
    };
    /**
     * 设置封面
     * @param  {String} 专辑ID
     * @return {Void}
     */
    _proPlayer._$setCover = function(_aid){
        !_aid ? _n._$exec('player.setCoverDefault')
              : _n._$exec('player.setCover',''+_aid,'album');
    };
    /**
     * native事件回调
     * @param  {String} 事件名称
     * @return {Void}
     */
    _proPlayer.__onNativeEvent = (function(){
        var _actions = {
            play:function(){
                this._$dispatchEvent('onplay');
            },
            pause:function(){
                this._$pause();
            },
            stop:function(){
                this._$stop();
            },
            prev:function(){
                this._$dispatchEvent('ontrackchange',{
                    flag:-1
                });
            },
            next:function(){
                this._$dispatchEvent('ontrackchange',{
                    flag:1
                });
            },
            mode:function(){
                this._$dispatchEvent('onnextmode');
            }
        };
        return function(_name){
            switch(_name){
                case 'dataloaded':
                    this._$resume();
                    this.__load = !1;
                return;
                case 'play':
                    this._$dispatchEvent('onstatechange',{
                        state:1
                    });
                return;
                case 'pause':
                    this._$dispatchEvent('onstatechange',{
                        state:2
                    });
                return;
                case 'stop':
                    this._$dispatchEvent('onstatechange',{
                        state:3
                    });
                return;
                case 'ended':
                    this._$dispatchEvent('onstatechange',{
                        state:4
                    });
                return;
                case 'synctime':
                    this._$dispatchEvent('onpositionchange',{
                        current:_n._$exec('player.getCurrentTime')||0,
                        duration:_player.duration||0
                    });
                return;
                case 'timeupdate':
                    if (!this.__load){
                        this.__onNativeEvent('synctime');
                    }
                    // lock loading
                    var _loading = _n._$exec('player.getDownloadSchedule')||0;
                    if (_loading==1&&this.__loading==1) return;
                    this.__loading = _loading;
                    this._$dispatchEvent('onloading',{
                        loaded:this.__loading,total:1
                    });
                return;
                case 'volumechange':
                    this._$dispatchEvent('onvolumechange',{
                        volume:_n._$exec('player.getVolume')
                    });
                return;
                case 'cachefailed':
                    this._$dispatchEvent('onstatechange',{
                        state:5,
                        code:-100
                    });
                    this.__onNativeEvent('synctime');
                return;
                case 'dataloadfailed':
                    this._$dispatchEvent('onstatechange',{
                        state:5,
                        code:-101
                    });
                    this.__onNativeEvent('synctime');
                return;
                case 'error':
                    this._$dispatchEvent('onstatechange',{
                        state:5,
                        code:_player.errorCode
                    });
                    this.__onNativeEvent('synctime');
                return;
                case 'notify':
                    // TODO
                return;
                case 'playpre':
                case 'playnext':
                    this._$dispatchEvent('ontrackchange',{
                        flag:_name=='playpre'?-1:1
                    });
                return;
                case 'playmode':
                    this._$dispatchEvent('onmodechange',{
                        mode:arguments[1]
                    });
                return;
                case 'lyricsupdate':
                    this._$dispatchEvent('onlrcupdate',{
                        id:arguments[1],lrc:arguments[2]
                    });
                return;
                case 'loading':
                case 'buffering':
                    this._$dispatchEvent('onstatechange',{
                        state:0
                    });
                return;
                case 'playmodechange':
                    this._$dispatchEvent('onnextmode');
                return;
                case 'volumeupdate':
                    this._$stepVolume(arguments[1]);
                return;
                case 'action':
                    (_actions[arguments[1]]||_f).call(this);
                return;
            }
        };
    })();
};
NEJ.define('{lib}native/cef/util/player.js',
          ['{lib}util/event.js'
          ,'{lib}native/command.js'],f);<commit_msg>cef player<commit_after>/**
 * ------------------------------------------
 * 播放器控件实现文件
 * @version  1.0
 * @author   genify(caijf@corp.netease.com)
 * ------------------------------------------
 */
var f = function() {
    // variable declaration
    var _  = NEJ.P,
        _e = _('nej.e'),
        _u = _('nej.u'),
        _t = _('nej.ut'),
        _n = _('nej.n'),
        _p = _('nej.cef.ut'),
        _player = _('player'),
        _proPlayer;
    /**
     * 播放器控件，单例模式使用
     *
     * @singleton
     * @class   {nej.cef.ut._$$Player}
     * @extends {nej.ut._$$Event}
     * @param   {Object} 配置参数
     * @config  {Number} step 音量调节步长，0-1之间，默认0.1
     *
     * [hr]
     * 播放状态变化触发事件，播放状态值说明
     * [ntb]
     *   状态值  |  说明
     *   ------------------
     *  -1    |  初始化阶段
     *   0    |  缓冲阶段，出loading提示
     *   1    |  播放状态
     *   2    |  暂停状态
     *   3    |  停止状态
     *   4    |  播放至结尾
     *   5    |  播放异常
     * [/ntb]
     * @event  {onstatechange}
     * @param  {Object} 状态信息
     * @config {Number} state 状态值，见说明表
     *
     * [hr]
     * 歌曲文件下载进度
     * @event  {onloading}
     * @param  {Object} 进度信息
     * @config {Number} loaded 已下载，如0.5
     * @config {Number} total  总数，为1
     *
     * [hr]
     * 播放位置变化触发事件
     * @event  {onpositionchange}
     * @param  {Object} 播放信息
     * @config {Float} current  当前位置
     * @config {Float} duration 音乐总时长
     *
     * [hr]
     * 音量变化触发事件
     * @event  {onvolumechange}
     * @param  {Object} 音量信息
     * @config {Float}  volume 当前音量值，0.0-1.0
     *
     * [hr]
     * 静音状态变化触发事件
     * @event  {onmutechange}
     * @param  {Object}  静音状态信息
     * @config {Boolean} mute 静音状态，true-静音，false-非静音
     *
     * [hr]
     * 歌曲变化触发事件
     * @event  {ontrackchange}
     * @param  {Object}  静音状态信息
     * @config {Boolean} flag 变化标识，-1-上一首，1-下一首
     *
     * [hr]
     * 播放模式变化触发事件，模式说明
     * [ntb]
     *   名称                       |  说明
     *   -----------------------
     *   playorder  |  顺序播放
     *   playcycle  |  循环播放
     *   playrandom |  随机播放
     * [/ntb]
     * @event  {onmodechange}
     * @param  {Object}  静音状态信息
     * @config {Boolean} mode 模式，见描述
     *
     * [hr]
     * 歌词更新触发事件
     * @event  {onlrcupdate}
     * @param  {Object}  歌词信息
     * @config {String}  id  歌曲ID
     * @config {String}  lrc 歌词内容
     *
     * [hr]
     * 请求切换到下一个模式
     * @event  {onnextmode}
     * @param  {Object} 模式信息
     */
    _p._$$Player = NEJ.C();
      _proPlayer = _p._$$Player._$extend(_t._$$Event);
    /**
     * 控件初始化
     * @return {Void}
     */
    _proPlayer.__init = function(){
        this.__nevt = [
            'playmodechange','error','playpre','loading',
            'volumechange','volumeupdate','notify','stop','dataloadfailed',
            'dataloaded','play','pause','ended','playmode','playnext',
            'timeupdate','lyricsupdate','buffering','action','cachefailed'
        ];
        this.__supInit();
    };
    /**
     * 控件重置
     * @param  {Object} 配置信息
     * @return {Void}
     */
    _proPlayer.__reset = (function(){
        var _mevent = {
            playing:'play',
            paused:'pause'
        };
        // add native event
        var _doAddEvent = function(_name){
            _player['on'+_name] = this.
                __onNativeEvent._$bind(this,_name);
        };
        return function(_options){
            this.__supReset(_options);
            this.__step = _options.step||0.1;
            _u._$forEach(
                this.__nevt,_doAddEvent,this
            );
            // sync player status
            var _status = _player.status||'pause';
            this.__onNativeEvent(
                _mevent[_status]||_status
            );
        };
    })();
    /**
     * 控件销毁
     * @return {Void}
     */
    _proPlayer.__destroy = (function(){
        var _doDelEvent = function(_name){
            delete _player['on'+_name];
        };
        return function(){
            this.__supDestroy();
            _u._$forEach(
                this.__nevt,_doDelEvent
            );
        };
    })();
    /**
     * 预加载歌曲
     * @param  {Object} 歌曲信息
     * @return {Void}
     */
    _proPlayer._$preload = function(_options){
        _n._$exec('player.preload',_options);
    };
    /**
     * 播放音乐
     * @param  {Object} 音乐信息
     * @return {Void}
     */
    _proPlayer._$play = function(_options){
        this.__load = !0;
        _n._$exec('player.load',_options);
        _n._$exec('player.setInfo',_options);
        this._$dispatchEvent('onstatechange',{
            state:-1
        });
    };
    /**
     * 恢复状态
     * @return {Void}
     */
    _proPlayer._$resume = function(){
        _n._$exec('player.play');
    };
    /**
     * 暂停播放
     * @return {Void}
     */
    _proPlayer._$pause = function(){
        _n._$exec('player.pause');
    };
    /**
     * 停止播放
     * @return {Void}
     */
    _proPlayer._$stop = function(){
        _n._$exec('player.stop');
    };
    /**
     * 设置静音
     * @param  {Boolean} 静音，true-静音，false-非静音
     * @return {Void}
     */
    _proPlayer._$setMute = function(_mute){
        _n._$exec('player.mute',!!_mute);
        this._$dispatchEvent('onmutechange',{
            mute:!!_mute
        });
    };
    /**
     * 设置模式
     * @param  {String} 播放模式
     * @return {Void}
     */
    _proPlayer._$setMode = function(_mode){
        _n._$exec('player.setPlayMode',_mode);
        this.__onNativeEvent('playmode',_mode);
    };
    /**
     * 设置音量
     * @param  {Float} 音量，范围：[0.0,1.0]
     * @return {Void}
     */
    _proPlayer._$setVolume = function(_volume){
        _n._$exec('player.setVolume',_volume);
        this._$setMute(_volume==0);
    };
    /**
     * 微调音量
     * @param  {Number} 调节标识, 1/-1
     * @return {Void}
     */
    _proPlayer._$stepVolume = function(_flag){
        var _vol = _n._$exec('player.getVolume')+(_flag||0)*this.__step;
        this._$setVolume(
            Math.max(0,Math.min(1,_u._$fixed(_vol,2)))
        );
    };
    /**
     * 设置播放位置
     * @param  {Float} 播放位置，百分比
     * @return {Void}
     */
    _proPlayer._$setPosition = function(_ratio){
        console.log('set position -> '+_ratio+':'+_player.duration);
        _n._$exec('player.setCurrentTime',_ratio*(_player.duration||0));
    };
    /**
     * 设置歌词
     * @param  {String} 歌词内容
     * @return {Void}
     */
    _proPlayer._$setLRC = function(_lrc){
        !_lrc ? _n._$exec('player.setLRCEmpty')
              : _n._$exec('player.setLRC',_lrc||'');
    };
    /**
     * 设置封面
     * @param  {String} 专辑ID
     * @return {Void}
     */
    _proPlayer._$setCover = function(_aid){
        !_aid ? _n._$exec('player.setCoverDefault')
              : _n._$exec('player.setCover',''+_aid,'album');
    };
    /**
     * native事件回调
     * @param  {String} 事件名称
     * @return {Void}
     */
    _proPlayer.__onNativeEvent = (function(){
        var _actions = {
            play:function(){
                this._$dispatchEvent('onplay');
            },
            pause:function(){
                this._$pause();
            },
            stop:function(){
                this._$stop();
            },
            prev:function(){
                this._$dispatchEvent('ontrackchange',{
                    flag:-1
                });
            },
            next:function(){
                this._$dispatchEvent('ontrackchange',{
                    flag:1
                });
            },
            mode:function(){
                this._$dispatchEvent('onnextmode');
            }
        };
        return function(_name){
            switch(_name){
                case 'dataloaded':
                    this._$resume();
                    this.__load = !1;
                return;
                case 'play':
                    this._$dispatchEvent('onstatechange',{
                        state:1
                    });
                return;
                case 'pause':
                    this._$dispatchEvent('onstatechange',{
                        state:2
                    });
                return;
                case 'stop':
                    this._$dispatchEvent('onstatechange',{
                        state:3
                    });
                return;
                case 'ended':
                    this._$dispatchEvent('onstatechange',{
                        state:4
                    });
                return;
                case 'synctime':
                    this._$dispatchEvent('onpositionchange',{
                        current:_n._$exec('player.getCurrentTime')||0,
                        duration:_player.duration||0
                    });
                return;
                case 'timeupdate':
                    if (!this.__load){
                        this.__onNativeEvent('synctime');
                    }
                    // lock loading
                    var _loading = _n._$exec('player.getDownloadSchedule')||0;
                    if (_loading==1&&this.__loading==1) return;
                    this.__loading = _loading;
                    this._$dispatchEvent('onloading',{
                        loaded:this.__loading,total:1
                    });
                return;
                case 'volumechange':
                    this._$dispatchEvent('onvolumechange',{
                        volume:_n._$exec('player.getVolume')
                    });
                return;
                case 'cachefailed':
                    this._$dispatchEvent('onstatechange',{
                        state:5,
                        code:-100
                    });
                    this.__onNativeEvent('synctime');
                return;
                case 'dataloadfailed':
                    this._$dispatchEvent('onstatechange',{
                        state:5,
                        code:-101
                    });
                    this.__onNativeEvent('synctime');
                return;
                case 'error':
                    this._$dispatchEvent('onstatechange',{
                        state:5,
                        code:_player.errorCode
                    });
                    this.__onNativeEvent('synctime');
                return;
                case 'notify':
                    // TODO
                return;
                case 'playpre':
                case 'playnext':
                    this._$dispatchEvent('ontrackchange',{
                        flag:_name=='playpre'?-1:1
                    });
                return;
                case 'playmode':
                    this._$dispatchEvent('onmodechange',{
                        mode:arguments[1]
                    });
                return;
                case 'lyricsupdate':
                    this._$dispatchEvent('onlrcupdate',{
                        id:arguments[1],lrc:arguments[2]
                    });
                return;
                case 'loading':
                case 'buffering':
                    this._$dispatchEvent('onstatechange',{
                        state:0
                    });
                return;
                case 'playmodechange':
                    this._$dispatchEvent('onnextmode');
                return;
                case 'volumeupdate':
                    this._$stepVolume(arguments[1]);
                return;
                case 'action':
                    (_actions[arguments[1]]||_f).call(this);
                return;
            }
        };
    })();
};
NEJ.define('{lib}native/cef/util/player.js',
          ['{lib}util/event.js'
          ,'{lib}native/command.js'],f);<|endoftext|>


<commit_before>/*
 * Christmas lights controller - Tim Poulsen
 * License MIT
 *
 *
 */
"use strict"

var fields = require("fields"),
	rpio = require('rpio');

const OFF = rpio.HIGH;
const ON = rpio.LOW;

var pins = [3, 5, 7, 8, 10, 11, 12, 13, 15, 16, 18, 19, 21, 22, 23, 24];
pins.forEach(function (pin) {
	rpio.open(pin, rpio.OUTPUT, OFF);
});

fields.set([
	fields.text({
		default: 16,
		promptLabel: 'How many channels to test?',
		validate: function (value) {
			return /^\d+$/.test(value) && value <= 16;
		}
	}),
]).prompt(function (err, value) {
	if (err) {
		console.error('There was an error!\n' + err);
	} else {
		testSequence(value);
	}
});

function testSequence(num) {
	var pin = 0;
	var looper = setInterval(function () {
		let p = pin;
		if (p === num - 1) {
			clearInterval(looper);
			looper = undefined;
		}
		rpio.write(pins[p], ON);
		pin++;
		setTimeout(function () {
			rpio.write(pins[p], OFF);
		}, 1000);
	}, 1250);
}<commit_msg>update testrelay script<commit_after>/*
 * Christmas lights controller - Tim Poulsen
 * License MIT
 *
 *
 */
"use strict"

var fields = require("fields"),
	rpio = require('rpio');

const OFF = rpio.HIGH;
const ON = rpio.LOW;
const INTERVAL = 1000;

var pins = [3, 5, 7, 8, 10, 11, 12, 13, 15, 16, 18, 19, 21, 22, 23, 24];
pins.forEach(function (pin) {
	rpio.open(pin, rpio.OUTPUT, OFF);
});

fields.set([
	fields.text({
		default: 16,
		promptLabel: 'How many channels to test?',
		validate: function (value) {
			return /^\d+$/.test(value) && value <= 16;
		}
	}),
]).prompt(function (err, value) {
	if (err) {
		console.error('There was an error!\n' + err);
	} else {
		testSequence(value);
	}
});

function testSequence(num) {
	var pin = 0;
	var looper = setInterval(function () {
		let p = pin;
		if (p === num - 1) {
			clearInterval(looper);
			looper = undefined;
		}
		rpio.write(pins[p], ON);
		pin++;
		setTimeout(function () {
			rpio.write(pins[p], OFF);
		}, INTERVAL);
	}, INTERVAL + 500);
}<|endoftext|>


<commit_before>'use strict';

angular.module('core')
	.filter('shouldDisplayPanel', filterShouldDisplayPanel);
// -----------------------------------------------------------------------------------
//
// Filter: Display Panel
// return true or false if the panel is valid for the context, project supplied
//
// -----------------------------------------------------------------------------------
filterShouldDisplayPanel.$inject = ['Authentication', '_'];
/* @ngInject */
function filterShouldDisplayPanel(Authentication, _) {

	var vis = {
		"project":{
			"admin":{
				"Initiated":["initiated", "documents",  "map"],
				"Submitted":["stream", "edit",  "map","documents", "doc-approvals"],
				"In Progress":["tombstone", "map", "edit", "activities", "documents", "doc-approvals"]
			},
			"eao":{
				"Initiated":["initiated",  "map","documents"],
				"Submitted":["stream", "edit",  "map","documents", "doc-approvals"],
				"In Progress":["tombstone", "map", "edit", "activities", "documents", "doc-approvals"]
			},
			"guest":{
				"Initiated":[],
				"Submitted":[],
				"In Progress":["tombstone", "map", "public-comments", "documents"]
			}
		}
	};

	return function(context, panel, key) {
		var panels = [];
		var roles = [];

		// no authenticated user so just show guest access.
		if (!Authentication.user.roles) {
			roles = ['guest'];
		} else {
			roles = Authentication.user.roles;
		}

		if (!vis[context]) {
			return false;
		}

		// if everything is there, see if this user is allowed to see the context.
		if (context && panel && key) {
			_.each(roles, function(role) {
				if (vis[context][role]) {
					if (vis[context][role][key]) {
						panels = _.union(panels, vis[context][role][key]);
					}
				}
			});
			return (panels.indexOf(panel) > -1);
		} else {
			return false;
		}
	};

}
<commit_msg>Fixing tombstone display: esm-202<commit_after>'use strict';

angular.module('core')
	.filter('shouldDisplayPanel', filterShouldDisplayPanel);
// -----------------------------------------------------------------------------------
//
// Filter: Display Panel
// return true or false if the panel is valid for the context, project supplied
//
// -----------------------------------------------------------------------------------
filterShouldDisplayPanel.$inject = ['Authentication', '_'];
/* @ngInject */
function filterShouldDisplayPanel(Authentication, _) {

	var vis = {
		"project":{
			"admin":{
				"Initiated":["initiated", "documents",  "map"],
				"Submitted":["tombstone", "stream", "edit",  "map","documents", "doc-approvals"],
				"In Progress":["tombstone", "map", "edit", "activities", "documents", "doc-approvals"]
			},
			"eao":{
				"Initiated":["initiated",  "map","documents"],
				"Submitted":["tombstone", "stream", "edit",  "map","documents", "doc-approvals"],
				"In Progress":["tombstone", "map", "edit", "activities", "documents", "doc-approvals"]
			},
			"guest":{
				"Initiated":[],
				"Submitted":[],
				"In Progress":["tombstone", "map", "public-comments", "documents"]
			}
		}
	};

	return function(context, panel, key) {
		var panels = [];
		var roles = [];

		// no authenticated user so just show guest access.
		if (!Authentication.user.roles) {
			roles = ['guest'];
		} else {
			roles = Authentication.user.roles;
		}

		if (!vis[context]) {
			return false;
		}

		// if everything is there, see if this user is allowed to see the context.
		if (context && panel && key) {
			_.each(roles, function(role) {
				if (vis[context][role]) {
					if (vis[context][role][key]) {
						panels = _.union(panels, vis[context][role][key]);
					}
				}
			});
			return (panels.indexOf(panel) > -1);
		} else {
			return false;
		}
	};

}
<|endoftext|>


<commit_before>/**
 * Functions
 */
describe('Patterns', function() {
	/**
	 * Pattern Array
	 */
	it('Pattern Array', function() {
leaf.ai.PatternList = new leaf.List([
					[
						{
							"pattern": [
								"I like basketball"
							],
							"content": [
								"I do too. Do you like football?"
							],
							"topic": [
								{
									pattern: [
										"yes",
									],
									"content": [
										"Me too!"
									]
								},
								{
									pattern: [
										"no",
									],
									"content": [
										"I enjoy it more than basketball."
									]
								},
							]
						}
					]
                ]);

		leaf.ai.chat("Hi leaf-ai.", function(response) {
			expect(response).toBe('Hello.');
		});
	});
	/**
	 * Header Array
	 */
	it('Header Array', function() {
		leaf.ai.PatternList = new leaf.List([
			{
				"pattern": [
					"Hello"
				],
				"header": [
					"Hello."
				]
			}
		]);

		leaf.ai.chat("Hello leaf-ai.", function(response) {
			expect(response).toBe('Hello.');
		});
	});
	/**
	 * Content Array
	 */
	it('Content Array', function() {
		leaf.ai.PatternList = new leaf.List([
			{
				"pattern": [
					"Hello"
				],
				"content": [
					"Hello."
				]
			}
		]);

		leaf.ai.chat("Hello leaf-ai.", function(response) {
			expect(response).toBe('Hello.');
		});
	});
	/**
	 * Footer array
	 */
	it('Footer string', function() {
		leaf.ai.PatternList = new leaf.List([
			{
				"pattern": [
					"Hello"
				],
				"footer": [
					"Hello."
				]
			}
		]);

		leaf.ai.chat("Hello leaf-ai.", function(response) {
			expect(response).toBe('Hello.');
		});
	});
	/**
	 * Custom commands
	 */
	it('Custom commands', function() {
		leaf.ai.PatternList = new leaf.List([
			{
				"pattern": [
					"Hello"
				],
				"content": [
					"Hello."
				],
				"custom": ""
			}
		]);

		leaf.ai.chat("Hello assistant.", function(response, model) {
			expect(
				leaf.isDefined(model.get('custom'))
			).toBe(true);
		});
	});
});
<commit_msg>Delete chat.js<commit_after><|endoftext|>