<commit_before>/**
* Native embed library:
*
* Enables embedPlayer support for native iOS/Android webView playback system
*/

( function( mw, $ ) { "use strict";
	//make the player transparent to see the native iOS/Android player
	if(mw.getConfig( "EmbedPlayer.ForceNativeComponent")){
		$('body,.videoHolder').css('background-color', 'transparent' );
	}

mw.EmbedPlayerNativeComponent = {
	//Instance Name
	instanceOf: 'NativeComponent',

	// Flag to only load the video ( not play it )
	onlyLoadFlag:false,

	//Callback fired once video is "loaded"
	onLoadedCallback: null,

	// The previous "currentTime" to sniff seek actions
	// NOTE the bug where onSeeked does not seem fire consistently may no longer be applicable
	prevCurrentTime: -1,

	// Store the progress event ( updated during monitor )
	progressEventData: null,

	// If the media loaded event has been fired
	mediaLoadedFlag: null,

	// A flag to keep the video tag offscreen.
	keepPlayerOffScreenFlag: null,

	// A flag to designate the first play event, as to not propagate the native event in this case
	ignoreNextNativeEvent: null,

	// A local var to store the current seek target time:
	currentSeekTargetTime: null,

	// All the native events per:
	// http://www.w3.org/TR/html5/video.html#mediaevents
	nativeEvents : [
		'stop',
		'play',
		'pause',
		'canplay',
		'seeking',
		'seeked',
		'ended',
		'error',
		'stalled',
		'loadedmetadata',
		'timeupdate',
		'progress',
		'enterfullscreen',
		'exitfullscreen',
		'durationchange',
		'chromecastDeviceConnected',
		'chromecastDeviceDisConnected'
	],

	nativeActions : [
		'share'
	],
	// Native player supported feature set
	supports: {
		'playHead' : true,
		'pause' : true,
		'fullscreen' : true,
		'SourceSelector': false,
		'timeDisplay' : true,
		'volumeControl' : false,
		'overlays' : true
	},

	embedPlayerHTML : function() {
		var _this = this;
		if ( !this.playerIsLoaded ){
			mw.log( "NativeComponent:: embedPlayerHTML" );
			// remove any existing pid ( if present )
			$( '#' + this.pid ).remove();

			var divElement = document.createElement("div");
			divElement.setAttribute('id', 'proxy');
			document.body.appendChild(divElement);

			this.proxyElement = divElement;
			try{
				if(NativeBridge.videoPlayer){
					NativeBridge.videoPlayer.registePlayer(this.getPlayerElement());
					NativeBridge.videoPlayer.registerEmbedPlayer( this );
				}
			}
			catch(e){
				alert( e );
			}

			this.applyMediaElementBindings();
			this.playerIsLoaded = true;
			this.getPlayerElement().attr('src', this.getSrc());
			this.bindHelper("SourceChange", function() {
				_this.getPlayerElement().attr('src', this.getSrc());
			});
			this.bindHelper("layoutBuildDone ended", function() {
				_this.getPlayerElement().notifyLayoutReady();
			});
			this.bindHelper("showChromecastDeviceList", function() {
				mw.log("EmbedPlayerNativeComponent:: showChromecastDeviceList::");
				_this.getPlayerElement().showChromecastDeviceList();
			});
		}
	},

	playerSwitchSource: function( source, switchCallback, doneCallback ) {
		mw.log( "NativeComponent:: playerSwitchSource" );
		var _this = this;
		var vid = this.getPlayerElement();
		var switchBindPostfix = '.playerSwitchSource';

		// add a loading indicator:
		_this.addPlayerSpinner();

		// empty out any existing sources:
		$( vid ).empty();

		// load the updated src
		//only on desktop safari we need to load - otherwise we get the same movie play again.
		if (mw.isDesktopSafari()){
			vid.load();
		}

		if( this.getSrc() != source.getSrc() ) {
			vid.attr( 'src', source.getSrc() );
		} else {
			vid.attr( 'src', this.getSrc() );
		}

		this.isPauseLoading = false;

		if( switchCallback ){
			_this.hideSpinner();
			switchCallback( vid );
		}

		// restore position once we have metadata
		$( vid ).bind( 'loadedmetadata' + switchBindPostfix, function(){
			$( vid ).unbind( 'loadedmetadata' + switchBindPostfix);
			mw.log("EmbedPlayerNative:: playerSwitchSource> loadedmetadata callback" );
			// ( do not update the duration )
			// Android and iOS <5 gives bogus duration, depend on external metadata

			// keep going towards playback! if  switchCallback has not been called yet
			// we need the "playing" event to trigger the switch callback
			if ( $.isFunction( switchCallback ) ){
				setTimeout( function() {
					vid.play();
				}, 100);
			}
		});

		// Add the end binding if we have a post event:
		if( $.isFunction( doneCallback ) ){
			$( vid ).bind( 'ended' + switchBindPostfix , function( event ) {
				// remove end binding:
				$( _this.getPlayerElement() ).unbind( switchBindPostfix );
				// issue the doneCallback
				doneCallback();

				// Support loop for older iOS
				// Temporarily disabled pending more testing or refactor into a better place.
				//if ( _this.loop ) {
				//	vid.play();
				//}
				return false;
			});
		}
	},

	/**
	 * Apply media element bindings
	 */
	applyMediaElementBindings: function() {
		var _this = this;
		mw.log("EmbedPlayerNative::MediaElementBindings");

		$.each( _this.nativeEvents, function( inx, eventName ){
			$( _this.getPlayerElement() ).unbind( eventName ).bind( eventName , function(){
				// make sure we propagating events, and the current instance is in the correct closure.
				if( _this._propagateEvents && _this.instanceOf == 'NativeComponent' ){
					var argArray = $.makeArray( arguments );
					// Check if there is local handler:

					if( _this[ '_on' + eventName ] ){
						_this[ '_on' + eventName ].apply( _this, argArray);
					} else {
						// No local handler directly propagate the event to the abstract object:
						$( _this ).trigger( eventName, argArray );
					}
				}
			});
		});
	},

	/**
	 * Get the embed player time
	 */
	getPlayerElementTime: function() {
		var _this = this;
		// Make sure we have .vid obj

		if ( !this.getPlayerElement() ) {
			mw.log( 'EmbedPlayerNative::getPlayerElementTime: ' + this.id + ' not in dom ( stop monitor)' );
			this.stop();
			return false;
		}
		var ct =  this.getPlayerElement().attr('currentTime');
		// Return 0 or a positive number:
		if( ! ct || isNaN( ct ) || ct < 0 || ! isFinite( ct ) ){
			return 0;
		}
		// Return the playerElement currentTime
		return  ct ;
	},

	/**
	 * Get /update the playerElement value
	 */
	getPlayerElement: function () {
		return this.proxyElement;
	},

	/**
	 * Stop the player ( end all listeners )
	 */
	stop: function(){
		mw.log("EmbedPlayerNativeComponent:: stop::");
		this.parent_stop();
		if( this.getPlayerElement() && this.getPlayerElement().attr('currentTime')){
			this.getPlayerElement().attr('currentTime', '0');
			this.getPlayerElement().stop();
		}
	},

	/**
	 * Play back the video stream
	 * calls parent_play to update the interface
	 */

	play: function() {
		mw.log("EmbedPlayerNativeComponent:: play::");
		$( this ).find( '.playerPoster' ).remove();

		if ( this.getPlayerElement() ) { // update player
			this.getPlayerElement().play();
		}
		$( this ).trigger( "playing" );

		if( this.parent_play() ){
			this.monitor();
		}
	},

	/**
	* Pause the video playback
	* calls parent_pause to update the interface
	*/
	pause: function() {
		mw.log("EmbedPlayerNativeComponent:: pause::");
		this.parent_pause(); // update interface
		if ( this.getPlayerElement() ) { // update player
			this.getPlayerElement().pause();
		}
	},

	seek: function( percentage ) {
		mw.log("EmbedPlayerNativeComponent:: seek::");
		var seekTime = percentage * this.getDuration();
		this.getPlayerElement().attr('currentTime', seekTime);
		this.parent_seek( percentage );
	},

	doNativeAction: function( actionParams ) {
		mw.log("EmbedPlayerNativeComponent:: doNativeAction::");
		this.getPlayerElement().attr('nativeAction', actionParams);
		this.getPlayerElement().doNativeAction();
	},

	nativeActionType: function ( actionName ) {
		return jQuery.inArray(actionName, this.nativeActions);
	},

	/**
	 * returns true if device can auto play
	 */
	canAutoPlay: function(){
		return true;
	},

	/**
	 * Handle the native play event
	 */
	_onplay: function(){
		mw.log("EmbedPlayerNativeComponent:: OnPlay::");

		$( this ).trigger( "playing" );

		if( this.paused  && this.parent_play() ){
			this.monitor();
		}
	},

	/**
	* Handle the native paused event
	*/
	/**
	 * Handle the native paused event
	 */
	_onpause: function(){
		mw.log("EmbedPlayerNativeComponent:: OnPause::");
		this.parent_pause();
	},

	/**
	 * Local method for seeking event
	 * fired when "seeking"
	 */
	_onseeking: function() {
		mw.log( "EmbedPlayerNative::onSeeking " );

		// Trigger the html5 "seeking" trigger
		mw.log("EmbedPlayerNative::seeking:trigger:: ");
		if( this._propagateEvents ){
			this.triggerHelper( 'seeking' );
		}
	},

	/**
	 * Local method for seeked event
	 * fired when done seeking
	 */
	_onseeked: function() {
		mw.log("EmbedPlayerNative::onSeeked " );
		this.seeking = false;

		if( this._propagateEvents ){
			mw.log( "EmbedPlayerNative:: trigger: seeked" );
			this.triggerHelper( 'seeked' );
		}

		this.monitor();
	},

	/**
	 * Local method for metadata ready
	 * fired when metadata becomes available
	 *
	 * Used to update the media duration to
	 * accurately reflect the src duration
	 */
	_onloadedmetadata: function() {
		//Fire "onLoaded" flags if set
		if( typeof this.onLoadedCallback == 'function' ) {
			this.onLoadedCallback();
		}

		// Trigger "media loaded"
		if( ! this.mediaLoadedFlag ){
			$( this ).trigger( 'mediaLoaded' );
			this.mediaLoadedFlag = true;
		}
	},

	/**
	 * Local method for end of media event
	 */
	_onended: function( event ) {
		if( this.getPlayerElement() ){
			mw.log( 'EmbedPlayer:native: onended:');
			if( this._propagateEvents ){
				this.onClipDone();
			}
		}
	},

	/**
	 * Local onClip done function for native player.
	 */
	onClipDone: function(){
		this.parent_onClipDone();
	},

	/**
	 * playback error
	 */
	_onerror: function ( event, data ) {
		this.triggerHelper( 'embedPlayerError', [ data ] );
	},

	/**
	 * buffer progress
	 * @param event
	 * @param progress
	 * @private
	 */
	_onprogress: function( event , progress ) {
		if ( typeof progress !== 'undefined' ) {
			this.updateBufferStatus( progress );
		}
	},

	/*
	 * Write the Embed html to the target
	 */
	getVideoElementPosition: function(){
		var videoElementDiv = parent.document.getElementById( this.id );
		var videoElementRect = videoElementDiv.getBoundingClientRect();

		return videoElementRect;
	},

	showNativePlayer: function(){
		this.getPlayerElement().showNativePlayer();
	},

	hideNativePlayer: function(){
		this.getPlayerElement().hideNativePlayer();
	},

	useNativePlayerControls: function() {
		return false;
	},

	/**
	 * Passes a fullscreen request to the layoutBuilder interface
	 */
	toggleFullscreen: function() {
		this.getPlayerElement().toggleFullscreen();
	},

	doneFSBtnPressed: function() {
		this.getPlayerElement().doneFSBtnPressed();
	},

	addNativeAirPlayButton: function() {
		this.getPlayerElement().addNativeAirPlayButton();
	},

	showNativeAirPlayButton: function( airPlayBtnPosition ) {
		var x = airPlayBtnPosition.left;
		var y = airPlayBtnPosition.top;
		var w = airPlayBtnPosition.right - airPlayBtnPosition.left;
		var h = airPlayBtnPosition.bottom - airPlayBtnPosition.top;

		this.getPlayerElement().showNativeAirPlayButton( [x, y, w, h] );
	},

	hideNativeAirPlayButton: function() {
		this.getPlayerElement().hideNativeAirPlayButton();
	},

	isVideoSiblingEnabled: function() {
		return false;
	}
};
} )( mediaWiki, jQuery );

<commit_msg>Share<commit_after>/**
* Native embed library:
*
* Enables embedPlayer support for native iOS/Android webView playback system
*/

( function( mw, $ ) { "use strict";
	//make the player transparent to see the native iOS/Android player
	if(mw.getConfig( "EmbedPlayer.ForceNativeComponent")){
		$('body,.videoHolder').css('background-color', 'transparent' );
	}

mw.EmbedPlayerNativeComponent = {
	//Instance Name
	instanceOf: 'NativeComponent',

	// Flag to only load the video ( not play it )
	onlyLoadFlag:false,

	//Callback fired once video is "loaded"
	onLoadedCallback: null,

	// The previous "currentTime" to sniff seek actions
	// NOTE the bug where onSeeked does not seem fire consistently may no longer be applicable
	prevCurrentTime: -1,

	// Store the progress event ( updated during monitor )
	progressEventData: null,

	// If the media loaded event has been fired
	mediaLoadedFlag: null,

	// A flag to keep the video tag offscreen.
	keepPlayerOffScreenFlag: null,

	// A flag to designate the first play event, as to not propagate the native event in this case
	ignoreNextNativeEvent: null,

	// A local var to store the current seek target time:
	currentSeekTargetTime: null,

	// All the native events per:
	// http://www.w3.org/TR/html5/video.html#mediaevents
	nativeEvents : [
		'stop',
		'play',
		'pause',
		'canplay',
		'seeking',
		'seeked',
		'ended',
		'error',
		'stalled',
		'loadedmetadata',
		'timeupdate',
		'progress',
		'enterfullscreen',
		'exitfullscreen',
		'durationchange',
		'chromecastDeviceConnected',
		'chromecastDeviceDisConnected'
	],

	nativeActions : [
		'share'
	],
	// Native player supported feature set
	supports: {
		'playHead' : true,
		'pause' : true,
		'fullscreen' : true,
		'SourceSelector': false,
		'timeDisplay' : true,
		'volumeControl' : false,
		'overlays' : true
	},

	embedPlayerHTML : function() {
		var _this = this;
		if ( !this.playerIsLoaded ){
			mw.log( "NativeComponent:: embedPlayerHTML" );
			// remove any existing pid ( if present )
			$( '#' + this.pid ).remove();

			var divElement = document.createElement("div");
			divElement.setAttribute('id', 'proxy');
			document.body.appendChild(divElement);

			this.proxyElement = divElement;
			try{
				if(NativeBridge.videoPlayer){
					NativeBridge.videoPlayer.registePlayer(this.getPlayerElement());
					NativeBridge.videoPlayer.registerEmbedPlayer( this );
				}
			}
			catch(e){
				alert( e );
			}

			this.applyMediaElementBindings();
			this.playerIsLoaded = true;
			this.getPlayerElement().attr('src', this.getSrc());
			this.bindHelper("SourceChange", function() {
				_this.getPlayerElement().attr('src', this.getSrc());
			});
			this.bindHelper("layoutBuildDone ended", function() {
				_this.getPlayerElement().notifyLayoutReady();
			});
			this.bindHelper("showChromecastDeviceList", function() {
				mw.log("EmbedPlayerNativeComponent:: showChromecastDeviceList::");
				_this.getPlayerElement().showChromecastDeviceList();
			});
		}
	},

	playerSwitchSource: function( source, switchCallback, doneCallback ) {
		mw.log( "NativeComponent:: playerSwitchSource" );
		var _this = this;
		var vid = this.getPlayerElement();
		var switchBindPostfix = '.playerSwitchSource';

		// add a loading indicator:
		_this.addPlayerSpinner();

		// empty out any existing sources:
		$( vid ).empty();

		// load the updated src
		//only on desktop safari we need to load - otherwise we get the same movie play again.
		if (mw.isDesktopSafari()){
			vid.load();
		}

		if( this.getSrc() != source.getSrc() ) {
			vid.attr( 'src', source.getSrc() );
		} else {
			vid.attr( 'src', this.getSrc() );
		}

		this.isPauseLoading = false;

		if( switchCallback ){
			_this.hideSpinner();
			switchCallback( vid );
		}

		// restore position once we have metadata
		$( vid ).bind( 'loadedmetadata' + switchBindPostfix, function(){
			$( vid ).unbind( 'loadedmetadata' + switchBindPostfix);
			mw.log("EmbedPlayerNative:: playerSwitchSource> loadedmetadata callback" );
			// ( do not update the duration )
			// Android and iOS <5 gives bogus duration, depend on external metadata

			// keep going towards playback! if  switchCallback has not been called yet
			// we need the "playing" event to trigger the switch callback
			if ( $.isFunction( switchCallback ) ){
				setTimeout( function() {
					vid.play();
				}, 100);
			}
		});

		// Add the end binding if we have a post event:
		if( $.isFunction( doneCallback ) ){
			$( vid ).bind( 'ended' + switchBindPostfix , function( event ) {
				// remove end binding:
				$( _this.getPlayerElement() ).unbind( switchBindPostfix );
				// issue the doneCallback
				doneCallback();

				// Support loop for older iOS
				// Temporarily disabled pending more testing or refactor into a better place.
				//if ( _this.loop ) {
				//	vid.play();
				//}
				return false;
			});
		}
	},

	/**
	 * Apply media element bindings
	 */
	applyMediaElementBindings: function() {
		var _this = this;
		mw.log("EmbedPlayerNative::MediaElementBindings");

		$.each( _this.nativeEvents, function( inx, eventName ){
			$( _this.getPlayerElement() ).unbind( eventName ).bind( eventName , function(){
				// make sure we propagating events, and the current instance is in the correct closure.
				if( _this._propagateEvents && _this.instanceOf == 'NativeComponent' ){
					var argArray = $.makeArray( arguments );
					// Check if there is local handler:

					if( _this[ '_on' + eventName ] ){
						_this[ '_on' + eventName ].apply( _this, argArray);
					} else {
						// No local handler directly propagate the event to the abstract object:
						$( _this ).trigger( eventName, argArray );
					}
				}
			});
		});
	},

	/**
	 * Get the embed player time
	 */
	getPlayerElementTime: function() {
		var _this = this;
		// Make sure we have .vid obj

		if ( !this.getPlayerElement() ) {
			mw.log( 'EmbedPlayerNative::getPlayerElementTime: ' + this.id + ' not in dom ( stop monitor)' );
			this.stop();
			return false;
		}
		var ct =  this.getPlayerElement().attr('currentTime');
		// Return 0 or a positive number:
		if( ! ct || isNaN( ct ) || ct < 0 || ! isFinite( ct ) ){
			return 0;
		}
		// Return the playerElement currentTime
		return  ct ;
	},

	/**
	 * Get /update the playerElement value
	 */
	getPlayerElement: function () {
		return this.proxyElement;
	},

	/**
	 * Stop the player ( end all listeners )
	 */
	stop: function(){
		mw.log("EmbedPlayerNativeComponent:: stop::");
		this.parent_stop();
		if( this.getPlayerElement() && this.getPlayerElement().attr('currentTime')){
			this.getPlayerElement().attr('currentTime', '0');
			this.getPlayerElement().stop();
		}
	},

	/**
	 * Play back the video stream
	 * calls parent_play to update the interface
	 */

	play: function() {
		mw.log("EmbedPlayerNativeComponent:: play::");
		$( this ).find( '.playerPoster' ).remove();

		if ( this.getPlayerElement() ) { // update player
			this.getPlayerElement().play();
		}
		$( this ).trigger( "playing" );

		if( this.parent_play() ){
			this.monitor();
		}
	},

	/**
	* Pause the video playback
	* calls parent_pause to update the interface
	*/
	pause: function() {
		mw.log("EmbedPlayerNativeComponent:: pause::");
		this.parent_pause(); // update interface
		if ( this.getPlayerElement() ) { // update player
			this.getPlayerElement().pause();
		}
	},

	seek: function( percentage ) {
		mw.log("EmbedPlayerNativeComponent:: seek::");
		var seekTime = percentage * this.getDuration();
		this.getPlayerElement().attr('currentTime', seekTime);
		this.parent_seek( percentage );
	},

	doNativeAction: function( actionParams ) {
		mw.log("EmbedPlayerNativeComponent:: doNativeAction::");
		this.getPlayerElement().attr('nativeAction', actionParams);
		this.getPlayerElement().doNativeAction();
	},

	nativeActionType: function ( actionName ) {
		return $.inArray(actionName, this.nativeActions);
	},

	/**
	 * returns true if device can auto play
	 */
	canAutoPlay: function(){
		return true;
	},

	/**
	 * Handle the native play event
	 */
	_onplay: function(){
		mw.log("EmbedPlayerNativeComponent:: OnPlay::");

		$( this ).trigger( "playing" );

		if( this.paused  && this.parent_play() ){
			this.monitor();
		}
	},

	/**
	* Handle the native paused event
	*/
	/**
	 * Handle the native paused event
	 */
	_onpause: function(){
		mw.log("EmbedPlayerNativeComponent:: OnPause::");
		this.parent_pause();
	},

	/**
	 * Local method for seeking event
	 * fired when "seeking"
	 */
	_onseeking: function() {
		mw.log( "EmbedPlayerNative::onSeeking " );

		// Trigger the html5 "seeking" trigger
		mw.log("EmbedPlayerNative::seeking:trigger:: ");
		if( this._propagateEvents ){
			this.triggerHelper( 'seeking' );
		}
	},

	/**
	 * Local method for seeked event
	 * fired when done seeking
	 */
	_onseeked: function() {
		mw.log("EmbedPlayerNative::onSeeked " );
		this.seeking = false;

		if( this._propagateEvents ){
			mw.log( "EmbedPlayerNative:: trigger: seeked" );
			this.triggerHelper( 'seeked' );
		}

		this.monitor();
	},

	/**
	 * Local method for metadata ready
	 * fired when metadata becomes available
	 *
	 * Used to update the media duration to
	 * accurately reflect the src duration
	 */
	_onloadedmetadata: function() {
		//Fire "onLoaded" flags if set
		if( typeof this.onLoadedCallback == 'function' ) {
			this.onLoadedCallback();
		}

		// Trigger "media loaded"
		if( ! this.mediaLoadedFlag ){
			$( this ).trigger( 'mediaLoaded' );
			this.mediaLoadedFlag = true;
		}
	},

	/**
	 * Local method for end of media event
	 */
	_onended: function( event ) {
		if( this.getPlayerElement() ){
			mw.log( 'EmbedPlayer:native: onended:');
			if( this._propagateEvents ){
				this.onClipDone();
			}
		}
	},

	/**
	 * Local onClip done function for native player.
	 */
	onClipDone: function(){
		this.parent_onClipDone();
	},

	/**
	 * playback error
	 */
	_onerror: function ( event, data ) {
		this.triggerHelper( 'embedPlayerError', [ data ] );
	},

	/**
	 * buffer progress
	 * @param event
	 * @param progress
	 * @private
	 */
	_onprogress: function( event , progress ) {
		if ( typeof progress !== 'undefined' ) {
			this.updateBufferStatus( progress );
		}
	},

	/*
	 * Write the Embed html to the target
	 */
	getVideoElementPosition: function(){
		var videoElementDiv = parent.document.getElementById( this.id );
		var videoElementRect = videoElementDiv.getBoundingClientRect();

		return videoElementRect;
	},

	showNativePlayer: function(){
		this.getPlayerElement().showNativePlayer();
	},

	hideNativePlayer: function(){
		this.getPlayerElement().hideNativePlayer();
	},

	useNativePlayerControls: function() {
		return false;
	},

	/**
	 * Passes a fullscreen request to the layoutBuilder interface
	 */
	toggleFullscreen: function() {
		this.getPlayerElement().toggleFullscreen();
	},

	doneFSBtnPressed: function() {
		this.getPlayerElement().doneFSBtnPressed();
	},

	addNativeAirPlayButton: function() {
		this.getPlayerElement().addNativeAirPlayButton();
	},

	showNativeAirPlayButton: function( airPlayBtnPosition ) {
		var x = airPlayBtnPosition.left;
		var y = airPlayBtnPosition.top;
		var w = airPlayBtnPosition.right - airPlayBtnPosition.left;
		var h = airPlayBtnPosition.bottom - airPlayBtnPosition.top;

		this.getPlayerElement().showNativeAirPlayButton( [x, y, w, h] );
	},

	hideNativeAirPlayButton: function() {
		this.getPlayerElement().hideNativeAirPlayButton();
	},

	isVideoSiblingEnabled: function() {
		return false;
	}
};
} )( mediaWiki, jQuery );

<|endoftext|>


<commit_before>import { t } from './locale';
import { Detect } from './detect';
import { remove as removeDiacritics } from 'diacritics';
import _ from 'lodash';

export function tagText(entity) {
    return d3.entries(entity.tags).map(function(e) {
        return e.key + '=' + e.value;
    }).join(', ');
}

export function entitySelector(ids) {
    return ids.length ? '.' + ids.join(',.') : 'nothing';
}

export function entityOrMemberSelector(ids, graph) {
    var s = entitySelector(ids);

    ids.forEach(function(id) {
        var entity = graph.hasEntity(id);
        if (entity && entity.type === 'relation') {
            entity.members.forEach(function(member) {
                s += ',.' + member.id;
            });
        }
    });

    return s;
}

export function displayName(entity) {
    var localizedNameKey = 'name:' + Detect().locale.toLowerCase().split('-')[0];
    var name = entity.tags[localizedNameKey] || entity.tags.name;
    if (!name && entity.tags.ref) {
        name = entity.tags.ref;
        if (entity.tags.network) {
            name = entity.tags.network + ' ' + name;
        }
    }
    return name;
}

export function displayType(id) {
    return {
        n: t('inspector.node'),
        w: t('inspector.way'),
        r: t('inspector.relation')
    }[id.charAt(0)];
}

export function stringQs(str) {
    return str.split('&').reduce(function(obj, pair){
        var parts = pair.split('=');
        if (parts.length === 2) {
            obj[parts[0]] = (null === parts[1]) ? '' : decodeURIComponent(parts[1]);
        }
        return obj;
    }, {});
}

export function qsString(obj, noencode) {
    function softEncode(s) {
      // encode everything except special characters used in certain hash parameters:
      // "/" in map states, ":", ",", {" and "}" in background
      return encodeURIComponent(s).replace(/(%2F|%3A|%2C|%7B|%7D)/g, decodeURIComponent);
    }
    return Object.keys(obj).sort().map(function(key) {
        return encodeURIComponent(key) + '=' + (
            noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
    }).join('&');
}

export function prefixDOMProperty(property) {
    var prefixes = ['webkit', 'ms', 'moz', 'o'],
        i = -1,
        n = prefixes.length,
        s = document.body;

    if (property in s)
        return property;

    property = property.substr(0, 1).toUpperCase() + property.substr(1);

    while (++i < n)
        if (prefixes[i] + property in s)
            return prefixes[i] + property;

    return false;
}

export function prefixCSSProperty(property) {
    var prefixes = ['webkit', 'ms', 'Moz', 'O'],
        i = -1,
        n = prefixes.length,
        s = document.body.style;

    if (property.toLowerCase() in s)
        return property.toLowerCase();

    while (++i < n)
        if (prefixes[i] + property in s)
            return '-' + prefixes[i].toLowerCase() + property.replace(/([A-Z])/g, '-$1').toLowerCase();

    return false;
}

var transformProperty;
export function setTransform(el, x, y, scale) {
    var prop = transformProperty = transformProperty || prefixCSSProperty('Transform'),
        translate = Detect().opera ?
            'translate('   + x + 'px,' + y + 'px)' :
            'translate3d(' + x + 'px,' + y + 'px,0)';
    return el.style(prop, translate + (scale ? ' scale(' + scale + ')' : ''));
}

export function getStyle(selector) {
    for (var i = 0; i < document.styleSheets.length; i++) {
        var rules = document.styleSheets[i].rules || document.styleSheets[i].cssRules || [];
        for (var k = 0; k < rules.length; k++) {
            var selectorText = rules[k].selectorText && rules[k].selectorText.split(', ');
            if (_.includes(selectorText, selector)) {
                return rules[k];
            }
        }
    }
}

// Calculates Levenshtein distance between two strings
// see:  https://en.wikipedia.org/wiki/Levenshtein_distance
// first converts the strings to lowercase and replaces diacritic marks with ascii equilivants.
export function editDistance(a, b) {
    a = removeDiacritics(a.toLowerCase());
    b = removeDiacritics(b.toLowerCase());
    if (a.length === 0) return b.length;
    if (b.length === 0) return a.length;
    var matrix = [];
    for (var i = 0; i <= b.length; i++) { matrix[i] = [i]; }
    for (var j = 0; j <= a.length; j++) { matrix[0][j] = j; }
    for (i = 1; i <= b.length; i++) {
        for (j = 1; j <= a.length; j++) {
            if (b.charAt(i-1) === a.charAt(j-1)) {
                matrix[i][j] = matrix[i-1][j-1];
            } else {
                matrix[i][j] = Math.min(matrix[i-1][j-1] + 1, // substitution
                    Math.min(matrix[i][j-1] + 1, // insertion
                    matrix[i-1][j] + 1)); // deletion
            }
        }
    }
    return matrix[b.length][a.length];
}

// a d3.mouse-alike which
// 1. Only works on HTML elements, not SVG
// 2. Does not cause style recalculation
export function fastMouse(container) {
    var rect = container.getBoundingClientRect(),
        rectLeft = rect.left,
        rectTop = rect.top,
        clientLeft = +container.clientLeft,
        clientTop = +container.clientTop;
    return function(e) {
        return [
            e.clientX - rectLeft - clientLeft,
            e.clientY - rectTop - clientTop];
    };
}

/* eslint-disable no-proto */
export var getPrototypeOf = Object.getPrototypeOf || function(obj) { return obj.__proto__; };
/* eslint-enable no-proto */

export function asyncMap(inputs, func, callback) {
    var remaining = inputs.length,
        results = [],
        errors = [];

    inputs.forEach(function(d, i) {
        func(d, function done(err, data) {
            errors[i] = err;
            results[i] = data;
            remaining--;
            if (!remaining) callback(errors, results);
        });
    });
}

// wraps an index to an interval [0..length-1]
export function wrap(index, length) {
    if (index < 0)
        index += Math.ceil(-index/length)*length;
    return index % length;
}
<commit_msg>Prefer cycle_network over network<commit_after>import { t } from './locale';
import { Detect } from './detect';
import { remove as removeDiacritics } from 'diacritics';
import _ from 'lodash';

export function tagText(entity) {
    return d3.entries(entity.tags).map(function(e) {
        return e.key + '=' + e.value;
    }).join(', ');
}

export function entitySelector(ids) {
    return ids.length ? '.' + ids.join(',.') : 'nothing';
}

export function entityOrMemberSelector(ids, graph) {
    var s = entitySelector(ids);

    ids.forEach(function(id) {
        var entity = graph.hasEntity(id);
        if (entity && entity.type === 'relation') {
            entity.members.forEach(function(member) {
                s += ',.' + member.id;
            });
        }
    });

    return s;
}

export function displayName(entity) {
    var localizedNameKey = 'name:' + Detect().locale.toLowerCase().split('-')[0]
        name = entity.tags[localizedNameKey] || entity.tags.name || '',
        network = entity.tags.cycle_network || entity.tags.network;
    if (!name && entity.tags.ref) {
        name = entity.tags.ref;
        if (network) {
            name = network + ' ' + name;
        }
    }
    return name;
}

export function displayType(id) {
    return {
        n: t('inspector.node'),
        w: t('inspector.way'),
        r: t('inspector.relation')
    }[id.charAt(0)];
}

export function stringQs(str) {
    return str.split('&').reduce(function(obj, pair){
        var parts = pair.split('=');
        if (parts.length === 2) {
            obj[parts[0]] = (null === parts[1]) ? '' : decodeURIComponent(parts[1]);
        }
        return obj;
    }, {});
}

export function qsString(obj, noencode) {
    function softEncode(s) {
      // encode everything except special characters used in certain hash parameters:
      // "/" in map states, ":", ",", {" and "}" in background
      return encodeURIComponent(s).replace(/(%2F|%3A|%2C|%7B|%7D)/g, decodeURIComponent);
    }
    return Object.keys(obj).sort().map(function(key) {
        return encodeURIComponent(key) + '=' + (
            noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
    }).join('&');
}

export function prefixDOMProperty(property) {
    var prefixes = ['webkit', 'ms', 'moz', 'o'],
        i = -1,
        n = prefixes.length,
        s = document.body;

    if (property in s)
        return property;

    property = property.substr(0, 1).toUpperCase() + property.substr(1);

    while (++i < n)
        if (prefixes[i] + property in s)
            return prefixes[i] + property;

    return false;
}

export function prefixCSSProperty(property) {
    var prefixes = ['webkit', 'ms', 'Moz', 'O'],
        i = -1,
        n = prefixes.length,
        s = document.body.style;

    if (property.toLowerCase() in s)
        return property.toLowerCase();

    while (++i < n)
        if (prefixes[i] + property in s)
            return '-' + prefixes[i].toLowerCase() + property.replace(/([A-Z])/g, '-$1').toLowerCase();

    return false;
}

var transformProperty;
export function setTransform(el, x, y, scale) {
    var prop = transformProperty = transformProperty || prefixCSSProperty('Transform'),
        translate = Detect().opera ?
            'translate('   + x + 'px,' + y + 'px)' :
            'translate3d(' + x + 'px,' + y + 'px,0)';
    return el.style(prop, translate + (scale ? ' scale(' + scale + ')' : ''));
}

export function getStyle(selector) {
    for (var i = 0; i < document.styleSheets.length; i++) {
        var rules = document.styleSheets[i].rules || document.styleSheets[i].cssRules || [];
        for (var k = 0; k < rules.length; k++) {
            var selectorText = rules[k].selectorText && rules[k].selectorText.split(', ');
            if (_.includes(selectorText, selector)) {
                return rules[k];
            }
        }
    }
}

// Calculates Levenshtein distance between two strings
// see:  https://en.wikipedia.org/wiki/Levenshtein_distance
// first converts the strings to lowercase and replaces diacritic marks with ascii equilivants.
export function editDistance(a, b) {
    a = removeDiacritics(a.toLowerCase());
    b = removeDiacritics(b.toLowerCase());
    if (a.length === 0) return b.length;
    if (b.length === 0) return a.length;
    var matrix = [];
    for (var i = 0; i <= b.length; i++) { matrix[i] = [i]; }
    for (var j = 0; j <= a.length; j++) { matrix[0][j] = j; }
    for (i = 1; i <= b.length; i++) {
        for (j = 1; j <= a.length; j++) {
            if (b.charAt(i-1) === a.charAt(j-1)) {
                matrix[i][j] = matrix[i-1][j-1];
            } else {
                matrix[i][j] = Math.min(matrix[i-1][j-1] + 1, // substitution
                    Math.min(matrix[i][j-1] + 1, // insertion
                    matrix[i-1][j] + 1)); // deletion
            }
        }
    }
    return matrix[b.length][a.length];
}

// a d3.mouse-alike which
// 1. Only works on HTML elements, not SVG
// 2. Does not cause style recalculation
export function fastMouse(container) {
    var rect = container.getBoundingClientRect(),
        rectLeft = rect.left,
        rectTop = rect.top,
        clientLeft = +container.clientLeft,
        clientTop = +container.clientTop;
    return function(e) {
        return [
            e.clientX - rectLeft - clientLeft,
            e.clientY - rectTop - clientTop];
    };
}

/* eslint-disable no-proto */
export var getPrototypeOf = Object.getPrototypeOf || function(obj) { return obj.__proto__; };
/* eslint-enable no-proto */

export function asyncMap(inputs, func, callback) {
    var remaining = inputs.length,
        results = [],
        errors = [];

    inputs.forEach(function(d, i) {
        func(d, function done(err, data) {
            errors[i] = err;
            results[i] = data;
            remaining--;
            if (!remaining) callback(errors, results);
        });
    });
}

// wraps an index to an interval [0..length-1]
export function wrap(index, length) {
    if (index < 0)
        index += Math.ceil(-index/length)*length;
    return index % length;
}
<|endoftext|>


<commit_before>(function(window, factory) {
	var globalInstall = function(){
		factory(window.lazySizes);
		window.removeEventListener('lazyunveilread', globalInstall, true);
	};

	factory = factory.bind(null, window, window.document);

	if(typeof module == 'object' && module.exports){
		factory(require('lazysizes'));
	} else if(window.lazySizes) {
		globalInstall();
	} else {
		window.addEventListener('lazyunveilread', globalInstall, true);
	}
}(window, function(window, document, lazySizes) {
	'use strict';

	var imgSupport = 'loading' in HTMLImageElement.prototype;
	var iframeSupport = 'loading' in HTMLIFrameElement.prototype;

	console.warn('Not tested don\'t use in production');

	if (!window.addEventListener || !window.MutationObserver || (!imgSupport && !iframeSupport)) {
		return;
	}

	var nativeLoadingCfg;
	var isConfigSet = false;
	var oldPrematureUnveil = lazySizes.prematureUnveil;
	var cfg = lazySizes.cfg;

	function disableEvents() {
		var loader = lazySizes.loader;
		var throttledCheckElements = loader.checkElems;

		window.removeEventListener('scroll', throttledCheckElements, true);
		window.removeEventListener('scroll', loader._aLSL, true);
		window.removeEventListener('resize', throttledCheckElements, true);

		['focus', 'mouseover', 'click', 'load', 'transitionend', 'animationend', 'webkitAnimationEnd'].forEach(function(name){
			document.removeEventListener(name, throttledCheckElements, true);
		});
	}

	function runConfig() {
		isConfigSet = true;

		nativeLoadingCfg = cfg.nativeLoading || {};

		if (imgSupport && iframeSupport && nativeLoadingCfg.disableListeners) {
			disableEvents();
			nativeLoadingCfg.setLoadingAttribute = true;
		}

		if (nativeLoadingCfg.setLoadingAttribute) {
			window.addEventListener('lazybeforeunveil', function(e){
				var element = e.target;

				if ('loading' in element && !element.getAttribute('loading')) {
					element.setAttribute('loading', 'lazy');
				}
			}, true);
		}
	}

	lazySizes.prematureUnveil = function prematureUnveil(element) {

		if (!isConfigSet) {
			runConfig();
		}

		if ('loading' in element &&
			(nativeLoadingCfg.setLoadingAttribute || element.getAttribute('loading')) &&
			(element.getAttribute('data-sizes') != 'auto' || element.offsetWidth)) {
			lazySizes.loader.unveil(element);
			return true;
		}

		if (oldPrematureUnveil) {
			return oldPrematureUnveil(element);
		}
	};

}));
<commit_msg>Native-Loading: Properly remove missing scroll handler<commit_after>(function(window, factory) {
	var globalInstall = function(){
		factory(window.lazySizes);
		window.removeEventListener('lazyunveilread', globalInstall, true);
	};

	factory = factory.bind(null, window, window.document);

	if(typeof module == 'object' && module.exports){
		factory(require('lazysizes'));
	} else if(window.lazySizes) {
		globalInstall();
	} else {
		window.addEventListener('lazyunveilread', globalInstall, true);
	}
}(window, function(window, document, lazySizes) {
	'use strict';

	var imgSupport = 'loading' in HTMLImageElement.prototype;
	var iframeSupport = 'loading' in HTMLIFrameElement.prototype;

	console.warn('Not tested don\'t use in production', 'supports image[loading]: '+ imgSupport);

	if (!window.addEventListener || !window.MutationObserver || (!imgSupport && !iframeSupport)) {
		return;
	}

	var nativeLoadingCfg;
	var isConfigSet = false;
	var oldPrematureUnveil = lazySizes.prematureUnveil;
	var cfg = lazySizes.cfg;

	function disableEvents() {
		var loader = lazySizes.loader;
		var throttledCheckElements = loader.checkElems;
		var removeALSL = function(){
			setTimeout(function(){
				window.removeEventListener('scroll', loader._aLSL, true);
			}, 1000);
		};

		window.addEventListener('load', removeALSL);
		removeALSL();

		window.removeEventListener('scroll', throttledCheckElements, true);

		window.removeEventListener('resize', throttledCheckElements, true);

		['focus', 'mouseover', 'click', 'load', 'transitionend', 'animationend', 'webkitAnimationEnd'].forEach(function(name){
			document.removeEventListener(name, throttledCheckElements, true);
		});
	}

	function runConfig() {
		isConfigSet = true;

		nativeLoadingCfg = cfg.nativeLoading || {};

		if (imgSupport && iframeSupport && nativeLoadingCfg.disableListeners) {
			disableEvents();
			nativeLoadingCfg.setLoadingAttribute = true;
		}

		if (nativeLoadingCfg.setLoadingAttribute) {
			window.addEventListener('lazybeforeunveil', function(e){
				var element = e.target;

				if ('loading' in element && !element.getAttribute('loading')) {
					element.setAttribute('loading', 'lazy');
				}
			}, true);
		}
	}

	lazySizes.prematureUnveil = function prematureUnveil(element) {

		if (!isConfigSet) {
			runConfig();
		}

		if ('loading' in element &&
			(nativeLoadingCfg.setLoadingAttribute || element.getAttribute('loading')) &&
			(element.getAttribute('data-sizes') != 'auto' || element.offsetWidth)) {
			lazySizes.loader.unveil(element);
			return true;
		}

		if (oldPrematureUnveil) {
			return oldPrematureUnveil(element);
		}
	};

}));
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import yubikiri from 'yubikiri';
import {QueryRenderer, graphql} from 'react-relay';

import CommentDecorationsController from '../controllers/comment-decorations-controller';
import ObserveModel from '../views/observe-model';
import RelayEnvironment from '../views/relay-environment';
import {GithubLoginModelPropType} from '../prop-types';
import {UNAUTHENTICATED, INSUFFICIENT} from '../shared/keytar-strategy';
import RelayNetworkLayerManager from '../relay-network-layer-manager';
import {PAGE_SIZE} from '../helpers';

export default class CommentDecorationsContainer extends React.Component {
  static propTypes = {
    workspace: PropTypes.object.isRequired,
    commandRegistry: PropTypes.object.isRequired,
    repository: PropTypes.object.isRequired,
    loginModel: GithubLoginModelPropType.isRequired,
  };

  fetchRepositoryData = repository => {
    return yubikiri({
      branches: repository.getBranches(),
      remotes: repository.getRemotes(),
      isMerging: repository.isMerging(),
      isRebasing: repository.isRebasing(),
      isAbsent: repository.isAbsent(),
      isLoading: repository.isLoading(),
      isPresent: repository.isPresent(),
      currentRemote: repository.getCurrentRemote(),
    });
  }

  fetchToken = (loginModel, repoData) => {
    if (!repoData) {
      return null;
    }

    const endpoint = repoData.currentRemote.getEndpoint();

    if (!endpoint) {
      return null;
    }
    return yubikiri({
      token: loginModel.getToken(endpoint.getLoginAccount()),
    });
  }

  render() {
    return (
      <ObserveModel model={this.props.repository} fetchData={this.fetchRepositoryData}>
        {repoData => this.renderWithRepositoryData(repoData)}
      </ObserveModel>
    );
  }

  renderWithRepositoryData(repoData) {
    if (!repoData) {
      return null;
    }

    return (
      <ObserveModel
        model={this.props.loginModel}
        fetchParams={[repoData, this.props.loginModel]}
        fetchData={this.fetchToken}>
        {token => this.renderWithToken(repoData, token)}
      </ObserveModel>
    );
  }

  renderWithToken = (repoData, tokenData) => {
    if (!tokenData || tokenData.token === UNAUTHENTICATED || tokenData.token === INSUFFICIENT) {
      // we're not going to prompt users to log in to render decorations for comments
      // just let it go and move on with our lives.
      return null;
    }

    if (!repoData) {
      return null;
    }

    const head = repoData.branches.getHeadBranch();
    if (!head.isPresent) {
      return null;
    }

    const push = head.getPush();
    if (!push.isPresent() || !push.isRemoteTracking()) {
      return null;
    }

    const pushRemote = repoData.remotes.withName(push.getRemoteName());
    if (!pushRemote.isPresent() || !pushRemote.isGithubRepo()) {
      return null;
    }

    const endpoint = repoData.currentRemote.getEndpoint();
    const environment = RelayNetworkLayerManager.getEnvironmentForHost(endpoint, tokenData.token);
    const query = graphql`
      query commentDecorationsContainerQuery(
        $headOwner: String!
        $headName: String!
        $headRef: String!
        $reviewCount: Int!
        $reviewCursor: String
        $threadCount: Int!
        $threadCursor: String
        $commentCount: Int!
        $commentCursor: String
        $first: Int!) {
        repository(owner: $headOwner, name: $headName) {
          ref(qualifiedName: $headRef) {
            associatedPullRequests(
              first: $first, states: [OPEN]) {
              totalCount
              nodes {
                ...commentDecorationsController_results
              }
            }
          }
        }
      }
    `;
    const variables = {
      headOwner: pushRemote.getOwner(),
      headName: pushRemote.getRepo(),
      headRef: push.getRemoteRef(),
      first: 1,
      reviewCount: PAGE_SIZE,
      reviewCursor: null,
      threadCount: PAGE_SIZE,
      threadCursor: null,
      commentCount: PAGE_SIZE,
      commentCursor: null,
    };

    return (
      <RelayEnvironment.Provider value={environment}>
        <QueryRenderer
          environment={environment}
          query={query}
          variables={variables}
          render={queryResult => this.renderWithGraphQLData(queryResult, repoData)}
        />
      </RelayEnvironment.Provider>
    );
  }

  renderWithGraphQLData({error, props, retry}, repoData, token) {
    if (error) {
      console.log(error);
      return null;
    }

    if (!props) {
      // no loading spinner for you
      // just fetch silently behind the scenes like a good little container
      return null;
    }

    if (!props.repository || !props.repository.ref) {
      // let's not try too hard.
      return null;
    }

    const associatedPullRequests = props.repository.ref.associatedPullRequests.nodes;

    return (
      <CommentDecorationsController
        workspace={this.props.workspace}
        localRepository={repoData}
        results={associatedPullRequests}
      />
    );
  }
}
<commit_msg>:fire: unnecessary local repository data<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import yubikiri from 'yubikiri';
import {QueryRenderer, graphql} from 'react-relay';

import CommentDecorationsController from '../controllers/comment-decorations-controller';
import ObserveModel from '../views/observe-model';
import RelayEnvironment from '../views/relay-environment';
import {GithubLoginModelPropType} from '../prop-types';
import {UNAUTHENTICATED, INSUFFICIENT} from '../shared/keytar-strategy';
import RelayNetworkLayerManager from '../relay-network-layer-manager';
import {PAGE_SIZE} from '../helpers';

export default class CommentDecorationsContainer extends React.Component {
  static propTypes = {
    workspace: PropTypes.object.isRequired,
    commandRegistry: PropTypes.object.isRequired,
    repository: PropTypes.object.isRequired,
    loginModel: GithubLoginModelPropType.isRequired,
  };

  fetchRepositoryData = repository => {
    return yubikiri({
      branches: repository.getBranches(),
      remotes: repository.getRemotes(),
      currentRemote: repository.getCurrentRemote(),
    });
  }

  fetchToken = (loginModel, repoData) => {
    if (!repoData) {
      return null;
    }

    const endpoint = repoData.currentRemote.getEndpoint();

    if (!endpoint) {
      return null;
    }
    return yubikiri({
      token: loginModel.getToken(endpoint.getLoginAccount()),
    });
  }

  render() {
    return (
      <ObserveModel model={this.props.repository} fetchData={this.fetchRepositoryData}>
        {repoData => this.renderWithRepositoryData(repoData)}
      </ObserveModel>
    );
  }

  renderWithRepositoryData(repoData) {
    if (!repoData) {
      return null;
    }

    return (
      <ObserveModel
        model={this.props.loginModel}
        fetchParams={[repoData, this.props.loginModel]}
        fetchData={this.fetchToken}>
        {token => this.renderWithToken(repoData, token)}
      </ObserveModel>
    );
  }

  renderWithToken = (repoData, tokenData) => {
    if (!tokenData || tokenData.token === UNAUTHENTICATED || tokenData.token === INSUFFICIENT) {
      // we're not going to prompt users to log in to render decorations for comments
      // just let it go and move on with our lives.
      return null;
    }

    if (!repoData) {
      return null;
    }

    const head = repoData.branches.getHeadBranch();
    if (!head.isPresent) {
      return null;
    }

    const push = head.getPush();
    if (!push.isPresent() || !push.isRemoteTracking()) {
      return null;
    }

    const pushRemote = repoData.remotes.withName(push.getRemoteName());
    if (!pushRemote.isPresent() || !pushRemote.isGithubRepo()) {
      return null;
    }

    const endpoint = repoData.currentRemote.getEndpoint();
    const environment = RelayNetworkLayerManager.getEnvironmentForHost(endpoint, tokenData.token);
    const query = graphql`
      query commentDecorationsContainerQuery(
        $headOwner: String!
        $headName: String!
        $headRef: String!
        $reviewCount: Int!
        $reviewCursor: String
        $threadCount: Int!
        $threadCursor: String
        $commentCount: Int!
        $commentCursor: String
        $first: Int!) {
        repository(owner: $headOwner, name: $headName) {
          ref(qualifiedName: $headRef) {
            associatedPullRequests(
              first: $first, states: [OPEN]) {
              totalCount
              nodes {
                ...commentDecorationsController_results
              }
            }
          }
        }
      }
    `;
    const variables = {
      headOwner: pushRemote.getOwner(),
      headName: pushRemote.getRepo(),
      headRef: push.getRemoteRef(),
      first: 1,
      reviewCount: PAGE_SIZE,
      reviewCursor: null,
      threadCount: PAGE_SIZE,
      threadCursor: null,
      commentCount: PAGE_SIZE,
      commentCursor: null,
    };

    return (
      <RelayEnvironment.Provider value={environment}>
        <QueryRenderer
          environment={environment}
          query={query}
          variables={variables}
          render={queryResult => this.renderWithGraphQLData(queryResult, repoData)}
        />
      </RelayEnvironment.Provider>
    );
  }

  renderWithGraphQLData({error, props, retry}, repoData, token) {
    if (error) {
      console.log(error);
      return null;
    }

    if (!props) {
      // no loading spinner for you
      // just fetch silently behind the scenes like a good little container
      return null;
    }

    if (!props.repository || !props.repository.ref) {
      // let's not try too hard.
      return null;
    }

    const associatedPullRequests = props.repository.ref.associatedPullRequests.nodes;

    return (
      <CommentDecorationsController
        workspace={this.props.workspace}
        localRepository={repoData}
        results={associatedPullRequests}
      />
    );
  }
}
<|endoftext|>


<commit_before>'use strict'

var path = require('path')

var gulp = require('gulp')
var exeq = require('exeq')

var platform = process.platform

gulp.task('sqlite', () => {
  // TODO - make this work on Windows & Linux
  var sqliteBinaryFullDir

  if(platform === 'darwin'){
    sqliteBinaryFullDir = '/usr/local/opt/sqlite/'
  }
  // else if(platform === 'darwin'){
  //
  // }
  // else if(platform === 'win32'){
  //
  // }

  var electronVersion = require(path.resolve('', 'package.json')).dependencies['electron-prebuilt'].slice(1)

  return exeq(
    `npm install sqlite3 --runtime=electron --target=${ electronVersion } --build-from-source --sqlite=${ sqliteBinaryFullDir }`
  )
  .then(function() {
    console.log('Successfully compiled sqlite3 lib binding')
  })
  .catch(function(err) {
    console.error('There was an error building sqlite3 lib binding', err)
  })

})
<commit_msg>Updated sqlite build task in gulp<commit_after>'use strict'

var path = require('path')

var gulp = require('gulp')
var exeq = require('exeq')

var platform = process.platform
var electronVersion = require(path.resolve('', 'package.json')).dependencies['electron-prebuilt'].slice(1)

gulp.task('sqlite', () => {
  // TODO - make this work on Windows & Linux
  var sqliteBinaryFullDir

  if(platform === 'darwin'){
    /****
     * Homebrew sqlite installed folder
     * /usr/local/opt/sqlite/ is a symlink to the most up to date version installed in /usr/local/Cellar/sqlite
     */
    sqliteBinaryFullDir = '/usr/local/opt/sqlite/'
  }
  // else if(platform === 'linux'){
  //
  // }
  // else if(platform === 'win32'){
  //
  // }

  return exeq(
    `npm install sqlite3 --runtime=electron --target=${ electronVersion } --target_arch=${ process.arch } --target_platform=${ platform } --build-from-source --sqlite=${ sqliteBinaryFullDir }`
  )
  .then(function() {
    console.log('Successfully compiled sqlite3 lib binding')
  })
  .catch(function(err) {
    console.error('There was an error building sqlite3 lib binding', err)
  })

})
<|endoftext|>


<commit_before>/* global require, module, process, console, __dirname */
/* jshint -W097 */
'use strict';

var
  fs         = require('fs'),
  express    = require('express'),
  mongoose   = require('mongoose'),
  rootDir    = __dirname + '/../../../',
  routesDir  = __dirname + '/routes/';

if(process.env.APP_DIR_FOR_CODE_COVERAGE) {
 rootDir += '../../../../';
}

// MONGO CONF.
// =============================================================================
var mongoConfigParser = require('../../lib/mongoConfigParser');

var mongoConn = new mongoConfigParser()
  .setEnvDir( rootDir + 'db/mongo/env' );

// connect
mongoose.connect(mongoConn.getConnectionString(), mongoConn.getConnectionOptions());

// API ROUTES
// =============================================================================
var router = express.Router();

// middleware to use for all requests
router.use(function(req, res, next) {
  next(); // make sure we go to the next routes and don't stop here
});

// test route to make sure everything is working (accessed at GET http://localhost:PORT/api)
router.get('/', function(req, res) {
  res.json({ message: 'hooray! welcome to our api!' });
});

// load the routes
fs.readdirSync(routesDir).forEach(function(file) {
  var route = routesDir + file.substr(0, file.indexOf('.'));
  console.log('Adding route:' + route);
  require(route)(router);
});

module.exports = router;
<commit_msg>Travis debug<commit_after>/* global require, module, process, console, __dirname */
/* jshint -W097 */
'use strict';

var
  fs         = require('fs'),
  express    = require('express'),
  mongoose   = require('mongoose'),
  rootDir    = __dirname + '/../../../',
  routesDir  = __dirname + '/routes/';

if(process.env.APP_DIR_FOR_CODE_COVERAGE) {
 rootDir += '../../../';
}

// MONGO CONF.
// =============================================================================
var mongoConfigParser = require('../../lib/mongoConfigParser');

var mongoConn = new mongoConfigParser()
  .setEnvDir( rootDir + 'db/mongo/env' );

// connect
mongoose.connect(mongoConn.getConnectionString(), mongoConn.getConnectionOptions());

// API ROUTES
// =============================================================================
var router = express.Router();

// middleware to use for all requests
router.use(function(req, res, next) {
  next(); // make sure we go to the next routes and don't stop here
});

// test route to make sure everything is working (accessed at GET http://localhost:PORT/api)
router.get('/', function(req, res) {
  res.json({ message: 'hooray! welcome to our api!' });
});

// load the routes
fs.readdirSync(routesDir).forEach(function(file) {
  var route = routesDir + file.substr(0, file.indexOf('.'));
  console.log('Adding route:' + route);
  require(route)(router);
});

module.exports = router;
<|endoftext|>


<commit_before>var utils = require('../lib/utils.js');

var george = {
	info: {
		name: 'george',
		style: 1
	},
	ai: (playerState, enemiesState, gameEnvironment) => {
		var directionToAmmo;

		if (utils.canKill(playerState, enemiesState) && playerState.ammo) {
			return 'shoot';
		}

		var myPosition = playerState.position;

		if (gameEnvironment.ammoPosition.length) {
			var distance = 10000;
			var index = -1;
			for(var i=0;i<gameEnvironment.ammoPosition.length;i++){
				var d = utils.getDistance(myPosition, gameEnvironment.ammoPosition[i]);
				if(d<distance){
					index =i;
					distance = d;
				}
			}

			directionToAmmo = utils.getDirection(
				playerState.position,
				gameEnvironment.ammoPosition[index]
			);

			if (directionToAmmo !== playerState.direction) {
				return directionToAmmo;
			}
			return 'move';
		}

		return utils.randomMove();
		}
};

module.exports = george;
<commit_msg>new method<commit_after>var utils = require('../lib/utils.js');

function avoidEnemy(playerState, enemiesStates){
	if(playerState.ammo)
		return null;

	var myPosition = playerState.position;
	for(var i=0;i<enemiesStates.length;i++){
		if(enemiesStates[i].ammo){
			var directionToEnemy = utils.getDirection(
				gameEnvironment.ammoPosition[index],
				playerState.position
			);
			if(directionToEnemy==enemiesStates[i].direction)
				return null;
		}
	}
}

var george = {
	info: {
		name: 'george',
		style: 1
	},
	ai: (playerState, enemiesStates, gameEnvironment) => {
		var directionToAmmo;

		if (utils.canKill(playerState, enemiesStates) && playerState.ammo) {
			return 'shoot';
		}

		var myPosition = playerState.position;

		if (gameEnvironment.ammoPosition.length) {
			var distance = 10000;
			var index = -1;
			for(var i=0;i<gameEnvironment.ammoPosition.length;i++){
				var d = utils.getDistance(myPosition, gameEnvironment.ammoPosition[i]);
				if(d<distance){
					index =i;
					distance = d;
				}
			}

			directionToAmmo = utils.getDirection(
				playerState.position,
				gameEnvironment.ammoPosition[index]
			);

			if (directionToAmmo !== playerState.direction) {
				return directionToAmmo;
			}
			return 'move';
		}

		return utils.randomMove();
		}
};

module.exports = george;
<|endoftext|>


<commit_before>/* ========================================================================
 * Bootstrap: scrollspy.js v3.1.1
 * http://getbootstrap.com/javascript/#scrollspy
 * ========================================================================
 * Copyright 2011-2014 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */

+function ($) {
  'use strict';

  // SCROLLSPY CLASS DEFINITION
  // ==========================

  function ScrollSpy(element, options) {
    var href
    var process  = $.proxy(this.process, this)

    this.$element       = $(element).is('body') ? $(window) : $(element)
    this.$body          = $('body')
    this.$scrollElement = this.$element.on('scroll.bs.scrollspy', process)
    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)
    this.selector       = (this.options.target
      || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
      || '') + ' .nav li > a'
    this.offsets        = $([])
    this.targets        = $([])
    this.activeTarget   = null

    this.refresh()
    this.process()
  }

  ScrollSpy.VERSION  = '3.1.1'

  ScrollSpy.DEFAULTS = {
    offset: 10
  }

  ScrollSpy.prototype.refresh = function () {
    var offsetMethod = this.$element[0] == window ? 'offset' : 'position'

    this.offsets = $([])
    this.targets = $([])

    var self     = this

    this.$body
      .find(this.selector)
      .filter(':visible')
      .map(function () {
        var $el   = $(this)
        var href  = $el.data('target') || $el.attr('href')
        var $href = /^#./.test(href) && $(href)

        return ($href
          && $href.length
          && $href.is(':visible')
          && [[ $href[offsetMethod]().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]]) || null
      })
      .sort(function (a, b) { return a[0] - b[0] })
      .each(function () {
        self.offsets.push(this[0])
        self.targets.push(this[1])
      })
  }

  ScrollSpy.prototype.process = function () {
    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset
    var scrollHeight = this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
    var maxScroll    = scrollHeight - this.$scrollElement.height()
    var offsets      = this.offsets
    var targets      = this.targets
    var activeTarget = this.activeTarget
    var i

    if (scrollTop >= maxScroll) {
      return activeTarget != (i = targets.last()[0]) && this.activate(i)
    }

    if (activeTarget && scrollTop <= offsets[0]) {
      return activeTarget != (i = targets[0]) && this.activate(i)
    }

    for (i = offsets.length; i--;) {
      activeTarget != targets[i]
        && scrollTop >= offsets[i]
        && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
        && this.activate( targets[i] )
    }
  }

  ScrollSpy.prototype.activate = function (target) {
    this.activeTarget = target

    $(this.selector)
      .parentsUntil(this.options.target, '.active')
      .removeClass('active')

    var selector = this.selector +
        '[data-target="' + target + '"],' +
        this.selector + '[href="' + target + '"]'

    var active = $(selector)
      .parents('li')
      .addClass('active')

    if (active.parent('.dropdown-menu').length) {
      active = active
        .closest('li.dropdown')
        .addClass('active')
    }

    active.trigger('activate.bs.scrollspy')
  }

  // SCROLLSPY PLUGIN DEFINITION
  // ===========================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.scrollspy')
      var options = typeof option == 'object' && option

      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  var old = $.fn.scrollspy

  $.fn.scrollspy             = Plugin
  $.fn.scrollspy.Constructor = ScrollSpy

  // SCROLLSPY NO CONFLICT
  // =====================

  $.fn.scrollspy.noConflict = function () {
    $.fn.scrollspy = old
    return this
  }

  // SCROLLSPY DATA-API
  // ==================

  $(window).on('load.bs.scrollspy.data-api', function () {
    $('[data-spy="scroll"]').each(function () {
      var $spy = $(this)
      Plugin.call($spy, $spy.data())
    })
  })

}(jQuery);
<commit_msg>Adjust for Scrollspy offset when calculating maxScroll.<commit_after>/* ========================================================================
 * Bootstrap: scrollspy.js v3.1.1
 * http://getbootstrap.com/javascript/#scrollspy
 * ========================================================================
 * Copyright 2011-2014 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */

+function ($) {
  'use strict';

  // SCROLLSPY CLASS DEFINITION
  // ==========================

  function ScrollSpy(element, options) {
    var href
    var process  = $.proxy(this.process, this)

    this.$element       = $(element).is('body') ? $(window) : $(element)
    this.$body          = $('body')
    this.$scrollElement = this.$element.on('scroll.bs.scrollspy', process)
    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)
    this.selector       = (this.options.target
      || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
      || '') + ' .nav li > a'
    this.offsets        = $([])
    this.targets        = $([])
    this.activeTarget   = null

    this.refresh()
    this.process()
  }

  ScrollSpy.VERSION  = '3.1.1'

  ScrollSpy.DEFAULTS = {
    offset: 10
  }

  ScrollSpy.prototype.refresh = function () {
    var offsetMethod = this.$element[0] == window ? 'offset' : 'position'

    this.offsets = $([])
    this.targets = $([])

    var self     = this

    this.$body
      .find(this.selector)
      .filter(':visible')
      .map(function () {
        var $el   = $(this)
        var href  = $el.data('target') || $el.attr('href')
        var $href = /^#./.test(href) && $(href)

        return ($href
          && $href.length
          && $href.is(':visible')
          && [[ $href[offsetMethod]().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]]) || null
      })
      .sort(function (a, b) { return a[0] - b[0] })
      .each(function () {
        self.offsets.push(this[0])
        self.targets.push(this[1])
      })
  }

  ScrollSpy.prototype.process = function () {
    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset
    var scrollHeight = this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
    var maxScroll    = this.options.offset + scrollHeight - this.$scrollElement.height()
    var offsets      = this.offsets
    var targets      = this.targets
    var activeTarget = this.activeTarget
    var i

    if (scrollTop >= maxScroll) {
      return activeTarget != (i = targets.last()[0]) && this.activate(i)
    }

    if (activeTarget && scrollTop <= offsets[0]) {
      return activeTarget != (i = targets[0]) && this.activate(i)
    }

    for (i = offsets.length; i--;) {
      activeTarget != targets[i]
        && scrollTop >= offsets[i]
        && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
        && this.activate( targets[i] )
    }
  }

  ScrollSpy.prototype.activate = function (target) {
    this.activeTarget = target

    $(this.selector)
      .parentsUntil(this.options.target, '.active')
      .removeClass('active')

    var selector = this.selector +
        '[data-target="' + target + '"],' +
        this.selector + '[href="' + target + '"]'

    var active = $(selector)
      .parents('li')
      .addClass('active')

    if (active.parent('.dropdown-menu').length) {
      active = active
        .closest('li.dropdown')
        .addClass('active')
    }

    active.trigger('activate.bs.scrollspy')
  }

  // SCROLLSPY PLUGIN DEFINITION
  // ===========================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.scrollspy')
      var options = typeof option == 'object' && option

      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  var old = $.fn.scrollspy

  $.fn.scrollspy             = Plugin
  $.fn.scrollspy.Constructor = ScrollSpy

  // SCROLLSPY NO CONFLICT
  // =====================

  $.fn.scrollspy.noConflict = function () {
    $.fn.scrollspy = old
    return this
  }

  // SCROLLSPY DATA-API
  // ==================

  $(window).on('load.bs.scrollspy.data-api', function () {
    $('[data-spy="scroll"]').each(function () {
      var $spy = $(this)
      Plugin.call($spy, $spy.data())
    })
  })

}(jQuery);
<|endoftext|>


<commit_before>#!/usr/bin/env node

var program   = require('commander');
var fs        = require('fs');
var package   = require('../package.json');
var writeGood = require('../write-good');
var annotate  = require('../lib/annotate');

program
  .version(package.version)
  .usage('[options] <file ...>')
  .description('write-good is a naive linter for English prose.')
  .option('--checks <module>',
    'add a custom checks module. ' +
    'If you specify such a module, write-good will support additional options to (de)activate checks of the custom module.',
    {isDefault: true}
  )
  .option(
    '--text <text>',
    'provide direct text input instead of glob/file name'
  )
  .option(
    '--parse',
    'activate parse-happy output and a more conventional Unix exit code'
  );

var args = process.argv.slice(2);
var checksArg = args.find(function (arg) {
    return arg.startsWith('--checks');
});

var checksModule = checksArg ? checksArg.replace('--checks=', '') : undefined;

var checks = [ // default checks
  ['weasel', 'weasel word'],
  ['illusion', 'lexical illusion'],
  ['so', 'so'],
  ['thereIs', 'there is'],
  ['passive', 'passive voice'],
  ['adverb', 'adverb weakens meaning'],
  ['tooWordy', 'too wordy'],
  ['cliches', 'clichés']
];

function generateDeactivationDescription(checkName) {
  return "deactivate the '" +  checkName + "' check";
}

function generateActivationDescription(checkName) {
  return "activate the '" +  checkName + "' check and" +
    "deactivate all other checks that aren't explicitly activated";
}

function generateCheckOptions(checkParams) {
  var checkOption = Array.isArray(checkParams) ? checkParams[0] : checkParams;
  var checkName = Array.isArray(checkParams) ? checkParams[1] : checkParams;
  program
    .option(
      '--no-' + checkOption,
      generateDeactivationDescription(checkName),
      {isDefault: true}
    )
    .option(
      '--' + checkOption,
      generateActivationDescription(checkName),
      {isDefault: true}
    );
  opts[checkOption] = null;
}

var opts = {};
if (!checksModule) {
  opts = {
    eprime: false // user must opt-in
  };
  program
  .option(
    '--eprime',
    generateActivationDescription('E-Prime')
  )
  .option(
    '--yes-eprime',
    "activate 'E-Prime' check, without deactivating the other checks"
  );
  checks.forEach(generateCheckOptions);
} else { // set custom ops, for example to lint a non-English document
  try {
    opts.checks = require(checksModule);
  } catch (e) {
    console.log(
      'Could not import custom check module. ' +
      'Check for spelling errors and make sure you have the module installed.');
    process.exit(1);
  }
  // dynamically set up custom options
  Object.keys(opts.checks).forEach(generateCheckOptions);
}

var files = program.parse(process.argv).args;
// 'parse' is a commander.js edge case:
var shouldParse = Object.keys(program).indexOf('parse') !== -1;

var hasTextArg = args.some(function(arg) {
  return arg.startsWith('--text')
});
if (files.length === 0 && !hasTextArg) {
  console.log('You did not provide any files to check.');
  process.exit(1);
}

var hasChecks = args.some(function(arg) {
  return arg.startsWith('--checks');
});

var handleInvalidArgument = function(arg) {
  console.log('"' + arg + '" is not a valid argument.');
  process.exit(1);
}

if(hasChecks) {
  // validate base args and infer valid check args from the imported custom check module
  args.slice(1).forEach(function(arg) {
    if(arg.startsWith('--text') || arg.startsWith('--checks') || arg === '--parse') return;
    var isValid = Object.keys(opts.checks).some(function(check) {
      return arg === '--' + check || arg === '--no-' + check;
    });
    if(!isValid) {
      handleInvalidArgument(arg);
    }
  });
} else {
  var optionArgs = args.filter(function(arg) {
    return !files.includes(arg);
  });
  // validate default args if no custom checks module is provided
  optionArgs.forEach(function(arg) {
    if(arg.startsWith('--text')) return;
    var isValid = program.options.some(function (option) {
      return arg === option.long || arg === option.short;
    });
    if(!isValid) {
      handleInvalidArgument(arg);
    }
  });
}

var include = true;
var inputSupplied = files.length;
var textInputSupplied = false;

args.filter(function (arg) {
  return arg.substr(0, 2) === '--';
}).map(function (arg) {
  return arg.substr(2);
}).forEach(function (arg) {
  if (arg.indexOf('text=') !== -1) {
    opts[arg.substr(0, 4)] = arg.substr(5);
    textInputSupplied = inputSupplied = true;
  } else if (arg.substr(0, 3) === 'no-') {
    opts[arg.substr(3)] = false;
  } else if (arg.substr(0, 4) === 'yes-') {
    opts[arg.substr(4)] = true;
  } else if (arg == 'parse') {
  } else if (arg.indexOf('checks=') === -1) {
    opts[arg] = true;
    include = false;
  }
});

Object.keys(opts).forEach(function (name) {
  if (typeof opts[name] !== 'boolean'
  &&  name !== 'text'                 // --text="text to check"
  && name !== 'checks') {             // --checks="custom-check-module"
    opts[name] = include;
  }
});

if (!inputSupplied) {
  console.log('You did not provide any input (file or text) to check');
  process.exit(1);
}

var exitCode = 0;

if (textInputSupplied) {
  displaySuggestions('text', opts['text'], opts);
} else {
  files.forEach(function (file) {
    var contents = fs.readFileSync(file, 'utf8');
    displaySuggestions(file, contents, opts);
  })
};

function displaySuggestions(source, contents, opts) {
  var suggestions = writeGood(contents, opts);

  if (shouldParse) {
    exitCode = suggestions.length > 0 ? -1 : 0;
    console.log(annotate(contents, suggestions, true).map(function(ann){return [source,ann.line,ann.col, ann.reason.replace("\n", " ")].join(":")}).join("\n"));
  } else {
    exitCode += suggestions.length;
    if (suggestions.length) {
      console.log('In ' + source);
      console.log('=============');
      console.log(annotate(contents, suggestions).join('\n-------------\n'));
    }
  }
}

process.exit(exitCode);
<commit_msg>Add extra  space (#100)<commit_after>#!/usr/bin/env node

var program   = require('commander');
var fs        = require('fs');
var package   = require('../package.json');
var writeGood = require('../write-good');
var annotate  = require('../lib/annotate');

program
  .version(package.version)
  .usage('[options] <file ...>')
  .description('write-good is a naive linter for English prose.')
  .option('--checks <module>',
    'add a custom checks module. ' +
    'If you specify such a module, write-good will support additional options to (de)activate checks of the custom module.',
    {isDefault: true}
  )
  .option(
    '--text <text>',
    'provide direct text input instead of glob/file name'
  )
  .option(
    '--parse',
    'activate parse-happy output and a more conventional Unix exit code'
  );

var args = process.argv.slice(2);
var checksArg = args.find(function (arg) {
    return arg.startsWith('--checks');
});

var checksModule = checksArg ? checksArg.replace('--checks=', '') : undefined;

var checks = [ // default checks
  ['weasel', 'weasel word'],
  ['illusion', 'lexical illusion'],
  ['so', 'so'],
  ['thereIs', 'there is'],
  ['passive', 'passive voice'],
  ['adverb', 'adverb weakens meaning'],
  ['tooWordy', 'too wordy'],
  ['cliches', 'clichés']
];

function generateDeactivationDescription(checkName) {
  return "deactivate the '" +  checkName + "' check";
}

function generateActivationDescription(checkName) {
  return "activate the '" +  checkName + "' check and " +
    "deactivate all other checks that aren't explicitly activated";
}

function generateCheckOptions(checkParams) {
  var checkOption = Array.isArray(checkParams) ? checkParams[0] : checkParams;
  var checkName = Array.isArray(checkParams) ? checkParams[1] : checkParams;
  program
    .option(
      '--no-' + checkOption,
      generateDeactivationDescription(checkName),
      {isDefault: true}
    )
    .option(
      '--' + checkOption,
      generateActivationDescription(checkName),
      {isDefault: true}
    );
  opts[checkOption] = null;
}

var opts = {};
if (!checksModule) {
  opts = {
    eprime: false // user must opt-in
  };
  program
  .option(
    '--eprime',
    generateActivationDescription('E-Prime')
  )
  .option(
    '--yes-eprime',
    "activate 'E-Prime' check, without deactivating the other checks"
  );
  checks.forEach(generateCheckOptions);
} else { // set custom ops, for example to lint a non-English document
  try {
    opts.checks = require(checksModule);
  } catch (e) {
    console.log(
      'Could not import custom check module. ' +
      'Check for spelling errors and make sure you have the module installed.');
    process.exit(1);
  }
  // dynamically set up custom options
  Object.keys(opts.checks).forEach(generateCheckOptions);
}

var files = program.parse(process.argv).args;
// 'parse' is a commander.js edge case:
var shouldParse = Object.keys(program).indexOf('parse') !== -1;

var hasTextArg = args.some(function(arg) {
  return arg.startsWith('--text')
});
if (files.length === 0 && !hasTextArg) {
  console.log('You did not provide any files to check.');
  process.exit(1);
}

var hasChecks = args.some(function(arg) {
  return arg.startsWith('--checks');
});

var handleInvalidArgument = function(arg) {
  console.log('"' + arg + '" is not a valid argument.');
  process.exit(1);
}

if(hasChecks) {
  // validate base args and infer valid check args from the imported custom check module
  args.slice(1).forEach(function(arg) {
    if(arg.startsWith('--text') || arg.startsWith('--checks') || arg === '--parse') return;
    var isValid = Object.keys(opts.checks).some(function(check) {
      return arg === '--' + check || arg === '--no-' + check;
    });
    if(!isValid) {
      handleInvalidArgument(arg);
    }
  });
} else {
  var optionArgs = args.filter(function(arg) {
    return !files.includes(arg);
  });
  // validate default args if no custom checks module is provided
  optionArgs.forEach(function(arg) {
    if(arg.startsWith('--text')) return;
    var isValid = program.options.some(function (option) {
      return arg === option.long || arg === option.short;
    });
    if(!isValid) {
      handleInvalidArgument(arg);
    }
  });
}

var include = true;
var inputSupplied = files.length;
var textInputSupplied = false;

args.filter(function (arg) {
  return arg.substr(0, 2) === '--';
}).map(function (arg) {
  return arg.substr(2);
}).forEach(function (arg) {
  if (arg.indexOf('text=') !== -1) {
    opts[arg.substr(0, 4)] = arg.substr(5);
    textInputSupplied = inputSupplied = true;
  } else if (arg.substr(0, 3) === 'no-') {
    opts[arg.substr(3)] = false;
  } else if (arg.substr(0, 4) === 'yes-') {
    opts[arg.substr(4)] = true;
  } else if (arg == 'parse') {
  } else if (arg.indexOf('checks=') === -1) {
    opts[arg] = true;
    include = false;
  }
});

Object.keys(opts).forEach(function (name) {
  if (typeof opts[name] !== 'boolean'
  &&  name !== 'text'                 // --text="text to check"
  && name !== 'checks') {             // --checks="custom-check-module"
    opts[name] = include;
  }
});

if (!inputSupplied) {
  console.log('You did not provide any input (file or text) to check');
  process.exit(1);
}

var exitCode = 0;

if (textInputSupplied) {
  displaySuggestions('text', opts['text'], opts);
} else {
  files.forEach(function (file) {
    var contents = fs.readFileSync(file, 'utf8');
    displaySuggestions(file, contents, opts);
  })
};

function displaySuggestions(source, contents, opts) {
  var suggestions = writeGood(contents, opts);

  if (shouldParse) {
    exitCode = suggestions.length > 0 ? -1 : 0;
    console.log(annotate(contents, suggestions, true).map(function(ann){return [source,ann.line,ann.col, ann.reason.replace("\n", " ")].join(":")}).join("\n"));
  } else {
    exitCode += suggestions.length;
    if (suggestions.length) {
      console.log('In ' + source);
      console.log('=============');
      console.log(annotate(contents, suggestions).join('\n-------------\n'));
    }
  }
}

process.exit(exitCode);
<|endoftext|>