<commit_before>// Copyright 2016, University of Colorado Boulder

/**
 * Module representing the sun (as an energy source) in the model.  This
 * includes the clouds that can block the sun's rays.
 *
 * @author  John Blanco (original Java)
 * @author  Andrew Adare (js port)
 */
define( function( require ) {
  'use strict';

  // Modules
  var Cloud = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/Cloud' );
  var EFACConstants = require( 'ENERGY_FORMS_AND_CHANGES/common/EFACConstants' );
  var Energy = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/Energy' );
  var EnergyChunk = require( 'ENERGY_FORMS_AND_CHANGES/common/model/EnergyChunk' );
  var energyFormsAndChanges = require( 'ENERGY_FORMS_AND_CHANGES/energyFormsAndChanges' );
  var EnergySource = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/EnergySource' );
  var EnergyType = require( 'ENERGY_FORMS_AND_CHANGES/common/model/EnergyType' );
  var Image = require( 'SCENERY/nodes/Image' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Random = require( 'DOT/Random' );
  var Util = require( 'DOT/Util' );
  var Vector2 = require( 'DOT/Vector2' );

  // Constants
  var RADIUS = 0.02; // In meters, apparent size, not (obviously) actual size.
  var OFFSET_TO_CENTER_OF_SUN = new Vector2( -0.05, 0.12 );
  var ENERGY_CHUNK_EMISSION_PERIOD = 0.11; // In seconds.
  var RAND = new Random();
  var MAX_DISTANCE_OF_E_CHUNKS_FROM_SUN = 0.5; // In meters.

  // Constants that control the nature of the emission sectors.  These are
  // used to make emission look random yet still have a fairly steady rate
  // within each sector.  One sector is intended to point at the solar panel.
  var NUM_EMISSION_SECTORS = 10;
  var EMISSION_SECTOR_SPAN = 2 * Math.PI / NUM_EMISSION_SECTORS;

  // Used to tweak sector positions to make sure solar panel gets consistent flow of E's.
  var EMISSION_SECTOR_OFFSET = EMISSION_SECTOR_SPAN * 0.71;

  var SUN_ICON = require( 'image!ENERGY_FORMS_AND_CHANGES/sun_icon.png' );

  /**
   * @param {EnergyConverter} solarPanel
   * @param {Property.<boolean>} energyChunksVisibleProperty
   * @constructor
   */
  function SunEnergySource( solarPanel, energyChunksVisibleProperty ) {

    var self = this;

    EnergySource.call( this, new Image( SUN_ICON ) );

    this.energyChunksVisibleProperty = energyChunksVisibleProperty;

    this.solarPanel = solarPanel;

    this.energyChunkEmissionCountdownTimer = ENERGY_CHUNK_EMISSION_PERIOD;

    this.sectorList = _.shuffle( _.range( NUM_EMISSION_SECTORS ) );

    // List of energy chunks that should be allowed to pass through the clouds
    // without bouncing (i.e. being reflected).
    this.energyChunksPassingThroughClouds = [];

    this.currentSectorIndex = 0;

    this.sunPosition = OFFSET_TO_CENTER_OF_SUN;

    this.radius = RADIUS;

    // Clouds that can potentially block the sun's rays.  The positions are
    // set so that they appear between the sun and the solar panel, and must
    // not overlap with one another.
    this.clouds = [
      new Cloud( new Vector2( -0.01, 0.08 ), this.positionProperty ),
      new Cloud( new Vector2( 0.017, 0.0875 ), this.positionProperty ),
      new Cloud( new Vector2( 0.02, 0.105 ), this.positionProperty )
    ];

    this.addProperty( 'cloudiness', 0 );

    // Add/remove clouds based on the value of the cloudiness property.
    this.cloudinessProperty.link( function( cloudiness ) {
      var nClouds = self.clouds.length;
      for ( var i = 0; i < nClouds; i++ ) {
        // Stagger the existence strength of the clouds.
        var value = Util.clamp( cloudiness * ( nClouds - i ), 0, 1 );
        self.clouds[ i ].existenceStrengthProperty.set( value );
      }
    } );

    this.positionProperty.link( function( position ) {
      self.sunPosition = position.plus( OFFSET_TO_CENTER_OF_SUN );
    } );

  }

  energyFormsAndChanges.register( 'SunEnergySource', SunEnergySource );

  return inherit( EnergySource, SunEnergySource, {

    step: function( dt ) {
      var energyProduced = 0;
      if ( this.active === true ) {

        // See if it is time to emit a new energy chunk.
        this.energyChunkEmissionCountdownTimer -= dt;
        if ( this.energyChunkEmissionCountdownTimer <= 0 ) {
          // Create a new chunk and start it on its way.
          this.emitEnergyChunk();
          this.energyChunkEmissionCountdownTimer += ENERGY_CHUNK_EMISSION_PERIOD;
        }

        // Move the energy chunks.
        this.updateEnergyChunkPositions( dt );

        // Calculate the amount of energy produced.
        energyProduced = EFACConstants.MAX_ENERGY_PRODUCTION_RATE * ( 1 - this.cloudiness ) * dt;
      }

      // Produce the energy.
      return new Energy( EnergyType.LIGHT, energyProduced, 0 );
    },

    // @private
    updateEnergyChunkPositions: function( dt ) {

      var self = this;

      // Check for bouncing and absorption of the energy chunks.
      this.energyChunkList.forEach( function( chunk ) {

        var distanceFromSun = chunk.positionProperty.value.distance( self.sunPosition.plus( OFFSET_TO_CENTER_OF_SUN ) );

        // This energy chunk was absorbed by the solar panel, so
        // put it on the list of outgoing chunks.
        if ( self.solarPanel.active && self.solarPanel.getAbsorptionShape().bounds.containsPoint( chunk.position ) ) {
          self.outgoingEnergyChunks.push( chunk );
        }

        // This energy chunk is out of visible range, so remove it.
        else if ( distanceFromSun > MAX_DISTANCE_OF_E_CHUNKS_FROM_SUN ) {
          self.energyChunkList.remove( chunk );
          _.pull( self.energyChunksPassingThroughClouds, chunk );
        }

        // Chunks encountering clouds
        else {
          self.clouds.forEach( function( cloud ) {

            var inClouds = cloud.getCloudAbsorptionReflectionShape().bounds.containsPoint( chunk.position );
            var inList = _.contains( self.energyChunksPassingThroughClouds, chunk );
            var deltaPhi = chunk.velocity.angle() - chunk.position.minus( self.sunPosition ).angle();

            if ( inClouds && !inList && Math.abs( deltaPhi ) < Math.PI / 10 ) {

              // Decide whether this energy chunk should pass
              // through the clouds or be reflected.
              if ( RAND.nextDouble() < cloud.existenceStrengthProperty.get() ) {

                // Reflect the energy chunk.  It looks a little weird if they go back to the sun, so the
                // code below tries to avoid that.
                var angleTowardsSun = chunk.velocity.angle() + Math.PI;
                var reflectionAngle = chunk.position.minus( cloud.getCenterPosition() ).angle();

                if ( reflectionAngle < angleTowardsSun ) {
                  chunk.setVelocity( chunk.velocity.rotated( 0.7 * Math.PI + RAND.nextDouble() * Math.PI / 8 ) );
                } else {
                  chunk.setVelocity( chunk.velocity.rotated( -0.7 * Math.PI - RAND.nextDouble() * Math.PI / 8 ) );
                }

              } else {
                // Let it pass through the cloud.
                self.energyChunksPassingThroughClouds.push( chunk );
              }
            }
          } );
        }
      } );

      this.energyChunkList.forEach( function( chunk ) {
        chunk.translateBasedOnVelocity( dt );
      } );
    },

    // @private
    emitEnergyChunk: function() {
      var emissionAngle = this.chooseNextEmissionAngle();
      var velocity = new Vector2( EFACConstants.ENERGY_CHUNK_VELOCITY, 0 ).rotated( emissionAngle );
      var startPoint = this.sunPosition.plus( new Vector2( RADIUS / 2, 0 ).rotated( emissionAngle ) );
      var chunk = new EnergyChunk( EnergyType.LIGHT, startPoint, velocity, this.energyChunksVisibleProperty );

      this.energyChunkList.add( chunk );
    },

    // @public
    // @override
    preLoadEnergyChunks: function() {
      this.clearEnergyChunks();
      var preLoadTime = 6; // In simulated seconds, empirically determined.
      var dt = 1 / EFACConstants.FRAMES_PER_SECOND;
      this.energyChunkEmissionCountdownTimer = 0;

      // Simulate energy chunks moving through the system.
      while ( preLoadTime > 0 ) {
        this.energyChunkEmissionCountdownTimer -= dt;
        if ( this.energyChunkEmissionCountdownTimer <= 0 ) {
          this.emitEnergyChunk();
          this.energyChunkEmissionCountdownTimer += ENERGY_CHUNK_EMISSION_PERIOD;
        }
        this.updateEnergyChunkPositions( dt );
        preLoadTime -= dt;
      }

      // Remove any chunks that actually made it to the solar panel.
      this.outgoingEnergyChunks.clear();
    },

    /**
     * Return a structure containing type, rate, and direction of emitted energy
     * @return {Energy}
     */
    getEnergyOutputRate: function() {
      return new Energy( EnergyType.LIGHT, EFACConstants.MAX_ENERGY_PRODUCTION_RATE * ( 1 - this.cloudiness ) );
    },

    /**
     * @return {number} emission angle
     * @private
     */
    chooseNextEmissionAngle: function() {
      var sector = this.sectorList[ this.currentSectorIndex ];
      this.currentSectorIndex++;

      if ( this.currentSectorIndex >= NUM_EMISSION_SECTORS ) {
        this.currentSectorIndex = 0;
      }

      // Angle is a function of the selected sector and a random offset
      // within the sector.
      return sector * EMISSION_SECTOR_SPAN + ( RAND.nextDouble() * EMISSION_SECTOR_SPAN ) + EMISSION_SECTOR_OFFSET;
    },

    /**
     * Pre-populate the space around the sun with energy chunks.
     * The number of iterations is chosen carefully such that there are chunks
     * that are close, but not quite reaching, the solar panel.
     * @public
     * @override
     */
    activate: function() {
      EnergySource.prototype.activate.call( this );

      for ( var i = 0; i < 100; i++ ) {
        this.step( EFACConstants.SIM_TIME_PER_TICK_NORMAL );
      }
    },

    /**
     * Deactivate the sun
     * @public
     * @override
     */
    deactivate: function() {
      EnergySource.prototype.deactivate.call( this );
      this.cloudinessProperty.reset();
    }

  }, {
    // @public
    OFFSET_TO_CENTER_OF_SUN: OFFSET_TO_CENTER_OF_SUN
  } );
} );

<commit_msg>Use positionProperty.value<commit_after>// Copyright 2016, University of Colorado Boulder

/**
 * Module representing the sun (as an energy source) in the model.  This
 * includes the clouds that can block the sun's rays.
 *
 * @author  John Blanco (original Java)
 * @author  Andrew Adare (js port)
 */
define( function( require ) {
  'use strict';

  // Modules
  var Cloud = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/Cloud' );
  var EFACConstants = require( 'ENERGY_FORMS_AND_CHANGES/common/EFACConstants' );
  var Energy = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/Energy' );
  var EnergyChunk = require( 'ENERGY_FORMS_AND_CHANGES/common/model/EnergyChunk' );
  var energyFormsAndChanges = require( 'ENERGY_FORMS_AND_CHANGES/energyFormsAndChanges' );
  var EnergySource = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/EnergySource' );
  var EnergyType = require( 'ENERGY_FORMS_AND_CHANGES/common/model/EnergyType' );
  var Image = require( 'SCENERY/nodes/Image' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Random = require( 'DOT/Random' );
  var Util = require( 'DOT/Util' );
  var Vector2 = require( 'DOT/Vector2' );

  // Constants
  var RADIUS = 0.02; // In meters, apparent size, not (obviously) actual size.
  var OFFSET_TO_CENTER_OF_SUN = new Vector2( -0.05, 0.12 );
  var ENERGY_CHUNK_EMISSION_PERIOD = 0.11; // In seconds.
  var RAND = new Random();
  var MAX_DISTANCE_OF_E_CHUNKS_FROM_SUN = 0.5; // In meters.

  // Constants that control the nature of the emission sectors.  These are
  // used to make emission look random yet still have a fairly steady rate
  // within each sector.  One sector is intended to point at the solar panel.
  var NUM_EMISSION_SECTORS = 10;
  var EMISSION_SECTOR_SPAN = 2 * Math.PI / NUM_EMISSION_SECTORS;

  // Used to tweak sector positions to make sure solar panel gets consistent flow of E's.
  var EMISSION_SECTOR_OFFSET = EMISSION_SECTOR_SPAN * 0.71;

  var SUN_ICON = require( 'image!ENERGY_FORMS_AND_CHANGES/sun_icon.png' );

  /**
   * @param {EnergyConverter} solarPanel
   * @param {Property.<boolean>} energyChunksVisibleProperty
   * @constructor
   */
  function SunEnergySource( solarPanel, energyChunksVisibleProperty ) {

    var self = this;

    EnergySource.call( this, new Image( SUN_ICON ) );

    this.energyChunksVisibleProperty = energyChunksVisibleProperty;

    this.solarPanel = solarPanel;

    this.energyChunkEmissionCountdownTimer = ENERGY_CHUNK_EMISSION_PERIOD;

    this.sectorList = _.shuffle( _.range( NUM_EMISSION_SECTORS ) );

    // List of energy chunks that should be allowed to pass through the clouds
    // without bouncing (i.e. being reflected).
    this.energyChunksPassingThroughClouds = [];

    this.currentSectorIndex = 0;

    this.sunPosition = OFFSET_TO_CENTER_OF_SUN;

    this.radius = RADIUS;

    // Clouds that can potentially block the sun's rays.  The positions are
    // set so that they appear between the sun and the solar panel, and must
    // not overlap with one another.
    this.clouds = [
      new Cloud( new Vector2( -0.01, 0.08 ), this.positionProperty ),
      new Cloud( new Vector2( 0.017, 0.0875 ), this.positionProperty ),
      new Cloud( new Vector2( 0.02, 0.105 ), this.positionProperty )
    ];

    this.addProperty( 'cloudiness', 0 );

    // Add/remove clouds based on the value of the cloudiness property.
    this.cloudinessProperty.link( function( cloudiness ) {
      var nClouds = self.clouds.length;
      for ( var i = 0; i < nClouds; i++ ) {
        // Stagger the existence strength of the clouds.
        var value = Util.clamp( cloudiness * ( nClouds - i ), 0, 1 );
        self.clouds[ i ].existenceStrengthProperty.set( value );
      }
    } );

    this.positionProperty.link( function( position ) {
      self.sunPosition = position.plus( OFFSET_TO_CENTER_OF_SUN );
    } );

  }

  energyFormsAndChanges.register( 'SunEnergySource', SunEnergySource );

  return inherit( EnergySource, SunEnergySource, {

    step: function( dt ) {
      var energyProduced = 0;
      if ( this.active === true ) {

        // See if it is time to emit a new energy chunk.
        this.energyChunkEmissionCountdownTimer -= dt;
        if ( this.energyChunkEmissionCountdownTimer <= 0 ) {
          // Create a new chunk and start it on its way.
          this.emitEnergyChunk();
          this.energyChunkEmissionCountdownTimer += ENERGY_CHUNK_EMISSION_PERIOD;
        }

        // Move the energy chunks.
        this.updateEnergyChunkPositions( dt );

        // Calculate the amount of energy produced.
        energyProduced = EFACConstants.MAX_ENERGY_PRODUCTION_RATE * ( 1 - this.cloudiness ) * dt;
      }

      // Produce the energy.
      return new Energy( EnergyType.LIGHT, energyProduced, 0 );
    },

    // @private
    updateEnergyChunkPositions: function( dt ) {

      var self = this;

      // Check for bouncing and absorption of the energy chunks.
      this.energyChunkList.forEach( function( chunk ) {

        var distanceFromSun = chunk.positionProperty.value.distance( self.sunPosition.plus( OFFSET_TO_CENTER_OF_SUN ) );

        // This energy chunk was absorbed by the solar panel, so
        // put it on the list of outgoing chunks.
        if ( self.solarPanel.active && self.solarPanel.getAbsorptionShape().bounds.containsPoint( chunk.positionProperty.value ) ) {
          self.outgoingEnergyChunks.push( chunk );
        }

        // This energy chunk is out of visible range, so remove it.
        else if ( distanceFromSun > MAX_DISTANCE_OF_E_CHUNKS_FROM_SUN ) {
          self.energyChunkList.remove( chunk );
          _.pull( self.energyChunksPassingThroughClouds, chunk );
        }

        // Chunks encountering clouds
        else {
          self.clouds.forEach( function( cloud ) {

            var inClouds = cloud.getCloudAbsorptionReflectionShape().bounds.containsPoint( chunk.positionProperty.value );
            var inList = _.contains( self.energyChunksPassingThroughClouds, chunk );
            var deltaPhi = chunk.velocity.angle() - chunk.positionProperty.value.minus( self.sunPosition ).angle();

            if ( inClouds && !inList && Math.abs( deltaPhi ) < Math.PI / 10 ) {

              // Decide whether this energy chunk should pass
              // through the clouds or be reflected.
              if ( RAND.nextDouble() < cloud.existenceStrengthProperty.get() ) {

                // Reflect the energy chunk.  It looks a little weird if they go back to the sun, so the
                // code below tries to avoid that.
                var angleTowardsSun = chunk.velocity.angle() + Math.PI;
                var reflectionAngle = chunk.positionProperty.value.minus( cloud.getCenterPosition() ).angle();

                if ( reflectionAngle < angleTowardsSun ) {
                  chunk.setVelocity( chunk.velocity.rotated( 0.7 * Math.PI + RAND.nextDouble() * Math.PI / 8 ) );
                } else {
                  chunk.setVelocity( chunk.velocity.rotated( -0.7 * Math.PI - RAND.nextDouble() * Math.PI / 8 ) );
                }

              } else {
                // Let it pass through the cloud.
                self.energyChunksPassingThroughClouds.push( chunk );
              }
            }
          } );
        }
      } );

      this.energyChunkList.forEach( function( chunk ) {
        chunk.translateBasedOnVelocity( dt );
      } );
    },

    // @private
    emitEnergyChunk: function() {
      var emissionAngle = this.chooseNextEmissionAngle();
      var velocity = new Vector2( EFACConstants.ENERGY_CHUNK_VELOCITY, 0 ).rotated( emissionAngle );
      var startPoint = this.sunPosition.plus( new Vector2( RADIUS / 2, 0 ).rotated( emissionAngle ) );
      var chunk = new EnergyChunk( EnergyType.LIGHT, startPoint, velocity, this.energyChunksVisibleProperty );

      this.energyChunkList.add( chunk );
    },

    // @public
    // @override
    preLoadEnergyChunks: function() {
      this.clearEnergyChunks();
      var preLoadTime = 6; // In simulated seconds, empirically determined.
      var dt = 1 / EFACConstants.FRAMES_PER_SECOND;
      this.energyChunkEmissionCountdownTimer = 0;

      // Simulate energy chunks moving through the system.
      while ( preLoadTime > 0 ) {
        this.energyChunkEmissionCountdownTimer -= dt;
        if ( this.energyChunkEmissionCountdownTimer <= 0 ) {
          this.emitEnergyChunk();
          this.energyChunkEmissionCountdownTimer += ENERGY_CHUNK_EMISSION_PERIOD;
        }
        this.updateEnergyChunkPositions( dt );
        preLoadTime -= dt;
      }

      // Remove any chunks that actually made it to the solar panel.
      this.outgoingEnergyChunks.clear();
    },

    /**
     * Return a structure containing type, rate, and direction of emitted energy
     * @return {Energy}
     */
    getEnergyOutputRate: function() {
      return new Energy( EnergyType.LIGHT, EFACConstants.MAX_ENERGY_PRODUCTION_RATE * ( 1 - this.cloudiness ) );
    },

    /**
     * @return {number} emission angle
     * @private
     */
    chooseNextEmissionAngle: function() {
      var sector = this.sectorList[ this.currentSectorIndex ];
      this.currentSectorIndex++;

      if ( this.currentSectorIndex >= NUM_EMISSION_SECTORS ) {
        this.currentSectorIndex = 0;
      }

      // Angle is a function of the selected sector and a random offset
      // within the sector.
      return sector * EMISSION_SECTOR_SPAN + ( RAND.nextDouble() * EMISSION_SECTOR_SPAN ) + EMISSION_SECTOR_OFFSET;
    },

    /**
     * Pre-populate the space around the sun with energy chunks.
     * The number of iterations is chosen carefully such that there are chunks
     * that are close, but not quite reaching, the solar panel.
     * @public
     * @override
     */
    activate: function() {
      EnergySource.prototype.activate.call( this );

      for ( var i = 0; i < 100; i++ ) {
        this.step( EFACConstants.SIM_TIME_PER_TICK_NORMAL );
      }
    },

    /**
     * Deactivate the sun
     * @public
     * @override
     */
    deactivate: function() {
      EnergySource.prototype.deactivate.call( this );
      this.cloudinessProperty.reset();
    }

  }, {
    // @public
    OFFSET_TO_CENTER_OF_SUN: OFFSET_TO_CENTER_OF_SUN
  } );
} );

<|endoftext|>


<commit_before>// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require bootstrap
//= require_tree .

if ($('html').hasClass('himmeli')) {
  $('span[rel=tooltip]').tooltip({
    placement: "top"
  });
}

if (_.isNull(Himmeli)) Himmeli = {};
var controller = $('html').attr('class').split(' ').pop();

if (controller == 'people' && $('.person-details').length) {
  $.get('/people/' + Himmeli.id + '.json').then(function(data) {
    Himmeli['scoresPerEvent'] = data.scoresPerEvent;
    Himmeli['medianReplyTimes'] = data.medianReplyTimes;
    Himmeli['levelHighscores'] = data.levelHighscores;
  });

  $('.scores-chart-pills a').on('click', function(e) {
    e.preventDefault();

    var $tgt = $(e.target);
    $tgt.parent('li').addClass('active').siblings().removeClass('active');
    Himmeli.scoresPerEventChart($tgt.data('level'));
    Himmeli.medianReplyTimesChart($tgt.data('level'));
  });

  setTimeout(function() {
    Himmeli.scoresPerEventChart();
    Himmeli.medianReplyTimesChart();
  }, 1000);
}

if (controller == 'game') {
  //
}

// Helper functions
Himmeli.scoresPerEventChart = function(level) {
  var lvl = level || 1,
    events = Himmeli.scoresPerEvent[lvl - 1],
    data = _.pluck(events, 'scores'),
    labels = [];

  _.each(events, function(e, index) {
    labels.push(e.aborted ? 'A' : index + 1);
  });

  var lineChartData = {
    labels: labels,
    datasets: [{
      fillColor: "rgba(151,187,205,0.5)",
      strokeColor: "rgba(151,187,205,1)",
      pointColor: "rgba(151,187,205,1)",
      pointStrokeColor: "#fff",
      data: data
    }]
  };

  var chartLine = new Chart(document.getElementById("scoresPerEventChart").getContext("2d")).Bar(lineChartData);
};

Himmeli.medianReplyTimesChart = function(level) {
  var lvl = level || 1,
    data = Himmeli.medianReplyTimes[lvl - 1],
    labels = [];

  _.each(data, function(e, index) {
    labels.push(index + 1);
  });

  var lineChartData = {
    labels: labels,
    datasets: [{
      fillColor: "rgba(151,187,205,0.5)",
      strokeColor: "rgba(151,187,205,1)",
      pointColor: "rgba(151,187,205,1)",
      pointStrokeColor: "#fff",
      data: data
    }]
  };

  var chartLine = new Chart(document.getElementById("medianReplyTimesChart").getContext("2d")).Line(lineChartData);
};

Himmeli.addEvent = function(gameEvent) {
  // token
  var token = $('input[name=authenticity_token]').val();

  // request object
  var json = {
    'utf8': '✓',
    'authenticity_token': token,
    'event': gameEvent
  };

  // request
  return $.ajax({
    dataType: 'json',
    method: 'post',
    url: '/events',
    data: json
  });
};

Himmeli.updatePersonLevel = function(level) {
  // token
  var token = $('input[name=authenticity_token]').val();

  // request object
  var json = {
    'utf8': '✓',
    'authenticity_token': token,
    'person': {
      'level': level
    }
  };

  // request
  return $.ajax({
    dataType: 'json',
    method: 'put',
    url: '/people/' + Himmeli.id,
    data: json
  });
};

Himmeli.getVersions = function() {
  return $.getJSON('/versions.json');
};

Himmeli.statsView = function() {
  var $body = $('body');

  var stats = '

' +
    'Palaa peliin' +
    '
' + Himmeli.first_name + ' ' + Himmeli.last_name + '
' +
    // '
Nimi: ' + Himmeli.first_name + ' ' + Himmeli.last_name + '
' +
    '
' +
    '
' +
    '
Taso 1
' +
    '
Taso 2
' +
    '
Taso 3
' +
    '
Taso 4
' +
    '
Taso 5
' +
    '
Taso 6
' +
    '
' +
    // '
' +
    '
Pisteitä per pelikerta
' +
    '<canvas id="scoresPerEventChart" width="738" height="400"></canvas>' +
    '
Keskimääräinen vastausaika (mediaani)
' +
    '<canvas id="medianReplyTimesChart" width="738" height="400"></canvas>' +
    '

';

  $body.append(stats);

  $('.scores-chart-pills a').on('click', function(e) {
    e.preventDefault();

    var $tgt = $(e.target);
    $tgt.parent('li').addClass('active').siblings().removeClass('active');
    Himmeli.scoresPerEventChart($tgt.data('level'));
    Himmeli.medianReplyTimesChart($tgt.data('level'));
  });

  $('.close-btn').on('click', function(e) {
    e.preventDefault();

    $('.stats').fadeOut(700, function() {
      $('.close-btn').off('click');
      $('.scores-chart-pills a').off('click');
      $('.stats').remove();
      $('#cr-stage').show();
    });
  });

  // update stats
  $.get('/people/' + Himmeli.id + '.json').then(function(data) {
    Himmeli['scoresPerEvent'] = data.scoresPerEvent;
    Himmeli['medianReplyTimes'] = data.medianReplyTimes;

    $('.stats').fadeIn(700, function() {
      setTimeout(function() {
        Himmeli.scoresPerEventChart();
        Himmeli.medianReplyTimesChart();
      }, 1000);
    });
  });
};

$('body').on('click', '.help_button', function(e) {
  Himmeli.statsView();
  $('#cr-stage').hide();
});

/*
var gameEvent = {
  'person_id': 2,
  'version_id': 1,
  'duration': 1098,
  'level': 4,
  'scores': 3,
  'aborted': 1,
  'items_attributes': [{
    'duration': 23939,
    'answer': 1,
    'pointer': 1,
    'target': 1
  }, {
    'duration': 23939,
    'answer': 1,
    'pointer': 1,
    'target': 1
  },{
    'duration': 23939,
    'answer': 1,
    'pointer': 1,
    'target': 1
  }, {
    'duration': 23939,
    'answer': 1,
    'pointer': 1,
    'target': 1
  }]
};
console.log(Himmeli.addEvent(gameEvent));
*/<commit_msg>canvas size<commit_after>// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require bootstrap
//= require_tree .

if ($('html').hasClass('himmeli')) {
  $('span[rel=tooltip]').tooltip({
    placement: "top"
  });
}

if (_.isNull(Himmeli)) Himmeli = {};
var controller = $('html').attr('class').split(' ').pop();

if (controller == 'people' && $('.person-details').length) {
  $.get('/people/' + Himmeli.id + '.json').then(function(data) {
    Himmeli['scoresPerEvent'] = data.scoresPerEvent;
    Himmeli['medianReplyTimes'] = data.medianReplyTimes;
    Himmeli['levelHighscores'] = data.levelHighscores;
  });

  $('.scores-chart-pills a').on('click', function(e) {
    e.preventDefault();

    var $tgt = $(e.target);
    $tgt.parent('li').addClass('active').siblings().removeClass('active');
    Himmeli.scoresPerEventChart($tgt.data('level'));
    Himmeli.medianReplyTimesChart($tgt.data('level'));
  });

  setTimeout(function() {
    Himmeli.scoresPerEventChart();
    Himmeli.medianReplyTimesChart();
  }, 1000);
}

if (controller == 'game') {
  //
}

// Helper functions
Himmeli.scoresPerEventChart = function(level) {
  var lvl = level || 1,
    events = Himmeli.scoresPerEvent[lvl - 1],
    data = _.pluck(events, 'scores'),
    labels = [];

  _.each(events, function(e, index) {
    labels.push(e.aborted ? 'A' : index + 1);
  });

  var lineChartData = {
    labels: labels,
    datasets: [{
      fillColor: "rgba(151,187,205,0.5)",
      strokeColor: "rgba(151,187,205,1)",
      pointColor: "rgba(151,187,205,1)",
      pointStrokeColor: "#fff",
      data: data
    }]
  };

  var chartLine = new Chart(document.getElementById("scoresPerEventChart").getContext("2d")).Bar(lineChartData);
};

Himmeli.medianReplyTimesChart = function(level) {
  var lvl = level || 1,
    data = Himmeli.medianReplyTimes[lvl - 1],
    labels = [];

  _.each(data, function(e, index) {
    labels.push(index + 1);
  });

  var lineChartData = {
    labels: labels,
    datasets: [{
      fillColor: "rgba(151,187,205,0.5)",
      strokeColor: "rgba(151,187,205,1)",
      pointColor: "rgba(151,187,205,1)",
      pointStrokeColor: "#fff",
      data: data
    }]
  };

  var chartLine = new Chart(document.getElementById("medianReplyTimesChart").getContext("2d")).Line(lineChartData);
};

Himmeli.addEvent = function(gameEvent) {
  // token
  var token = $('input[name=authenticity_token]').val();

  // request object
  var json = {
    'utf8': '✓',
    'authenticity_token': token,
    'event': gameEvent
  };

  // request
  return $.ajax({
    dataType: 'json',
    method: 'post',
    url: '/events',
    data: json
  });
};

Himmeli.updatePersonLevel = function(level) {
  // token
  var token = $('input[name=authenticity_token]').val();

  // request object
  var json = {
    'utf8': '✓',
    'authenticity_token': token,
    'person': {
      'level': level
    }
  };

  // request
  return $.ajax({
    dataType: 'json',
    method: 'put',
    url: '/people/' + Himmeli.id,
    data: json
  });
};

Himmeli.getVersions = function() {
  return $.getJSON('/versions.json');
};

Himmeli.statsView = function() {
  var $body = $('body');

  var stats = '

' +
    'Palaa peliin' +
    '
' + Himmeli.first_name + ' ' + Himmeli.last_name + '
' +
    // '
Nimi: ' + Himmeli.first_name + ' ' + Himmeli.last_name + '
' +
    '
' +
    '
' +
    '
Taso 1
' +
    '
Taso 2
' +
    '
Taso 3
' +
    '
Taso 4
' +
    '
Taso 5
' +
    '
Taso 6
' +
    '
' +
    // '
' +
    '
Pisteitä per pelikerta
' +
    '<canvas id="scoresPerEventChart" width="738" height="370"></canvas>' +
    '
Keskimääräinen vastausaika (mediaani)
' +
    '<canvas id="medianReplyTimesChart" width="738" height="370"></canvas>' +
    '

';

  $body.append(stats);

  $('.scores-chart-pills a').on('click', function(e) {
    e.preventDefault();

    var $tgt = $(e.target);
    $tgt.parent('li').addClass('active').siblings().removeClass('active');
    Himmeli.scoresPerEventChart($tgt.data('level'));
    Himmeli.medianReplyTimesChart($tgt.data('level'));
  });

  $('.close-btn').on('click', function(e) {
    e.preventDefault();

    $('.stats').fadeOut(700, function() {
      $('.close-btn').off('click');
      $('.scores-chart-pills a').off('click');
      $('.stats').remove();
      $('#cr-stage').show();
    });
  });

  // update stats
  $.get('/people/' + Himmeli.id + '.json').then(function(data) {
    Himmeli['scoresPerEvent'] = data.scoresPerEvent;
    Himmeli['medianReplyTimes'] = data.medianReplyTimes;

    $('.stats').fadeIn(700, function() {
      setTimeout(function() {
        Himmeli.scoresPerEventChart();
        Himmeli.medianReplyTimesChart();
      }, 1000);
    });
  });
};

$('body').on('click', '.help_button', function(e) {
  Himmeli.statsView();
  $('#cr-stage').hide();
});

/*
var gameEvent = {
  'person_id': 2,
  'version_id': 1,
  'duration': 1098,
  'level': 4,
  'scores': 3,
  'aborted': 1,
  'items_attributes': [{
    'duration': 23939,
    'answer': 1,
    'pointer': 1,
    'target': 1
  }, {
    'duration': 23939,
    'answer': 1,
    'pointer': 1,
    'target': 1
  },{
    'duration': 23939,
    'answer': 1,
    'pointer': 1,
    'target': 1
  }, {
    'duration': 23939,
    'answer': 1,
    'pointer': 1,
    'target': 1
  }]
};
console.log(Himmeli.addEvent(gameEvent));
*/<|endoftext|>


<commit_before>import React from 'react';

import LinearProgress from 'material-ui/LinearProgress';
import {Card, CardActions, CardHeader, CardMedia, CardTitle, CardText} from 'material-ui/Card';
import CircleIcon from 'material-ui/svg-icons/av/fiber-manual-record';

import DiffPanel from './utils/DiffPanel';

import Git from 'nodegit';

var url = require("file!./static/branchIcon.svg");

const constStyles = {
  fontFamily: `apple-system,
          BlinkMacSystemFont,"Segoe UI",
          Roboto,Helvetica,Arial,sans-serif,
          "Apple Color Emoji","Segoe UI Emoji",
          "Segoe UI Symbol"`,
  darkRed: '#b60a0a',
  grey: '#ededed',
  borderGrey: '#7e7e7e',
  yellow: '#b97005',
};

class gitFunctions {

  static getCommits(repoPath, sha, that) {

    let pathToRepo = require('path').resolve(repoPath);
    Git.Repository.open(pathToRepo)
    .then(function(repo) {
      return repo.getCommit(sha);
    })
    .then(function( commit ) {
      let history = commit.history( Git.Revwalk.SORT.Time);
      history.on("end", walk);
      history.start();
    })
    .done();

    //   function passed to history.on() listener to receive commits' info.
    //   calls the setCommitState of App class to set new state
    let walk = (function(commitsArr){
      let commits = [];
        commitsArr.forEach( function(commit) {
          commits.push({
            sha: commit.sha(),
            author: commit.author().name(),
            email: commit.author().email(),
            date: commit.date().toString(),
            message: commit.message()
          });
        });
        //TODO: pass a promise object to the function and can the
        //history event listener from there
        that.returnRepo(commits);
    }).bind(that);

  }

  static getCommitDiff(sha, path) {

    return Git.Repository.open(require('path').resolve(path))
    .then(function(repo) {
      return repo.getCommit(sha);
    })
    .then(function(commit) {
      return commit.getDiff();
    });
  }
}

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

  handleOnClick = (commit) => {

    this.props.getCommitDiff(commit);

    // gitFunctions.getCommitDiff(commit.sha, this.props.repoPath);

  }

  render() {
    const styles={
      span: {
        fontWeight: 500,
      },
      commitDiv: {
        display: 'flex',
        overflow: 'hidden',
        textOverflow: 'ellipsis',
        whiteSpace: 'nowrap',
        fontFamily: '"Roboto", sans-serif',
        padding: 1,
        margin: 0,
        backgroundColor: '#fff6dc',
        borderBottom: '2px solid #ffffff',
        color: constStyles.yellow,
      },
      circleIcon: {
        minWidth: 13,
        maxWidth: 13,
        minHeight: 13,
        maxHeight: 13,
      },
      message: {
        fontFamily: constStyles.fontFamily,
        overflow: 'hidden',
        textOverflow: 'ellipsis',
        whiteSpace: 'nowrap',
        padding: 2,
        margin: 4,
        fontSize: 15,
      },
      sha: {
        fontSize: 12,
        fontFamily: 'monospace',
      },
      sideBar: {
        position: 'relative',
        display: 'flex',
        alignItems: 'center',
      },
      line: {
        position: 'absolute',
        left: '42%',
        width: 2,
        height: 90,
        backgroundColor: constStyles.yellow,
      }
    };
    const commit = this.props.commit;

    return (

 { this.handleOnClick(commit) }} >

          <CircleIcon style={styles.circleIcon} color={constStyles.yellow}/>

{commit.author}

          {commit.sha?{commit.sha.slice(0, 8)+'  '}:null}
          {commit.message}

    )
  }
}

class CommitInfo extends React.Component {

  constructor(props) {
    super(props);
  }

  render = () => {
    let commit = '';
    if(this.props.commit) {
      commit = this.props.commit;
    }

    const styles= {
      main: {
        backgroundColor: '#ffffff',
        fontFamily: constStyles.fontFamily,
        fontSize: 15,
        border: '2px solid'+ constStyles.yellow,
        borderBottom: '1px solid'+ constStyles.yellow,
        letterSpacing: -1,
      },
      margin: {
        margin: 10,
      },
      author: {
        margin: 7,
        fontSize: 32,
        fontWeight: 700,
        color: constStyles.yellow,
      },
      message: {
        color: constStyles.yellow,
        fontSize: 20,
      },
      dateSha: {
        color: constStyles.yellow,
        fontSize: 15,
      }
    };
    return (

{commit.author}

{commit.message}

            {commit.sha?
              {commit.sha.slice(0, 8)}
              :null}
            {' '+commit.date}

    );
  }
}

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

  render = () => {

    const styles={
      main:{
        display: 'flex',
        flexDirection: 'column',
        justifyContent: 'center',
        alignItems: 'center',
        width: '65%',
        border: '2px solid'+ constStyles.yellow,
        color: constStyles.yellow,
        fontFamily: constStyles.fontFamily,
        fontSize: 40,
        fontWeight: 800,
        letterSpacing: -2,
      },
      progressBar: {
        marginTop: 15,
        width: 200
      }
    };

    return (

        Loading. Hang Tight!
        <LinearProgress
        color={constStyles.yellow}
        style={styles.progressBar}
        mode="indeterminate" />

    );
  }
}

class CommitTree extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      commits: [],
      diffs: [],
      selected_commit: null,
    };
    this.getCommitDiff = this.getCommitDiff.bind(this);
  }

  getCommitDiff = (commit) => {

    //for CommitInfo component
    this.setState({
      selected_commit: commit
    });

    gitFunctions.getCommitDiff(commit.sha, this.props.repo.path)
    .done((diffList) => {
        this.setState({
          diffs: diffList,
        });
    });
  }

  returnRepo = (commits) => {
    this.setState({
      commits : commits
    });
    // to load the first commit's diff info by default
    this.getCommitDiff(commits[0]);
  }

  componentDidMount = () => {
    if(this.props.repo && this.props.branchRef.sha)
    {
      gitFunctions.getCommits(this.props.repo.path, this.props.branchRef.sha, this);
    }
  }

  componentWillReceiveProps = (newprops) => {
    if(newprops.repo && newprops.branchRef.sha)
    {
      this.setState({
        selected_commit: null
      });
      gitFunctions.getCommits(newprops.repo.path, newprops.branchRef.sha, this);
    }
  }
  render() {

    const styles={
      commits: {
        border: '2px solid'+ constStyles.yellow,
        borderTop: '0px',
        borderRadius: '0px 0px 4px 4px',
        overflow: 'auto',
        height: 350,
      },
      branchName: {
        color: constStyles.yellow,
        display: 'flex',
        fontFamily: constStyles.fontFamily,
        fontWeight: 500,
        fontSize: 20,
        backgroundColor: '#fff6dc',
        border: '2px solid'+ constStyles.yellow,
        borderBottom: '1px solid'+ constStyles.yellow,
        zIndex: 10,
        margin: 0,
        padding: 20,
      },
      diffProps: {
        type: {
          color: constStyles.yellow,
        },
        file: {
          color: constStyles.yellow,
        },
        border: {
          color: constStyles.yellow,
        }
      }
    };

    let rows=[];
    this.state.commits.forEach((commit, index) => {
      rows.push(<Commit getCommitDiff={this.getCommitDiff} commit={commit} key={index} />);
    });
    return (

{' '+this.props.branchRef.name}

            { rows }

        {this.state.selected_commit?

            <CommitInfo commit={this.state.selected_commit} />

              <DiffPanel diffs={this.state.diffs} diffStyle={styles.diffProps} />

:
          <LoadingCommitInfo />}

    )
  }
}

export default CommitTree;<commit_msg>View: Changed bgColor of commitInfo component<commit_after>import React from 'react';

import LinearProgress from 'material-ui/LinearProgress';
import {Card, CardActions, CardHeader, CardMedia, CardTitle, CardText} from 'material-ui/Card';
import CircleIcon from 'material-ui/svg-icons/av/fiber-manual-record';

import DiffPanel from './utils/DiffPanel';

import Git from 'nodegit';

var url = require("file!./static/branchIcon.svg");

const constStyles = {
  fontFamily: `apple-system,
          BlinkMacSystemFont,"Segoe UI",
          Roboto,Helvetica,Arial,sans-serif,
          "Apple Color Emoji","Segoe UI Emoji",
          "Segoe UI Symbol"`,
  darkRed: '#b60a0a',
  grey: '#ededed',
  borderGrey: '#7e7e7e',
  yellow: '#b97005',
};

class gitFunctions {

  static getCommits(repoPath, sha, that) {

    let pathToRepo = require('path').resolve(repoPath);
    Git.Repository.open(pathToRepo)
    .then(function(repo) {
      return repo.getCommit(sha);
    })
    .then(function( commit ) {
      let history = commit.history( Git.Revwalk.SORT.Time);
      history.on("end", walk);
      history.start();
    })
    .done();

    //   function passed to history.on() listener to receive commits' info.
    //   calls the setCommitState of App class to set new state
    let walk = (function(commitsArr){
      let commits = [];
        commitsArr.forEach( function(commit) {
          commits.push({
            sha: commit.sha(),
            author: commit.author().name(),
            email: commit.author().email(),
            date: commit.date().toString(),
            message: commit.message()
          });
        });
        //TODO: pass a promise object to the function and can the
        //history event listener from there
        that.returnRepo(commits);
    }).bind(that);

  }

  static getCommitDiff(sha, path) {

    return Git.Repository.open(require('path').resolve(path))
    .then(function(repo) {
      return repo.getCommit(sha);
    })
    .then(function(commit) {
      return commit.getDiff();
    });
  }
}

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

  handleOnClick = (commit) => {

    this.props.getCommitDiff(commit);

    // gitFunctions.getCommitDiff(commit.sha, this.props.repoPath);

  }

  render() {
    const styles={
      span: {
        fontWeight: 500,
      },
      commitDiv: {
        display: 'flex',
        overflow: 'hidden',
        textOverflow: 'ellipsis',
        whiteSpace: 'nowrap',
        fontFamily: '"Roboto", sans-serif',
        padding: 1,
        margin: 0,
        backgroundColor: '#fff6dc',
        borderBottom: '2px solid #ffffff',
        color: constStyles.yellow,
      },
      circleIcon: {
        minWidth: 13,
        maxWidth: 13,
        minHeight: 13,
        maxHeight: 13,
      },
      message: {
        fontFamily: constStyles.fontFamily,
        overflow: 'hidden',
        textOverflow: 'ellipsis',
        whiteSpace: 'nowrap',
        padding: 2,
        margin: 4,
        fontSize: 15,
      },
      sha: {
        fontSize: 12,
        fontFamily: 'monospace',
      },
      sideBar: {
        position: 'relative',
        display: 'flex',
        alignItems: 'center',
      },
      line: {
        position: 'absolute',
        left: '42%',
        width: 2,
        height: 90,
        backgroundColor: constStyles.yellow,
      }
    };
    const commit = this.props.commit;

    return (

 { this.handleOnClick(commit) }} >

          <CircleIcon style={styles.circleIcon} color={constStyles.yellow}/>

{commit.author}

          {commit.sha?{commit.sha.slice(0, 8)+'  '}:null}
          {commit.message}

    )
  }
}

class CommitInfo extends React.Component {

  constructor(props) {
    super(props);
  }

  render = () => {
    let commit = '';
    if(this.props.commit) {
      commit = this.props.commit;
    }

    const styles= {
      main: {
        backgroundColor: '#fffdf8',
        fontFamily: constStyles.fontFamily,
        fontSize: 15,
        border: '2px solid'+ constStyles.yellow,
        borderBottom: '1px solid'+ constStyles.yellow,
        letterSpacing: -1,
      },
      margin: {
        margin: 10,
      },
      author: {
        margin: 7,
        fontSize: 32,
        fontWeight: 700,
        color: constStyles.yellow,
      },
      message: {
        color: constStyles.yellow,
        fontSize: 20,
      },
      dateSha: {
        color: constStyles.yellow,
        fontSize: 15,
      }
    };
    return (

{commit.author}

{commit.message}

            {commit.sha?
              {commit.sha.slice(0, 8)}
              :null}
            {' '+commit.date}

    );
  }
}

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

  render = () => {

    const styles={
      main:{
        display: 'flex',
        flexDirection: 'column',
        justifyContent: 'center',
        alignItems: 'center',
        width: '65%',
        border: '2px solid'+ constStyles.yellow,
        color: constStyles.yellow,
        fontFamily: constStyles.fontFamily,
        fontSize: 40,
        fontWeight: 800,
        letterSpacing: -2,
      },
      progressBar: {
        marginTop: 15,
        width: 200
      }
    };

    return (

        Loading. Hang Tight!
        <LinearProgress
        color={constStyles.yellow}
        style={styles.progressBar}
        mode="indeterminate" />

    );
  }
}

class CommitTree extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      commits: [],
      diffs: [],
      selected_commit: null,
    };
    this.getCommitDiff = this.getCommitDiff.bind(this);
  }

  getCommitDiff = (commit) => {

    //for CommitInfo component
    this.setState({
      selected_commit: commit
    });

    gitFunctions.getCommitDiff(commit.sha, this.props.repo.path)
    .done((diffList) => {
        this.setState({
          diffs: diffList,
        });
    });
  }

  returnRepo = (commits) => {
    this.setState({
      commits : commits
    });
    // to load the first commit's diff info by default
    this.getCommitDiff(commits[0]);
  }

  componentDidMount = () => {
    if(this.props.repo && this.props.branchRef.sha)
    {
      gitFunctions.getCommits(this.props.repo.path, this.props.branchRef.sha, this);
    }
  }

  componentWillReceiveProps = (newprops) => {
    if(newprops.repo && newprops.branchRef.sha)
    {
      this.setState({
        selected_commit: null
      });
      gitFunctions.getCommits(newprops.repo.path, newprops.branchRef.sha, this);
    }
  }
  render() {

    const styles={
      commits: {
        border: '2px solid'+ constStyles.yellow,
        borderTop: '0px',
        borderRadius: '0px 0px 4px 4px',
        overflow: 'auto',
        height: 350,
      },
      branchName: {
        color: constStyles.yellow,
        display: 'flex',
        fontFamily: constStyles.fontFamily,
        fontWeight: 500,
        fontSize: 20,
        backgroundColor: '#fff6dc',
        border: '2px solid'+ constStyles.yellow,
        borderBottom: '1px solid'+ constStyles.yellow,
        zIndex: 10,
        margin: 0,
        padding: 20,
      },
      diffProps: {
        type: {
          color: constStyles.yellow,
        },
        file: {
          color: constStyles.yellow,
        },
        border: {
          color: constStyles.yellow,
        }
      }
    };

    let rows=[];
    this.state.commits.forEach((commit, index) => {
      rows.push(<Commit getCommitDiff={this.getCommitDiff} commit={commit} key={index} />);
    });
    return (

{' '+this.props.branchRef.name}

            { rows }

        {this.state.selected_commit?

            <CommitInfo commit={this.state.selected_commit} />

              <DiffPanel diffs={this.state.diffs} diffStyle={styles.diffProps} />

:
          <LoadingCommitInfo />}

    )
  }
}

export default CommitTree;<|endoftext|>


<commit_before>'use strict';

angular
  .module('fireideaz')

  .controller('MainCtrl', ['$scope', '$filter', '$window', 'Utils', 'Auth',
  '$rootScope', 'FirebaseService', 'ModalService', 'VoteService',
    function ($scope, $filter, $window, utils, auth, $rootScope, firebaseService, modalService, voteService) {
      $scope.loading = true;
      $scope.messageTypes = utils.messageTypes;
      $scope.utils = utils;
      $scope.newBoard = {
        name: ''
      };
      $scope.userId = $window.location.hash.substring(1) || '';
      $scope.sortField = 'date_created';
      $scope.selectedType = 1;
      $scope.import = {
        data : [],
        mapping : []
      };

      $scope.closeAllModals = function(){
        modalService.closeAll();
      };

      $scope.getNumberOfVotesOnMessage = function(userId, messageId) {
        return new Array(voteService.returnNumberOfVotesOnMessage(userId, messageId));
      };

      $scope.droppedEvent = function(dragEl, dropEl) {
        var drag = $('#' + dragEl);
        var drop = $('#' + dropEl);
        var dragMessageRef = firebaseService.getMessageRef($scope.userId, drag.attr('messageId'));

        dragMessageRef.once('value', function() {
          dragMessageRef.update({
            type: {
              id: drop.data('column-id')
            }
          });
        });
      };

      function getBoardAndMessages(userData) {
        $scope.userId = $window.location.hash.substring(1) || '499sm';

        var messagesRef = firebaseService.getMessagesRef($scope.userId);
        var board = firebaseService.getBoardRef($scope.userId);

        board.on('value', function(board) {
          if (board.val() === null) {
            window.location.hash = '';
            location.reload();
          }

          $scope.board = board.val();
          $scope.maxVotes = board.val().max_votes ? board.val().max_votes : 6;
          $scope.boardId = $rootScope.boardId = board.val().boardId;
          $scope.boardContext = $rootScope.boardContext = board.val().boardContext;
          $scope.loading = false;
        });

        $scope.boardRef = board;
        $scope.messagesRef = messagesRef;
        $scope.userUid = userData.uid;
        $scope.messages = firebaseService.newFirebaseArray(messagesRef);
      }

      if ($scope.userId !== '') {
        auth.logUser($scope.userId, getBoardAndMessages);
      } else {
        $scope.loading = false;
      }

      $scope.isColumnSelected = function(type) {
        return parseInt($scope.selectedType) === parseInt(type);
      };

      $scope.getSortFields = function() {
        return $scope.sortField === 'votes' ? ['-votes', 'date_created'] : 'date_created';
      };

      $scope.saveMessage = function(message) {
        message.creating = false;
        $scope.messages.$save(message);
      };

      $scope.vote = function(messageKey, votes) {
        if(voteService.isAbleToVote($scope.userId, $scope.maxVotes, $scope.messages)) {
          $scope.messagesRef.child(messageKey).update({
            votes: votes + 1,
            date: firebaseService.getServerTimestamp()
          });

          voteService.increaseMessageVotes($scope.userId, messageKey);
        }
      };

      $scope.unvote = function(messageKey, votes) {
        if(voteService.canUnvoteMessage($scope.userId, messageKey)) {
          var newVotes = (votes >= 1) ? votes - 1 : 0;

          $scope.messagesRef.child(messageKey).update({
            votes: newVotes,
            date: firebaseService.getServerTimestamp()
          });

          voteService.decreaseMessageVotes($scope.userId, messageKey);
        }
      };

      function redirectToBoard() {
        window.location.href = window.location.origin +
          window.location.pathname + '#' + $scope.userId;
      }

      $scope.isBoardNameInvalid = function() {
        return !$scope.newBoard.name;
      };

      $scope.isMaxVotesValid = function() {
        return Number.isInteger($scope.newBoard.max_votes);
      };

      $scope.createNewBoard = function() {
        $scope.loading = true;
        modalService.closeAll();
        $scope.userId = utils.createUserId();

        var callback = function(userData) {
          var board = firebaseService.getBoardRef($scope.userId);
          board.set({
            boardId: $scope.newBoard.name,
            date_created: new Date().toString(),
            columns: $scope.messageTypes,
            user_id: userData.uid,
            max_votes: $scope.newBoard.max_votes || 6
          }, function(error) {
             if (error) {
                $scope.loading = false;
             } else {
                redirectToBoard();
             }
          });

          $scope.newBoard.name = '';
        };

        auth.createUserAndLog($scope.userId, callback);
      };

      $scope.changeBoardContext = function() {
        $scope.boardRef.update({
          boardContext: $scope.boardContext
        });
      };

      $scope.changeBoardName = function(newBoardName) {
        $scope.boardRef.update({
          boardId: newBoardName
        });
        modalService.closeAll();
      };

      $scope.addNewColumn = function(name) {
        if(typeof name === 'undefined' || name === '') {
          return;
        }

        $scope.board.columns.push({
          value: name,
          id: utils.getNextId($scope.board)
        });

        var boardColumns = firebaseService.getBoardColumns($scope.userId);
        boardColumns.set(utils.toObject($scope.board.columns));

        modalService.closeAll();
      };

      $scope.changeColumnName = function(id, newName) {
        if(typeof newName === 'undefined' || newName === '') {
          return;
        }

        $scope.board.columns.map(function(column, index, array) {
          if (column.id === id) {
            array[index].value = newName;
          }
        });

        var boardColumns = firebaseService.getBoardColumns($scope.userId);
        boardColumns.set(utils.toObject($scope.board.columns));

        modalService.closeAll();
      };

      $scope.deleteColumn = function(column) {
        $scope.board.columns = $scope.board.columns.filter(function(_column) {
            return _column.id !== column.id;
        });

        var boardColumns = firebaseService.getBoardColumns($scope.userId);
        boardColumns.set(utils.toObject($scope.board.columns));
        modalService.closeAll();
      };

      $scope.deleteMessage = function(message) {
        $scope.messages.$remove(message);
        modalService.closeAll();
      };

      function addMessageCallback(message) {
        var id = message.key;
        angular.element($('#' + id)).scope().isEditing = true;
        $('#' + id).find('textarea').focus();
      }

      $scope.addNewMessage = function(type) {
        $scope.messages.$add({
          text: '',
          creating: true,
          user_id: $scope.userUid,
          type: {
            id: type.id
          },
          date: firebaseService.getServerTimestamp(),
          date_created: firebaseService.getServerTimestamp(),
          votes: 0
        }).then(addMessageCallback);
      };

      $scope.deleteCards = function() {
        $($scope.messages).each(function(index, message) {
          $scope.messages.$remove(message);
        });

        modalService.closeAll();
      };

      $scope.deleteBoard = function() {
        $scope.deleteCards();
        $scope.boardRef.ref.remove();

        modalService.closeAll();
        window.location.hash = '';
        location.reload();
      };

      $scope.getBoardText = function() {
        if ($scope.board) {
          var clipboard = '';

          $($scope.board.columns).each(function(index, column) {
            if (index === 0) {
              clipboard += '' + column.value + '
';
            } else {
              clipboard += '
' + column.value + '
';
            }
            var filteredArray = $filter('orderBy')($scope.messages,
              $scope.getSortFields());

            $(filteredArray).each(function(index2, message) {
              if (message.type.id === column.id) {
                clipboard += '- ' + message.text + ' (' + message.votes + ' votes)
';
              }
            });
          });

          return clipboard;
        } else return '';
      };

      $scope.submitImportFile = function (file) {
        $scope.cleanImportData ();
        if (file) {
          if (file.size === 0){
            $scope.import.error = 'The file you are trying to import seems to be  empty';
            return;
          }
          /* globals Papa */
          Papa.parse(file, {
            complete: function(results) {
              if (results.data.length > 0){
                $scope.import.data = results.data;
                $scope.board.columns.forEach (function (column){
                  $scope.import.mapping.push({mapFrom:'-1', mapTo:column.id, name: column.value});
                });
                if (results.errors.length > 0)
                   $scope.import.error = results.errors[0].message;
                $scope.$apply();
              }
            }
          });
        }
      };

       $scope.importMessages = function (){
         var data = $scope.import.data;
         var mapping = $scope.import.mapping;
         for (var importIndex = 1; importIndex < data.length; importIndex++ )
         {
           for (var mappingIndex = 0; mappingIndex < mapping.length; mappingIndex++)
           {
             var mapFrom = mapping[mappingIndex].mapFrom;
             var mapTo = mapping[mappingIndex].mapTo;
             if (mapFrom === -1)
              continue;

             var cardText = data[importIndex][mapFrom];
             if (cardText)
             {
                $scope.messages.$add({
                text: cardText,
                user_id: $scope.userUid,
                type: {
                  id: mapTo
                },
                date: firebaseService.getServerTimestamp(),
                votes: 0});
             }
           }
         }
         $scope.closeAllModals();
       };

      $scope.cleanImportData = function (){
        $scope.import.data = [];
        $scope.import.mapping = [];
        $scope.import.error = '';
      };

      $scope.submitOnEnter = function(event, method, data){
        if (event.keyCode === 13) {
          switch (method){
            case 'createNewBoard':
                if (!$scope.isBoardNameInvalid()) {
                  $scope.createNewBoard();
                }
                break;
            case 'addNewColumn':
                if (data) {
                  $scope.addNewColumn(data);
                  $scope.newColumn = '';
                }
                break;
          }
        }
      };

      $scope.incrementMaxVotes = function() {
        $scope.boardRef.update({
          max_votes: $scope.maxVotes + 1
        });
      };

      $scope.decrementMaxVotes = function() {
        $scope.boardRef.update({
          max_votes: Math.min(Math.max($scope.maxVotes - 1, 1), 100)
        });
      };

      angular.element($window).bind('hashchange', function() {
        $scope.loading = true;
        $scope.userId = $window.location.hash.substring(1) || '';
        auth.logUser($scope.userId, getBoardAndMessages);
      });
    }
  ]);
<commit_msg>Fix spaces<commit_after>'use strict';

angular
  .module('fireideaz')

  .controller('MainCtrl', ['$scope', '$filter', '$window', 'Utils', 'Auth',
  '$rootScope', 'FirebaseService', 'ModalService', 'VoteService',
    function ($scope, $filter, $window, utils, auth, $rootScope, firebaseService, modalService, voteService) {
      $scope.loading = true;
      $scope.messageTypes = utils.messageTypes;
      $scope.utils = utils;
      $scope.newBoard = {
        name: ''
      };
      $scope.userId = $window.location.hash.substring(1) || '';
      $scope.sortField = 'date_created';
      $scope.selectedType = 1;
      $scope.import = {
        data : [],
        mapping : []
      };

      $scope.closeAllModals = function(){
        modalService.closeAll();
      };

      $scope.getNumberOfVotesOnMessage = function(userId, messageId) {
        return new Array(voteService.returnNumberOfVotesOnMessage(userId, messageId));
      };

      $scope.droppedEvent = function(dragEl, dropEl) {
        var drag = $('#' + dragEl);
        var drop = $('#' + dropEl);
        var dragMessageRef = firebaseService.getMessageRef($scope.userId, drag.attr('messageId'));

        dragMessageRef.once('value', function() {
          dragMessageRef.update({
            type: {
              id: drop.data('column-id')
            }
          });
        });
      };

      function getBoardAndMessages(userData) {
        $scope.userId = $window.location.hash.substring(1) || '499sm';

        var messagesRef = firebaseService.getMessagesRef($scope.userId);
        var board = firebaseService.getBoardRef($scope.userId);

        board.on('value', function(board) {
          if (board.val() === null) {
            window.location.hash = '';
            location.reload();
          }

          $scope.board = board.val();
          $scope.maxVotes = board.val().max_votes ? board.val().max_votes : 6;
          $scope.boardId = $rootScope.boardId = board.val().boardId;
          $scope.boardContext = $rootScope.boardContext = board.val().boardContext;
          $scope.loading = false;
        });

        $scope.boardRef = board;
        $scope.messagesRef = messagesRef;
        $scope.userUid = userData.uid;
        $scope.messages = firebaseService.newFirebaseArray(messagesRef);
      }

      if ($scope.userId !== '') {
        auth.logUser($scope.userId, getBoardAndMessages);
      } else {
        $scope.loading = false;
      }

      $scope.isColumnSelected = function(type) {
        return parseInt($scope.selectedType) === parseInt(type);
      };

      $scope.getSortFields = function() {
        return $scope.sortField === 'votes' ? ['-votes', 'date_created'] : 'date_created';
      };

      $scope.saveMessage = function(message) {
        message.creating = false;
        $scope.messages.$save(message);
      };

      $scope.vote = function(messageKey, votes) {
        if(voteService.isAbleToVote($scope.userId, $scope.maxVotes, $scope.messages)) {
          $scope.messagesRef.child(messageKey).update({
            votes: votes + 1,
            date: firebaseService.getServerTimestamp()
          });

          voteService.increaseMessageVotes($scope.userId, messageKey);
        }
      };

      $scope.unvote = function(messageKey, votes) {
        if(voteService.canUnvoteMessage($scope.userId, messageKey)) {
          var newVotes = (votes >= 1) ? votes - 1 : 0;

          $scope.messagesRef.child(messageKey).update({
            votes: newVotes,
            date: firebaseService.getServerTimestamp()
          });

          voteService.decreaseMessageVotes($scope.userId, messageKey);
        }
      };

      function redirectToBoard() {
        window.location.href = window.location.origin +
          window.location.pathname + '#' + $scope.userId;
      }

      $scope.isBoardNameInvalid = function() {
        return !$scope.newBoard.name;
      };

      $scope.isMaxVotesValid = function() {
        return Number.isInteger($scope.newBoard.max_votes);
      };

      $scope.createNewBoard = function() {
        $scope.loading = true;
        modalService.closeAll();
        $scope.userId = utils.createUserId();

        var callback = function(userData) {
          var board = firebaseService.getBoardRef($scope.userId);
          board.set({
            boardId: $scope.newBoard.name,
            date_created: new Date().toString(),
            columns: $scope.messageTypes,
            user_id: userData.uid,
            max_votes: $scope.newBoard.max_votes || 6
          }, function(error) {
             if (error) {
                $scope.loading = false;
             } else {
                redirectToBoard();
             }
          });

          $scope.newBoard.name = '';
        };

        auth.createUserAndLog($scope.userId, callback);
      };

      $scope.changeBoardContext = function() {
        $scope.boardRef.update({
          boardContext: $scope.boardContext
        });
      };

      $scope.changeBoardName = function(newBoardName) {
        $scope.boardRef.update({
          boardId: newBoardName
        });

        modalService.closeAll();
      };

      $scope.addNewColumn = function(name) {
        if(typeof name === 'undefined' || name === '') {
          return;
        }

        $scope.board.columns.push({
          value: name,
          id: utils.getNextId($scope.board)
        });

        var boardColumns = firebaseService.getBoardColumns($scope.userId);
        boardColumns.set(utils.toObject($scope.board.columns));

        modalService.closeAll();
      };

      $scope.changeColumnName = function(id, newName) {
        if(typeof newName === 'undefined' || newName === '') {
          return;
        }

        $scope.board.columns.map(function(column, index, array) {
          if (column.id === id) {
            array[index].value = newName;
          }
        });

        var boardColumns = firebaseService.getBoardColumns($scope.userId);
        boardColumns.set(utils.toObject($scope.board.columns));

        modalService.closeAll();
      };

      $scope.deleteColumn = function(column) {
        $scope.board.columns = $scope.board.columns.filter(function(_column) {
            return _column.id !== column.id;
        });

        var boardColumns = firebaseService.getBoardColumns($scope.userId);
        boardColumns.set(utils.toObject($scope.board.columns));
        modalService.closeAll();
      };

      $scope.deleteMessage = function(message) {
        $scope.messages.$remove(message);

        modalService.closeAll();
      };

      function addMessageCallback(message) {
        var id = message.key;
        angular.element($('#' + id)).scope().isEditing = true;
        $('#' + id).find('textarea').focus();
      }

      $scope.addNewMessage = function(type) {
        $scope.messages.$add({
          text: '',
          creating: true,
          user_id: $scope.userUid,
          type: {
            id: type.id
          },
          date: firebaseService.getServerTimestamp(),
          date_created: firebaseService.getServerTimestamp(),
          votes: 0
        }).then(addMessageCallback);
      };

      $scope.deleteCards = function() {
        $($scope.messages).each(function(index, message) {
          $scope.messages.$remove(message);
        });

        modalService.closeAll();
      };

      $scope.deleteBoard = function() {
        $scope.deleteCards();
        $scope.boardRef.ref.remove();

        modalService.closeAll();
        window.location.hash = '';
        location.reload();
      };

      $scope.getBoardText = function() {
        if ($scope.board) {
          var clipboard = '';

          $($scope.board.columns).each(function(index, column) {
            if (index === 0) {
              clipboard += '' + column.value + '
';
            } else {
              clipboard += '
' + column.value + '
';
            }
            var filteredArray = $filter('orderBy')($scope.messages,
              $scope.getSortFields());

            $(filteredArray).each(function(index2, message) {
              if (message.type.id === column.id) {
                clipboard += '- ' + message.text + ' (' + message.votes + ' votes)
';
              }
            });
          });

          return clipboard;
        } else return '';
      };

      $scope.submitImportFile = function (file) {
        $scope.cleanImportData ();
        if (file) {
          if (file.size === 0){
            $scope.import.error = 'The file you are trying to import seems to be  empty';
            return;
          }
          /* globals Papa */
          Papa.parse(file, {
            complete: function(results) {
              if (results.data.length > 0){
                $scope.import.data = results.data;
                $scope.board.columns.forEach (function (column){
                  $scope.import.mapping.push({mapFrom:'-1', mapTo:column.id, name: column.value});
                });
                if (results.errors.length > 0)
                   $scope.import.error = results.errors[0].message;
                $scope.$apply();
              }
            }
          });
        }
      };

       $scope.importMessages = function (){
         var data = $scope.import.data;
         var mapping = $scope.import.mapping;
         for (var importIndex = 1; importIndex < data.length; importIndex++ )
         {
           for (var mappingIndex = 0; mappingIndex < mapping.length; mappingIndex++)
           {
             var mapFrom = mapping[mappingIndex].mapFrom;
             var mapTo = mapping[mappingIndex].mapTo;
             if (mapFrom === -1)
              continue;

             var cardText = data[importIndex][mapFrom];
             if (cardText)
             {
                $scope.messages.$add({
                text: cardText,
                user_id: $scope.userUid,
                type: {
                  id: mapTo
                },
                date: firebaseService.getServerTimestamp(),
                votes: 0});
             }
           }
         }
         $scope.closeAllModals();
       };

      $scope.cleanImportData = function (){
        $scope.import.data = [];
        $scope.import.mapping = [];
        $scope.import.error = '';
      };

      $scope.submitOnEnter = function(event, method, data) {
        if (event.keyCode === 13) {
          switch (method) {
            case 'createNewBoard':
              if (!$scope.isBoardNameInvalid()) {
                $scope.createNewBoard();
              }
              break;
            case 'addNewColumn':
              if (data) {
                $scope.addNewColumn(data);
                $scope.newColumn = '';
              }
              break;
          }
        }
      };

      $scope.incrementMaxVotes = function() {
        $scope.boardRef.update({
          max_votes: $scope.maxVotes + 1
        });
      };

      $scope.decrementMaxVotes = function() {
        $scope.boardRef.update({
          max_votes: Math.min(Math.max($scope.maxVotes - 1, 1), 100)
        });
      };

      angular.element($window).bind('hashchange', function() {
        $scope.loading = true;
        $scope.userId = $window.location.hash.substring(1) || '';
        auth.logUser($scope.userId, getBoardAndMessages);
      });
    }
  ]);
<|endoftext|>


<commit_before>import uniq from 'lodash/uniq';
import { decode } from 'gw2e-chat-codes'
import { markdownTable } from '../utils';

export function chatlinks(room, message) {
    const rows = [];

    uniq(message.text.match(/\[&[a-zA-Z0-9+\/]+=*\]/ig)).forEach(link => {
        const data = decode(link);

        switch(data.type) {
            case 'item':
            case 'map':
            case 'skill':
            case 'trait':
            case 'recipe':
            case 'skin':
            case 'outfit':
                link = `[${link}](https://api.guildwars2.com/v2/${data.type}s/${data.id})`;
                break;
        }

        rows.push([link, JSON.stringify(data)]);
    });

    if(rows.length > 0) {
        room.send(markdownTable(['Chatlink', 'Data'], rows));
    }
}<commit_msg>better chatlinks 🎉<commit_after>import uniq from 'lodash/uniq';
import groupBy from 'lodash/groupBy';
import map from 'lodash/map';
import keyBy from 'lodash/keyBy';
import { gw2 } from '../gw2'
import { decode } from 'gw2e-chat-codes'
import { markdownTable } from '../utils';

// creates the describing text for a chatlink (icon + name)
function text({raw, data}, details) {
    return (details.icon ? `![icon](${details.icon.replace(/^.*file\/(.*)\.png$/, 'https://darthmaim-cdn.de/gw2treasures/icons/$1-16px.png')}) ` : '')
        + (details.name || '');
}

// creates the external links for a chatlink
function externalLinks({raw, data}, details) {
    return [
        // API link
        `[A](https://api.guildwars2.com/v2/${data.type}s/${data.id})`,

        // GW2Treasures
        ['item', 'skill', 'trait', 'skin'].indexOf(data.type) !== -1 && `[T](https://gw2treasures.com/${data.type}/${data.id})`,

        // GW2Treasures for recipes (links to the output item with the recipe as scroll anchor)
        data.type === 'recipe' && `[T](https://gw2treasures.com/item/${details.output_item_id}#r${data.id})`,

        // Wiki
        `[W](http://wiki.guildwars2.com/index.php?title=Special:Search&search=${encodeURIComponent(details.name || raw)})`
    ].filter(Boolean).join(' ');
}

// handler
export function chatlinks(room, message) {

    // decode all chatlinks
    const all = uniq(message.text.match(/\[&[a-zA-Z0-9+\/]+=*\](?!`)/ig))
        .map(raw => ({ raw, data: decode(raw) }));

    // bail out of the message didn't contain any chatlinks
    if(all.length === 0) {
        return;
    }

    // load details from the api
    Promise.all(map(groupBy(all, 'data.type'), (links, type) =>
        gw2[type + 's']().many(links.map(link => link.data.id)).then(entries => ({ type, entries }))
    )).then(data => {
        // build lookup table
        data = keyBy(map(data, ({type, entries}) => ({ type, entries: keyBy(entries, 'id') })), 'type');

        // map all chat links to table rows
        const rows = all.map(link => [
            `\`${link.raw}\``,
            link.data.type,
            link.data.id,
            text(link, data[link.data.type].entries[link.data.id]),
            externalLinks(link, data[link.data.type].entries[link.data.id])
        ]);

        // send the table
        room.send(markdownTable(['link', 'type', 'id', 'info', 'links'], rows));
    });
}
<|endoftext|>


<commit_before>import React from 'react';

import LinearProgress from 'material-ui/LinearProgress';
import {Card, CardActions, CardHeader, CardMedia, CardTitle, CardText} from 'material-ui/Card';
import CircleIcon from 'material-ui/svg-icons/av/fiber-manual-record';

import DiffPanel from './utils/DiffPanel';

import Git from 'nodegit';

var url = require("file!./static/branchIcon.svg");

const constStyles = {
  fontFamily: `apple-system,
          BlinkMacSystemFont,"Segoe UI",
          Roboto,Helvetica,Arial,sans-serif,
          "Apple Color Emoji","Segoe UI Emoji",
          "Segoe UI Symbol"`,
  darkRed: '#b60a0a',
  grey: '#ededed',
  borderGrey: '#7e7e7e',
  yellow: '#b97005',
};

class gitFunctions {

  static getCommits(repoPath, sha, that) {

    let pathToRepo = require('path').resolve(repoPath);
    Git.Repository.open(pathToRepo)
    .then(function(repo) {
      return repo.getCommit(sha);
    })
    .then(function( commit ) {
      let history = commit.history( Git.Revwalk.SORT.Time);
      history.on("end", walk);
      history.start();
    })
    .done();

    //   function passed to history.on() listener to receive commits' info.
    //   calls the setCommitState of App class to set new state
    let walk = (function(commitsArr){
      let commits = [];
        commitsArr.forEach( function(commit) {
          commits.push({
            sha: commit.sha(),
            author: commit.author().name(),
            email: commit.author().email(),
            date: commit.date().toString(),
            message: commit.message()
          });
        });
        //TODO: pass a promise object to the function and can the
        //history event listener from there
        that.returnRepo(commits);
    }).bind(that);

  }

  static getCommitDiff(sha, path) {

    return Git.Repository.open(require('path').resolve(path))
    .then(function(repo) {
      return repo.getCommit(sha);
    })
    .then(function(commit) {
      return commit.getDiff();
    });
  }
}

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

  handleOnClick = (commit) => {

    this.props.getCommitDiff(commit);

    // gitFunctions.getCommitDiff(commit.sha, this.props.repoPath);

  }

  render() {
    const styles={
      span: {
        fontWeight: 500,
      },
      commitDiv: {
        display: 'flex',
        overflow: 'hidden',
        textOverflow: 'ellipsis',
        whiteSpace: 'nowrap',
        fontFamily: '"Roboto", sans-serif',
        padding: 1,
        margin: 0,
        backgroundColor: '#fff6dc',
        borderBottom: '2px solid #ffffff',
        color: constStyles.yellow,
      },
      circleIcon: {
        minWidth: 13,
        maxWidth: 13,
        minHeight: 13,
        maxHeight: 13,
      },
      message: {
        fontFamily: constStyles.fontFamily,
        overflow: 'hidden',
        textOverflow: 'ellipsis',
        whiteSpace: 'nowrap',
        padding: 2,
        margin: 4,
        fontSize: 15,
      },
      sha: {
        fontSize: 12,
        fontFamily: 'monospace',
      },
      sideBar: {
        position: 'relative',
        display: 'flex',
        alignItems: 'center',
      },
      line: {
        position: 'absolute',
        left: '42%',
        width: 2,
        height: 90,
        backgroundColor: constStyles.yellow,
      }
    };
    const commit = this.props.commit;

    return (

 { this.handleOnClick(commit) }} >

          <CircleIcon style={styles.circleIcon} color={constStyles.yellow}/>

{commit.author}

          {commit.sha?{commit.sha.slice(0, 8)+'  '}:null}
          {commit.message}

    )
  }
}

class CommitInfo extends React.Component {

  constructor(props) {
    super(props);
  }

  render = () => {
    let commit = '';
    if(this.props.commit) {
      commit = this.props.commit;
    }

    const styles= {
      main: {
        backgroundColor: '#ffffff',
        fontFamily: constStyles.fontFamily,
        fontSize: 15,
        border: '2px solid'+ constStyles.darkRed,
        borderBottom: '1px solid'+ constStyles.darkRed,
        letterSpacing: -1,
      },
      margin: {
        margin: 10,
      },
      author: {
        margin: 7,
        fontSize: 32,
        fontWeight: 700,
        color: constStyles.darkRed,
      },
      message: {
        color: constStyles.darkRed,
        fontSize: 20,
      },
      dateSha: {
        color: constStyles.darkRed,
        fontSize: 15,
      }
    };
    return (

{commit.author}

{commit.message}

            {commit.sha?
              {commit.sha.slice(0, 8)}
              :null}
            {' '+commit.date}

    );
  }
}

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

  render = () => {

    const styles={
      main:{
        display: 'flex',
        flexDirection: 'column',
        justifyContent: 'center',
        alignItems: 'center',
        width: '65%',
        border: '2px solid'+ constStyles.darkRed,
        color: constStyles.darkRed,
        fontFamily: constStyles.fontFamily,
        fontSize: 40,
        fontWeight: 800,
        letterSpacing: -2,
      },
      progressBar: {
        marginTop: 15,
        width: 200
      }
    };

    return (

        Loading. Hang Tight!
        <LinearProgress
        color={constStyles.darkRed}
        style={styles.progressBar}
        mode="indeterminate" />

    );
  }
}

class CommitTree extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      commits: [],
      diffs: [],
      selected_commit: null,
    };
    this.getCommitDiff = this.getCommitDiff.bind(this);
  }

  getCommitDiff = (commit) => {

    //for CommitInfo component
    this.setState({
      selected_commit: commit
    });

    gitFunctions.getCommitDiff(commit.sha, this.props.repo.path)
    .done((diffList) => {
        this.setState({
          diffs: diffList,
        });
    });
  }

  returnRepo = (commits) => {
    this.setState({
      commits : commits
    });
    // to load the first commit's diff info by default
    this.getCommitDiff(commits[0]);
  }

  componentDidMount = () => {
    if(this.props.repo && this.props.branchRef.sha)
    {
      gitFunctions.getCommits(this.props.repo.path, this.props.branchRef.sha, this);
    }
  }

  componentWillReceiveProps = (newprops) => {
    if(newprops.repo && newprops.branchRef.sha)
    {
      this.setState({
        selected_commit: null
      });
      gitFunctions.getCommits(newprops.repo.path, newprops.branchRef.sha, this);
    }
  }
  render() {

    const styles={
      commits: {
        border: '2px solid'+ constStyles.yellow,
        borderTop: '0px',
        borderRadius: '0px 0px 4px 4px',
        overflow: 'auto',
        height: 350,
      },
      branchName: {
        color: constStyles.yellow,
        display: 'flex',
        fontFamily: constStyles.fontFamily,
        fontWeight: 500,
        fontSize: 20,
        backgroundColor: '#fff6dc',
        border: '2px solid'+ constStyles.yellow,
        borderBottom: '1px solid'+ constStyles.yellow,
        zIndex: 10,
        margin: 0,
        padding: 20,
      },
    };

    let rows=[];
    this.state.commits.forEach((commit, index) => {
      rows.push(<Commit getCommitDiff={this.getCommitDiff} commit={commit} key={index} />);
    });
    return (

{' '+this.props.branchRef.name}

            { rows }

        {this.state.selected_commit?

            <CommitInfo commit={this.state.selected_commit} />

              <DiffPanel diffs={this.state.diffs} />

:
          <LoadingCommitInfo />}

    )
  }
}

export default CommitTree;<commit_msg>View: Changed styles of commitInfo, diff and loadingDiff components<commit_after>import React from 'react';

import LinearProgress from 'material-ui/LinearProgress';
import {Card, CardActions, CardHeader, CardMedia, CardTitle, CardText} from 'material-ui/Card';
import CircleIcon from 'material-ui/svg-icons/av/fiber-manual-record';

import DiffPanel from './utils/DiffPanel';

import Git from 'nodegit';

var url = require("file!./static/branchIcon.svg");

const constStyles = {
  fontFamily: `apple-system,
          BlinkMacSystemFont,"Segoe UI",
          Roboto,Helvetica,Arial,sans-serif,
          "Apple Color Emoji","Segoe UI Emoji",
          "Segoe UI Symbol"`,
  darkRed: '#b60a0a',
  grey: '#ededed',
  borderGrey: '#7e7e7e',
  yellow: '#b97005',
};

class gitFunctions {

  static getCommits(repoPath, sha, that) {

    let pathToRepo = require('path').resolve(repoPath);
    Git.Repository.open(pathToRepo)
    .then(function(repo) {
      return repo.getCommit(sha);
    })
    .then(function( commit ) {
      let history = commit.history( Git.Revwalk.SORT.Time);
      history.on("end", walk);
      history.start();
    })
    .done();

    //   function passed to history.on() listener to receive commits' info.
    //   calls the setCommitState of App class to set new state
    let walk = (function(commitsArr){
      let commits = [];
        commitsArr.forEach( function(commit) {
          commits.push({
            sha: commit.sha(),
            author: commit.author().name(),
            email: commit.author().email(),
            date: commit.date().toString(),
            message: commit.message()
          });
        });
        //TODO: pass a promise object to the function and can the
        //history event listener from there
        that.returnRepo(commits);
    }).bind(that);

  }

  static getCommitDiff(sha, path) {

    return Git.Repository.open(require('path').resolve(path))
    .then(function(repo) {
      return repo.getCommit(sha);
    })
    .then(function(commit) {
      return commit.getDiff();
    });
  }
}

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

  handleOnClick = (commit) => {

    this.props.getCommitDiff(commit);

    // gitFunctions.getCommitDiff(commit.sha, this.props.repoPath);

  }

  render() {
    const styles={
      span: {
        fontWeight: 500,
      },
      commitDiv: {
        display: 'flex',
        overflow: 'hidden',
        textOverflow: 'ellipsis',
        whiteSpace: 'nowrap',
        fontFamily: '"Roboto", sans-serif',
        padding: 1,
        margin: 0,
        backgroundColor: '#fff6dc',
        borderBottom: '2px solid #ffffff',
        color: constStyles.yellow,
      },
      circleIcon: {
        minWidth: 13,
        maxWidth: 13,
        minHeight: 13,
        maxHeight: 13,
      },
      message: {
        fontFamily: constStyles.fontFamily,
        overflow: 'hidden',
        textOverflow: 'ellipsis',
        whiteSpace: 'nowrap',
        padding: 2,
        margin: 4,
        fontSize: 15,
      },
      sha: {
        fontSize: 12,
        fontFamily: 'monospace',
      },
      sideBar: {
        position: 'relative',
        display: 'flex',
        alignItems: 'center',
      },
      line: {
        position: 'absolute',
        left: '42%',
        width: 2,
        height: 90,
        backgroundColor: constStyles.yellow,
      }
    };
    const commit = this.props.commit;

    return (

 { this.handleOnClick(commit) }} >

          <CircleIcon style={styles.circleIcon} color={constStyles.yellow}/>

{commit.author}

          {commit.sha?{commit.sha.slice(0, 8)+'  '}:null}
          {commit.message}

    )
  }
}

class CommitInfo extends React.Component {

  constructor(props) {
    super(props);
  }

  render = () => {
    let commit = '';
    if(this.props.commit) {
      commit = this.props.commit;
    }

    const styles= {
      main: {
        backgroundColor: '#ffffff',
        fontFamily: constStyles.fontFamily,
        fontSize: 15,
        border: '2px solid'+ constStyles.yellow,
        borderBottom: '1px solid'+ constStyles.yellow,
        letterSpacing: -1,
      },
      margin: {
        margin: 10,
      },
      author: {
        margin: 7,
        fontSize: 32,
        fontWeight: 700,
        color: constStyles.yellow,
      },
      message: {
        color: constStyles.yellow,
        fontSize: 20,
      },
      dateSha: {
        color: constStyles.yellow,
        fontSize: 15,
      }
    };
    return (

{commit.author}

{commit.message}

            {commit.sha?
              {commit.sha.slice(0, 8)}
              :null}
            {' '+commit.date}

    );
  }
}

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

  render = () => {

    const styles={
      main:{
        display: 'flex',
        flexDirection: 'column',
        justifyContent: 'center',
        alignItems: 'center',
        width: '65%',
        border: '2px solid'+ constStyles.yellow,
        color: constStyles.yellow,
        fontFamily: constStyles.fontFamily,
        fontSize: 40,
        fontWeight: 800,
        letterSpacing: -2,
      },
      progressBar: {
        marginTop: 15,
        width: 200
      }
    };

    return (

        Loading. Hang Tight!
        <LinearProgress
        color={constStyles.yellow}
        style={styles.progressBar}
        mode="indeterminate" />

    );
  }
}

class CommitTree extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      commits: [],
      diffs: [],
      selected_commit: null,
    };
    this.getCommitDiff = this.getCommitDiff.bind(this);
  }

  getCommitDiff = (commit) => {

    //for CommitInfo component
    this.setState({
      selected_commit: commit
    });

    gitFunctions.getCommitDiff(commit.sha, this.props.repo.path)
    .done((diffList) => {
        this.setState({
          diffs: diffList,
        });
    });
  }

  returnRepo = (commits) => {
    this.setState({
      commits : commits
    });
    // to load the first commit's diff info by default
    this.getCommitDiff(commits[0]);
  }

  componentDidMount = () => {
    if(this.props.repo && this.props.branchRef.sha)
    {
      gitFunctions.getCommits(this.props.repo.path, this.props.branchRef.sha, this);
    }
  }

  componentWillReceiveProps = (newprops) => {
    if(newprops.repo && newprops.branchRef.sha)
    {
      this.setState({
        selected_commit: null
      });
      gitFunctions.getCommits(newprops.repo.path, newprops.branchRef.sha, this);
    }
  }
  render() {

    const styles={
      commits: {
        border: '2px solid'+ constStyles.yellow,
        borderTop: '0px',
        borderRadius: '0px 0px 4px 4px',
        overflow: 'auto',
        height: 350,
      },
      branchName: {
        color: constStyles.yellow,
        display: 'flex',
        fontFamily: constStyles.fontFamily,
        fontWeight: 500,
        fontSize: 20,
        backgroundColor: '#fff6dc',
        border: '2px solid'+ constStyles.yellow,
        borderBottom: '1px solid'+ constStyles.yellow,
        zIndex: 10,
        margin: 0,
        padding: 20,
      },
    };

    let rows=[];
    this.state.commits.forEach((commit, index) => {
      rows.push(<Commit getCommitDiff={this.getCommitDiff} commit={commit} key={index} />);
    });
    return (

{' '+this.props.branchRef.name}

            { rows }

        {this.state.selected_commit?

            <CommitInfo commit={this.state.selected_commit} />

              <DiffPanel diffs={this.state.diffs} />

:
          <LoadingCommitInfo />}

    )
  }
}

export default CommitTree;<|endoftext|>