<commit_before>/**
* Adds captions support
*/
( function( mw, $ ) { "use strict";

	mw.KTimedText = function( embedPlayer, captionPluginName, callback ){
		return this.init( embedPlayer, captionPluginName, callback );
	};
	mw.KTimedText.prototype = {
		bindPostfix : '.kTimedText',
		init: function( embedPlayer, captionPluginName, callback ){
			var _this = this;

			this.embedPlayer = embedPlayer;
			// Set the caption plugin name so that we can get config from the correct location.
			this.pluginName = captionPluginName;

			// Check for kaltura plugin representation of offset:
			if( _this.getConfig('timeOffset') ){
				_this.timeOffset = _this.getConfig('timeOffset');
			}
			// Check for existing timedText on player and retain visibility.
			var existingLayout = null;
			if( embedPlayer.timedText ){
				existingLayout = embedPlayer.timedText.config.layout;
			}

			// Set captions layout of player based on plugin Name:
			if( this.pluginName == 'closedCaptionsOverPlayer' ){
				this.defaultDisplayMode = 'ontop';
			} else if( this.pluginName == 'closedCaptionsUnderPlayer' ){
				this.defaultDisplayMode = 'below';
			}

			// Inherit the timed text support via the base TimedText module:
			var baseTimedText = new mw.TimedText( embedPlayer );
			for( var i in _this ){
				if( baseTimedText[ i ] ){
					baseTimedText[ 'parent_' + i ] = baseTimedText[i];
				}
				baseTimedText[i] = _this[i];
			}
			embedPlayer.timedText = baseTimedText;

			// if using the customCaptionsButton existingLayout always starts as "off"
			if ( _this.embedPlayer.getKalturaConfig( '', 'customCaptionsButton' ) ) {
				existingLayout =  'off';
			}

			// Update the layout options per existing layout or uiConf preference.
			if( existingLayout !== null ){
				embedPlayer.timedText.setLayoutMode( existingLayout );
			} else if( _this.getConfig( 'hideClosedCaptions' ) == true ){
				embedPlayer.timedText.setLayoutMode( 'off' );
			}
			// Bind player at player ready time
			_this.bindPlayer( embedPlayer );
			callback();
		},
        /* Override bindTextButton for allowing captions toggle */
        bindTextButton: function($textButton){
			var _this = this;
			$textButton.unbind('click.textMenu').bind('click.textMenu', function() {
                if ( _this.embedPlayer.getKalturaConfig( '', 'customCaptionsButton' ) ) {
                    _this.toggleCaptions();
                }
                else {
                    _this.showTextMenu();
                }
				return true;
			} );
		},
        /* Override buildMenu for allowing captions toggle */
        buildMenu: function( autoShow ) {
            var _this = this;
            if ( _this.embedPlayer.getKalturaConfig( '', 'customCaptionsButton' ) ) {
                return;
            } else {
                this.parent_buildMenu( autoShow );
            }
        },
		/* get the captions css from configuration options */
		getCaptionCss: function(){
			var style = {'display': 'inline'};

			if( this.getConfig( 'bg' ) ) {
				style["background-color"] = mw.getHexColor( this.getConfig( 'bg' ) );
			}
			if( this.getConfig( 'fontColor' ) ) {
				style["color"] = mw.getHexColor( this.getConfig( 'fontColor' ) );
			}
			if( this.getConfig( 'fontFamily' ) ){
				style["font-family"] = this.getConfig( 'fontFamily' );
			}
			if( this.getConfig( 'fontsize') ) {
				// Translate to em size so that font-size parent percentage
				// base on http://pxtoem.com/
				var emFontMap = { '6': .375, '7': .438, '8' : .5, '9': .563, '10': .625, '11':.688,
						'12':.75, '13': .813, '14': .875, '15':.938, '16':1, '17':1.063, '18': 1.125, '19': 1.888,
						'20':1.25, '21':1.313, '22':1.375, '23':1.438, '24':1.5};
				// Make sure its an int:
				var fontsize = parseInt( this.getConfig( 'fontsize' ) );
				style[ "font-size" ] = ( emFontMap[ fontsize ] ) ?
						emFontMap[ fontsize ] +'em' :
						(  fontsize > 24 )?  emFontMap[ 24 ]+'em' : emFontMap[ 6 ];
			}
			if( this.getConfig('useGlow' ) && this.getConfig('glowBlur') && this.getConfig('glowColor') ) {
				style["text-shadow"] = '0 0 ' + this.getConfig('glowBlur') + 'px ' + mw.getHexColor( this.getConfig('glowColor') );
			}
			return style;
		},
		bindPlayer: function( embedPlayer ){
			var _this = this;
			// Remove any old timed text bindings:
			$( embedPlayer ).unbind( this.bindPostfix );

			// Trigger changed caption
			$( embedPlayer ).bind( 'TimedText_ChangeSource' + this.bindPostfix , function() {
				$( embedPlayer ).trigger( 'changedClosedCaptions' );
			});

			// Support hide show notifications:
			$( embedPlayer ).bind( 'Kaltura_SendNotification'+ this.bindPostfix , function( event, notificationName, notificationData){
				switch( notificationName ){
					case 'showHideClosedCaptions':
						embedPlayer.timedText.toggleCaptions();
						break;
					case 'showClosedCaptions':
						embedPlayer.timedText.setLayoutMode(  embedPlayer.timedText.defaultDisplayMode );
						break;
					case 'hideClosedCaptions':
						embedPlayer.timedText.setLayoutMode( 'off' );
						break;
				}
			});

			// Support SetKDP attribute style caption updates
			$( embedPlayer ).bind( 'Kaltura_SetKDPAttribute' + this.bindPostfix, function( event, componentName, property, value ){
				if( componentName == _this.pluginName ){
					if( property == 'ccUrl' ){
						// empty the text sources:
						embedPlayer.timedText.textSources = null;
						// re-setup sources will run loadTextSources
						embedPlayer.timedText.setupTextSources();
					}
				}
			});
		},
		/*
		 *
		 *
		 // TODO support addInterface based on uiConf position.
		 addInterface: function(){

		  <hbox id="ccOverComboBoxWrapper" horizontalalign="right" width="100%" height="100%" paddingright="5" paddingtop="5">
          <plugin id="captionsOverFader" width="0%" height="0%" includeinlayout="false" target="{ccOverComboBoxWrapper}" hovertarget="{PlayerHolder}" duration="0.5" autohide="true" path="faderPlugin.swf"></plugin>
          <combobox id="ccOverComboBox" width="90" stylename="_kdp" selectedindex="{closedCaptionsOverPlayer.currentCCFileIndex}"
	           kevent_change="sendNotification( 'closedCaptionsSelected' , ccOverComboBox.selectedItem)"
	           dataprovider="{closedCaptionsOverPlayer.availableCCFilesLabels}" prompt="Captions" tooltip="">
          </combobox>

          <Button id="custom1BtnControllerScreen" height="22"
          focusRectPadding="0" buttonType="iconButton"
          kClick="jsCall('customFunc1', mediaProxy.entry.id )"
          styleName="controllerScreen" icon="generalIcon"
          k_buttonType="buttonIconControllerArea" tooltip="captions"
          color1="14540253" color2="16777215" color3="3355443"
          color4="10066329" color5="16777215" font="Arial"/>

          ( this.parent_addInterface();

		 }
		 */
		includeCaptionButton:function(){
			return true;
		},
		getConfig: function( attrName ){
			return this.embedPlayer.getKalturaConfig( this.pluginName, attrName );
		},
		getKalturaClient: function(){
			if( ! this.kClient ){
				this.kClient = mw.kApiGetPartnerClient( this.embedPlayer.kwidgetid );
			}
			return this.kClient;
		},
		/**
		 * Load the list of captions sources from the kaltura api, or from plugin config
		 */
		loadTextSources: function( callback ) {
			var _this = this;
			// Check if text sources are already loaded ( not null )
			if( this.textSources.length ){
				callback();
				return ;
			}
			// init timedText sources:
			this.textSources = [];

			// Check for kaltura ccUrl style text tracks ( not eagle api )
			if( this.getConfig('ccUrl') ){
				mw.log( 'KTimedText:: loadTextSources> add textSources from ccUrl:' + this.getConfig('ccUrl') );
				// Set up a single source from the custom vars:
				var textSource = this.getTextSource( this.getConfig('ccUrl'), this.getConfig('type') );
				if( textSource ){
					_this.textSources.push( textSource);
				}
			}

			// Api sources require that a api query
			_this.getKalturaClient().getKS( function( ks ) {
				_this.ksCache = ks;
				_this.getTextSourcesFromApi( function( dbTextSources ){
					$.each( dbTextSources, function( inx, dbTextSource ){
						mw.log( 'KTimedText:: loadTextSources> add textSources from db:' + inx, _this.getTextSourceFromDB( dbTextSource ) );
						_this.textSources.push(
							_this.getTextSourceFromDB( dbTextSource )
						);
						$( _this.embedPlayer ).trigger('KalturaSupport_NewClosedCaptionsData');
					});
					$( _this.embedPlayer ).trigger('KalturaSupport_CCDataLoaded');
					// Done adding source issue callback
					mw.log( 'KTimedText:: loadTextSources> total source count: ' + _this.textSources.length );
					callback();
				});
			});
		},
		/**
		 * Get the text sources from the api:
		 */
		getTextSourcesFromApi: function( callback ){
			var _this = this;
			this.getKalturaClient().doRequest( {
				'service' : 'caption_captionasset',
				'action' : 'list',
				'filter:objectType' : 'KalturaAssetFilter',
				'filter:entryIdEqual' : _this.embedPlayer.kentryid,
				'filter:statusEqual' : 2
			}, function( data ) {
				mw.log( "KTimedText:: getTextSourcesFromApi: " + data.totalCount, data.objects );
				// TODO is this needed does the api not return an empty set?
				if( data.totalCount > 0 ) {
					callback( data.objects );
				} else {
					callback( [] );
				}
			});
		},
		getTextContentType: function( type ){
			switch( type ){
				case 'srt':
					return 'text/x-srt';
					break;
				case 'tt':
					return 'text/xml';
					break;
			}
		},
		getTextSource: function( ccUrl, type ){
			var _this = this;
			if( !ccUrl ){
				mw.log("Error: KTimedText error missing text source from custom vars");
				return null;
			}
			if( !type ){
				type  = 'text/x-srt';
			}

			var embedSource = this.embedPlayer.mediaElement.tryAddSource(
				$( '<track />' ).attr({
					'kind'		: 'subtitles',
					'label'		: 'English',
					'srclang' 	: 'en',
					'fileExt'	: type,
					'type'		: this.getTextContentType( type ),
					'src'		: ccUrl
				})[0]
				);
			// Return a "textSource" object:
			return new mw.TextSource( embedSource );
		},

		/**
		 * Gets a text source we can use the application from a database textSource
		 * @param {Object} textSource
		 */
		getTextSourceFromDB: function( dbTextSource ){
			var _this = this;
			// Try to insert the track source:
			var embedSource = this.embedPlayer.mediaElement.tryAddSource(
				$( '<track />' ).attr({
					'kind'		: 'subtitles',
					'language'	: dbTextSource.language,
					'srclang' 	: dbTextSource.languageCode,
					'label'		: dbTextSource.label,
					'id'		: dbTextSource.id,
					'fileExt'	: dbTextSource.fileExt,
					'src'		: _this.getCaptionUrl( dbTextSource.id, dbTextSource.fileExt ),
					'title'		: dbTextSource.label,
					'default'	: dbTextSource.isDefault
				})[0]
			);
			// Return a "textSource" object:
			return new mw.TextSource( embedSource );
		},

		/**
		* Returns the caption serve url
		* @param {String} captionId - caption asset id
		* @param {String} type - caption asset type
		*/
		getCaptionUrl: function( captionId, type ){
			// Sample Url for Caption serve
			// http://www.kaltura.com/api_v3/index.php?service=caption_captionasset&action=serve&captionAssetId=@ID@&ks=@KS@
			var params = {
				'action': 'serve',
				'captionAssetId': captionId,
				'ks': this.ksCache
			};
			var kalsig = this.getKalturaClient().getSignature( params );
			var baseUrl = mw.getConfig('Kaltura.ServiceUrl') + mw.getConfig('Kaltura.ServiceBase').replace('index.php', '');
			return baseUrl + 'caption_captionasset&' + $.param( params ) + '&kalsig=' + kalsig + '&.' + type;
		}
	};

} )( window.mw, jQuery );<commit_msg>fixes #131 only issue caption loaded event once caption data is loaded<commit_after>/**
* Adds captions support
*/
( function( mw, $ ) { "use strict";

	mw.KTimedText = function( embedPlayer, captionPluginName, callback ){
		return this.init( embedPlayer, captionPluginName, callback );
	};
	mw.KTimedText.prototype = {
		bindPostfix : '.kTimedText',
		init: function( embedPlayer, captionPluginName, callback ){
			var _this = this;

			this.embedPlayer = embedPlayer;
			// Set the caption plugin name so that we can get config from the correct location.
			this.pluginName = captionPluginName;

			// Check for kaltura plugin representation of offset:
			if( _this.getConfig('timeOffset') ){
				_this.timeOffset = _this.getConfig('timeOffset');
			}
			// Check for existing timedText on player and retain visibility.
			var existingLayout = null;
			if( embedPlayer.timedText ){
				existingLayout = embedPlayer.timedText.config.layout;
			}

			// Set captions layout of player based on plugin Name:
			if( this.pluginName == 'closedCaptionsOverPlayer' ){
				this.defaultDisplayMode = 'ontop';
			} else if( this.pluginName == 'closedCaptionsUnderPlayer' ){
				this.defaultDisplayMode = 'below';
			}

			// Inherit the timed text support via the base TimedText module:
			var baseTimedText = new mw.TimedText( embedPlayer );
			for( var i in _this ){
				if( baseTimedText[ i ] ){
					baseTimedText[ 'parent_' + i ] = baseTimedText[i];
				}
				baseTimedText[i] = _this[i];
			}
			embedPlayer.timedText = baseTimedText;

			// if using the customCaptionsButton existingLayout always starts as "off"
			if ( _this.embedPlayer.getKalturaConfig( '', 'customCaptionsButton' ) ) {
				existingLayout =  'off';
			}

			// Update the layout options per existing layout or uiConf preference.
			if( existingLayout !== null ){
				embedPlayer.timedText.setLayoutMode( existingLayout );
			} else if( _this.getConfig( 'hideClosedCaptions' ) == true ){
				embedPlayer.timedText.setLayoutMode( 'off' );
			}
			// Bind player at player ready time
			_this.bindPlayer( embedPlayer );
			callback();
		},
        /* Override bindTextButton for allowing captions toggle */
        bindTextButton: function($textButton){
			var _this = this;
			$textButton.unbind('click.textMenu').bind('click.textMenu', function() {
                if ( _this.embedPlayer.getKalturaConfig( '', 'customCaptionsButton' ) ) {
                    _this.toggleCaptions();
                }
                else {
                    _this.showTextMenu();
                }
				return true;
			} );
		},
        /* Override buildMenu for allowing captions toggle */
        buildMenu: function( autoShow ) {
            var _this = this;
            if ( _this.embedPlayer.getKalturaConfig( '', 'customCaptionsButton' ) ) {
                return;
            } else {
                this.parent_buildMenu( autoShow );
            }
        },
		/* get the captions css from configuration options */
		getCaptionCss: function(){
			var style = {'display': 'inline'};

			if( this.getConfig( 'bg' ) ) {
				style["background-color"] = mw.getHexColor( this.getConfig( 'bg' ) );
			}
			if( this.getConfig( 'fontColor' ) ) {
				style["color"] = mw.getHexColor( this.getConfig( 'fontColor' ) );
			}
			if( this.getConfig( 'fontFamily' ) ){
				style["font-family"] = this.getConfig( 'fontFamily' );
			}
			if( this.getConfig( 'fontsize') ) {
				// Translate to em size so that font-size parent percentage
				// base on http://pxtoem.com/
				var emFontMap = { '6': .375, '7': .438, '8' : .5, '9': .563, '10': .625, '11':.688,
						'12':.75, '13': .813, '14': .875, '15':.938, '16':1, '17':1.063, '18': 1.125, '19': 1.888,
						'20':1.25, '21':1.313, '22':1.375, '23':1.438, '24':1.5};
				// Make sure its an int:
				var fontsize = parseInt( this.getConfig( 'fontsize' ) );
				style[ "font-size" ] = ( emFontMap[ fontsize ] ) ?
						emFontMap[ fontsize ] +'em' :
						(  fontsize > 24 )?  emFontMap[ 24 ]+'em' : emFontMap[ 6 ];
			}
			if( this.getConfig('useGlow' ) && this.getConfig('glowBlur') && this.getConfig('glowColor') ) {
				style["text-shadow"] = '0 0 ' + this.getConfig('glowBlur') + 'px ' + mw.getHexColor( this.getConfig('glowColor') );
			}
			return style;
		},
		bindPlayer: function( embedPlayer ){
			var _this = this;
			// Remove any old timed text bindings:
			$( embedPlayer ).unbind( this.bindPostfix );

			// Trigger changed caption
			$( embedPlayer ).bind( 'TimedText_ChangeSource' + this.bindPostfix , function() {
				$( embedPlayer ).trigger( 'changedClosedCaptions' );
			});

			// Support hide show notifications:
			$( embedPlayer ).bind( 'Kaltura_SendNotification'+ this.bindPostfix , function( event, notificationName, notificationData){
				switch( notificationName ){
					case 'showHideClosedCaptions':
						embedPlayer.timedText.toggleCaptions();
						break;
					case 'showClosedCaptions':
						embedPlayer.timedText.setLayoutMode(  embedPlayer.timedText.defaultDisplayMode );
						break;
					case 'hideClosedCaptions':
						embedPlayer.timedText.setLayoutMode( 'off' );
						break;
				}
			});

			// Support SetKDP attribute style caption updates
			$( embedPlayer ).bind( 'Kaltura_SetKDPAttribute' + this.bindPostfix, function( event, componentName, property, value ){
				if( componentName == _this.pluginName ){
					if( property == 'ccUrl' ){
						// empty the text sources:
						embedPlayer.timedText.textSources = null;
						// re-setup sources will run loadTextSources
						embedPlayer.timedText.setupTextSources();
					}
				}
			});
		},
		/*
		 *
		 *
		 // TODO support addInterface based on uiConf position.
		 addInterface: function(){

		  <hbox id="ccOverComboBoxWrapper" horizontalalign="right" width="100%" height="100%" paddingright="5" paddingtop="5">
          <plugin id="captionsOverFader" width="0%" height="0%" includeinlayout="false" target="{ccOverComboBoxWrapper}" hovertarget="{PlayerHolder}" duration="0.5" autohide="true" path="faderPlugin.swf"></plugin>
          <combobox id="ccOverComboBox" width="90" stylename="_kdp" selectedindex="{closedCaptionsOverPlayer.currentCCFileIndex}"
	           kevent_change="sendNotification( 'closedCaptionsSelected' , ccOverComboBox.selectedItem)"
	           dataprovider="{closedCaptionsOverPlayer.availableCCFilesLabels}" prompt="Captions" tooltip="">
          </combobox>

          <Button id="custom1BtnControllerScreen" height="22"
          focusRectPadding="0" buttonType="iconButton"
          kClick="jsCall('customFunc1', mediaProxy.entry.id )"
          styleName="controllerScreen" icon="generalIcon"
          k_buttonType="buttonIconControllerArea" tooltip="captions"
          color1="14540253" color2="16777215" color3="3355443"
          color4="10066329" color5="16777215" font="Arial"/>

          ( this.parent_addInterface();

		 }
		 */
		includeCaptionButton:function(){
			return true;
		},
		getConfig: function( attrName ){
			return this.embedPlayer.getKalturaConfig( this.pluginName, attrName );
		},
		getKalturaClient: function(){
			if( ! this.kClient ){
				this.kClient = mw.kApiGetPartnerClient( this.embedPlayer.kwidgetid );
			}
			return this.kClient;
		},
		/**
		 * Load the list of captions sources from the kaltura api, or from plugin config
		 */
		loadTextSources: function( callback ) {
			var _this = this;
			// Check if text sources are already loaded ( not null )
			if( this.textSources.length ){
				callback();
				return ;
			}
			// init timedText sources:
			this.textSources = [];

			// Check for kaltura ccUrl style text tracks ( not eagle api )
			if( this.getConfig('ccUrl') ){
				mw.log( 'KTimedText:: loadTextSources> add textSources from ccUrl:' + this.getConfig('ccUrl') );
				// Set up a single source from the custom vars:
				var textSource = this.getTextSource( this.getConfig('ccUrl'), this.getConfig('type') );
				if( textSource ){
					_this.textSources.push( textSource);
				}
			}

			// Api sources require that a api query
			_this.getKalturaClient().getKS( function( ks ) {
				_this.ksCache = ks;
				_this.getTextSourcesFromApi( function( dbTextSources ){
					$.each( dbTextSources, function( inx, dbTextSource ){
						mw.log( 'KTimedText:: loadTextSources> add textSources from db:' + inx, _this.getTextSourceFromDB( dbTextSource ) );
						_this.textSources.push(
							_this.getTextSourceFromDB( dbTextSource )
						);
					});
					$( _this.embedPlayer ).trigger('KalturaSupport_CCDataLoaded');
					// Done adding source issue callback
					mw.log( 'KTimedText:: loadTextSources> total source count: ' + _this.textSources.length );
					callback();
				});
			});
		},
		/**
		 * Get the text sources from the api:
		 */
		getTextSourcesFromApi: function( callback ){
			var _this = this;
			this.getKalturaClient().doRequest( {
				'service' : 'caption_captionasset',
				'action' : 'list',
				'filter:objectType' : 'KalturaAssetFilter',
				'filter:entryIdEqual' : _this.embedPlayer.kentryid,
				'filter:statusEqual' : 2
			}, function( data ) {
				mw.log( "KTimedText:: getTextSourcesFromApi: " + data.totalCount, data.objects );
				$( _this.embedPlayer ).trigger('KalturaSupport_NewClosedCaptionsData');
				// TODO is this needed? Does the api not return an empty set?
				if( data.totalCount > 0 ) {
					callback( data.objects );
				} else {
					callback( [] );
				}
			});
		},
		getTextContentType: function( type ){
			switch( type ){
				case 'srt':
					return 'text/x-srt';
					break;
				case 'tt':
					return 'text/xml';
					break;
			}
		},
		getTextSource: function( ccUrl, type ){
			var _this = this;
			if( !ccUrl ){
				mw.log("Error: KTimedText error missing text source from custom vars");
				return null;
			}
			if( !type ){
				type  = 'text/x-srt';
			}

			var embedSource = this.embedPlayer.mediaElement.tryAddSource(
				$( '<track />' ).attr({
					'kind'		: 'subtitles',
					'label'		: 'English',
					'srclang' 	: 'en',
					'fileExt'	: type,
					'type'		: this.getTextContentType( type ),
					'src'		: ccUrl
				})[0]
				);
			// Return a "textSource" object:
			return new mw.TextSource( embedSource );
		},

		/**
		 * Gets a text source we can use the application from a database textSource
		 * @param {Object} textSource
		 */
		getTextSourceFromDB: function( dbTextSource ){
			var _this = this;
			// Try to insert the track source:
			var embedSource = this.embedPlayer.mediaElement.tryAddSource(
				$( '<track />' ).attr({
					'kind'		: 'subtitles',
					'language'	: dbTextSource.language,
					'srclang' 	: dbTextSource.languageCode,
					'label'		: dbTextSource.label,
					'id'		: dbTextSource.id,
					'fileExt'	: dbTextSource.fileExt,
					'src'		: _this.getCaptionUrl( dbTextSource.id, dbTextSource.fileExt ),
					'title'		: dbTextSource.label,
					'default'	: dbTextSource.isDefault
				})[0]
			);
			// Return a "textSource" object:
			return new mw.TextSource( embedSource );
		},

		/**
		* Returns the caption serve url
		* @param {String} captionId - caption asset id
		* @param {String} type - caption asset type
		*/
		getCaptionUrl: function( captionId, type ){
			// Sample Url for Caption serve
			// http://www.kaltura.com/api_v3/index.php?service=caption_captionasset&action=serve&captionAssetId=@ID@&ks=@KS@
			var params = {
				'action': 'serve',
				'captionAssetId': captionId,
				'ks': this.ksCache
			};
			var kalsig = this.getKalturaClient().getSignature( params );
			var baseUrl = mw.getConfig('Kaltura.ServiceUrl') + mw.getConfig('Kaltura.ServiceBase').replace('index.php', '');
			return baseUrl + 'caption_captionasset&' + $.param( params ) + '&kalsig=' + kalsig + '&.' + type;
		}
	};

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


<commit_before>const SCHOLAR_CONFIG = {
	GUID: 'scholar@chnm.gmu.edu',
	DB_FILE: 'scholar.sqlite',
	DB_REBUILD: false, // erase DB and recreate from schema
	DEBUG_LOGGING: true,
	DEBUG_TO_CONSOLE: true, // dump debug messages to console rather than (much slower) Debug Logger
	REPOSITORY_URL: 'http://chnm.gmu.edu/firefoxscholar/repo',
	REPOSITORY_CHECK_INTERVAL: 86400, // 24 hours
	REPOSITORY_CHECK_RETRY: 3600 // 1 hour
};

/*
 * Core functions
 */
var Scholar = new function(){
	var _initialized = false;
	var _localizedStringBundle;

	// Privileged (public) methods
	this.init = init;
	this.debug = debug;
	this.varDump = varDump;
	this.getString = getString;
	this.flattenArguments = flattenArguments;
	this.join = join;
	this.inArray = inArray;
	this.arraySearch = arraySearch;
	this.randomString = randomString;
	this.getRandomID = getRandomID;

	// Public properties
	this.version;

	/*
	 * Initialize the extension
	 */
	function init(){
		if (_initialized){
			return false;
		}

		// Load in the extension version from the extension manager
		var nsIUpdateItem = Components.interfaces.nsIUpdateItem;
		var gExtensionManager =
			Components.classes["@mozilla.org/extensions/manager;1"]
				.getService(Components.interfaces.nsIExtensionManager);
		var itemType = nsIUpdateItem.TYPE_EXTENSION;
		this.version
			= gExtensionManager.getItemForID(SCHOLAR_CONFIG['GUID']).version;

		// Load in the localization stringbundle for use by getString(name)
		var src = 'chrome://scholar/locale/scholar.properties';
		var localeService =
			Components.classes["@mozilla.org/intl/nslocaleservice;1"]
			.getService(Components.interfaces.nsILocaleService);
		var appLocale = localeService.getApplicationLocale();
		var stringBundleService =
			Components.classes["@mozilla.org/intl/stringbundle;1"]
			.getService(Components.interfaces.nsIStringBundleService);
		_localizedStringBundle = stringBundleService.createBundle(src, appLocale);

		// Trigger updating of schema and scrapers
		Scholar.Schema.updateSchema();
		Scholar.Schema.updateScrapersRemote();

		_initialized = true;
		return true;
	}

	/*
	 * Debug logging function
	 *
	 * Uses DebugLogger extension available from http://mozmonkey.com/debuglogger/
	 * if available, otherwise the console (in which case boolean browser.dom.window.dump.enabled
	 * must be created and set to true in about:config)
	 *
	 * Defaults to log level 3 if level not provided
	 */
	function debug(message, level) {
		if (!SCHOLAR_CONFIG['DEBUG_LOGGING']){
			return false;
		}

		if (typeof message!='string'){
			message = Scholar.varDump(message);
		}

		if (!level){
			level = 3;
		}

		if (!SCHOLAR_CONFIG['DEBUG_TO_CONSOLE']){
			try {
				var logManager =
				Components.classes["@mozmonkey.com/debuglogger/manager;1"]
				.getService(Components.interfaces.nsIDebugLoggerManager);
				var logger = logManager.registerLogger("Firefox Scholar");
			}
			catch (e){}
		}

		if (logger){
			logger.log(level, message);
		}
		else {
			dump('scholar(' + level + '): ' + message + "\n\n");
		}
		return true;
	}

	/**
	 * PHP var_dump equivalent for JS
	 *
	 * Adapted from http://binnyva.blogspot.com/2005/10/dump-function-javascript-equivalent-of.html
	 */
	function varDump(arr,level) {
		var dumped_text = "";
		if (!level){
			level = 0;
		}

		// The padding given at the beginning of the line.
		var level_padding = "";
		for (var j=0;j<level+1;j++){
			level_padding += "    ";
		}

		if (typeof(arr) == 'object') { // Array/Hashes/Objects
			for (var item in arr) {
				var value = arr[item];

				if (typeof(value) == 'object') { // If it is an array,
					dumped_text += level_padding + "'" + item + "' ...\n";
					dumped_text += arguments.callee(value,level+1);
				}
				else {
					if (typeof value == 'function'){
						dumped_text += level_padding + "'" + item + "' => function(...){...} \n";
					}
					else {
						dumped_text += level_padding + "'" + item + "' => \"" + value + "\"\n";
					}
				}
			}
		}
		else { // Stings/Chars/Numbers etc.
			dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
		}
		return dumped_text;
	}

	function getString(name){
		return _localizedStringBundle.GetStringFromName(name);
	}

	/*
	 * Flattens mixed arrays/values in a passed _arguments_ object and returns
	 * an array of values -- allows for functions to accept both arrays of
	 * values and/or an arbitrary number of individual values
	 */
	function flattenArguments(args){
		// Put passed scalar values into an array
		if (typeof args!='object'){
			args = [args];
		}

		var returns = new Array();

		for (var i=0; i<args.length; i++){
			if (typeof args[i]=='object'){
				for (var j=0; j<args[i].length; j++){
					returns.push(args[i][j]);
				}
			}
			else {
				returns.push(args[i]);
			}
		}

		return returns;
	}

	/*
	 * A version of join() that operates externally for use on objects other
	 * than arrays (e.g. _arguments_)
	 *
	 * Note that this is safer than extending Object()
	 */
	function join(obj, delim){
		var a = [];
		for (var i=0, len=obj.length; i<len; i++){
			a.push(obj[i]);
		}
		return a.join(delim);
	}

	/*
	 * PHP's in_array() for JS -- returns true if a value is contained in
	 * an array, false otherwise
	 */
	function inArray(needle, haystack){
		for (var i in haystack){
			if (haystack[i]==needle){
				return true;
			}
		}
		return false;
	}

	/*
	 * PHP's array_search() for JS -- searches an array for a value and
	 * returns the key if found, false otherwise
	 */
	function arraySearch(needle, haystack){
		for (var i in haystack){
			if (haystack[i]==needle){
				return i;
			}
		}
		return false;
	}

	/**
	* Generate a random string of length 'len' (defaults to 8)
	**/
	function randomString(len) {
		var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
		if (!len){
			len = 8;
		}
		var randomstring = '';
		for (var i=0; i<len; i++) {
			var rnum = Math.floor(Math.random() * chars.length);
			randomstring += chars.substring(rnum,rnum+1);
		}
		return randomstring;
	}

	/**
	* Find a unique random id for use in a DB table
	**/
	function getRandomID(table, column, max){
		if (!table){
			throw('SQL query not provided');
		}

		if (!column){
			throw('SQL query not provided');
		}

		var sql = 'SELECT COUNT(*) FROM ' + table + ' WHERE ' + column + '=';

		if (!max){
			max = 16383;
		}

		var tries = 10; // # of tries to find a unique id
		do {
			// If no luck after number of tries, try a larger range
			if (!tries){
				max = max * 2;
			}
			var rnd = Math.floor(Math.random()*max);
			var exists = Scholar.DB.valueQuery(sql + rnd);
			tries--;
		}
		while (exists);

		return rnd;
	}
};

/**
* Class for creating hash arrays that behave a bit more sanely
*
*   Hashes can be created in the constructor by alternating key and val:
*
*   var hasharray = new Scholar.Hash('foo','foovalue','bar','barvalue');
*
*   Or using hasharray.set(key, val)
*
*   _val_ defaults to true if not provided
*
*   If using foreach-style looping, be sure to use _for (i in arr.items)_
*   rather than just _for (i in arr)_, or else you'll end up with the
*   methods and members instead of the hash items
*
*   Most importantly, hasharray.length will work as expected, even with
*   non-numeric keys
*
* Adapated from http://www.mojavelinux.com/articles/javascript_hashes.html
* (c) Mojavelinux, Inc.
* License: Creative Commons
**/
Scholar.Hash = function(){
	this.length = 0;
	this.items = new Array();

	// Public methods defined on prototype below

	for (var i = 0; i < arguments.length; i += 2) {
		if (typeof(arguments[i + 1]) != 'undefined') {
			this.items[arguments[i]] = arguments[i + 1];
			this.length++;
		}
	}
}

Scholar.Hash.prototype.get = function(in_key){
	return this.items[in_key];
}

Scholar.Hash.prototype.set = function(in_key, in_value){
	// Default to a boolean hash if value not provided
	if (typeof(in_value) == 'undefined'){
		in_value = true;
	}

	if (typeof(this.items[in_key]) == 'undefined') {
		this.length++;
	}

	this.items[in_key] = in_value;

	return in_value;
}

Scholar.Hash.prototype.remove = function(in_key){
	var tmp_value;
	if (typeof(this.items[in_key]) != 'undefined') {
		this.length--;
		var tmp_value = this.items[in_key];
		delete this.items[in_key];
	}

	return tmp_value;
}

Scholar.Hash.prototype.has = function(in_key){
	return typeof(this.items[in_key]) != 'undefined';
}

Scholar.HTTP = new function(){

	this.doGet = doGet;
	this.doPost = doPost;
	this.browserIsOffline = browserIsOffline;

	/**
	* Send an HTTP GET request via XMLHTTPRequest
	*
	* Returns false if browser is offline
	**/
	function doGet(url, onStatus, onDone){
		if (this.browserIsOffline()){
			return false;
		}

		var xmlhttp = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
					.createInstance();

		xmlhttp.open('GET', url, true);

		xmlhttp.onreadystatechange = function(){
			_stateChange(xmlhttp, onStatus, onDone);
		};
		xmlhttp.send(null);

		return true;
	}

	/**
	* Send an HTTP POST request via XMLHTTPRequest
	*
	* Returns false if browser is offline
	**/
	function doPost(url, body, onStatus, onDone){
		if (this.browserIsOffline()){
			return false;
		}

		var xmlhttp = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
					.createInstance();

		xmlhttp.open('POST', url, true);

		xmlhttp.onreadystatechange = function(){
			_stateChange(xmlhttp, onStatus, onDone);
		};
		xmlhttp.send(body);

		return true;
	}

	function browserIsOffline(){
		return Components.classes["@mozilla.org/network/io-service;1"]
			.getService(Components.interfaces.nsIIOService).offline;
	}

	function _stateChange(xmlhttp, onStatus, onDone){
		switch (xmlhttp.readyState){

			// Request not yet made
			case 1:
			break;

			// Contact established with server but nothing downloaded yet
			case 2:
				try {
					// Check for HTTP status 200
					if (xmlhttp.status != 200){
						if (onStatus) {
							onStatus(
								xmlhttp.status,
								xmlhttp.statusText,
								xmlhttp
							);
							xmlhttp.abort();
						}
					}
				}
				catch (e){
					Scholar.debug(e, 2);
				}
			break;

			// Called multiple while downloading in progress
			case 3:
			break;

			// Download complete
			case 4:
				try {
					if (onDone){
						onDone(xmlhttp);
					}
				}
				catch (e){
					Scholar.debug(e, 2);
				}
			break;
		}
	}
}

Scholar.Date = new function(){
	this.sqlToDate = sqlToDate;

	/**
	* Convert an SQL date in the form '2006-06-13 11:03:05' into a JS Date object
	*
	* Can also accept just the date part (e.g. '2006-06-13')
	**/
	function sqlToDate(sqldate){
		try {
			var datetime = sqldate.split(' ');
			var dateparts = datetime[0].split('-');
			if (datetime[1]){
				var timeparts = datetime[1].split(':');
			}
			else {
				timeparts = [false, false, false];
			}
			return new Date(dateparts[0], dateparts[1]-1, dateparts[2],
				timeparts[0], timeparts[1], timeparts[2]);
		}
		catch (e){
			Scholar.debug(sqldate + ' is not a valid SQL date', 2)
			return false;
		}
	}
}<commit_msg>Set repository check timer to 1 hour during development<commit_after>const SCHOLAR_CONFIG = {
	GUID: 'scholar@chnm.gmu.edu',
	DB_FILE: 'scholar.sqlite',
	DB_REBUILD: false, // erase DB and recreate from schema
	DEBUG_LOGGING: true,
	DEBUG_TO_CONSOLE: true, // dump debug messages to console rather than (much slower) Debug Logger
	REPOSITORY_URL: 'http://chnm.gmu.edu/firefoxscholar/repo',
	REPOSITORY_CHECK_INTERVAL: 3600 // 86400, // 24 hours
	REPOSITORY_CHECK_RETRY: 3600 // 1 hour
};

/*
 * Core functions
 */
var Scholar = new function(){
	var _initialized = false;
	var _localizedStringBundle;

	// Privileged (public) methods
	this.init = init;
	this.debug = debug;
	this.varDump = varDump;
	this.getString = getString;
	this.flattenArguments = flattenArguments;
	this.join = join;
	this.inArray = inArray;
	this.arraySearch = arraySearch;
	this.randomString = randomString;
	this.getRandomID = getRandomID;

	// Public properties
	this.version;

	/*
	 * Initialize the extension
	 */
	function init(){
		if (_initialized){
			return false;
		}

		// Load in the extension version from the extension manager
		var nsIUpdateItem = Components.interfaces.nsIUpdateItem;
		var gExtensionManager =
			Components.classes["@mozilla.org/extensions/manager;1"]
				.getService(Components.interfaces.nsIExtensionManager);
		var itemType = nsIUpdateItem.TYPE_EXTENSION;
		this.version
			= gExtensionManager.getItemForID(SCHOLAR_CONFIG['GUID']).version;

		// Load in the localization stringbundle for use by getString(name)
		var src = 'chrome://scholar/locale/scholar.properties';
		var localeService =
			Components.classes["@mozilla.org/intl/nslocaleservice;1"]
			.getService(Components.interfaces.nsILocaleService);
		var appLocale = localeService.getApplicationLocale();
		var stringBundleService =
			Components.classes["@mozilla.org/intl/stringbundle;1"]
			.getService(Components.interfaces.nsIStringBundleService);
		_localizedStringBundle = stringBundleService.createBundle(src, appLocale);

		// Trigger updating of schema and scrapers
		Scholar.Schema.updateSchema();
		Scholar.Schema.updateScrapersRemote();

		_initialized = true;
		return true;
	}

	/*
	 * Debug logging function
	 *
	 * Uses DebugLogger extension available from http://mozmonkey.com/debuglogger/
	 * if available, otherwise the console (in which case boolean browser.dom.window.dump.enabled
	 * must be created and set to true in about:config)
	 *
	 * Defaults to log level 3 if level not provided
	 */
	function debug(message, level) {
		if (!SCHOLAR_CONFIG['DEBUG_LOGGING']){
			return false;
		}

		if (typeof message!='string'){
			message = Scholar.varDump(message);
		}

		if (!level){
			level = 3;
		}

		if (!SCHOLAR_CONFIG['DEBUG_TO_CONSOLE']){
			try {
				var logManager =
				Components.classes["@mozmonkey.com/debuglogger/manager;1"]
				.getService(Components.interfaces.nsIDebugLoggerManager);
				var logger = logManager.registerLogger("Firefox Scholar");
			}
			catch (e){}
		}

		if (logger){
			logger.log(level, message);
		}
		else {
			dump('scholar(' + level + '): ' + message + "\n\n");
		}
		return true;
	}

	/**
	 * PHP var_dump equivalent for JS
	 *
	 * Adapted from http://binnyva.blogspot.com/2005/10/dump-function-javascript-equivalent-of.html
	 */
	function varDump(arr,level) {
		var dumped_text = "";
		if (!level){
			level = 0;
		}

		// The padding given at the beginning of the line.
		var level_padding = "";
		for (var j=0;j<level+1;j++){
			level_padding += "    ";
		}

		if (typeof(arr) == 'object') { // Array/Hashes/Objects
			for (var item in arr) {
				var value = arr[item];

				if (typeof(value) == 'object') { // If it is an array,
					dumped_text += level_padding + "'" + item + "' ...\n";
					dumped_text += arguments.callee(value,level+1);
				}
				else {
					if (typeof value == 'function'){
						dumped_text += level_padding + "'" + item + "' => function(...){...} \n";
					}
					else {
						dumped_text += level_padding + "'" + item + "' => \"" + value + "\"\n";
					}
				}
			}
		}
		else { // Stings/Chars/Numbers etc.
			dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
		}
		return dumped_text;
	}

	function getString(name){
		return _localizedStringBundle.GetStringFromName(name);
	}

	/*
	 * Flattens mixed arrays/values in a passed _arguments_ object and returns
	 * an array of values -- allows for functions to accept both arrays of
	 * values and/or an arbitrary number of individual values
	 */
	function flattenArguments(args){
		// Put passed scalar values into an array
		if (typeof args!='object'){
			args = [args];
		}

		var returns = new Array();

		for (var i=0; i<args.length; i++){
			if (typeof args[i]=='object'){
				for (var j=0; j<args[i].length; j++){
					returns.push(args[i][j]);
				}
			}
			else {
				returns.push(args[i]);
			}
		}

		return returns;
	}

	/*
	 * A version of join() that operates externally for use on objects other
	 * than arrays (e.g. _arguments_)
	 *
	 * Note that this is safer than extending Object()
	 */
	function join(obj, delim){
		var a = [];
		for (var i=0, len=obj.length; i<len; i++){
			a.push(obj[i]);
		}
		return a.join(delim);
	}

	/*
	 * PHP's in_array() for JS -- returns true if a value is contained in
	 * an array, false otherwise
	 */
	function inArray(needle, haystack){
		for (var i in haystack){
			if (haystack[i]==needle){
				return true;
			}
		}
		return false;
	}

	/*
	 * PHP's array_search() for JS -- searches an array for a value and
	 * returns the key if found, false otherwise
	 */
	function arraySearch(needle, haystack){
		for (var i in haystack){
			if (haystack[i]==needle){
				return i;
			}
		}
		return false;
	}

	/**
	* Generate a random string of length 'len' (defaults to 8)
	**/
	function randomString(len) {
		var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
		if (!len){
			len = 8;
		}
		var randomstring = '';
		for (var i=0; i<len; i++) {
			var rnum = Math.floor(Math.random() * chars.length);
			randomstring += chars.substring(rnum,rnum+1);
		}
		return randomstring;
	}

	/**
	* Find a unique random id for use in a DB table
	**/
	function getRandomID(table, column, max){
		if (!table){
			throw('SQL query not provided');
		}

		if (!column){
			throw('SQL query not provided');
		}

		var sql = 'SELECT COUNT(*) FROM ' + table + ' WHERE ' + column + '=';

		if (!max){
			max = 16383;
		}

		var tries = 10; // # of tries to find a unique id
		do {
			// If no luck after number of tries, try a larger range
			if (!tries){
				max = max * 2;
			}
			var rnd = Math.floor(Math.random()*max);
			var exists = Scholar.DB.valueQuery(sql + rnd);
			tries--;
		}
		while (exists);

		return rnd;
	}
};

/**
* Class for creating hash arrays that behave a bit more sanely
*
*   Hashes can be created in the constructor by alternating key and val:
*
*   var hasharray = new Scholar.Hash('foo','foovalue','bar','barvalue');
*
*   Or using hasharray.set(key, val)
*
*   _val_ defaults to true if not provided
*
*   If using foreach-style looping, be sure to use _for (i in arr.items)_
*   rather than just _for (i in arr)_, or else you'll end up with the
*   methods and members instead of the hash items
*
*   Most importantly, hasharray.length will work as expected, even with
*   non-numeric keys
*
* Adapated from http://www.mojavelinux.com/articles/javascript_hashes.html
* (c) Mojavelinux, Inc.
* License: Creative Commons
**/
Scholar.Hash = function(){
	this.length = 0;
	this.items = new Array();

	// Public methods defined on prototype below

	for (var i = 0; i < arguments.length; i += 2) {
		if (typeof(arguments[i + 1]) != 'undefined') {
			this.items[arguments[i]] = arguments[i + 1];
			this.length++;
		}
	}
}

Scholar.Hash.prototype.get = function(in_key){
	return this.items[in_key];
}

Scholar.Hash.prototype.set = function(in_key, in_value){
	// Default to a boolean hash if value not provided
	if (typeof(in_value) == 'undefined'){
		in_value = true;
	}

	if (typeof(this.items[in_key]) == 'undefined') {
		this.length++;
	}

	this.items[in_key] = in_value;

	return in_value;
}

Scholar.Hash.prototype.remove = function(in_key){
	var tmp_value;
	if (typeof(this.items[in_key]) != 'undefined') {
		this.length--;
		var tmp_value = this.items[in_key];
		delete this.items[in_key];
	}

	return tmp_value;
}

Scholar.Hash.prototype.has = function(in_key){
	return typeof(this.items[in_key]) != 'undefined';
}

Scholar.HTTP = new function(){

	this.doGet = doGet;
	this.doPost = doPost;
	this.browserIsOffline = browserIsOffline;

	/**
	* Send an HTTP GET request via XMLHTTPRequest
	*
	* Returns false if browser is offline
	**/
	function doGet(url, onStatus, onDone){
		if (this.browserIsOffline()){
			return false;
		}

		var xmlhttp = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
					.createInstance();

		xmlhttp.open('GET', url, true);

		xmlhttp.onreadystatechange = function(){
			_stateChange(xmlhttp, onStatus, onDone);
		};
		xmlhttp.send(null);

		return true;
	}

	/**
	* Send an HTTP POST request via XMLHTTPRequest
	*
	* Returns false if browser is offline
	**/
	function doPost(url, body, onStatus, onDone){
		if (this.browserIsOffline()){
			return false;
		}

		var xmlhttp = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
					.createInstance();

		xmlhttp.open('POST', url, true);

		xmlhttp.onreadystatechange = function(){
			_stateChange(xmlhttp, onStatus, onDone);
		};
		xmlhttp.send(body);

		return true;
	}

	function browserIsOffline(){
		return Components.classes["@mozilla.org/network/io-service;1"]
			.getService(Components.interfaces.nsIIOService).offline;
	}

	function _stateChange(xmlhttp, onStatus, onDone){
		switch (xmlhttp.readyState){

			// Request not yet made
			case 1:
			break;

			// Contact established with server but nothing downloaded yet
			case 2:
				try {
					// Check for HTTP status 200
					if (xmlhttp.status != 200){
						if (onStatus) {
							onStatus(
								xmlhttp.status,
								xmlhttp.statusText,
								xmlhttp
							);
							xmlhttp.abort();
						}
					}
				}
				catch (e){
					Scholar.debug(e, 2);
				}
			break;

			// Called multiple while downloading in progress
			case 3:
			break;

			// Download complete
			case 4:
				try {
					if (onDone){
						onDone(xmlhttp);
					}
				}
				catch (e){
					Scholar.debug(e, 2);
				}
			break;
		}
	}
}

Scholar.Date = new function(){
	this.sqlToDate = sqlToDate;

	/**
	* Convert an SQL date in the form '2006-06-13 11:03:05' into a JS Date object
	*
	* Can also accept just the date part (e.g. '2006-06-13')
	**/
	function sqlToDate(sqldate){
		try {
			var datetime = sqldate.split(' ');
			var dateparts = datetime[0].split('-');
			if (datetime[1]){
				var timeparts = datetime[1].split(':');
			}
			else {
				timeparts = [false, false, false];
			}
			return new Date(dateparts[0], dateparts[1]-1, dateparts[2],
				timeparts[0], timeparts[1], timeparts[2]);
		}
		catch (e){
			Scholar.debug(sqldate + ' is not a valid SQL date', 2)
			return false;
		}
	}
}<|endoftext|>


<commit_before>/**
 * This processor grabs the draft timings from the parsed replay.
 * This is ideally to be used only for captain modes formats.
 * The output is:
 * order: the order of the pick or ban (1-20) (10 bans and 10 picks)
 * pick: whether the draft stage was a pick or ban. pick == true, ban == false
 * active_team: the active team during the draft stage (2 or 3) if 0
 * then not captains mode. Added check to ignore no CM games.
 * hero_id: the id of the hero banned or picked in the draft stage
 * player_slot: null for bans, the player_slot assoicated with the hero_id
 * time: removed for total time taken
 * extra_time: how much of the extra time is left at the end of the draft stage
 * total_time_taken: the time taken for the draft stage
 */

function processDraftTimings(entries, meta) {
  const draftTimings = [];
  const heroIdToSlot = meta.hero_id_to_slot;
  let sumActiveTeam = 0;
  let previousActiveTeam = 0;
  for (let i = 0; i < entries.length; i += 1) {
    const e = entries[i];
    const heroId = e.hero_id;
    if (e.type === 'draft_timings') {
      // The active team needs to be downshifted by 1, so ignore the final observation.
      if (i < (entries.length - 1)) {
        sumActiveTeam += e.draft_active_team;
      }
      const currpickban = {
        order: e.draft_order,
        pick: e.pick,
        active_team: previousActiveTeam,
        hero_id: e.hero_id,
        player_slot: e.pick === true ? heroIdToSlot[heroId] : null,
        time: e.time,
        extra_time: e.draft_active_team === 2 ? e.draft_extime0 : e.draft_extime1,
        total_time_taken: 0,
      };
      draftTimings.push(JSON.parse(JSON.stringify(currpickban)));
      previousActiveTeam = e.draft_active_team;
    }
  }
  // ignore Source 1 games
  if (draftTimings.length !== 0) {
    // update the team that had the first pick/ban
    draftTimings[0].active_team = ((sumActiveTeam % 2) + 2);
    for (let j = 0; j < draftTimings.length; j += 1) {
      if (draftTimings[j].order === 1) {
        draftTimings[j].total_time_taken = (draftTimings[j].time);
      } else {
        let index2;
        // find the time of the end of the previous order
        for (let i = 0; i < draftTimings.length; i += 1) {
          const currpick = draftTimings[i];
          if (currpick.order === (draftTimings[j].order - 1)) {
            index2 = i;
          }
        }
        // calculate the timings
        draftTimings[j].total_time_taken = (draftTimings[j].time - draftTimings[index2].time);
      }
    }
  }
  // remove the time, no need for it
  for (let i = 0; i < draftTimings.length; i += 1) {
    delete draftTimings[i].time;
  }
  return draftTimings;
}
module.exports = processDraftTimings;
<commit_msg> Implemented new calculation for the first draft. (Parser) (#1909)<commit_after>/**
 * This processor grabs the draft timings from the parsed replay.
 * This is ideally to be used only for captain modes formats.
 * The output is:
 * order: the order of the pick or ban (1-20) (10 bans and 10 picks)
 * pick: whether the draft stage was a pick or ban. pick == true, ban == false
 * active_team: the active team during the draft stage (2 or 3) if 0
 * then not captains mode. Added check to ignore no CM games.
 * hero_id: the id of the hero banned or picked in the draft stage
 * player_slot: null for bans, the player_slot assoicated with the hero_id
 * time: removed for total time taken
 * extra_time: how much of the extra time is left at the end of the draft stage
 * total_time_taken: the time taken for the draft stage
 */

function processDraftTimings(entries, meta) {
  const draftTimings = [];
  const heroIdToSlot = meta.hero_id_to_slot;
  let sumActiveTeam = 0;
  let previousActiveTeam = 0;
  let draftStart = 0;

  for (let i = 0; i < entries.length; i += 1) {
    const e = entries[i];
    const heroId = e.hero_id;
    if (e.type === 'draft_timings') {
      // The active team needs to be downshifted by 1, so ignore the final observation.
      if (i < (entries.length - 1)) {
        sumActiveTeam += e.draft_active_team;
      }
      const currpickban = {
        order: e.draft_order,
        pick: e.pick,
        active_team: previousActiveTeam,
        hero_id: e.hero_id,
        player_slot: e.pick === true ? heroIdToSlot[heroId] : null,
        time: e.time,
        extra_time: e.draft_active_team === 2 ? e.draft_extime0 : e.draft_extime1,
        total_time_taken: 0,
      };
      draftTimings.push(JSON.parse(JSON.stringify(currpickban)));
      previousActiveTeam = e.draft_active_team;
    } else if (e.type === 'draft_start') {
      draftStart = e.time;
    }
  }
  // ignore Source 1 games
  if (draftTimings.length !== 0) {
    // update the team that had the first pick/ban
    draftTimings[0].active_team = ((sumActiveTeam % 2) + 2);
    for (let j = 0; j < draftTimings.length; j += 1) {
      if (draftTimings[j].order === 1) {
        draftTimings[j].total_time_taken = (draftTimings[j].time - draftStart);
      } else {
        let index2;
        // find the time of the end of the previous order
        for (let i = 0; i < draftTimings.length; i += 1) {
          const currpick = draftTimings[i];
          if (currpick.order === (draftTimings[j].order - 1)) {
            index2 = i;
          }
        }
        // calculate the timings
        draftTimings[j].total_time_taken = (draftTimings[j].time - draftTimings[index2].time);
      }
    }
  }
  // remove the time, no need for it
  for (let i = 0; i < draftTimings.length; i += 1) {
    delete draftTimings[i].time;
  }
  return draftTimings;
}
module.exports = processDraftTimings;
<|endoftext|>


<commit_before>if(!Draw.popMatrix) {
  Draw.popMatrix = function() {
    if(!Canvas.configured) {
      console.warn("KAPhy Warning - You must use Canvas.configure(); before you can draw!");
      return;
    }

    var oldFillStyle    = Canvas.context.fillStyle;
    var oldStrokeStyle  = Canvas.context.strokeStyle;
    var oldLineWidth    = Canvas.context.lineWidth;
    var oldLineCap      = Canvas.context.lineCap;
    var oldLineJoin     = Canvas.context.lineJoin;
    var oldGlobalAlpha  = Canvas.context.globalAlpha;
    var oldMiterLimit   = Canvas.context.miterLimit;
    var oldFont         = Canvas.context.font;
    var oldTextAlign    = Canvas.context.textAlign;
    var oldTextBaseline = Canvas.context.textBaseline;
    var oldSmoothing    = Canvas.context.imageSmoothingEnabled;

    Canvas.context.restore();

    Canvas.context.fillStyle    = oldFillStyle;
    Canvas.context.strokeStyle  = oldStrokeStyle;
    Canvas.context.lineWidth    = oldLineWidth;
    Canvas.context.lineCap      = oldLineCap;
    Canvas.context.lineJoin     = oldLineJoin;
    Canvas.context.globalAlpha  = oldGlobalAlpha;
    Canvas.context.miterLimit   = oldMiterLimit;
    Canvas.context.font         = oldFont;
    Canvas.context.textAlign    = oldTextAlign;
    Canvas.context.textBaseline = oldTextBaseline;
    Canvas.context.imageSmoothingEnabled = oldSmoothing;
  };
}
<commit_msg>Update popmatrix.js<commit_after>if(!Draw.popMatrix) {
  Draw.popMatrix = function() {
    if(!Canvas.configured) {
      console.warn("KAPhy Warning - You must use Canvas.configure(); before you can draw!");
      return;
    }

    if(Draw.shapeOn) {
      console.warn("KAPhy Warning - You cannot use transformation commands in shape mode.");
      return;
    }

    var oldFillStyle    = Canvas.context.fillStyle;
    var oldStrokeStyle  = Canvas.context.strokeStyle;
    var oldLineWidth    = Canvas.context.lineWidth;
    var oldLineCap      = Canvas.context.lineCap;
    var oldLineJoin     = Canvas.context.lineJoin;
    var oldGlobalAlpha  = Canvas.context.globalAlpha;
    var oldMiterLimit   = Canvas.context.miterLimit;
    var oldFont         = Canvas.context.font;
    var oldTextAlign    = Canvas.context.textAlign;
    var oldTextBaseline = Canvas.context.textBaseline;
    var oldSmoothing    = Canvas.context.imageSmoothingEnabled;

    Canvas.context.restore();

    Canvas.context.fillStyle    = oldFillStyle;
    Canvas.context.strokeStyle  = oldStrokeStyle;
    Canvas.context.lineWidth    = oldLineWidth;
    Canvas.context.lineCap      = oldLineCap;
    Canvas.context.lineJoin     = oldLineJoin;
    Canvas.context.globalAlpha  = oldGlobalAlpha;
    Canvas.context.miterLimit   = oldMiterLimit;
    Canvas.context.font         = oldFont;
    Canvas.context.textAlign    = oldTextAlign;
    Canvas.context.textBaseline = oldTextBaseline;
    Canvas.context.imageSmoothingEnabled = oldSmoothing;
  };
}
<|endoftext|>


<commit_before>'use strict';

var aseq = require('../lib/aseq');

var a = function(a, b, c, callback)
{
	console.log(arguments);
	callback('callback argument');
};

var b = function(a, b, c, callback)
{
	console.log(arguments);
	callback('callback argument');
};

var c = function(a, b, c, callback)
{
	console.log(arguments);
	callback('callback argument');
};

var d = function(a, b, c, callback)
{
	console.log(arguments);
	callback('callback argument');
};

var seq = new aseq();
seq.append(a, null, 'a', 'b');
seq.append(b, null, 'c', 'd');
seq.append(c, null, 'e', 'f');
seq.append(d, null, 'g', 'h');

seq.run('additional argument');
<commit_msg>Updated example<commit_after>'use strict';

var aseq = require('../lib/aseq');

var a = function(a, b, c, callback)
{
	console.log(arguments, this);
	callback('callback argument');
};

var b = function(a, callback)
{
	console.log(arguments, this);
	callback('callback argument');
};

var c = function(a, b, c, callback)
{
	console.log(arguments, this);
	callback('callback argument');
};

var d = function(a, callback)
{
	console.log(arguments, this);
	callback('callback argument');
};

var seq = new aseq();
seq.append(a, null, 'a', 'b');
seq.append(b, {test: 'test'});
seq.append(c, {test: 'test'}, 'e', 'f');
seq.append(d);

seq.run('additional argument');
<|endoftext|>


<commit_before>let map;

const initMap = function initMap() {
	map = new google.maps.Map(document.getElementById('map'), { // eslint-disable-line no-undef
		center: { lat: -23.55, lng: -46.633333 },
		zoom: 10,
	});

	const myHeaders = new Headers();

	myHeaders.append('Content-Type', 'application/json');

	const myInit = {
		method: 'GET',
		headers: myHeaders,
		mode: 'cors',
		cache: 'default',
	};

	const myRequest = new Request('/dist/js/districts.json');

	fetch(myRequest, myInit)
		.then((response) => {
			const contentType = response.headers.get('content-type');

			if (contentType && contentType.includes('application/json')) {
				return response.json();
			}

			throw new TypeError("Oops, we haven't got JSON!");
		})
		.then((districtsList) => {
			for (let i = 0; i < districtsList.region.length; i += 1) {
				const district = districtsList.region[i];
				const points = [];
				const geoJSON = JSON.parse(district.geo_json);

				for (let j = 0; j < geoJSON.coordinates.length; j += 1) {
					const coord = geoJSON.coordinates[j];
					for (let k = 0; k < coord.length; k += 1) {
						const corner = coord[k];
						points[points.length] = {
							lat: corner[1],
							lng: corner[0],
						};
					}
				}

				// Construct the polygon.
				const districtToDraw = new google.maps.Polygon({ // eslint-disable-line no-undef
					paths: points,
					strokeColor: '#FF0000',
					strokeOpacity: 0.8,
					strokeWeight: 2,
					fillColor: '#FF0000',
					fillOpacity: 0.35,
				});

				districtToDraw.setMap(map);
			}
		})
		.catch((error) => {
			throw new TypeError(error);
		});
};

export { initMap as default };
<commit_msg>Allow district filter by `data-` map attribute<commit_after>let map;

const initMap = function initMap() {
	const mapElement = document.getElementById('map');

	map = new google.maps.Map(mapElement, { // eslint-disable-line no-undef
		center: { lat: -23.55, lng: -46.633333 },
		zoom: 10,
	});

	const myHeaders = new Headers();

	myHeaders.append('Content-Type', 'application/json');

	const myInit = {
		method: 'GET',
		headers: myHeaders,
		mode: 'cors',
		cache: 'default',
	};

	const myRequest = new Request('/dist/js/districts.json');

	fetch(myRequest, myInit)
		.then((response) => {
			const contentType = response.headers.get('content-type');

			if (contentType && contentType.includes('application/json')) {
				return response.json();
			}

			throw new TypeError("Oops, we haven't got JSON!");
		})
		.then((districtsList) => {
			let districts = districtsList.regions;

			if (mapElement.hasAttribute('data-district')) {
				const districtToDraw = parseInt(mapElement.getAttribute('data-district'), 10);

				districts = districts.filter(x => x.id === districtToDraw);
			}

			for (let i = 0; i < districts.length; i += 1) {
				const district = districts[i];
				const points = [];
				const geoJSON = JSON.parse(district.geo_json);

				for (let j = 0; j < geoJSON.coordinates.length; j += 1) {
					const coord = geoJSON.coordinates[j];
					for (let k = 0; k < coord.length; k += 1) {
						const corner = coord[k];
						points[points.length] = {
							lat: corner[1],
							lng: corner[0],
						};
					}
				}

				// Construct the polygon.
				const districtToDraw = new google.maps.Polygon({ // eslint-disable-line no-undef
					paths: points,
					strokeColor: '#FF0000',
					strokeOpacity: 0.8,
					strokeWeight: 2,
					fillColor: '#FF0000',
					fillOpacity: 0.35,
				});

				districtToDraw.setMap(map);
			}
		})
		.catch((error) => {
			throw new TypeError(error);
		});
};

export { initMap as default };
<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();
var authentication = require('../authentication');
var request = require('request-promise');
var url = require('url');

// Simple route middleware to ensure user is authenticated.
//   Use this route middleware on any resource that needs to be protected.  If
//   the request is authenticated (typically via a persistent login session),
//   the request will proceed.  Otherwise, the user will be redirected to the
//   login page.
function ensureAuthenticated(req, res, next) {
  if (req.isAuthenticated()) {
    return next()
  }
  res.status(401).send({
    authUri: authentication.getAuthUri(),
    msg: 'Authentication required.'
  });
}

router.post('/logout', function(req, res) {
  req.session.destroy();
  return res.send({});
});

router.getSession = function(req, res) {
  request.get({
    uri: 'https://partner.dev.onshape.com/api/users/session',
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {
    res.send(data);
  }).catch(function(data) {
    console.log('****** getSession - CATCH ' + data.statusCode);
    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        router.getElementList(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting session: ', err);
      });
    } else {
      console.log('GET /api/users/session error: ', data);
    }
  });
};

exports.getDocuments = function(req, res) {
  request.get({
    uri: 'https://partner.dev.onshape.com/api/documents',
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {
    res.send(data);
  }).catch(function(data) {
    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        getDocuments(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting documents: ', err);
      });
    } else {
      console.log('GET /api/documents error: ', data);
    }
  });
};

router.getElementList = function(req, res) {
  request.get({
    uri: 'https://partner.dev.onshape.com/api/documents/d/' + req.query.documentId + '/w/' + req.query.workspaceId,
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {
    //console.log('****** getElementList - send data');

    res.send(data);
  }).catch(function(data) {
    console.log('****** getElementList - CATCH ' + data.statusCode);
    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        router.getElementList(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting elements: ', err);
      });
    } else {
      console.log('GET /api/documents/elements error: ', data);
    }
  });
};

router.getShadedView = function(req, res) {
  request.get({
    uri: 'https://partner.dev.onshape.com/api/assemblies/d/' + req.query.documentId +
    '/w/' + req.query.workspaceId + '/e/' + req.query.elementId + 'shadedviews?' +
    '&outputHeight=' + req.qeury.outputHeight + '&outputWidth=' + req.query.outputWidth + '&pixelSize=' + req.query.pixelSize +
    '&viewMatrix=' + req.query.viewMatrix1 + '&viewMatrix=' + req.query.viewMatrix2 + '&viewMatrix=' + req.query.viewMatrix3 + '&viewMatrix=' + req.query.viewMatrix4 +
    '&viewMatrix=' + req.query.viewMatrix5 + '&viewMatrix=' + req.query.viewMatrix6 + '&viewMatrix=' + req.query.viewMatrix7 + '&viewMatrix=' + req.query.viewMatrix8 +
    '&viewMatrix=' + req.query.viewMatrix9 + '&viewMatrix=' + req.query.viewMatrix10 + '&viewMatrix=' + req.query.viewMatrix11 + '&viewMatrix=' + req.query.viewMatrix12,
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {

    res.send(data);
  }).catch(function(data) {

    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        router.getElementList(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting elements: ', err);
      });
    } else {
      console.log('GET /api/assemblies/boundingbox error: ', data);
    }
  });
};

router.getBoundingBox = function(req, res) {
  request.get({
    uri: 'https://partner.dev.onshape.com/api/assemblies/d/' + req.query.documentId +
          '/w/' + req.query.workspaceId + '/e/' + req.query.elementId + '/boundingboxes/',
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {

    res.send(data);
  }).catch(function(data) {
    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        router.getElementList(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting elements: ', err);
      });
    } else {
      console.log('GET /api/assemblies/boundingbox error: ', data);
    }
  });
};

router.getPartsList = function(req, res) {
  request.get({
    uri: 'https://partner.dev.onshape.com/api/parts/d/' + req.query.documentId + '/w/' + req.query.workspaceId,
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {
    res.send(data);
  }).catch(function(data) {
    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        getDocuments(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting elements: ', err);
      });
    } else {
      console.log('GET /api/parts/workspace error: ', data);
    }
  });
};

router.getAssemblyDefinition = function(req, res) {
  request.get({
    uri: 'https://partner.dev.onshape.com/api/assemblies/d/' + req.query.documentId + '/w/' + req.query.workspaceId + '/e/' + req.query.nextElement + '?includeMateFeatures=false',
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {
    res.send(data);
  }).catch(function(data) {
    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        getDocuments(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting definition: ', err);
      });
    } else {
      console.log('GET /api/models/assembly/definition error: ', data);
    }
  });
};

router.getStl = function(req, res) {

  var url = 'https://partner.dev.onshape.com/api/documents/' + req.query.documentId + '/export/' + req.query.stlElementId +
      '?workspaceId=' + req.query.workspaceId +
      '&format=STL&mode=' + 'text'  +
      '&scale=1&units=inch';
  if (req.query.partId !== '') {
    url += '&partId=' + req.query.partId;
  }
  if (req.query.angleTolerance !== '' && req.query.chordTolerance !== '') {
    url += '&angleTolerance=' + req.query.angleTolerance +'&chordTolerance=' + req.query.chordTolerance;
  }

  request.get({
    uri: url,
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {
    res.send(data);
  }).catch(function(data) {
    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        getDocuments(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting elements: ', err);
      });
    } else {
      console.log('GET /api/parts/workspace error: ', data);
    }
  });
};

router.get('/documents', function(req, res) {
  getDocuments(req, res);
});

module.exports = router;
<commit_msg>fix for elements<commit_after>var express = require('express');
var router = express.Router();
var authentication = require('../authentication');
var request = require('request-promise');
var url = require('url');

// Simple route middleware to ensure user is authenticated.
//   Use this route middleware on any resource that needs to be protected.  If
//   the request is authenticated (typically via a persistent login session),
//   the request will proceed.  Otherwise, the user will be redirected to the
//   login page.
function ensureAuthenticated(req, res, next) {
  if (req.isAuthenticated()) {
    return next()
  }
  res.status(401).send({
    authUri: authentication.getAuthUri(),
    msg: 'Authentication required.'
  });
}

router.post('/logout', function(req, res) {
  req.session.destroy();
  return res.send({});
});

router.getSession = function(req, res) {
  request.get({
    uri: 'https://partner.dev.onshape.com/api/users/session',
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {
    res.send(data);
  }).catch(function(data) {
    console.log('****** getSession - CATCH ' + data.statusCode);
    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        router.getElementList(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting session: ', err);
      });
    } else {
      console.log('GET /api/users/session error: ', data);
    }
  });
};

exports.getDocuments = function(req, res) {
  request.get({
    uri: 'https://partner.dev.onshape.com/api/documents',
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {
    res.send(data);
  }).catch(function(data) {
    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        getDocuments(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting documents: ', err);
      });
    } else {
      console.log('GET /api/documents error: ', data);
    }
  });
};

router.getElementList = function(req, res) {
  request.get({
    uri: 'https://partner.dev.onshape.com/api/documents/d/' + req.query.documentId + '/w/' + req.query.workspaceId + '/elements',
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {
    //console.log('****** getElementList - send data');

    res.send(data);
  }).catch(function(data) {
    console.log('****** getElementList - CATCH ' + data.statusCode);
    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        router.getElementList(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting elements: ', err);
      });
    } else {
      console.log('GET /api/documents/elements error: ', data);
    }
  });
};

router.getShadedView = function(req, res) {
  request.get({
    uri: 'https://partner.dev.onshape.com/api/assemblies/d/' + req.query.documentId +
    '/w/' + req.query.workspaceId + '/e/' + req.query.elementId + 'shadedviews?' +
    '&outputHeight=' + req.qeury.outputHeight + '&outputWidth=' + req.query.outputWidth + '&pixelSize=' + req.query.pixelSize +
    '&viewMatrix=' + req.query.viewMatrix1 + '&viewMatrix=' + req.query.viewMatrix2 + '&viewMatrix=' + req.query.viewMatrix3 + '&viewMatrix=' + req.query.viewMatrix4 +
    '&viewMatrix=' + req.query.viewMatrix5 + '&viewMatrix=' + req.query.viewMatrix6 + '&viewMatrix=' + req.query.viewMatrix7 + '&viewMatrix=' + req.query.viewMatrix8 +
    '&viewMatrix=' + req.query.viewMatrix9 + '&viewMatrix=' + req.query.viewMatrix10 + '&viewMatrix=' + req.query.viewMatrix11 + '&viewMatrix=' + req.query.viewMatrix12,
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {

    res.send(data);
  }).catch(function(data) {

    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        router.getElementList(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting elements: ', err);
      });
    } else {
      console.log('GET /api/assemblies/boundingbox error: ', data);
    }
  });
};

router.getBoundingBox = function(req, res) {
  request.get({
    uri: 'https://partner.dev.onshape.com/api/assemblies/d/' + req.query.documentId +
          '/w/' + req.query.workspaceId + '/e/' + req.query.elementId + '/boundingboxes/',
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {

    res.send(data);
  }).catch(function(data) {
    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        router.getElementList(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting elements: ', err);
      });
    } else {
      console.log('GET /api/assemblies/boundingbox error: ', data);
    }
  });
};

router.getPartsList = function(req, res) {
  request.get({
    uri: 'https://partner.dev.onshape.com/api/parts/d/' + req.query.documentId + '/w/' + req.query.workspaceId,
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {
    res.send(data);
  }).catch(function(data) {
    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        getDocuments(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting elements: ', err);
      });
    } else {
      console.log('GET /api/parts/workspace error: ', data);
    }
  });
};

router.getAssemblyDefinition = function(req, res) {
  request.get({
    uri: 'https://partner.dev.onshape.com/api/assemblies/d/' + req.query.documentId + '/w/' + req.query.workspaceId + '/e/' + req.query.nextElement + '?includeMateFeatures=false',
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {
    res.send(data);
  }).catch(function(data) {
    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        getDocuments(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting definition: ', err);
      });
    } else {
      console.log('GET /api/models/assembly/definition error: ', data);
    }
  });
};

router.getStl = function(req, res) {

  var url = 'https://partner.dev.onshape.com/api/documents/' + req.query.documentId + '/export/' + req.query.stlElementId +
      '?workspaceId=' + req.query.workspaceId +
      '&format=STL&mode=' + 'text'  +
      '&scale=1&units=inch';
  if (req.query.partId !== '') {
    url += '&partId=' + req.query.partId;
  }
  if (req.query.angleTolerance !== '' && req.query.chordTolerance !== '') {
    url += '&angleTolerance=' + req.query.angleTolerance +'&chordTolerance=' + req.query.chordTolerance;
  }

  request.get({
    uri: url,
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {
    res.send(data);
  }).catch(function(data) {
    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        getDocuments(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting elements: ', err);
      });
    } else {
      console.log('GET /api/parts/workspace error: ', data);
    }
  });
};

router.get('/documents', function(req, res) {
  getDocuments(req, res);
});

module.exports = router;
<|endoftext|>


<commit_before>angular.module( 'angularUtils.filters.ordinalDate', [] )

    .filter('ordinalDate', ['$filter', function($filter) {

        var getOrdinalSuffix = function(number) {
            var suffixes = ["'th'", "'st'", "'nd'", "'rd'"];
            var relevantDigits = (number < 30) ? number % 20 : number % 30;
            return (relevantDigits <= 3) ? suffixes[relevantDigits] : suffixes[0];
        };

        /**
         * Look through the format string for any possible match for 'd'.
         * It needs to ignore 'dd' and also occurrences of the letter d inside
         * string such as "d 'day of' MM'.
         * @param format
         */
        var getIndecesOfDayCharacter = function(format) {
            var dayRegex = /(?:'(?:[^']|'')*')|(?:d+)/g;
            var matchingIndices = [];
            var finishedLooking = false;

            while(!finishedLooking) {
                var matches = dayRegex.exec(format);
                if (matches) {
                    dayRegex.lastIndex = matches.index + matches[0].length;
                    if (matches[0] === 'd') {
                        matchingIndices.push(matches.index + 1);
                    }
                } else {
                    finishedLooking = true;
                }
            }

            return matchingIndices;
        };

        /**
         * Insert a string at a given index of another string
         * @param inputString
         * @param index
         * @param stringToInsert
         * @returns {string}
         */
        var insertAtIndex = function(inputString, index, stringToInsert) {
            var partBeforeIndex = inputString.substring(0, index);
            var partAfterIndex = inputString.substring(index, inputString.length);
            return partBeforeIndex + stringToInsert + partAfterIndex;
        };

        return function(timestamp, format) {
            var date = new Date(timestamp);
            var dayOfMonth = date.getDate();
            var suffix = getOrdinalSuffix(dayOfMonth);

            var matchingIndices = getIndecesOfDayCharacter(format);

            // now we to insert the suffix at the index(-ces) that we found
            for (var i = matchingIndices.length; i > 0; i --) {
                format = insertAtIndex(format, matchingIndices[i-1], suffix);
            }
            return $filter('date')(date, format);
        };
    }]);<commit_msg>used string.replace<commit_after>angular.module( 'angularUtils.filters.ordinalDate', [] )

    .filter('ordinalDate', ['$filter', function($filter) {

        var getOrdinalSuffix = function(number) {
            var suffixes = ["'th'", "'st'", "'nd'", "'rd'"];
            var relevantDigits = (number < 30) ? number % 20 : number % 30;
            return "d" + ((relevantDigits <= 3) ? suffixes[relevantDigits] : suffixes[0]);
        };

        return function(timestamp, format) {
            var regex = /d(?=[^d])((?!\w*(?='))(?!d))/g;
            var date = new Date(timestamp);
            var dayOfMonth = date.getDate();
            var suffix = getOrdinalSuffix(dayOfMonth);

            format = format.replace(regex, suffix);
            return $filter('date')(date, format);
        };
    }]);<|endoftext|>


<commit_before>/**
 * Put tasks defined in ~extend.js appended files within the more general tasks listed below.
 */
'use strict';

const gulp = require('gulp');

gulp.task('contrib:data', [
]);

gulp.task('contrib:frontend-copy', [
// Comment or delete if you wish to disable this.
  'stylus:frontend-copy'
]);

gulp.task('contrib:once', [
// Comment or delete if you wish to disable this.
  'stylus:once'
]);

gulp.task('contrib:static', [
]);

gulp.task('contrib:syncback', [
]);

gulp.task('contrib:tcp-ip', [
]);

gulp.task('contrib:template', [
]);

gulp.task('contrib:watch', [
// Comment or delete if you wish to disable this.
  'stylus:watch'
]);
<commit_msg>comment indentation update<commit_after>/**
 * Put tasks defined in ~extend.js appended files within the more general tasks listed below.
 */
'use strict';

const gulp = require('gulp');

gulp.task('contrib:data', [
]);

gulp.task('contrib:frontend-copy', [
  // Comment or delete if you wish to disable this.
  'stylus:frontend-copy'
]);

gulp.task('contrib:once', [
  // Comment or delete if you wish to disable this.
  'stylus:once'
]);

gulp.task('contrib:static', [
]);

gulp.task('contrib:syncback', [
]);

gulp.task('contrib:tcp-ip', [
]);

gulp.task('contrib:template', [
]);

gulp.task('contrib:watch', [
  // Comment or delete if you wish to disable this.
  'stylus:watch'
]);
<|endoftext|>


<commit_before>'use strict';

var o = { foo: 'bar' };

module.exports = function (t, a) {
	var o = { foo: 'bar' }, x = {};
	t('foo', x)(o);
	a(o.foo, x);
};
<commit_msg>-- cleanup<commit_after>'use strict';

module.exports = function (t, a) {
	var o = { foo: 'bar' }, x = {};
	t('foo', x)(o);
	a(o.foo, x);
};
<|endoftext|>


<commit_before>/**
 * routes/api.js - Defines /api/search and /api/browse routes for API requests
 *
 * Authors: Ian McGaunn; Dave Zimmelman
 * Modified: 09 Mar 15
 */

var express = require('express');
var request = require('request');
var xml2js = require('xml2js');
var router = express.Router();
var parser = new xml2js.Parser({explicitArray: false});
var parseString = parser.parseString;

var clientKey = require('../lib/clientkey').Key;
var Cache = require('../lib/badcache');
var Podcasts = require('../lib/podcasts');
var isFavorited = require('../lib/users').isFavorited;

/**
 * Routes for api/view URLs
 */
router.get('/view/splash', function (req, res, next) {
    var casts;
    if (req.session.user) {
        res.render('splash', {
            user: req.session.user,
            genres: Podcasts.Genres});
    }
    else {
        res.render('splash-guest', {
            genres: Podcasts.Genres});
    }
});
router.get('/view/podcast/:id', function (req, res, next) {
    var id = req.params.id;
    // HTTP request information on podcast ID via Apple API
    Podcasts.getPodcast(id, function (error, msg) {
        res.render('error', { message: msg, error: error});
    }, function (podcast) {
        request(podcast.feedUrl, function (error, response, body) {
            // Data returned in XML format, and must be parsed.
            if (error) {
                console.log('Error retrieving feed:');
                console.log('\t' + JSON.stringify(error));
                res.render('error', {error: error});
            }
            else {
                parseString(body, function (err, obj) {
                    // Render client 'podcast' page/view, passing necessary data.
                    if (err) {
                        console.log('Error parsing podcast feed:');
                        console.log('\t' + JSON.stringify(err));
                        res.render('error', {error: err});
                    }
                    else {
                        // Increase podcast popularity
                        podcasts.modifyPodcastPoints(podcast._id, 1);
                        res.render('podcast', {id: id,
                                               user: req.session.user,
                                               isFavorited: isFavorited,
                                               title: podcast.title,
                                               podcast: podcast,
                                               safetitle: id + '/' + podcast.title_uri,
                                               feed: obj.rss.channel });
                    }
                });
            }
        });
    });
});
router.get('/castcat/:gid', function (req, res, next) {
    if (req.session.user) {
        Cache.aggregate_cat(req.params.gid,
                            req.session.user.subscriptions,
                            function (err, msg) {
            console.log(msg);
            console.log(err);
            res.send(msg);
        }, function (data) {
            res.json({podcasts: data[0], favorites: data[1]});
        });
    } else {
        Cache.aggregate_cat(req.params.gid, false, function (err, msg) {
            console.log(msg);
            console.log(err);
            res.send(msg);
        }, function (data) {
            res.json({podcasts: data[0]});
        });
    }
});

/**
 * Route for api/clientkey URL
 */
router.post('/clientkey', function (req, res, next) {
    if (!req.body.key) {
        res.json({status: 400,
                  message: "Bad Request"});
    }
    else if (req.body.key !== 'fish') {
        res.json({status: 401,
                  message: "Unauthorized"});
    }
    else {
        res.json({status: 200,
                  message: clientKey});
    }
});

/**
 * Route for api/search URL
 */
router.get('/search', function (req, res, next) {
    var api = 'https://itunes.apple.com/search?entity=podcast&term=';
    // Name is ambiguous, and might confuse things when we implement local searching by station/artist/etc.
    // For now, it's best to use `term` to avoid confusion.
    var queryURL = api + req.query.term;

    console.log('url: ' + queryURL);

    // Send requested search data received from Apple API back to caller.
    request(queryURL, function (error, response, body) {
        // Parse JSON results
        var results = JSON.parse(body).results;
        if (results) {
            // Cache results
            Podcasts.cacheSearchResults(results, function (err, msg) {
                console.log(msg);
                console.log(err);
                res.json({"error": msg});
            }, function (pcasts) {
                Cache.search[req.query.term] = pcasts;
                res.json(pcasts);
            });
        } else {
            res.json({});
        }
    });
});

/**
 * Route for api/quicksearch URL
 */
router.get('/quicksearch', function (req, res, next) {
    Podcasts.searchByTerm(req.query.term, function (data) {
        res.json(data);
    });
});

/**
 * Route for api/browse URL
 */
router.get('/browse', function (req, res, next) {
    var api = 'https://itunes.apple.com/us/rss/toppodcasts';
    var limit = (req.query.limit && req.query.limit >= 0 && req.query.limit <= 200)
        ? '/limit=' + req.query.limit
        : '/limit=50';
    var explicit = (req.query.safe)
        ? '/explicit=false'
        : '/explicit=true';
    var genre = (req.query.genre && req.query.genre !== 0)
        ? '/genre=' + req.query.genre
        : '';
    var queryURL = api + limit + genre + explicit + '/json';

    console.log('url: ' + queryURL);

    // Send requested browse data received from Apple API back to caller.
    request(queryURL, function (error, response, body) {
        // Update cache with request
        Cache.browse[req.query.genre] = JSON.parse(body);
        res.send(body);
    });
});

// Expose routes
module.exports = router;
<commit_msg>[Fix] Bad reference<commit_after>/**
 * routes/api.js - Defines /api/search and /api/browse routes for API requests
 *
 * Authors: Ian McGaunn; Dave Zimmelman
 * Modified: 09 Mar 15
 */

var express = require('express');
var request = require('request');
var xml2js = require('xml2js');
var router = express.Router();
var parser = new xml2js.Parser({explicitArray: false});
var parseString = parser.parseString;

var clientKey = require('../lib/clientkey').Key;
var Cache = require('../lib/badcache');
var Podcasts = require('../lib/podcasts');
var isFavorited = require('../lib/users').isFavorited;

/**
 * Routes for api/view URLs
 */
router.get('/view/splash', function (req, res, next) {
    var casts;
    if (req.session.user) {
        res.render('splash', {
            user: req.session.user,
            genres: Podcasts.Genres});
    }
    else {
        res.render('splash-guest', {
            genres: Podcasts.Genres});
    }
});
router.get('/view/podcast/:id', function (req, res, next) {
    var id = req.params.id;
    // HTTP request information on podcast ID via Apple API
    Podcasts.getPodcast(id, function (error, msg) {
        res.render('error', { message: msg, error: error});
    }, function (podcast) {
        request(podcast.feedUrl, function (error, response, body) {
            // Data returned in XML format, and must be parsed.
            if (error) {
                console.log('Error retrieving feed:');
                console.log('\t' + JSON.stringify(error));
                res.render('error', {error: error});
            }
            else {
                parseString(body, function (err, obj) {
                    // Render client 'podcast' page/view, passing necessary data.
                    if (err) {
                        console.log('Error parsing podcast feed:');
                        console.log('\t' + JSON.stringify(err));
                        res.render('error', {error: err});
                    }
                    else {
                        // Increase podcast popularity
                        Podcasts.modifyPodcastPoints(podcast._id, 1);
                        res.render('podcast', {id: id,
                                               user: req.session.user,
                                               isFavorited: isFavorited,
                                               title: podcast.title,
                                               podcast: podcast,
                                               safetitle: id + '/' + podcast.title_uri,
                                               feed: obj.rss.channel });
                    }
                });
            }
        });
    });
});
router.get('/castcat/:gid', function (req, res, next) {
    if (req.session.user) {
        Cache.aggregate_cat(req.params.gid,
                            req.session.user.subscriptions,
                            function (err, msg) {
            console.log(msg);
            console.log(err);
            res.send(msg);
        }, function (data) {
            res.json({podcasts: data[0], favorites: data[1]});
        });
    } else {
        Cache.aggregate_cat(req.params.gid, false, function (err, msg) {
            console.log(msg);
            console.log(err);
            res.send(msg);
        }, function (data) {
            res.json({podcasts: data[0]});
        });
    }
});

/**
 * Route for api/clientkey URL
 */
router.post('/clientkey', function (req, res, next) {
    if (!req.body.key) {
        res.json({status: 400,
                  message: "Bad Request"});
    }
    else if (req.body.key !== 'fish') {
        res.json({status: 401,
                  message: "Unauthorized"});
    }
    else {
        res.json({status: 200,
                  message: clientKey});
    }
});

/**
 * Route for api/search URL
 */
router.get('/search', function (req, res, next) {
    var api = 'https://itunes.apple.com/search?entity=podcast&term=';
    // Name is ambiguous, and might confuse things when we implement local searching by station/artist/etc.
    // For now, it's best to use `term` to avoid confusion.
    var queryURL = api + req.query.term;

    console.log('url: ' + queryURL);

    // Send requested search data received from Apple API back to caller.
    request(queryURL, function (error, response, body) {
        // Parse JSON results
        var results = JSON.parse(body).results;
        if (results) {
            // Cache results
            Podcasts.cacheSearchResults(results, function (err, msg) {
                console.log(msg);
                console.log(err);
                res.json({"error": msg});
            }, function (pcasts) {
                Cache.search[req.query.term] = pcasts;
                res.json(pcasts);
            });
        } else {
            res.json({});
        }
    });
});

/**
 * Route for api/quicksearch URL
 */
router.get('/quicksearch', function (req, res, next) {
    Podcasts.searchByTerm(req.query.term, function (data) {
        res.json(data);
    });
});

/**
 * Route for api/browse URL
 */
router.get('/browse', function (req, res, next) {
    var api = 'https://itunes.apple.com/us/rss/toppodcasts';
    var limit = (req.query.limit && req.query.limit >= 0 && req.query.limit <= 200)
        ? '/limit=' + req.query.limit
        : '/limit=50';
    var explicit = (req.query.safe)
        ? '/explicit=false'
        : '/explicit=true';
    var genre = (req.query.genre && req.query.genre !== 0)
        ? '/genre=' + req.query.genre
        : '';
    var queryURL = api + limit + genre + explicit + '/json';

    console.log('url: ' + queryURL);

    // Send requested browse data received from Apple API back to caller.
    request(queryURL, function (error, response, body) {
        // Update cache with request
        Cache.browse[req.query.genre] = JSON.parse(body);
        res.send(body);
    });
});

// Expose routes
module.exports = router;
<|endoftext|>


<commit_before>/** @jsx React.DOM */
var React = require("react");
var PropsMethodMixin = require("../../../mixins/PropsMethodMixin");
var uniqueId = require('lodash-node/modern/utilities/uniqueId');

var AnswerRadioInput = React.createClass({
  mixins: [PropsMethodMixin],
  propTypes: {
    id: React.PropTypes.string,
    name: React.PropTypes.string.isRequired,
    label: React.PropTypes.string.isRequired,
    value: React.PropTypes.string.isRequired,
    checked: React.PropTypes.bool
  },
  getDefaultProps: function () {
    return {
      id: uniqueId('radio-'),
      checked: false
    };
  },
  getInitialState: function () {
    return {
      checked: !!this.props.checked
    };
  },
  componentWillReceiveProps: function (nextProps) {
    if(nextProps.checked !== undefined) {
      this.setState({
        checked: nextProps.checked
      });
    }
  },
  handleChanged: function (e) {
    var checked = e.target.checked;
    this.setState({checked: checked});
    if(checked) {
      this.callMethodOnProps('onChanged', this.props.value);
    }
  },
  render: function () {
    return (

          <input type="radio"
            name={this.props.name}
            id={this.props.id}
            value={this.props.value}
            checked={this.state.checked}
            onChange={this.handleChanged} />
          {this.props.label}

    );
  }
});

module.exports = AnswerRadioInput;
<commit_msg>Refinements for book text<commit_after>/** @jsx React.DOM */
var React = require("react");
var uniqueId = require('lodash-node/modern/utilities/uniqueId');

var AnswerRadioInput = React.createClass({
  propTypes: {
    id: React.PropTypes.string,
    name: React.PropTypes.string.isRequired,
    label: React.PropTypes.string.isRequired,
    value: React.PropTypes.string.isRequired,
    checked: React.PropTypes.bool,
    onChanged: React.PropTypes.func.isRequired
  },
  getDefaultProps: function () {
    return {
      checked: false
    };
  },
  getInitialState: function () {
    return {
      checked: !!this.props.checked,
      id: this.props.id ? this.props.id : uniqueId('radio-')
    };
  },
  componentWillReceiveProps: function (nextProps) {
    if(nextProps.checked !== undefined) {
      this.setState({
        checked: nextProps.checked
      });
    }
  },
  handleChanged: function (e) {
    var checked = e.target.checked;
    this.setState({checked: checked});
    if(checked) {
      this.props.onChanged(this.props.value);
    }
  },
  render: function () {
    return (

          <input type="radio"
            name={this.props.name}
            id={this.state.id}
            checked={this.state.checked}
            onChange={this.handleChanged} />
          {this.props.label}

    );
  }
});

module.exports = AnswerRadioInput;
<|endoftext|>


<commit_before>/* @flow */
import path from 'path';

import express from 'express';
import React from 'react';
import ReactDOM from 'react-dom/server';
import { createServerDispatcher } from 'isomorphic-dispatcher';

import { storeA, storeB, storeC } from './stores';
import App from './app';

/*------------------------------------------------------------------------------------------------*/
//	--- Create server ---
/*------------------------------------------------------------------------------------------------*/
let app = express();
app.use('/', (req, res, next) => {
	if(req.url !== '/') {
		next();
		return;
	}

	const dispatcher = createServerDispatcher({ storeA, storeB, storeC }, () => req);
	const appMarkup = ReactDOM.renderToString(
		<App dispatcher={dispatcher} />
	);
	const pageMarkup = ReactDOM.renderToStaticMarkup(

				<title>Example - react-isomorphic-dispatcher</title>