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

	//Currently use native support when available, e.g. Safari desktop and Edge
	if (Hls.isSupported() && !mw.isDesktopSafari() && !mw.isEdge() && mw.getConfig("LeadWithHLSOnJs")) {
		// Add HLS Logic player:
		//Force HLS streamer type
		mw.setConfig("streamerType", "hls");
		var config = mw.config.get("KalturaSupport.PlayerConfig");
		config.vars.streamerType = "hls";
		mw.config.set("KalturaSupport.PlayerConfig", config);
		var orig_supportsFlash = mw.supportsFlash;
		mw.supportsFlash = function () {
			return false;
		};
		$(mw).bind('EmbedPlayerUpdateMediaPlayers', function (event, mediaPlayers) {
			if (Hls.isSupported()) {
				//application/vnd.apple.mpegurl
				var hlsPlayer = new mw.MediaPlayer('hlsPlayer', ['video/h264', 'video/mp4', 'application/vnd.apple.mpegurl'], 'Native');
				mediaPlayers.addPlayer(hlsPlayer);
				mw.EmbedTypes.mediaPlayers.setMIMETypePlayers('application/vnd.apple.mpegurl', 'Native');
			}
		});

		var hlsjs = mw.KBasePlugin.extend({

			defaultConfig: {
				options: {}
			},

			/** @type {Number} */
			mediaErrorRecoveryCounter: 0,
			/** type {boolean} */
			LoadHLS: false,
			/** type {boolean} */
			loaded: false,
			/** type {boolean} */
			isLevelSwitching: false,
			/** type {Number} */
			levelIndex: -1,

			/**
			 * Check is HLS is supported
			 * @returns {boolean}
			 */
			isSafeEnviornment: function () {
				return Hls.isSupported();
			},
			/**
			 * Setup the HLS playback engine wrapper with supplied config options
			 */
			setup: function () {
				this.log("version: " + Hls.version );
				mw.setConfig('isHLS_JS', true);
				this.addBindings();
			},
			/**
			 *
			 */
			addBindings: function () {
				this.bind("onSelectSource", this.checkIfHLSNeeded.bind(this));
				this.bind("playerReady", this.initHls.bind(this));
				this.bind("onChangeMedia", this.clean.bind(this));
			},
			/**
			 * Check if HLS engine is required, e.g. sources contain HLS source
			 * @param event
			 * @param sources
			 */
			checkIfHLSNeeded: function (event, sources) {
				var _this = this;
				//Check if sources contain HLS source, if so then raise a flag to init the player
				$.each(sources, function (index, item) {
					if (item.mimeType === "application/vnd.apple.mpegurl") {
						_this.getPlayer().mediaElement.selectedSource = item;
						_this.LoadHLS = true;
					}
				});
			},
			/**
			 * Clean method
			 */
			clean: function () {
				this.log("Clean");
				this.LoadHLS = false;
				this.loaded = false;
				this.unRegisterHlsEvents();
				this.restorePlayerMethods();
				this.hls.detachMedia();
				this.hls.destroy();
				this.hls = null;
			},
			/**
			 * Register the playback events and attach the playback engine to the video element
			 */
			initHls: function () {
				if (this.LoadHLS && !this.loaded) {
					this.log("Init");
					//Set streamerType to hls
					this.embedPlayer.streamerType = 'hls';
					//Init the HLS playback engine
					this.hls = new Hls(this.getConfig("options"));

					this.loaded = true;
					//Reset the error recovery counter
					this.mediaErrorRecoveryCounter = 0;
					//Disable update of video source tag, MSE uses blob urls!
					this.getPlayer().skipUpdateSource = true;

					this.registerHlsEvents();
					this.overridePlayerMethods();

					//Attach video tag to HLS engine
					this.hls.attachMedia(this.getPlayer().getPlayerElement());
				}
			},
			/**
			 * Register HLS playback engine events
			 */
			registerHlsEvents: function () {
				this.onMediaAttachedHandler = this.onMediaAttached.bind(this);
				this.hls.on(Hls.Events.MEDIA_ATTACHED, this.onMediaAttachedHandler);
				this.onManifestParsedHandler = this.onManifestParsed.bind(this);
				this.hls.on(Hls.Events.MANIFEST_PARSED, this.onManifestParsedHandler);
				this.onFragParsingMetadataHandler = this.onFragParsingMetadata.bind(this);
				this.hls.on(Hls.Events.FRAG_PARSING_METADATA, this.onFragParsingMetadataHandler);
				this.onLevelSwitchHandler = this.onLevelSwitch.bind(this);
				this.hls.on(Hls.Events.LEVEL_SWITCH, this.onLevelSwitchHandler);
				this.onFragChangedHandler = this.onFragChanged.bind(this);
				this.hls.on(Hls.Events.FRAG_CHANGED, this.onFragChangedHandler);
				this.onErrorHandler = this.onError.bind(this);
				this.hls.on(Hls.Events.ERROR, this.onErrorHandler);
			},
			/**
			 * Unregister HLS playback engine events
			 */
			unRegisterHlsEvents: function () {
				this.hls.off(Hls.Events.MEDIA_ATTACHED, this.onMediaAttachedHandler);
				this.onMediaAttachedHandler = null;
				this.hls.off(Hls.Events.MANIFEST_PARSED, this.onManifestParsedHandler);
				this.onManifestParsedHandler = null;
				this.hls.off(Hls.Events.FRAG_PARSING_METADATA, this.onFragParsingMetadataHandler);
				this.onFragParsingMetadataHandler = null;
				this.hls.off(Hls.Events.LEVEL_SWITCH, this.onLevelSwitchHandler);
				this.onLevelSwitchHandler = null;
				this.hls.off(Hls.Events.FRAG_CHANGED, this.onFragChangedHandler);
				this.onFragChangedHandler = null;
				this.hls.off(Hls.Events.ERROR, this.onErrorHandler);
				this.onErrorHandler = null;
			},
			//Event handlers
			/**
			 * Load source after media is attached
			 */
			onMediaAttached: function () {
				this.log("Media attached");
				//Once media is attached load the manifest
				var selectedSource = this.getPlayer().getSrc();
				this.getPlayer().resolveSrcURL( selectedSource ).then( function(source){
					this.hls.loadSource(source);
				}.bind(this));
			},
			/**
			 *
			 * @param event
			 * @param data
			 */
			onFragParsingMetadata: function (e, data) {
				//data: { samples : [ id3 pes - pts and dts timestamp are relative, values are in seconds]}

				//Get the data from the event + Unicode transform
				var id3TagData = String.fromCharCode.apply( null, new Uint8Array( data.samples[data.samples.length-1].data ) );
				//Get the JSON substring
				var id3TagString=id3TagData.substring(id3TagData.indexOf("{"), id3TagData.lastIndexOf("}")+1);
				//Parse JSON
				var id3Tag=JSON.parse(id3TagString);

				this.getPlayer().triggerHelper('onId3Tag', id3Tag);
			},
			/**
			 * Extract metadata from parsed manifest data, e.g. ABR etc.
			 * @param event
			 * @param data
			 */
			onManifestParsed: function (event, data) {
				this.log("manifest loaded, found " + data.levels.length + " quality level");
				this.addAbrFlavors(data.levels);
			},
			/**
			 * Trigger source switch start handler
			 * @param event
			 * @param data
			 */
			onLevelSwitch: function (event, data) {
				//Set and report bitrate change
				var source = this.hls.levels[data.level];
				this.getPlayer().currentBitrate = source.bitrate/ 1024;
				this.getPlayer().triggerHelper('bitrateChange', this.getPlayer().currentBitrate);
				//Notify sourceSwitchingStarted
				if (this.isLevelSwitching && this.levelIndex == data.level) {
					this.getPlayer().triggerHelper("sourceSwitchingStarted");
				}
			},
			/**
			 * Trigger source switch ended handler
			 * @param event
			 * @param data
			 */
			onFragChanged: function (event, data) {
				if ( data && data.frag && data.frag.duration){
					this.fragmentDuration = data.frag.duration;
				}
				if (this.isLevelSwitching &&
					(data && data.frag && (this.levelIndex == data.frag.level))) {
					this.isLevelSwitching = false;
					this.getPlayer().triggerHelper("sourceSwitchingEnd");
				}
			},
			/**
			 * Error handler
			 * @param event
			 * @param data
			 */
			onError: function (event, data) {
				//TODO: Need to decide when we dispatch player bug to be shown to viewer
				if (data.fatal) {
					switch (data.type) {
						case Hls.ErrorTypes.NETWORK_ERROR:
							// try to recover network error
							this.log("fatal network error encountered, try to recover");
							this.hls.startLoad();
							break;
						case Hls.ErrorTypes.MEDIA_ERROR:
							if (this.mediaErrorRecoveryCounter > 1) {
								this.log("fatal media error encountered, try to recover - switch audio codec");
								//Try to switch audio codec if first recoverMediaError call didn't work
								this.hls.swapAudioCodec();
							}
							this.log("fatal media error encountered, try to recover");
							this.hls.recoverMediaError();
							this.mediaErrorRecoveryCounter += 1;
							break;
						default:
							// cannot recover
							this.log("fatal media error encountered, cannot recover");
							this.clean();
							if( mw.supportsFlash() ) {
								this.log("Try flash fallback");
								this.fallbackToFlash();
							} else {
								mw.log("MediaError error code: " + error);
								this.triggerHelper('embedPlayerError', [ data ]);
							}
							break;
					}
				} else {
					//If not fatal then log issue, we can switch case errors for specific issues
					this.log("Error: " + data.type + ", " + data.details);
				}
			},
			fallbackToFlash: function(){
				//In case HLS js fails fallback to Flash OSMF if applicable
				//1. Remove hls from native players
				//2. Add Flash player
				//3. Set flag to force HLS on flash and not on JS
				//4. Stop current media playback
				//5. Set autoplay to restart playback after flash engine is loaded
				//6. Call setupSourcePlayer to reload playback engine
				mw.EmbedTypes.mediaPlayers.removeMIMETypePlayers('application/vnd.apple.mpegurl', 'Native');
				mw.EmbedTypes.mediaPlayers.setMIMETypePlayers('application/vnd.apple.mpegurl', 'Kplayer');
				mw.EmbedTypes.addFlashPlayer();
				var embedPlayer = this.getPlayer();
				embedPlayer.setKalturaConfig("", "LeadWithHLSOnJs", false);
				embedPlayer.setKalturaConfig("", "LeadWithHLSOnFlash", true);
				embedPlayer.stop();
				embedPlayer.autoplay = true;
				embedPlayer.setupSourcePlayer();
			},
			/**
			 * Parse ABR data to model
			 * @param levels
			 */
			addAbrFlavors: function (levels) {
				if (levels && levels.length > 1) {
					var flavors = levels.map(function (level, index) {
						var sourceAspect = Math.round(( level.width / level.height ) * 100) / 100;
						// Setup a source object:
						return {
							'data-bandwidth': level.bitrate,
							'data-width': level.width,
							'data-height': level.height,
							'data-aspect': sourceAspect,
							'type': 'video/mp4',
							'data-frameRate': level.frameRate,
							'data-assetid': index
						};
					});
					this.getPlayer().setKDPAttribute('sourceSelector', 'visible', true);
					this.getPlayer().onFlavorsListChanged(flavors);
				}
			},
			/**
			 * Enable override player methods for HLS playback
			 */
			overridePlayerMethods: function () {
				this.orig_backToLive = this.getPlayer().backToLive;
				this.orig_switchSrc = this.getPlayer().switchSrc;
				this.orig_changeMediaCallback = this.getPlayer().changeMediaCallback;
				this.getPlayer().backToLive = this.backToLive.bind(this);
				this.getPlayer().switchSrc = this.switchSrc.bind(this);
				this.getPlayer().changeMediaCallback = null;
			},
			/**
			 * Disable override player methods for HLS playback
			 */
			restorePlayerMethods: function () {
				this.getPlayer().backToLive = this.orig_backToLive;
				this.getPlayer().switchSrc = this.orig_switchSrc;
				this.getPlayer().changeMediaCallback = this.orig_changeMediaCallback;
				mw.supportsFlash = orig_supportsFlash;
			},
			//Overidable player methods, "this" is bound to HLS plugin instance!
			/**
			 * Override player method for back to live mode
			 */
			backToLive: function () {
				var _this = this;
				var vid = this.getPlayer().getPlayerElement();
				this.embedPlayer.goingBackToLive = true;
				vid.currentTime = vid.duration - (this.fragmentDuration || 10) * 3;
				//for some reason on Mac the isLive client response is a little bit delayed, so in order to get update
				// liveUI properly, we need to delay "movingBackToLive" helper
				setTimeout(function () {
					_this.getPlayer().triggerHelper('movingBackToLive');
					_this.embedPlayer.goingBackToLive = false;
				}, 1000);
			},
			/**
			 * Override player method for source switch
			 * @param source
			 */
			switchSrc: function (source) {
				if (source !== -1) {
					var sourceIndex = this.getPlayer().getSourceIndex(source);
					if (sourceIndex != null) {
						this.isLevelSwitching = true;
						this.levelIndex = sourceIndex;
						if (this.hls.currentLevel == sourceIndex) {
							this.onLevelSwitch(Hls.Events.LEVEL_SWITCH, {level: sourceIndex});
							this.onFragChanged(Hls.Events.LEVEL_LOADED, {frag: {level: sourceIndex}});
							this.getPlayer().currentBitrate = source.getBitrate();
							this.getPlayer().triggerHelper('bitrateChange', source.getBitrate());
						} else {
							this.hls.nextLevel = sourceIndex;
						}
					}
				} else {
					this.hls.nextLevel = -1;
				}
			}

		});

		mw.PluginManager.add('hlsjs', hlsjs);
	}
} )( window.mw, window.jQuery ,window.Hls);<commit_msg>FEC-5245 (#2707)<commit_after>( function( mw, $ , Hls ) {"use strict";

	//Currently use native support when available, e.g. Safari desktop and Edge
	if (Hls.isSupported() && !mw.isDesktopSafari() && !mw.isEdge() && mw.getConfig("LeadWithHLSOnJs")) {
		// Add HLS Logic player:
		//Force HLS streamer type
		mw.setConfig("streamerType", "hls");
		var config = mw.config.get("KalturaSupport.PlayerConfig");
		config.vars.streamerType = "hls";
		mw.config.set("KalturaSupport.PlayerConfig", config);
		var orig_supportsFlash = mw.supportsFlash;
		mw.supportsFlash = function () {
			return false;
		};
		$(mw).bind('EmbedPlayerUpdateMediaPlayers', function (event, mediaPlayers) {
			if (Hls.isSupported()) {
				//application/vnd.apple.mpegurl
				var hlsPlayer = new mw.MediaPlayer('hlsPlayer', ['video/h264', 'video/mp4', 'application/vnd.apple.mpegurl'], 'Native');
				mediaPlayers.addPlayer(hlsPlayer);
				mw.EmbedTypes.mediaPlayers.setMIMETypePlayers('application/vnd.apple.mpegurl', 'Native');
			}
		});

		var hlsjs = mw.KBasePlugin.extend({

			defaultConfig: {
				options: {}
			},

			/** @type {Number} */
			mediaErrorRecoveryCounter: 0,
			/** type {boolean} */
			LoadHLS: false,
			/** type {boolean} */
			loaded: false,
			/** type {boolean} */
			isLevelSwitching: false,
			/** type {Number} */
			levelIndex: -1,

			/**
			 * Check is HLS is supported
			 * @returns {boolean}
			 */
			isSafeEnviornment: function () {
				return Hls.isSupported();
			},
			/**
			 * Setup the HLS playback engine wrapper with supplied config options
			 */
			setup: function () {
				this.log("version: " + Hls.version );
				mw.setConfig('isHLS_JS', true);
				this.addBindings();
			},
			/**
			 *
			 */
			addBindings: function () {
				this.bind("onSelectSource", this.checkIfHLSNeeded.bind(this));
				this.bind("playerReady", this.initHls.bind(this));
				this.bind("onChangeMedia", this.clean.bind(this));
			},
			/**
			 * Check if HLS engine is required, e.g. sources contain HLS source
			 * @param event
			 * @param sources
			 */
			checkIfHLSNeeded: function (event, sources) {
				var _this = this;
				//Check if sources contain HLS source, if so then raise a flag to init the player
				$.each(sources, function (index, item) {
					if (item.mimeType === "application/vnd.apple.mpegurl") {
						_this.getPlayer().mediaElement.selectedSource = item;
						_this.LoadHLS = true;
					}
				});
			},
			/**
			 * Clean method
			 */
			clean: function () {
				this.log("Clean");
				this.LoadHLS = false;
				this.loaded = false;
				this.unRegisterHlsEvents();
				this.restorePlayerMethods();
				this.hls.detachMedia();
				this.hls.destroy();
				this.hls = null;
			},
			/**
			 * Register the playback events and attach the playback engine to the video element
			 */
			initHls: function () {
				if (this.LoadHLS && !this.loaded) {
					this.log("Init");
					//Set streamerType to hls
					this.embedPlayer.streamerType = 'hls';
					//Init the HLS playback engine
					this.hls = new Hls(this.getConfig("options"));

					this.loaded = true;
					//Reset the error recovery counter
					this.mediaErrorRecoveryCounter = 0;
					//Disable update of video source tag, MSE uses blob urls!
					this.getPlayer().skipUpdateSource = true;

					this.registerHlsEvents();
					this.overridePlayerMethods();

					//Attach video tag to HLS engine
					this.hls.attachMedia(this.getPlayer().getPlayerElement());
				}
			},
			/**
			 * Register HLS playback engine events
			 */
			registerHlsEvents: function () {
				this.onMediaAttachedHandler = this.onMediaAttached.bind(this);
				this.hls.on(Hls.Events.MEDIA_ATTACHED, this.onMediaAttachedHandler);
				this.onManifestParsedHandler = this.onManifestParsed.bind(this);
				this.hls.on(Hls.Events.MANIFEST_PARSED, this.onManifestParsedHandler);
				this.onFragParsingMetadataHandler = this.onFragParsingMetadata.bind(this);
				this.hls.on(Hls.Events.FRAG_PARSING_METADATA, this.onFragParsingMetadataHandler);
				this.onLevelSwitchHandler = this.onLevelSwitch.bind(this);
				this.hls.on(Hls.Events.LEVEL_SWITCH, this.onLevelSwitchHandler);
				this.onFragChangedHandler = this.onFragChanged.bind(this);
				this.hls.on(Hls.Events.FRAG_CHANGED, this.onFragChangedHandler);
				this.onErrorHandler = this.onError.bind(this);
				this.hls.on(Hls.Events.ERROR, this.onErrorHandler);
			},
			/**
			 * Unregister HLS playback engine events
			 */
			unRegisterHlsEvents: function () {
				this.hls.off(Hls.Events.MEDIA_ATTACHED, this.onMediaAttachedHandler);
				this.onMediaAttachedHandler = null;
				this.hls.off(Hls.Events.MANIFEST_PARSED, this.onManifestParsedHandler);
				this.onManifestParsedHandler = null;
				this.hls.off(Hls.Events.FRAG_PARSING_METADATA, this.onFragParsingMetadataHandler);
				this.onFragParsingMetadataHandler = null;
				this.hls.off(Hls.Events.LEVEL_SWITCH, this.onLevelSwitchHandler);
				this.onLevelSwitchHandler = null;
				this.hls.off(Hls.Events.FRAG_CHANGED, this.onFragChangedHandler);
				this.onFragChangedHandler = null;
				this.hls.off(Hls.Events.ERROR, this.onErrorHandler);
				this.onErrorHandler = null;
			},
			//Event handlers
			/**
			 * Load source after media is attached
			 */
			onMediaAttached: function () {
				this.log("Media attached");
				//Once media is attached load the manifest
				var selectedSource = this.getPlayer().getSrc();
				this.getPlayer().resolveSrcURL( selectedSource ).then( function(source){
					this.hls.loadSource(source);
				}.bind(this));
			},
			/**
			 *
			 * @param event
			 * @param data
			 */
			onFragParsingMetadata: function (e, data) {
				//data: { samples : [ id3 pes - pts and dts timestamp are relative, values are in seconds]}

				//Get the data from the event + Unicode transform
				var id3TagData = String.fromCharCode.apply( null, new Uint8Array( data.samples[data.samples.length-1].data ) );
				//Get the JSON substring
				var id3TagString=id3TagData.substring(id3TagData.indexOf("{"), id3TagData.lastIndexOf("}")+1);
				//Parse JSON
				var id3Tag=JSON.parse(id3TagString);

				this.getPlayer().triggerHelper('onId3Tag', id3Tag);
			},
			/**
			 * Extract metadata from parsed manifest data, e.g. ABR etc.
			 * @param event
			 * @param data
			 */
			onManifestParsed: function (event, data) {
				this.log("manifest loaded, found " + data.levels.length + " quality level");
				this.addAbrFlavors(data.levels);
			},
			/**
			 * Trigger source switch start handler
			 * @param event
			 * @param data
			 */
			onLevelSwitch: function (event, data) {
				//Set and report bitrate change
				var source = this.hls.levels[data.level];
				this.getPlayer().currentBitrate = source.bitrate/ 1024;
				this.getPlayer().triggerHelper('bitrateChange', this.getPlayer().currentBitrate);
				//Notify sourceSwitchingStarted
				if (this.isLevelSwitching && this.levelIndex == data.level) {
					this.getPlayer().triggerHelper("sourceSwitchingStarted");
				}
			},
			/**
			 * Trigger source switch ended handler
			 * @param event
			 * @param data
			 */
			onFragChanged: function (event, data) {
				if ( data && data.frag && data.frag.duration){
					this.fragmentDuration = data.frag.duration;
				}
				if (this.isLevelSwitching &&
					(data && data.frag && (this.levelIndex == data.frag.level))) {
					this.isLevelSwitching = false;
					this.getPlayer().triggerHelper("sourceSwitchingEnd");
				}
			},
			/**
			 * Error handler
			 * @param event
			 * @param data
			 */
			onError: function (event, data) {
				//TODO: Need to decide when we dispatch player bug to be shown to viewer
				if (data.fatal) {
					switch (data.type) {
						case Hls.ErrorTypes.NETWORK_ERROR:
							// try to recover network error
							this.log("fatal network error encountered, try to recover");
							this.hls.startLoad();
							break;
						case Hls.ErrorTypes.MEDIA_ERROR:
							if (this.mediaErrorRecoveryCounter > 1) {
								this.log("fatal media error encountered, try to recover - switch audio codec");
								//Try to switch audio codec if first recoverMediaError call didn't work
								this.hls.swapAudioCodec();
							}
							this.log("fatal media error encountered, try to recover");
							this.hls.recoverMediaError();
							this.mediaErrorRecoveryCounter += 1;
							break;
						default:
							// cannot recover
							this.log("fatal media error encountered, cannot recover");
							this.clean();
							if( mw.supportsFlash() ) {
								this.log("Try flash fallback");
								this.fallbackToFlash();
							} else {
								mw.log("MediaError error code: " + error);
								this.triggerHelper('embedPlayerError', [ data ]);
							}
							break;
					}
				} else {
					//If not fatal then log issue, we can switch case errors for specific issues
					this.log("Error: " + data.type + ", " + data.details);
				}
			},
			fallbackToFlash: function(){
				//In case HLS js fails fallback to Flash OSMF if applicable
				//1. Remove hls from native players
				//2. Add Flash player
				//3. Set flag to force HLS on flash and not on JS
				//4. Stop current media playback
				//5. Set autoplay to restart playback after flash engine is loaded
				//6. Call setupSourcePlayer to reload playback engine
				mw.EmbedTypes.mediaPlayers.removeMIMETypePlayers('application/vnd.apple.mpegurl', 'Native');
				mw.EmbedTypes.mediaPlayers.setMIMETypePlayers('application/vnd.apple.mpegurl', 'Kplayer');
				mw.EmbedTypes.addFlashPlayer();
				var embedPlayer = this.getPlayer();
				embedPlayer.setKalturaConfig("", "LeadWithHLSOnJs", false);
				embedPlayer.setKalturaConfig("", "LeadWithHLSOnFlash", true);
				embedPlayer.stop();
				embedPlayer.autoplay = true;
				embedPlayer.setupSourcePlayer();
			},
			/**
			 * Parse ABR data to model
			 * @param levels
			 */
			addAbrFlavors: function (levels) {
				if (levels && levels.length > 1) {
					var flavors = levels.map(function (level, index) {
						var sourceAspect = Math.round(( level.width / level.height ) * 100) / 100;
						// Setup a source object:
						return {
							'data-bandwidth': level.bitrate,
							'data-width': level.width,
							'data-height': level.height,
							'data-aspect': sourceAspect,
							'type': 'video/mp4',
							'data-frameRate': level.frameRate,
							'data-assetid': index
						};
					});
					this.getPlayer().setKDPAttribute('sourceSelector', 'visible', true);
					this.getPlayer().onFlavorsListChanged(flavors);
				}
			},
			/**
			 * Enable override player methods for HLS playback
			 */
			overridePlayerMethods: function () {
				this.orig_backToLive = this.getPlayer().backToLive;
				this.orig_switchSrc = this.getPlayer().switchSrc;
				this.orig_changeMediaCallback = this.getPlayer().changeMediaCallback;
				this.orig_load = this.getPlayer().load;
				this.getPlayer().backToLive = this.backToLive.bind(this);
				this.getPlayer().switchSrc = this.switchSrc.bind(this);
				this.getPlayer().changeMediaCallback = this.changeMediaCallback.bind(this);
				this.getPlayer().load = this.load.bind(this);
			},
			/**
			 * Disable override player methods for HLS playback
			 */
			restorePlayerMethods: function () {
				this.getPlayer().backToLive = this.orig_backToLive;
				this.getPlayer().switchSrc = this.orig_switchSrc;
				this.getPlayer().changeMediaCallback = this.orig_changeMediaCallback;
				this.getPlayer().load = this.orig_load;
				mw.supportsFlash = orig_supportsFlash;
			},
			//Overidable player methods, "this" is bound to HLS plugin instance!
			/**
			 * Override player method for back to live mode
			 */
			backToLive: function () {
				var _this = this;
				var vid = this.getPlayer().getPlayerElement();
				this.embedPlayer.goingBackToLive = true;
				vid.currentTime = vid.duration - (this.fragmentDuration || 10) * 3;
				//for some reason on Mac the isLive client response is a little bit delayed, so in order to get update
				// liveUI properly, we need to delay "movingBackToLive" helper
				setTimeout(function () {
					_this.getPlayer().triggerHelper('movingBackToLive');
					_this.embedPlayer.goingBackToLive = false;
				}, 1000);
			},
			/**
			 * Override player method for source switch
			 * @param source
			 */
			switchSrc: function (source) {
				if (source !== -1) {
					var sourceIndex = this.getPlayer().getSourceIndex(source);
					if (sourceIndex != null) {
						this.isLevelSwitching = true;
						this.levelIndex = sourceIndex;
						if (this.hls.currentLevel == sourceIndex) {
							this.onLevelSwitch(Hls.Events.LEVEL_SWITCH, {level: sourceIndex});
							this.onFragChanged(Hls.Events.LEVEL_LOADED, {frag: {level: sourceIndex}});
							this.getPlayer().currentBitrate = source.getBitrate();
							this.getPlayer().triggerHelper('bitrateChange', source.getBitrate());
						} else {
							this.hls.nextLevel = sourceIndex;
						}
					}
				} else {
					this.hls.nextLevel = -1;
				}
			},
			/**
			 * Override player method for loading the video element
			 */
			load: function(){
				this.hls.startLoad();
			},
			/**
			 * Override player callback after changing media
			 */
			changeMediaCallback: function(){
				this.getPlayer().play();
				this.getPlayer().changeMediaStarted = false;
				this.getPlayer().triggerHelper('onChangeMediaDone');
			}
		});

		mw.PluginManager.add('hlsjs', hlsjs);
	}
} )( window.mw, window.jQuery ,window.Hls);<|endoftext|>


<commit_before>Pebble.addEventListener('ready', function() {
  console.log('PebbleKit JS ready!');
});

Pebble.addEventListener('showConfiguration', function() {
  var url = 'https://kirby.ngrok.io';

  console.log('Showing configuration page: ' + url);

  Pebble.openURL(url);
});

Pebble.addEventListener('webviewclosed', function(e) {
  var configData = JSON.parse(decodeURIComponent(e.response));

  console.log('Configuration page returned: ' + JSON.stringify(configData));
});
<commit_msg>Add showConfiguration event listener.<commit_after>Pebble.addEventListener('ready', function() {
  console.log('PebbleKit JS ready!');
});

Pebble.addEventListener('showConfiguration', function() {
  var url = 'https://kirby.ngrok.io';

  console.log('Showing configuration page: ' + url);

  Pebble.openURL(url);
});
<|endoftext|>


<commit_before>var config = require('../config');
var flag = require('./flag');
var getProperties = require('./getProperties');
var isProxyEnabled = require('./isProxyEnabled');

/*!
 * Chai - proxify utility
 * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>
 * MIT Licensed
 */

/**
 * ### .proxify(object)
 *
 * Return a proxy of given object that throws an error when a non-existent
 * property is read. By default, the root cause is assumed to be a misspelled
 * property, and thus an attempt is made to offer a reasonable suggestion from
 * the list of existing properties. However, if a nonChainableMethodName is
 * provided, then the root cause is instead a failure to invoke a non-chainable
 * method prior to reading the non-existent property.
 *
 * If proxies are unsupported or disabled via the user's Chai config, then
 * return object without modification.
 *
 * @param {Object} obj
 * @param {String} nonChainableMethodName
 * @namespace Utils
 * @name proxify
 */

var builtins = ['__flags', '__methods', '_obj', 'assert'];

module.exports = function proxify(obj, nonChainableMethodName) {
  if (!isProxyEnabled()) return obj;

  return new Proxy(obj, {
    get: function proxyGetter(target, property) {
      // This check is here because we should not throw errors on Symbol properties
      // such as `Symbol.toStringTag`.
      // The values for which an error should be thrown can be configured using
      // the `config.proxyExcludedKeys` setting.
      if (typeof property === 'string' &&
          config.proxyExcludedKeys.indexOf(property) === -1 &&
          !Reflect.has(target, property)) {
        // Special message for invalid property access of non-chainable methods.
        if (nonChainableMethodName) {
          throw Error('Invalid Chai property: ' + nonChainableMethodName + '.' +
            property + '. See docs for proper usage of "' +
            nonChainableMethodName + '".');
        }

        var orderedProperties = getProperties(target).filter(function(property) {
          return !Object.prototype.hasOwnProperty(property) &&
            builtins.indexOf(property) === -1;
        }).sort(function(a, b) {
          return stringDistance(property, a) - stringDistance(property, b);
        });

        if (orderedProperties.length &&
            stringDistance(orderedProperties[0], property) < 4) {
          // If the property is reasonably close to an existing Chai property,
          // suggest that property to the user.
          throw Error('Invalid Chai property: ' + property +
            '. Did you mean "' + orderedProperties[0] + '"?');
        } else {
          throw Error('Invalid Chai property: ' + property);
        }
      }

      // Use this proxy getter as the starting point for removing implementation
      // frames from the stack trace of a failed assertion. For property
      // assertions, this prevents the proxy getter from showing up in the stack
      // trace since it's invoked before the property getter. For method and
      // chainable method assertions, this flag will end up getting changed to
      // the method wrapper, which is good since this frame will no longer be in
      // the stack once the method is invoked. Note that Chai builtin assertion
      // properties such as `__flags` are skipped since this is only meant to
      // capture the starting point of an assertion. This step is also skipped
      // if the `lockSsfi` flag is set, thus indicating that this assertion is
      // being called from within another assertion. In that case, the `ssfi`
      // flag is already set to the outer assertion's starting point.
      if (builtins.indexOf(property) === -1 && !flag(target, 'lockSsfi')) {
        flag(target, 'ssfi', proxyGetter);
      }

      return Reflect.get(target, property);
    }
  });
};

/**
 * # stringDistance(strA, strB)
 * Return the Levenshtein distance between two strings.
 * @param {string} strA
 * @param {string} strB
 * @return {number} the string distance between strA and strB
 * @api private
 */

function stringDistance(strA, strB, memo) {
  if (!memo) {
    // `memo` is a two-dimensional array containing a cache of distances
    // memo[i][j] is the distance between strA.slice(0, i) and
    // strB.slice(0, j).
    memo = [];
    for (var i = 0; i <= strA.length; i++) {
      memo[i] = [];
    }
  }

  if (!memo[strA.length] || !memo[strA.length][strB.length]) {
    if (strA.length === 0 || strB.length === 0) {
      memo[strA.length][strB.length] = Math.max(strA.length, strB.length);
    } else {
      var sliceA = strA.slice(0, -1);
      var sliceB = strB.slice(0, -1);
      memo[strA.length][strB.length] = Math.min(
        stringDistance(sliceA, strB, memo) + 1,
        stringDistance(strA, sliceB, memo) + 1,
        stringDistance(sliceA, sliceB, memo) +
          (strA.slice(-1) === strB.slice(-1) ? 0 : 1)
      );
    }
  }

  return memo[strA.length][strB.length];
}
<commit_msg>perf: Optimize proxify and stringDistance (#1098)<commit_after>var config = require('../config');
var flag = require('./flag');
var getProperties = require('./getProperties');
var isProxyEnabled = require('./isProxyEnabled');

/*!
 * Chai - proxify utility
 * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>
 * MIT Licensed
 */

/**
 * ### .proxify(object)
 *
 * Return a proxy of given object that throws an error when a non-existent
 * property is read. By default, the root cause is assumed to be a misspelled
 * property, and thus an attempt is made to offer a reasonable suggestion from
 * the list of existing properties. However, if a nonChainableMethodName is
 * provided, then the root cause is instead a failure to invoke a non-chainable
 * method prior to reading the non-existent property.
 *
 * If proxies are unsupported or disabled via the user's Chai config, then
 * return object without modification.
 *
 * @param {Object} obj
 * @param {String} nonChainableMethodName
 * @namespace Utils
 * @name proxify
 */

var builtins = ['__flags', '__methods', '_obj', 'assert'];

module.exports = function proxify(obj, nonChainableMethodName) {
  if (!isProxyEnabled()) return obj;

  return new Proxy(obj, {
    get: function proxyGetter(target, property) {
      // This check is here because we should not throw errors on Symbol properties
      // such as `Symbol.toStringTag`.
      // The values for which an error should be thrown can be configured using
      // the `config.proxyExcludedKeys` setting.
      if (typeof property === 'string' &&
          config.proxyExcludedKeys.indexOf(property) === -1 &&
          !Reflect.has(target, property)) {
        // Special message for invalid property access of non-chainable methods.
        if (nonChainableMethodName) {
          throw Error('Invalid Chai property: ' + nonChainableMethodName + '.' +
            property + '. See docs for proper usage of "' +
            nonChainableMethodName + '".');
        }

        // If the property is reasonably close to an existing Chai property,
        // suggest that property to the user. Only suggest properties with a
        // distance less than 4.
        var suggestion = null;
        var suggestionDistance = 4;
        getProperties(target).forEach(function(prop) {
          if (
            !Object.prototype.hasOwnProperty(prop) &&
            builtins.indexOf(prop) === -1
          ) {
            var dist = stringDistanceCapped(
              property,
              prop,
              suggestionDistance
            );
            if (dist < suggestionDistance) {
              suggestion = prop;
              suggestionDistance = dist;
            }
          }
        });

        if (suggestion !== null) {
          throw Error('Invalid Chai property: ' + property +
            '. Did you mean "' + suggestion + '"?');
        } else {
          throw Error('Invalid Chai property: ' + property);
        }
      }

      // Use this proxy getter as the starting point for removing implementation
      // frames from the stack trace of a failed assertion. For property
      // assertions, this prevents the proxy getter from showing up in the stack
      // trace since it's invoked before the property getter. For method and
      // chainable method assertions, this flag will end up getting changed to
      // the method wrapper, which is good since this frame will no longer be in
      // the stack once the method is invoked. Note that Chai builtin assertion
      // properties such as `__flags` are skipped since this is only meant to
      // capture the starting point of an assertion. This step is also skipped
      // if the `lockSsfi` flag is set, thus indicating that this assertion is
      // being called from within another assertion. In that case, the `ssfi`
      // flag is already set to the outer assertion's starting point.
      if (builtins.indexOf(property) === -1 && !flag(target, 'lockSsfi')) {
        flag(target, 'ssfi', proxyGetter);
      }

      return Reflect.get(target, property);
    }
  });
};

/**
 * # stringDistanceCapped(strA, strB, cap)
 * Return the Levenshtein distance between two strings, but no more than cap.
 * @param {string} strA
 * @param {string} strB
 * @param {number} number
 * @return {number} min(string distance between strA and strB, cap)
 * @api private
 */

function stringDistanceCapped(strA, strB, cap) {
  if (Math.abs(strA.length - strB.length) >= cap) {
    return cap;
  }

  var memo = [];
  // `memo` is a two-dimensional array containing distances.
  // memo[i][j] is the distance between strA.slice(0, i) and
  // strB.slice(0, j).
  for (var i = 0; i <= strA.length; i++) {
    memo[i] = Array(strB.length + 1).fill(0);
    memo[i][0] = i;
  }
  for (var j = 0; j < strB.length; j++) {
    memo[0][j] = j;
  }

  for (var i = 1; i <= strA.length; i++) {
    var ch = strA.charCodeAt(i - 1);
    for (var j = 1; j <= strB.length; j++) {
      if (Math.abs(i - j) >= cap) {
        memo[i][j] = cap;
        continue;
      }
      memo[i][j] = Math.min(
        memo[i - 1][j] + 1,
        memo[i][j - 1] + 1,
        memo[i - 1][j - 1] +
          (ch === strB.charCodeAt(j - 1) ? 0 : 1)
      );
    }
  }

  return memo[strA.length][strB.length];
}
<|endoftext|>


<commit_before>/*global
 define, require, console
 */
/*jslint
 browser:true,
 vars: true,
 white: true
 */
define([
    'bluebird'
        // 'kb_types',
        // 'kb.runtime'
],
    function (Promise) {
        'use strict';

        function factory(config) {
            var plugins = {},
                runtime = config.runtime,
                moduleBase = config.moduleBase || '/modules',
                services = {};

            /*
             * All of these installXXX installers return an array of
             * promises.
             */

            function registerService(serviceNames, serviceDef) {
                serviceNames.forEach(function (name) {
                    services[name] = serviceDef;
                });
            }
            function getService(name) {
                return services[name];
            }

            function arrayExtend(to, from) {
                if (from) {
                    from.forEach(function (item) {
                        to.push(item);
                    });
                }
                return to;
            }

            function installIntoService(pluralTypeName, def) {
                return Promise.try(function () {
                    var typeName;
                    // weird, perhaps, way to strip off a terminal "s".
                    var nameMatch = pluralTypeName.match(/(.*?)(:?(s)|($))$/);
                    if (!nameMatch) {
                        return;
                    }
                    typeName = nameMatch[1];
                    if (!runtime.hasService(typeName)) {
                        throw {
                            name: 'MissingService',
                            message: 'The requested service "' + typeName + '" was not registered in the plugin manager',
                            suggestion: 'This is a web app configuration issue, not a user error'
                        };
                    }
                    var service = runtime.getService(typeName);
                    if (service.pluginHandler) {
                        return service.pluginHandler(def);
                    }
                });
            }

            function installPlugin(pluginLocation, pluginDef) {
                // build up a list of modules and add them to the require config.
                return new Promise(function (resolve, reject) {
                    var paths = {},
                        shims = {},
                        sourcePath = pluginLocation.directory,
                        dependencies = [];

                    // load any styles.
                    // NB these are styles for the plugin as a whole.
                    // TODO: do away with this. the styles should be dependencies
                    // of the panel and widgets. widget css code is below...
                    if (pluginDef.source) {
                        if (pluginDef.source.styles) {
                            pluginDef.source.styles.forEach(function (style) {
                                if (style.file) {
                                    dependencies.push('css!' + sourcePath + '/resources/css/' + style.file);
                                }
                            });
                        }

                        // Add each module defined to the require config paths.
                        if (pluginDef.source.modules) {
                            pluginDef.source.modules.forEach(function (source) {
                                var jsSourceFile = source.file,
                                    matched = jsSourceFile.match(/^(.+?)(?:(?:\.js$)|(?:$))/);
                                if (matched) {
                                    jsSourceFile = matched[1];
                                    var sourceFile = sourcePath + '/modules/' + jsSourceFile;
                                    paths[source.module] = sourceFile;
                                    // A module may also have an accompanying css file, which will
                                    // be added as a dependency via shims.
                                    if (source.css) {
                                        var styleModule = source.module + '_css';
                                        paths[styleModule] = sourceFile;
                                        shims[source.module] = {deps: ['css!' + styleModule]};
                                    }
                                }
                            });
                        }
                    }

                    // This usage of require.config will merge with the existing
                    // require configuration.
                    require.config({paths: paths, shim: shims});

                    // Create a dynamic module for the plugin to use. The current use
                    // case is for code within the plugin to have access to the path
                    // to the plugin for loading other files.
                    //
                    // NB: this implies that the plugin package name is unique in
                    // the system. To enforce or at least help developers with this
                    // we should have a plugin registry.
                    define('kb_plugin_' + pluginDef.package.name, [], function () {
                        return {
                            plugin: {
                                path: '/' + sourcePath + '/resources',
                                modulePath: '/' + sourcePath + '/resources',
                                fullPath: moduleBase + '/' + sourcePath + '/resources'
                            }
                        };
                    });

                    // Now install any routes.
                    if (pluginDef.install) {
                        require(dependencies, function () {
                            var installSteps = [];

                            Object.keys(pluginDef.install).forEach(function (serviceName) {
                                var installDef = pluginDef.install[serviceName],
                                    intallationPromise = installIntoService(serviceName, installDef);
                                arrayExtend(installSteps, [intallationPromise]);
                            });
                            // Do all of the install steps.
                            Promise.all(installSteps)
                                .then(function (doneSteps) {
                                    resolve();
                                })
                                .catch(function (err) {
                                    console.log('ERROR');
                                    console.log(err);
                                    reject(err);
                                });
                        });
                    } else {
                        console.log('No installation?');
                        resolve();
                    }
                });
            }
            function makePromiseIterator(actions) {
                var x = 0;
                return new Promise(function (topResolve, topReject) {
                    function promiseIterator(actions) {
                        var iter = String(x);
                        x += 1;
                        if (actions === undefined || actions.length === 0) {
                            topResolve('DONE');
                        }
                        var next = actions[0],
                            rest = actions.slice(1);
                        Promise.try(function () {
                            return new Promise(function (resolve, reject, notify) {
                                next(resolve, reject, notify);
                            });
                        }).then(function (result) {
                            return promiseIterator(rest);
                        }).catch(function (err) {
                            topReject(err);
                        });
                    }
                    promiseIterator(actions);
                });
            }

            /**
             *
             * @param {type} pluginDef
             * @returns {Promise}
             */
            function loadPlugin(pluginNameOrLocation) {
                var pluginLocation;
                if (typeof pluginNameOrLocation === 'string') {
                    pluginLocation = {
                        name: pluginNameOrLocation,
                        directory: 'plugins/' + pluginNameOrLocation
                    };
                } else {
                    pluginLocation = pluginNameOrLocation;
                }
                return new Promise(function (resolve, reject) {
                    require(['yaml!' + pluginLocation.directory + '/config.yml'], function (pluginConfig) {
                        installPlugin(pluginLocation, pluginConfig)
                            .then(function () {
                                resolve(pluginLocation);
                            })
                            .catch(function (err) {
                                reject(err);
                            });
                    });
                });
            }

            function installPlugins(pluginDefs) {
                var loaders = pluginDefs.map(function (plugin) {
                    return loadPlugin(plugin);
                });
                return Promise.all(loaders);
            }

            // plugins are in an array of arrays. each top level array is processed
            // strictly in sequential order.
            function installPluginSets(pluginDefs) {
                var loadSets = pluginDefs.map(function (set) {
                    return function (resolve, reject, notify) {
                        installPlugins(set)
                            .then(function () {
                                resolve();
                            })
                            .catch(function (err) {
                                reject(err);
                            });
                    };
                });

                return makePromiseIterator(loadSets);
            }

            return {
                installPlugins: installPlugins,
                installPluginSets: installPluginSets,
                registerService: registerService
            };
        }
        return {
            make: function (config) {
                return factory(config);
            }
        };
    });<commit_msg>code cleanup<commit_after>/*global
 define, require, console
 */
/*jslint
 browser:true,
 vars: true,
 white: true
 */
define([
    'bluebird'
],
    function (Promise) {
        'use strict';

        function factory(config) {
            var plugins = {},
                runtime = config.runtime,
                moduleBase = config.moduleBase || '/modules',
                services = {};

            /*
             * All of these installXXX installers return an array of
             * promises.
             */

            function registerService(serviceNames, serviceDef) {
                serviceNames.forEach(function (name) {
                    services[name] = serviceDef;
                });
            }

            function getService(name) {
                return services[name];
            }

            function arrayExtend(to, from) {
                if (from) {
                    from.forEach(function (item) {
                        to.push(item);
                    });
                }
                return to;
            }

            function installIntoService(pluralTypeName, def) {
                return Promise.try(function () {
                    var typeName;
                    // weird, perhaps, way to strip off a terminal "s".
                    var nameMatch = pluralTypeName.match(/(.*?)(:?(s)|($))$/);
                    if (!nameMatch) {
                        return;
                    }
                    typeName = nameMatch[1];
                    if (!runtime.hasService(typeName)) {
                        throw {
                            name: 'MissingService',
                            message: 'The requested service "' + typeName + '" was not registered in the plugin manager',
                            suggestion: 'This is a web app configuration issue, not a user error'
                        };
                    }
                    var service = runtime.getService(typeName);
                    if (service.pluginHandler) {
                        return service.pluginHandler(def);
                    }
                });
            }

            function installPlugin(pluginLocation, pluginDef) {
                // build up a list of modules and add them to the require config.
                return new Promise(function (resolve, reject) {
                    var paths = {},
                        shims = {},
                        sourcePath = pluginLocation.directory,
                        dependencies = [];

                    // load any styles.
                    // NB these are styles for the plugin as a whole.
                    // TODO: do away with this. the styles should be dependencies
                    // of the panel and widgets. widget css code is below...
                    if (pluginDef.source) {
                        if (pluginDef.source.styles) {
                            pluginDef.source.styles.forEach(function (style) {
                                if (style.file) {
                                    dependencies.push('css!' + sourcePath + '/resources/css/' + style.file);
                                }
                            });
                        }

                        // Add each module defined to the require config paths.
                        if (pluginDef.source.modules) {
                            pluginDef.source.modules.forEach(function (source) {
                                var jsSourceFile = source.file,
                                    matched = jsSourceFile.match(/^(.+?)(?:(?:\.js$)|(?:$))/);
                                if (matched) {
                                    jsSourceFile = matched[1];
                                    var sourceFile = sourcePath + '/modules/' + jsSourceFile;
                                    paths[source.module] = sourceFile;
                                    // A module may also have an accompanying css file, which will
                                    // be added as a dependency via shims.
                                    if (source.css) {
                                        var styleModule = source.module + '_css';
                                        paths[styleModule] = sourceFile;
                                        shims[source.module] = {deps: ['css!' + styleModule]};
                                    }
                                }
                            });
                        }
                    }

                    // This usage of require.config will merge with the existing
                    // require configuration.
                    require.config({paths: paths, shim: shims});

                    // Create a dynamic module for the plugin to use. The current use
                    // case is for code within the plugin to have access to the path
                    // to the plugin for loading other files.
                    //
                    // NB: this implies that the plugin package name is unique in
                    // the system. To enforce or at least help developers with this
                    // we should have a plugin registry.
                    define('kb_plugin_' + pluginDef.package.name, [], function () {
                        return {
                            plugin: {
                                path: '/' + sourcePath + '/resources',
                                modulePath: '/' + sourcePath + '/resources',
                                fullPath: moduleBase + '/' + sourcePath + '/resources'
                            }
                        };
                    });

                    // Now install any routes.
                    if (pluginDef.install) {
                        require(dependencies, function () {
                            var installSteps = [];

                            Object.keys(pluginDef.install).forEach(function (serviceName) {
                                var installDef = pluginDef.install[serviceName],
                                    intallationPromise = installIntoService(serviceName, installDef);
                                arrayExtend(installSteps, [intallationPromise]);
                            });
                            // Do all of the install steps.
                            Promise.all(installSteps)
                                .then(function (doneSteps) {
                                    resolve();
                                })
                                .catch(function (err) {
                                    console.error(err);
                                    reject(err);
                                });
                        });
                    } else {
                        resolve();
                    }
                });
            }

            function makePromiseIterator(actions) {
                return new Promise(function (topResolve, topReject) {
                    function promiseIterator(actions) {
                        if (actions === undefined || actions.length === 0) {
                            topResolve('DONE');
                        }
                        var next = actions[0],
                            rest = actions.slice(1);
                        Promise.try(function () {
                            return new Promise(function (resolve, reject, notify) {
                                next(resolve, reject, notify);
                            });
                        }).then(function () {
                            return promiseIterator(rest);
                        }).catch(function (err) {
                            topReject(err);
                        });
                    }
                    promiseIterator(actions);
                });
            }

            /**
             *
             * @param {type} pluginDef
             * @returns {Promise}
             */
            function loadPlugin(pluginNameOrLocation) {
                var pluginLocation;
                if (typeof pluginNameOrLocation === 'string') {
                    pluginLocation = {
                        name: pluginNameOrLocation,
                        directory: 'plugins/' + pluginNameOrLocation
                    };
                } else {
                    pluginLocation = pluginNameOrLocation;
                }
                return new Promise(function (resolve, reject) {
                    require(['yaml!' + pluginLocation.directory + '/config.yml'], function (pluginConfig) {
                        installPlugin(pluginLocation, pluginConfig)
                            .then(function () {
                                resolve(pluginLocation);
                            })
                            .catch(function (err) {
                                reject(err);
                            });
                    });
                });
            }

            function installPlugins(pluginDefs) {
                var loaders = pluginDefs.map(function (plugin) {
                    return loadPlugin(plugin);
                });
                return Promise.all(loaders);
            }

            // plugins are in an array of arrays. each top level array is processed
            // strictly in sequential order.
            function installPluginSets(pluginDefs) {
                var loadSets = pluginDefs.map(function (set) {
                    return function (resolve, reject, notify) {
                        installPlugins(set)
                            .then(function () {
                                resolve();
                            })
                            .catch(function (err) {
                                reject(err);
                            });
                    };
                });

                return makePromiseIterator(loadSets);
            }

            return {
                installPlugins: installPlugins,
                installPluginSets: installPluginSets,
                registerService: registerService
            };
        }
        return {
            make: function (config) {
                return factory(config);
            }
        };
    });<|endoftext|>


<commit_before>import React from 'react';

import NavMore from './components.nav-more';

class Header extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      chatActive: true
    };
  }

  render() {
    let navigation;
    let headerClass;
    let logoClass;
    let backButtonClass;

    if (this.state.chatActive) {
      navigation = <NavChat/>;
      headerClass = 's-header state-chat';
      logoClass = 'logo';
      backButtonClass = 'back-button state-active';
    } else {
      navigation = <NavMain/>;
      headerClass = 's-header';
      logoClass = 'logo state-active';
      backButtonClass = 'back-button';
    }

    return (

        {navigation}

        <NavMore/>

    );
  }

  closeConversation() {
    this.setState({
      chatActive: false
    });
  }
}

class NavMain extends React.Component {
  render() {
    return (

Chats

Contacts

    );
  }
}

class NavChat extends React.Component {
  render() {
    return (

    );
  }
}

export default Header;
<commit_msg>add ids to header items<commit_after>import React from 'react';

import NavMore from './components.nav-more';

class Header extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      chatActive: false
    };
  }

  render() {
    let navigation;
    let headerClass;
    let logoClass;
    let backButtonClass;

    if (this.state.chatActive) {
      navigation = <NavChat/>;
      headerClass = 's-header state-chat';
      logoClass = 'logo';
      backButtonClass = 'back-button state-active';
    } else {
      navigation = <NavMain/>;
      headerClass = 's-header';
      logoClass = 'logo state-active';
      backButtonClass = 'back-button';
    }

    return (

        {navigation}

        <NavMore/>

    );
  }

  closeConversation() {
    this.setState({
      chatActive: false
    });
  }
}

class NavMain extends React.Component {
  render() {
    return (

Chats

Contacts

    );
  }
}

class NavChat extends React.Component {
  render() {
    return (

    );
  }
}

export default Header;
<|endoftext|>


<commit_before>var Promise = require('bluebird');
var nodemailer = require('nodemailer');
var service = require('./service');
var setting = require('./setting');
var user = setting.mail.username,
    pass = setting.mail.password;

var mail = {
    send: function(target, title, content) {
        return new Promise(function(resolve, reject) {
            var smtpTransport = nodemailer.createTransport({
                host: "smtp.163.com",
                auth: {
                    user: user,
                    pass: pass
                }
            });
            var targetMail = '<' + target + '>';
            smtpTransport.sendMail({
                from: '复旦二手工坊<' + user + '>',
                to: targetMail,
                subject: title,
                html: content
            }, function(error, result) {
                if (error) {
                    console.log(error);
                    reject(error);
                }
                if (result) {
                    resolve(result);
                }
            });
        })
    },
}
module.exports = mail;
<commit_msg>学邮验证邮箱变更<commit_after>var Promise = require('bluebird');
var nodemailer = require('nodemailer');
var setting = require('./setting');
var user = setting.mail.username,
    pass = setting.mail.password;

var mail = {
    send: function(target, title, content) {
        return new Promise(function(resolve, reject) {
            var smtpTransport = nodemailer.createTransport({
                host: "mail.fudan.edu.cn",
                auth: {
                    user: user,
                    pass: pass
                }
            });
            var targetMail = '<' + target + '>';
            smtpTransport.sendMail({
                from: '复旦二手工坊<' + user + '>',
                to: targetMail,
                subject: title,
                html: content
            }, function(error, result) {
                if (error) {
                    console.log(error);
                    reject(error);
                }
                if (result) {
                    resolve(result);
                }
            });
        })
    },
}

module.exports = mail;
<|endoftext|>


<commit_before>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

/* eslint-disable no-console, no-process-env */

var childProcess = require('child_process');
var readBenchConfig = require('./read-bench-config.js');
var path = require('path');
var ldj = require('ldjson-stream');
var fs = require('fs');
var util = require('util');
var process = require('process');
var console = require('console');
var setTimeout = require('timers').setTimeout;
var assert = require('assert');
var dgram = require('dgram');

var server = path.join(__dirname, 'bench_server.js');
var relay = path.join(__dirname, 'relay_server.js');
var trace = path.join(__dirname, 'trace_server.js');
var bench = path.join(__dirname, 'multi_bench.js');

process.stderr.setMaxListeners(Infinity);

var TorchCommand = ['sudo', 'torch', '{pid}', 'raw', '{time}'];
if (process.env.TORCH_COMMAND) {
    TorchCommand = process.env.TORCH_COMMAND.split(/\s+/);
}

module.exports = BenchmarkRunner;

function BenchmarkRunner(opts) {
    if (!(this instanceof BenchmarkRunner)) {
        return new BenchmarkRunner(opts);
    }

    var self = this;

    self.opts = opts;

    self.relayProcs = [];
    self.statsdServer = null;
    self.serverProcs = [];
    self.traceProc = null;
    self.benchProcs = [];
    self.benchCounter = 0;
    self.fileStream = null;
    self.startClientDelay = 1500;

    var SERVER_PORT = 7100;
    var TRACE_SERVER_PORT = 7039;
    var RELAY_SERVER_PORT = 7038;
    var RELAY_TRACE_PORT = 7037;
    var STATSD_PORT = 7036;
    var INSTANCE_COUNT = 72;
    var CLIENT_PORT = 7041;

    self.instanceCount = opts.instances || INSTANCE_COUNT;
    self.ports = {
        serverPort: SERVER_PORT,
        traceServerPort: TRACE_SERVER_PORT,
        relayServerPort: RELAY_SERVER_PORT,
        relayTraceServerPort: RELAY_TRACE_PORT,
        statsdPort: STATSD_PORT,
        clientPort: CLIENT_PORT
    };
    self.serviceName = 'benchmark';
}

BenchmarkRunner.prototype.start = function start() {
    var self = this;

    self.spawnSupportServices();

    self.spawnTargetServer();

    if (self.opts.relay || self.opts.trace) {
        setTimeout(startRelay, 1500);
    } else {
        setTimeout(startClient, self.startClientDelay);
    }

    function startRelay() {
        self.spawnRelayServer();

        setTimeout(startClient, self.startClientDelay);
    }

    function startClient() {
        self.spawnBenchmarkClient();

        if (self.opts.torch) {
            self.spawnTorchProcess();
        }
    }
};

BenchmarkRunner.prototype.spawnSupportServices =
function spawnSupportServices() {
    var self = this;

    self.startStatsd();
    self.openFileStream();
};

BenchmarkRunner.prototype.spawnTargetServer =
function spawnTargetServer() {
    var self = this;

    if (self.opts.multiProc) {
        self.startServer(self.ports.serverPort, 24);
        self.startServer(self.ports.serverPort + 24, 24);
        self.startServer(self.ports.serverPort + 48, 24);
    } else {
        self.startServer(self.ports.serverPort, self.instanceCount);
    }
};

BenchmarkRunner.prototype.spawnRelayServer =
function spawnRelayServer() {
    var self = this;

    self.startRelay('bench-relay');
    if (self.opts.trace) {
        self.startTraceServer();
        self.startRelay('trace-relay');
    }
};

BenchmarkRunner.prototype.spawnBenchmarkClient =
function spawnBenchmarkClient() {
    var self = this;

    if (self.opts.multiProc) {
        self.startClient(self.ports.clientPort);
        self.startClient(self.ports.clientPort + 200);
        self.startClient(self.ports.clientPort + 300);
    } else {
        self.startClient(self.ports.clientPort);
    }
};

BenchmarkRunner.prototype.spawnTorchProcess =
function spawnTorchProcess() {
    var self = this;

    if (self.opts.torch) {
        self.startTorch();
    }
};

BenchmarkRunner.prototype.startStatsd = function startStatsd() {
    var self = this;

    self.statsdServer = dgram.createSocket('udp4');
    self.statsdServer.bind(self.ports.statsdPort);
};

BenchmarkRunner.prototype.startServer =
function startServer(serverPort, instances) {
    var self = this;

    if (self.opts.goServer) {
        return self.startGoServer(serverPort, instances);
    }

    var noOverhead = self.opts.noEndpointOverhead;

    var serverProc = self.run(server, [
        self.opts.trace ? '--trace' : '--no-trace',
        '--traceRelayHostPort', '127.0.0.1:' + self.ports.relayTraceServerPort,
        '--port', String(serverPort),
        '--statsdPort', String(self.ports.statsdPort),
        '--instances', String(instances),
        '--pingOverhead', noOverhead ? 'none' : 'norm:10,5',
        '--setOverhead', noOverhead ? 'none' : 'norm:200,20',
        '--getOverhead', noOverhead ? 'none' : 'norm:100,10'
    ]);
    self.serverProcs.push(serverProc);
    serverProc.stdout.pipe(process.stderr);
    serverProc.stderr.pipe(process.stderr);
};

BenchmarkRunner.prototype.startGoServer =
function startGoServer(serverPort, instances) {
    var self = this;

    var serverProc = self.runExternal('../../golang/build/examples/bench/server', [
        '--host', '127.0.0.1',
        '--port', String(serverPort),
        '--instances', String(instances)
    ]);
    self.serverProcs.push(serverProc);
    serverProc.stdout.pipe(process.stderr);
    serverProc.stderr.pipe(process.stderr);
};

BenchmarkRunner.prototype.startTraceServer =
function startTraceServer() {
    var self = this;

    self.traceProc = self.run(trace);
    self.traceProc.stdout.pipe(process.stderr);
    self.traceProc.stderr.pipe(process.stdout);
};

BenchmarkRunner.prototype.startRelay =
function startRelay(type) {
    var self = this;

    // type = 'bench-relay'
    var relayProc = self.run(relay, [
        '--benchPort', String(self.ports.serverPort),
        '--tracePort', String(self.ports.traceServerPort),
        '--benchRelayPort', String(self.ports.relayServerPort),
        '--traceRelayPort', String(self.ports.relayTraceServerPort),
        '--type', type,
        '--instances', String(self.instanceCount),
        self.opts.trace ? '--trace' : '--no-trace',
        self.opts.debug ? '--debug' : '--no-debug'
    ]);
    self.relayProcs.push(relayProc);
    relayProc.stdout.pipe(process.stderr);
    relayProc.stderr.pipe(process.stderr);
};

BenchmarkRunner.prototype.openFileStream =
function openFileStream() {
    var self = this;

    if (self.opts.output) {
        self.fileStream = fs.createWriteStream(self.opts.output, {
            encoding: 'utf8'
        });
    }
};

BenchmarkRunner.prototype.startClient =
function startClient(clientPort) {
    var self = this;

    self.benchCounter++;

    var args = self.opts['--'];
    args = args.concat([
        '--benchPort', String(self.ports.serverPort),
        '--relayServerPort', String(self.ports.relayServerPort),
        '--clientPort', String(clientPort),
        '--instances', String(self.instanceCount),
        '--instanceNumber', String(self.benchCounter)
    ]);
    var benchProc = self.run(bench, args);
    self.benchProcs.push(benchProc);

    benchProc.stderr.pipe(process.stderr);

    benchProc.stdout
        .pipe(ldj.parse())
        .on('data', function onChunk(result) {
            console.log(util.format(
                '%s: %s, %s/%s min/max/avg/p95: %s/%s/%s/%s %sms total, %s ops/sec',
                String(result.instanceNumber),
                lpad(result.descr, 13),
                lpad(result.pipeline, 5),
                result.numClients,
                lpad(result.min, 4),
                lpad(result.max, 4),
                lpad(result.mean.toFixed(2), 7),
                lpad(result.p95.toFixed(2), 7),
                lpad(result.elapsed, 6),
                lpad(typeof result.rate === 'number' ?
                    result.rate.toFixed(2) : 'NaN', 8
                )
            ));

            if (self.fileStream) {
                self.fileStream.write(JSON.stringify(result) + '\n');
            }
        });

    benchProc.once('close', function onClose() {
        if (--self.benchCounter === 0) {
            self.close();
        }
    });

    benchProc.once('exit', function onExit(code) {
        if (code !== 0) {
            /* eslint no-process-exit: 0 */
            process.exit(code);
        }
    });
};

BenchmarkRunner.prototype.close = function close() {
    var self = this;
    var i;

    console.error('benchmark finished');
    for (i = 0; i < self.serverProcs.length; i++) {
        self.serverProcs[i].kill();
    }
    if (self.traceProc) {
        self.traceProc.kill();
    }

    if (self.fileStream) {
        self.fileStream.end();
    }

    for (i = 0; i < self.relayProcs.length; i++) {
        self.relayProcs[i].kill();
    }

    self.statsdServer.close();
};

BenchmarkRunner.prototype.torchCommand =
function torchCommand() {
    var self = this;

    assert(self.opts.torch === 'client' ||
           self.opts.torch === 'relay' ||
           self.opts.torch === 'server',
           'Torch flag must be client or relay'
    );
    assert(self.opts.torchFile, 'torchFile needed');

    var torchPid;
    var torchTime = self.opts.torchTime || '30';
    var torchIndex = self.opts.torchIndex || 0;

    if (self.opts.torch === 'relay') {
        torchPid = self.relayProcs[torchIndex].pid;
    } else if (self.opts.torch === 'client') {
        torchPid = self.benchProcs[torchIndex].pid;
    } else if (self.opts.torch === 'server') {
        torchPid = self.serverProcs[torchIndex].pid;
    }

    return TorchCommand.map(function each(part) {
        if (part === '{pid}') {
            return torchPid;
        } else if (part === '{time}') {
            return torchTime;
        } else {
            return part;
        }
    });
};

BenchmarkRunner.prototype.startTorch =
function startTorch() {
    var self = this;

    var torchFile = self.opts.torchFile;
    var torchDelay = self.opts.torchDelay || 10 * 1000;

    var cmd = self.torchCommand();

    setTimeout(function delayTorching() {
        var torchProc = childProcess.spawn(cmd[0], cmd.slice(1));
        torchProc.stdout.pipe(
            fs.createWriteStream(torchFile)
        );
        torchProc.stderr.pipe(process.stderr);
        console.error('starting flaming');

        torchProc.once('close', function onTorchClose() {
            console.error('finished flaming');
        });
    }, torchDelay);
};

BenchmarkRunner.prototype.run = function run(script, args) {
    var name = script.replace(/\.js$/, '');
    args = args ? args.slice(0) : [];
    args.unshift(script);
    var child = childProcess.spawn(process.execPath, args);
    child.on('exit', function exited(code, signal) {
        console.error('child exited %s[%s] code %s signal %s',
                      name, child.pid, code, signal);
    });
    console.error('running %s[%s]', name, child.pid);
    return child;
};

BenchmarkRunner.prototype.runExternal = function runExternal(cmd, args) {
    var child = childProcess.spawn(cmd, args);
    console.error('running %s[%s]', cmd, child.pid);
    return child;
};

if (require.main === module) {
    var argv = readBenchConfig({
        '--': true,
        alias: {
            o: 'output'
        },
        boolean: ['relay', 'trace', 'debug', 'noEndpointOverhead']
    });
    var runner = BenchmarkRunner(argv);
    runner.start();
}

function lpad(input, len, chr) {
    var str = input.toString();
    chr = chr || ' ';

    while (str.length < len) {
        str = chr + str;
    }
    return str;
}
<commit_msg>multi_bench: do not set multiple instances for trace server<commit_after>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

/* eslint-disable no-console, no-process-env */

var childProcess = require('child_process');
var readBenchConfig = require('./read-bench-config.js');
var path = require('path');
var ldj = require('ldjson-stream');
var fs = require('fs');
var util = require('util');
var process = require('process');
var console = require('console');
var setTimeout = require('timers').setTimeout;
var assert = require('assert');
var dgram = require('dgram');

var server = path.join(__dirname, 'bench_server.js');
var relay = path.join(__dirname, 'relay_server.js');
var trace = path.join(__dirname, 'trace_server.js');
var bench = path.join(__dirname, 'multi_bench.js');

process.stderr.setMaxListeners(Infinity);

var TorchCommand = ['sudo', 'torch', '{pid}', 'raw', '{time}'];
if (process.env.TORCH_COMMAND) {
    TorchCommand = process.env.TORCH_COMMAND.split(/\s+/);
}

module.exports = BenchmarkRunner;

function BenchmarkRunner(opts) {
    if (!(this instanceof BenchmarkRunner)) {
        return new BenchmarkRunner(opts);
    }

    var self = this;

    self.opts = opts;

    self.relayProcs = [];
    self.statsdServer = null;
    self.serverProcs = [];
    self.traceProc = null;
    self.benchProcs = [];
    self.benchCounter = 0;
    self.fileStream = null;
    self.startClientDelay = 1500;

    var SERVER_PORT = 7100;
    var TRACE_SERVER_PORT = 7039;
    var RELAY_SERVER_PORT = 7038;
    var RELAY_TRACE_PORT = 7037;
    var STATSD_PORT = 7036;
    var INSTANCE_COUNT = 72;
    var CLIENT_PORT = 7041;

    self.instanceCount = opts.instances || INSTANCE_COUNT;
    self.ports = {
        serverPort: SERVER_PORT,
        traceServerPort: TRACE_SERVER_PORT,
        relayServerPort: RELAY_SERVER_PORT,
        relayTraceServerPort: RELAY_TRACE_PORT,
        statsdPort: STATSD_PORT,
        clientPort: CLIENT_PORT
    };
    self.serviceName = 'benchmark';
}

BenchmarkRunner.prototype.start = function start() {
    var self = this;

    self.spawnSupportServices();

    self.spawnTargetServer();

    if (self.opts.relay || self.opts.trace) {
        setTimeout(startRelay, 1500);
    } else {
        setTimeout(startClient, self.startClientDelay);
    }

    function startRelay() {
        self.spawnRelayServer();

        setTimeout(startClient, self.startClientDelay);
    }

    function startClient() {
        self.spawnBenchmarkClient();

        if (self.opts.torch) {
            self.spawnTorchProcess();
        }
    }
};

BenchmarkRunner.prototype.spawnSupportServices =
function spawnSupportServices() {
    var self = this;

    self.startStatsd();
    self.openFileStream();
};

BenchmarkRunner.prototype.spawnTargetServer =
function spawnTargetServer() {
    var self = this;

    if (self.opts.multiProc) {
        self.startServer(self.ports.serverPort, 24);
        self.startServer(self.ports.serverPort + 24, 24);
        self.startServer(self.ports.serverPort + 48, 24);
    } else {
        self.startServer(self.ports.serverPort, self.instanceCount);
    }
};

BenchmarkRunner.prototype.spawnRelayServer =
function spawnRelayServer() {
    var self = this;

    self.startRelay('bench-relay');
    if (self.opts.trace) {
        self.startTraceServer();
        self.startRelay('trace-relay');
    }
};

BenchmarkRunner.prototype.spawnBenchmarkClient =
function spawnBenchmarkClient() {
    var self = this;

    if (self.opts.multiProc) {
        self.startClient(self.ports.clientPort);
        self.startClient(self.ports.clientPort + 200);
        self.startClient(self.ports.clientPort + 300);
    } else {
        self.startClient(self.ports.clientPort);
    }
};

BenchmarkRunner.prototype.spawnTorchProcess =
function spawnTorchProcess() {
    var self = this;

    if (self.opts.torch) {
        self.startTorch();
    }
};

BenchmarkRunner.prototype.startStatsd = function startStatsd() {
    var self = this;

    self.statsdServer = dgram.createSocket('udp4');
    self.statsdServer.bind(self.ports.statsdPort);
};

BenchmarkRunner.prototype.startServer =
function startServer(serverPort, instances) {
    var self = this;

    if (self.opts.goServer) {
        return self.startGoServer(serverPort, instances);
    }

    var noOverhead = self.opts.noEndpointOverhead;

    var serverProc = self.run(server, [
        self.opts.trace ? '--trace' : '--no-trace',
        '--traceRelayHostPort', '127.0.0.1:' + self.ports.relayTraceServerPort,
        '--port', String(serverPort),
        '--statsdPort', String(self.ports.statsdPort),
        '--instances', String(instances),
        '--pingOverhead', noOverhead ? 'none' : 'norm:10,5',
        '--setOverhead', noOverhead ? 'none' : 'norm:200,20',
        '--getOverhead', noOverhead ? 'none' : 'norm:100,10'
    ]);
    self.serverProcs.push(serverProc);
    serverProc.stdout.pipe(process.stderr);
    serverProc.stderr.pipe(process.stderr);
};

BenchmarkRunner.prototype.startGoServer =
function startGoServer(serverPort, instances) {
    var self = this;

    var serverProc = self.runExternal('../../golang/build/examples/bench/server', [
        '--host', '127.0.0.1',
        '--port', String(serverPort),
        '--instances', String(instances)
    ]);
    self.serverProcs.push(serverProc);
    serverProc.stdout.pipe(process.stderr);
    serverProc.stderr.pipe(process.stderr);
};

BenchmarkRunner.prototype.startTraceServer =
function startTraceServer() {
    var self = this;

    self.traceProc = self.run(trace);
    self.traceProc.stdout.pipe(process.stderr);
    self.traceProc.stderr.pipe(process.stdout);
};

BenchmarkRunner.prototype.startRelay =
function startRelay(type) {
    var self = this;

    // type = 'bench-relay'
    var relayProc = self.run(relay, [
        '--benchPort', String(self.ports.serverPort),
        '--tracePort', String(self.ports.traceServerPort),
        '--benchRelayPort', String(self.ports.relayServerPort),
        '--traceRelayPort', String(self.ports.relayTraceServerPort),
        '--type', type,
        '--instances', type === 'trace-relay' ? '1' : String(self.instanceCount),
        self.opts.trace ? '--trace' : '--no-trace',
        self.opts.debug ? '--debug' : '--no-debug'
    ]);
    self.relayProcs.push(relayProc);
    relayProc.stdout.pipe(process.stderr);
    relayProc.stderr.pipe(process.stderr);
};

BenchmarkRunner.prototype.openFileStream =
function openFileStream() {
    var self = this;

    if (self.opts.output) {
        self.fileStream = fs.createWriteStream(self.opts.output, {
            encoding: 'utf8'
        });
    }
};

BenchmarkRunner.prototype.startClient =
function startClient(clientPort) {
    var self = this;

    self.benchCounter++;

    var args = self.opts['--'];
    args = args.concat([
        '--benchPort', String(self.ports.serverPort),
        '--relayServerPort', String(self.ports.relayServerPort),
        '--clientPort', String(clientPort),
        '--instances', String(self.instanceCount),
        '--instanceNumber', String(self.benchCounter)
    ]);
    var benchProc = self.run(bench, args);
    self.benchProcs.push(benchProc);

    benchProc.stderr.pipe(process.stderr);

    benchProc.stdout
        .pipe(ldj.parse())
        .on('data', function onChunk(result) {
            console.log(util.format(
                '%s: %s, %s/%s min/max/avg/p95: %s/%s/%s/%s %sms total, %s ops/sec',
                String(result.instanceNumber),
                lpad(result.descr, 13),
                lpad(result.pipeline, 5),
                result.numClients,
                lpad(result.min, 4),
                lpad(result.max, 4),
                lpad(result.mean.toFixed(2), 7),
                lpad(result.p95.toFixed(2), 7),
                lpad(result.elapsed, 6),
                lpad(typeof result.rate === 'number' ?
                    result.rate.toFixed(2) : 'NaN', 8
                )
            ));

            if (self.fileStream) {
                self.fileStream.write(JSON.stringify(result) + '\n');
            }
        });

    benchProc.once('close', function onClose() {
        if (--self.benchCounter === 0) {
            self.close();
        }
    });

    benchProc.once('exit', function onExit(code) {
        if (code !== 0) {
            /* eslint no-process-exit: 0 */
            process.exit(code);
        }
    });
};

BenchmarkRunner.prototype.close = function close() {
    var self = this;
    var i;

    console.error('benchmark finished');
    for (i = 0; i < self.serverProcs.length; i++) {
        self.serverProcs[i].kill();
    }
    if (self.traceProc) {
        self.traceProc.kill();
    }

    if (self.fileStream) {
        self.fileStream.end();
    }

    for (i = 0; i < self.relayProcs.length; i++) {
        self.relayProcs[i].kill();
    }

    self.statsdServer.close();
};

BenchmarkRunner.prototype.torchCommand =
function torchCommand() {
    var self = this;

    assert(self.opts.torch === 'client' ||
           self.opts.torch === 'relay' ||
           self.opts.torch === 'server',
           'Torch flag must be client or relay'
    );
    assert(self.opts.torchFile, 'torchFile needed');

    var torchPid;
    var torchTime = self.opts.torchTime || '30';
    var torchIndex = self.opts.torchIndex || 0;

    if (self.opts.torch === 'relay') {
        torchPid = self.relayProcs[torchIndex].pid;
    } else if (self.opts.torch === 'client') {
        torchPid = self.benchProcs[torchIndex].pid;
    } else if (self.opts.torch === 'server') {
        torchPid = self.serverProcs[torchIndex].pid;
    }

    return TorchCommand.map(function each(part) {
        if (part === '{pid}') {
            return torchPid;
        } else if (part === '{time}') {
            return torchTime;
        } else {
            return part;
        }
    });
};

BenchmarkRunner.prototype.startTorch =
function startTorch() {
    var self = this;

    var torchFile = self.opts.torchFile;
    var torchDelay = self.opts.torchDelay || 10 * 1000;

    var cmd = self.torchCommand();

    setTimeout(function delayTorching() {
        var torchProc = childProcess.spawn(cmd[0], cmd.slice(1));
        torchProc.stdout.pipe(
            fs.createWriteStream(torchFile)
        );
        torchProc.stderr.pipe(process.stderr);
        console.error('starting flaming');

        torchProc.once('close', function onTorchClose() {
            console.error('finished flaming');
        });
    }, torchDelay);
};

BenchmarkRunner.prototype.run = function run(script, args) {
    var name = script.replace(/\.js$/, '');
    args = args ? args.slice(0) : [];
    args.unshift(script);
    var child = childProcess.spawn(process.execPath, args);
    child.on('exit', function exited(code, signal) {
        console.error('child exited %s[%s] code %s signal %s',
                      name, child.pid, code, signal);
    });
    console.error('running %s[%s]', name, child.pid);
    return child;
};

BenchmarkRunner.prototype.runExternal = function runExternal(cmd, args) {
    var child = childProcess.spawn(cmd, args);
    console.error('running %s[%s]', cmd, child.pid);
    return child;
};

if (require.main === module) {
    var argv = readBenchConfig({
        '--': true,
        alias: {
            o: 'output'
        },
        boolean: ['relay', 'trace', 'debug', 'noEndpointOverhead']
    });
    var runner = BenchmarkRunner(argv);
    runner.start();
}

function lpad(input, len, chr) {
    var str = input.toString();
    chr = chr || ' ';

    while (str.length < len) {
        str = chr + str;
    }
    return str;
}
<|endoftext|>


<commit_before>basemodel = angular.module('basemodel', []);

basemodel.factory('BaseModel',
                   ['$filter', '$rootScope', '$q', '$http',
                   function($filter, $rootScope, $q, $http) {

    /*
     * A service that retrieves, manages and saves "data", a collection of
     * individual objects that can be identified using a unique id
     */

    var _data = null;
    var added_ids = 0;

    return {
        method: '--error--',

        handle_data: function(data) { return data; },
        construct_method: function(method) {
            return $rootScope.urlbase + "+" + method + "/";
        },

        retrieve: function() {
            var deferred = $q.defer();
            var m = this;
            if(_data) {
                deferred.resolve(_data);
                return deferred.promise;
            }

            $http.get(this.construct_method(this.method)).success(
                function(data, status, headers, config) {
                    _data = m.handle_data(data);
                    deferred.resolve(data);
                });
            return deferred.promise;
        },

        save: function() {
            var deferred = $q.defer();
            var m = this;
            $http.post($rootScope.urlbase + "+" + this.method + "/", {
                    data:$filter('json')(_data)
            }).success(
                function(data, status, headers, config) {
                    _data = m.handle_data(data);
                    deferred.resolve(data);
                }
            );
            return deferred.promise;
        },

        async: function() {
            return this.retrieve();
        },

        data: function() { return _data; },

        find: function(id) {
                var i;
                for(i = 0; i < _data.existing.length; i++) {
                    if(_data.existing[i].id == id) {
                        return _data.existing[i];
                    }
                }
            },
        add: function(data) {
            _data.existing.unshift(data);
            data.state = "added";
            data.id = "added_" + added_ids++;
            return data.id;
        },
        remove: function(id) {
            var existing = this.find(id);
            existing.state = "deleted";
        },
        update: function(id, data) {
            var existing = this.find(id);
            angular.extend(existing, data);
            if(existing.state != "added") {
                existing.state = "modified";
            }
        }
    };
}]);
<commit_msg>fixes<commit_after>basemodel = angular.module('basemodel', []);

basemodel.factory('BaseModel',
                   ['$filter', '$rootScope', '$q', '$http',
                   function($filter, $rootScope, $q, $http) {

    /*
     * A service that retrieves, manages and saves "data", a collection of
     * individual objects that can be identified using a unique id
     */

    var _data = null;
    var added_ids = 0;

    return {
        method: '--error--',

        handle_data: function(data) { return data; },
        construct_method: function(method) {
            return $rootScope.urlbase + "+" + method + "/";
        },

        retrieve: function() {
            var deferred = $q.defer();
            var m = this;
            if(_data) {
                deferred.resolve(_data);
                return deferred.promise;
            }

            $http.get(this.construct_method(this.method)).success(
                function(data, status, headers, config) {
                    _data = m.handle_data(data);
                    deferred.resolve(data);
                });
            return deferred.promise;
        },

        save: function() {
            var deferred = $q.defer();
            var m = this;
            $http.post(this.construct_method(this.method), {
                    data:$filter('json')(_data)
            }).success(
                function(data, status, headers, config) {
                    _data = m.handle_data(data);
                    deferred.resolve(data);
                }
            );
            return deferred.promise;
        },

        async: function() {
            return this.retrieve();
        },

        data: function() { return _data; },

        find: function(id) {
                var i;
                for(i = 0; i < _data.existing.length; i++) {
                    if(_data.existing[i].id == id) {
                        return _data.existing[i];
                    }
                }
            },
        add: function(data) {
            _data.existing.unshift(data);
            data.state = "added";
            data.id = "added_" + added_ids++;
            return data.id;
        },
        remove: function(id) {
            var existing = this.find(id);
            existing.state = "deleted";
        },
        update: function(id, data) {
            var existing = this.find(id);
            angular.extend(existing, data);
            if(existing.state != "added") {
                existing.state = "modified";
            }
            return existing;
        }
    };
}]);
<|endoftext|>