<commit_before>import symbols from './symbols.js';

/**
 * Mixin which adds single-selection semantics for items in a list.
 *
 * This mixin expects a component to provide an `items` Array or NodeList of
 * all elements in the list.
 *
 * This mixin tracks a single selected item in the list, and provides means to
 * get and set that state by item position (`selectedIndex`) or item identity
 * (`selectedItem`). The selection can be moved in the list via the methods
 * `selectFirst`, `selectLast`, `selectNext`, and `selectPrevious`.
 *
 * This mixin does not produce any user-visible effects to represent
 * selection.
 *
 * @module SingleSelectionMixin
 */
export default function SingleSelectionMixin(Base) {

  // The class prototype added by the mixin.
  class SingleSelection extends Base {

    /**
     * True if the selection can be moved to the next item, false if not (the
     * selected item is the last item in the list).
     *
     * @type {boolean}
     */
    get canSelectNext() {
      const count = this.items ? this.items.length : 0;
      const selectedIndex = this.state.selectedIndex;
      return count === 0 ?
        false :
        this.state.selectionWraps || selectedIndex < 0 || selectedIndex < count - 1;
    }

    /**
     * True if the selection can be moved to the previous item, false if not
     * (the selected item is the first one in the list).
     *
     * @type {boolean}
     */
    get canSelectPrevious() {
      const count = this.items ? this.items.length : 0;
      const selectedIndex = this.state.selectedIndex;
      return count === 0 ?
        false :
        this.state.selectionWraps || selectedIndex < 0 || selectedIndex > 0;
    }

    get defaultState() {
      return Object.assign({}, super.defaultState, {
        selectedIndex: -1,
        selectionRequired: false,
        selectionWraps: false
      });
    }

    componentDidUpdate(previousState) {
      if (super.componentDidUpdate) { super.componentDidUpdate(previousState); }

      const selectedIndex = this.state.selectedIndex;
      if (selectedIndex !== previousState.selectedIndex && this[symbols.raiseChangeEvents]) {
        const event = new CustomEvent('selected-index-changed', {
          detail: { selectedIndex }
        });
        this.dispatchEvent(event);
      }
    }

    itemCalcs(item, index) {
      const base = super.itemCalcs ? super.itemCalcs(item, index) : null;
      return Object.assign({}, base, {
        selected: index === this.state.selectedIndex
      });
    }

    /**
     * Select the first item in the list.
     *
     * @returns {Boolean} True if the selection changed, false if not.
     */
    selectFirst() {
      if (super.selectFirst) { super.selectFirst(); }
      return this.setState({
        selectedIndex: 0
      });
    }

    /**
     * The index of the currently-selected item, or -1 if no item is selected.
     *
     * @type {number}
     */
    get selectedIndex() {
      return this.state.selectedIndex;
    }
    set selectedIndex(selectedIndex) {
      const parsedIndex = typeof selectedIndex === 'string' ?
        parseInt(selectedIndex) :
        selectedIndex;
      this.setState({
        selectedIndex: parsedIndex
      });
    }

    /**
     * The currently-selected item, or null if no item is selected.
     *
     * @type {Element|null}
     */
    get selectedItem() {
      return this.items && this.items[this.state.selectedIndex];
    }
    set selectedItem(selectedItem) {
      if (!this.items) {
        return;
      }
      const selectedIndex = this.items.indexOf(selectedItem);
      if (selectedIndex >= 0) {
        this.setState({ selectedIndex });
      }
    }

    /**
     * True if the list should always have a selection (if it has items).
     *
     * @type {boolean}
     * @default false
     */
    get selectionRequired() {
      return this.state.selectionRequired;
    }
    set selectionRequired(selectionRequired) {
      this.setState({
        selectionRequired: String(selectionRequired) === 'true'
      });
    }

    /**
     * True if selection navigations wrap from last to first, and vice versa.
     *
     * @type {boolean}
     * @default false
     */
    get selectionWraps() {
      return this.state.selectionWraps;
    }
    set selectionWraps(selectionWraps) {
      this.setState({
        selectionWraps: String(selectionWraps) === 'true'
      });
    }

    /**
     * Select the last item in the list.
     *
     * @returns {Boolean} True if the selection changed, false if not.
     */
    selectLast() {
      if (super.selectLast) { super.selectLast(); }
      return this.setState({
        selectedIndex: this.items.length - 1
      });
    }

    /**
     * Select the next item in the list.
     *
     * If the list has no selection, the first item will be selected.
     *
     * @returns {Boolean} True if the selection changed, false if not.
     */
    selectNext() {
      if (super.selectNext) { super.selectNext(); }
      return this.setState({
        selectedIndex: this.state.selectedIndex + 1
      });
    }

    /**
     * Select the previous item in the list.
     *
     * If the list has no selection, the last item will be selected.
     *
     * @returns {Boolean} True if the selection changed, false if not.
     */
    selectPrevious() {
      if (super.selectPrevious) { super.selectPrevious(); }
      const selectedIndex = this.items && this.state.selectedIndex < 0 ?
        this.items.length - 1 :     // No selection yet; select last item.
        this.state.selectedIndex - 1;
      return this.setState({ selectedIndex });
    }

    validateState(state) {
      // Only validate if we've already received items.
      const items = this.itemsForState ?
        this.itemsForState(state) :
        state.items;
      if (items) {
        const count = items ? items.length : 0;
        const selectedIndex = state.selectedIndex;

        let validatedIndex;
        if (selectedIndex === -1 && state.selectionRequired && count > 0) {
          validatedIndex = 0;
        } else if (state.selectionWraps) {
          // Wrap the index.
          // JavaScript mod doesn't handle negative numbers the way we want to wrap.
          // See http://stackoverflow.com/a/18618250/76472
          validatedIndex = ((selectedIndex % count) + count) % count;
        } else {
          // Don't wrap, force index within bounds of -1 (no selection) to the
          // array length - 1.
          validatedIndex = Math.max(Math.min(selectedIndex, count - 1), -1);
        }

        if (validatedIndex !== selectedIndex) {
          return {
            selectedIndex: validatedIndex
          };
        }
      }

      return super.validateState && super.validateState(state);
    }

  }

  return SingleSelection;
}
<commit_msg>Fix bug where selectPrevious at beginning of non-wrapping list would wrap selection around to last item.<commit_after>import symbols from './symbols.js';

/**
 * Mixin which adds single-selection semantics for items in a list.
 *
 * This mixin expects a component to provide an `items` Array or NodeList of
 * all elements in the list.
 *
 * This mixin tracks a single selected item in the list, and provides means to
 * get and set that state by item position (`selectedIndex`) or item identity
 * (`selectedItem`). The selection can be moved in the list via the methods
 * `selectFirst`, `selectLast`, `selectNext`, and `selectPrevious`.
 *
 * This mixin does not produce any user-visible effects to represent
 * selection.
 *
 * @module SingleSelectionMixin
 */
export default function SingleSelectionMixin(Base) {

  // The class prototype added by the mixin.
  class SingleSelection extends Base {

    /**
     * True if the selection can be moved to the next item, false if not (the
     * selected item is the last item in the list).
     *
     * @type {boolean}
     */
    get canSelectNext() {
      const count = this.items ? this.items.length : 0;
      const selectedIndex = this.state.selectedIndex;
      return count === 0 ?
        false :
        this.state.selectionWraps || selectedIndex < 0 || selectedIndex < count - 1;
    }

    /**
     * True if the selection can be moved to the previous item, false if not
     * (the selected item is the first one in the list).
     *
     * @type {boolean}
     */
    get canSelectPrevious() {
      const count = this.items ? this.items.length : 0;
      const selectedIndex = this.state.selectedIndex;
      return count === 0 ?
        false :
        this.state.selectionWraps || selectedIndex < 0 || selectedIndex > 0;
    }

    get defaultState() {
      return Object.assign({}, super.defaultState, {
        selectedIndex: -1,
        selectionRequired: false,
        selectionWraps: false
      });
    }

    componentDidUpdate(previousState) {
      if (super.componentDidUpdate) { super.componentDidUpdate(previousState); }

      const selectedIndex = this.state.selectedIndex;
      if (selectedIndex !== previousState.selectedIndex && this[symbols.raiseChangeEvents]) {
        const event = new CustomEvent('selected-index-changed', {
          detail: { selectedIndex }
        });
        this.dispatchEvent(event);
      }
    }

    itemCalcs(item, index) {
      const base = super.itemCalcs ? super.itemCalcs(item, index) : null;
      return Object.assign({}, base, {
        selected: index === this.state.selectedIndex
      });
    }

    /**
     * Select the first item in the list.
     *
     * @returns {Boolean} True if the selection changed, false if not.
     */
    selectFirst() {
      if (super.selectFirst) { super.selectFirst(); }
      return this.setState({
        selectedIndex: 0
      });
    }

    /**
     * The index of the currently-selected item, or -1 if no item is selected.
     *
     * @type {number}
     */
    get selectedIndex() {
      return this.state.selectedIndex;
    }
    set selectedIndex(selectedIndex) {
      const parsedIndex = typeof selectedIndex === 'string' ?
        parseInt(selectedIndex) :
        selectedIndex;
      this.setState({
        selectedIndex: parsedIndex
      });
    }

    /**
     * The currently-selected item, or null if no item is selected.
     *
     * @type {Element|null}
     */
    get selectedItem() {
      return this.items && this.items[this.state.selectedIndex];
    }
    set selectedItem(selectedItem) {
      if (!this.items) {
        return;
      }
      const selectedIndex = this.items.indexOf(selectedItem);
      if (selectedIndex >= 0) {
        this.setState({ selectedIndex });
      }
    }

    /**
     * True if the list should always have a selection (if it has items).
     *
     * @type {boolean}
     * @default false
     */
    get selectionRequired() {
      return this.state.selectionRequired;
    }
    set selectionRequired(selectionRequired) {
      this.setState({
        selectionRequired: String(selectionRequired) === 'true'
      });
    }

    /**
     * True if selection navigations wrap from last to first, and vice versa.
     *
     * @type {boolean}
     * @default false
     */
    get selectionWraps() {
      return this.state.selectionWraps;
    }
    set selectionWraps(selectionWraps) {
      this.setState({
        selectionWraps: String(selectionWraps) === 'true'
      });
    }

    /**
     * Select the last item in the list.
     *
     * @returns {Boolean} True if the selection changed, false if not.
     */
    selectLast() {
      if (super.selectLast) { super.selectLast(); }
      return this.setState({
        selectedIndex: this.items.length - 1
      });
    }

    /**
     * Select the next item in the list.
     *
     * If the list has no selection, the first item will be selected.
     *
     * @returns {Boolean} True if the selection changed, false if not.
     */
    selectNext() {
      if (super.selectNext) { super.selectNext(); }
      return this.setState({
        selectedIndex: this.state.selectedIndex + 1
      });
    }

    /**
     * Select the previous item in the list.
     *
     * If the list has no selection, the last item will be selected.
     *
     * @returns {Boolean} True if the selection changed, false if not.
     */
    selectPrevious() {
      if (super.selectPrevious) { super.selectPrevious(); }
      let selectedIndex;
      if (this.items && this.state.selectedIndex < 0) {
        // No selection yet; select last item.
        selectedIndex = this.items.length - 1;
      } else if (this.state.selectionWraps || this.state.selectedIndex > 0) {
        selectedIndex = this.state.selectedIndex - 1;
      } else {
        // Already on first item, can't go previous.
        return false;
      }
      return this.setState({ selectedIndex });
    }

    validateState(state) {
      // Only validate if we've already received items.
      const items = this.itemsForState ?
        this.itemsForState(state) :
        state.items;
      if (items) {
        const count = items ? items.length : 0;
        const selectedIndex = state.selectedIndex;

        let validatedIndex;
        if (selectedIndex === -1 && state.selectionRequired && count > 0) {
          validatedIndex = 0;
        } else if (state.selectionWraps) {
          // Wrap the index.
          // JavaScript mod doesn't handle negative numbers the way we want to wrap.
          // See http://stackoverflow.com/a/18618250/76472
          validatedIndex = ((selectedIndex % count) + count) % count;
        } else {
          // Don't wrap, force index within bounds of -1 (no selection) to the
          // array length - 1.
          validatedIndex = Math.max(Math.min(selectedIndex, count - 1), -1);
        }

        if (validatedIndex !== selectedIndex) {
          return {
            selectedIndex: validatedIndex
          };
        }
      }

      return super.validateState && super.validateState(state);
    }

  }

  return SingleSelection;
}
<|endoftext|>


<commit_before>// Copyright 2014-2018, University of Colorado Boulder

/**
 * A fraction and associated operations.
 *
 * NOTE: The common version of this class in the PhET Java code base has a number of additional methods.  These methods
 * should be ported into this file as needed.  Please see edu.colorado.phet.fractions.common.math.Fraction.java in the
 * PhET Java code base.
 *
 * @author John Blanco
 * @author Chris Malley (PixelZoom, Inc.)
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var phetcommon = require( 'PHETCOMMON/phetcommon' );
  var Util = require( 'DOT/Util' );

  /**
   * @param {number} numerator must be an integer
   * @param {number} denominator must be an integer
   * @constructor
   */
  function Fraction( numerator, denominator ) {
    assert && assert( Util.isInteger( numerator ), 'numerator must be an integer: ' + numerator );
    assert && assert( Util.isInteger( denominator ), 'denominator must be an integer: ' + denominator );

    this.numerator = numerator;     // @public (read-only)
    this.denominator = denominator; // @public (read-only)
  }

  phetcommon.register( 'Fraction', Fraction );

  inherit( Object, Fraction, {

    // @public - Floating-point error is not an issue as long as numerator and denominator are integers < 2^53
    getValue: function() {
      return this.numerator / this.denominator;
    },

    // @public
    isInteger: function() {
      return Util.isInteger( this.getValue() );
    },

    // @public
    toString: function() {
      return this.numerator + '/' + this.denominator;
    },

    // @public
    copy: function() {
      return new Fraction( this.numerator, this.denominator );
    },

    /**
     * Reduces this fraction, modifies the numerator and denominator.
     * @returns {Fraction} returns this, to support chaining of operations
     * @public
     */
    reduce: function() {
      var gcd = Util.gcd( this.numerator, this.denominator );
      this.numerator = ( gcd === 0 ) ? 0 : Util.roundSymmetric( this.numerator / gcd );
      this.denominator = ( gcd === 0 ) ? 0 : Util.roundSymmetric( this.denominator / gcd );
      return this;
    },

    /**
     * Creates a reduced instance of this fraction.
     * @returns {Fraction}
     * @public
     */
    reduced: function() {
      return this.copy().reduce();
    },

    /**
     * Is this fraction reduced?
     * @returns {boolean}
     */
    isReduced: function() {
      return Util.gcd( this.numerator, this.denominator ) === 1;
    },

    /**
     * Returns whether the two fractions are equal (not whether their reduced values are equal).
     * @public
     *
     * @param {Fraction} fraction
     * @returns {boolean}
     */
    equals: function( fraction ) {
      return this.numerator === fraction.numerator && this.denominator === fraction.denominator;
    },

    /**
     * Returns whether this fraction has a value that is less than the provided fraction.
     * @public
     *
     * @param {Fraction} fraction
     * @returns {boolean}
     */
    isLessThan: function( fraction ) {
      assert && assert( fraction instanceof Fraction, 'fraction is not a Fraction: ' + fraction );

      return SCRATCH_FRACTION.set( this ).subtract( fraction ).sign === -1;
    },

    /**
     * Gets the sign of the value.
     * @returns {number} see Util.sign
     * @public
     */
    get sign() {
      return Util.sign( this.getValue() );
    },

    /**
     * Returns the absolute value of this fraction.
     * @returns {Fraction}
     * @public
     */
    abs: function() {
      return new Fraction( Math.abs( this.numerator ), Math.abs( this.denominator ) );
    },

    /**
     * Sets the value of this fraction to the provided fraction.
     * @param {Fraction} value
     * @returns {Fraction} - Reference to this for chaining
     * @public
     */
    set: function( value ) {
      this.numerator = value.numerator;
      this.denominator = value.denominator;
      return this;
    },

    /**
     * Sets the value of this fraction to the sum of the two fractions:
     * numerator1 / denominator1 + numerator2 / denominator2
     * @param {number} numerator1
     * @param {number} denominator1
     * @param {number} numerator2
     * @param {number} denominator2
     * @returns {Fraction} - Reference to this
     * @public
     */
    setToSum: function( numerator1, denominator1, numerator2, denominator2 ) {
      assert && assert( Util.isInteger( numerator1 ), 'numerator1 must be an integer' );
      assert && assert( Util.isInteger( denominator1 ), 'denominator1 must be an integer' );
      assert && assert( Util.isInteger( numerator2 ), 'numerator2 must be an integer' );
      assert && assert( Util.isInteger( denominator2 ), 'denominator2 must be an integer' );

      var lcm = Util.lcm( denominator1, denominator2 );
      this.numerator = Util.roundSymmetric( numerator1 * lcm / denominator1 ) +
                       Util.roundSymmetric( numerator2 * lcm / denominator2 );
      this.denominator = lcm;
      return this;
    },

    /**
     * Adds the provided fraction into this fraction (mutates this fraction). The result is NOT reduced,
     * and has a denominator that is the least-common multiple of the 2 denominators.
     * @param {Fraction} value
     * @returns {Fraction} - Reference to this (for chaining)
     * @public
     */
    add: function( value ) {
      assert && assert( value instanceof Fraction, 'value is not a Fraction: ' + value );

      return this.setToSum( this.numerator, this.denominator, value.numerator, value.denominator );
    },

    /**
     * Adds a fraction to this fraction to create a new fraction.
     * The result is not reduced, and has a denominator that is the least-common multiple of the 2 denominators.
     * @param {Fraction} value
     * @returns {Fraction}
     * @public
     */
    plus: function( value ) {
      return this.copy().add( value );
    },

    /**
     * Subtracts the provided fraction from this fraction (mutates this fraction). The result is NOT reduced,
     * and has a denominator that is the least-common multiple of the 2 denominators.
     * @param {Fraction} value
     * @returns {Fraction} - Reference to this (for chaining)
     * @public
     */
    subtract: function( value ) {
      assert && assert( value instanceof Fraction, 'value is not a Fraction: ' + value );

      return this.setToSum( this.numerator, this.denominator, -value.numerator, value.denominator );
    },

    /**
     * Subtracts a fraction from this fraction to create a new fraction.
     * The result is not reduced, and has a denominator that is the least-common multiple of the 2 denominators.
     * @param {Fraction} value
     * @returns {Fraction}
     * @public
     */
    minus: function( value ) {
      return this.copy().subtract( value );
    },

    /**
     * Multiplies the provided fraction and this fraction, setting the result into this fraction (mutates).
     * The value is not reduced.
     * @param {Fraction} value
     * @returns {Fraction} - Reference to this (for chaining)
     * @public
     */
    multiply: function( value ) {
      assert && assert( value instanceof Fraction, 'value is not a Fraction: ' + value );

      this.numerator *= value.numerator;
      this.denominator *= value.denominator;
      return this;
    },

    /**
     * Multiplies this fraction by another fraction to create a new fraction.
     * The result is not reduced.
     * @param {Fraction} value
     * @returns {Fraction}
     * @public
     */
    times: function( value ) {
      return this.copy().multiply( value );
    },

    /**
     * Divides this fraction by the provided fraction, setting the result into this fraction (mutates).
     * The value is not reduced.
     * @param {Fraction} value
     * @returns {Fraction} - Reference to this (for chaining)
     * @public
     */
    divide: function( value ) {
      assert && assert( value instanceof Fraction, 'value is not a Fraction: ' + value );

      this.numerator *= value.denominator;
      this.denominator *= value.numerator;
      return this;
    },

    /**
     * Divides this fraction by another fraction to create a new fraction.
     * The result is not reduced.
     * @param {Fraction} value
     * @returns {Fraction}
     * @public
     */
    divided: function( value ) {
      return this.copy().divide( value );
    },

    /**
     * Convenience method.
     * Adds an integer value to this fraction to create a new fraction.
     * The result is not reduced, and the denominator is the same as the denominator of this fraction.
     * @param {number} value - integer
     * @returns {Fraction}
     * @public
     */
    plusInteger: function( value ) {
      assert && assert( Util.isInteger( value ), 'value is not an integer: ' + value );
      return new Fraction( this.numerator + ( value * this.denominator ), this.denominator );
    },

    /**
     * Convenience method.
     * Subtracts an integer value from this fraction to create a new fraction.
     * The result is not reduced, and the denominator is the same as the denominator of this fraction.
     * @param {number} value - integer
     * @returns {Fraction}
     * @public
     */
    minusInteger: function( value ) {
      assert && assert( Util.isInteger( value ), 'value is not an integer: ' + value );
      return new Fraction( this.numerator - ( value * this.denominator ), this.denominator );
    },

    /**
     * Convenience method.
     * Multiplies this fraction by an integer to create a new fraction.
     * The result is not reduced, and the denominator is the same as the denominator of this fraction.
     * @param {number} value
     * @returns {Fraction}
     * @public
     */
    timesInteger: function( value ) {
      assert && assert( Util.isInteger( value ), 'value is not an integer: ' + value );
      return new Fraction( this.numerator * value, this.denominator );
    },

    /**
     * Convenience method.
     * Divides this fraction by an integer to create a new fraction.
     * This operation affects the value and sign of the denominator only, and the result is not reduced.
     * Careful! Division by zero is allowed here.
     * @param {number} value - integer
     * @returns {Fraction}
     * @public
     */
    dividedInteger: function( value ) {
      assert && assert( Util.isInteger( value ), 'value is not an integer: ' + value );
      return new Fraction( this.numerator, this.denominator * value );
    }
  }, {

    /**
     * Convenience method for constructing a fraction from an integer.
     * @param {number} value - must be an integer
     * @returns {Fraction}
     * @public
     * @static
     */
    fromInteger: function( value ) {
      return new Fraction( value, 1 );
    }
  } );

  // Used to avoid GC - NOTE: Do NOT move in front of the constructor/inherit, as it is creating a copy of the type
  // defined.
  var SCRATCH_FRACTION = new Fraction( 1, 1 );

  return Fraction;
} );<commit_msg>doc #43<commit_after>// Copyright 2014-2018, University of Colorado Boulder

/**
 * A fraction and associated operations.
 *
 * NOTE: The common version of this class in the PhET Java code base has a number of additional methods.  These methods
 * should be ported into this file as needed.  Please see edu.colorado.phet.fractions.common.math.Fraction.java in the
 * PhET Java code base.
 *
 * @author John Blanco
 * @author Chris Malley (PixelZoom, Inc.)
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var phetcommon = require( 'PHETCOMMON/phetcommon' );
  var Util = require( 'DOT/Util' );

  /**
   * @param {number} numerator must be an integer
   * @param {number} denominator must be an integer
   * @constructor
   */
  function Fraction( numerator, denominator ) {
    assert && assert( Util.isInteger( numerator ), 'numerator must be an integer: ' + numerator );
    assert && assert( Util.isInteger( denominator ), 'denominator must be an integer: ' + denominator );

    this.numerator = numerator;     // @public (read-only)
    this.denominator = denominator; // @public (read-only)
  }

  phetcommon.register( 'Fraction', Fraction );

  inherit( Object, Fraction, {

    // @public - Floating-point error is not an issue as long as numerator and denominator are integers < 2^53
    getValue: function() {
      return this.numerator / this.denominator;
    },

    // @public
    isInteger: function() {
      return Util.isInteger( this.getValue() );
    },

    // @public
    toString: function() {
      return this.numerator + '/' + this.denominator;
    },

    // @public
    copy: function() {
      return new Fraction( this.numerator, this.denominator );
    },

    /**
     * Reduces this fraction, modifies the numerator and denominator.
     * @returns {Fraction} returns this, to support chaining of operations
     * @public
     */
    reduce: function() {
      var gcd = Util.gcd( this.numerator, this.denominator );
      this.numerator = ( gcd === 0 ) ? 0 : Util.roundSymmetric( this.numerator / gcd );
      this.denominator = ( gcd === 0 ) ? 0 : Util.roundSymmetric( this.denominator / gcd );
      return this;
    },

    /**
     * Creates a reduced instance of this fraction.
     * @returns {Fraction}
     * @public
     */
    reduced: function() {
      return this.copy().reduce();
    },

    /**
     * Is this fraction reduced?
     * @returns {boolean}
     */
    isReduced: function() {
      return Util.gcd( this.numerator, this.denominator ) === 1;
    },

    /**
     * Returns whether the two fractions are equal (not whether their reduced values are equal).
     * @public
     *
     * @param {Fraction} fraction
     * @returns {boolean}
     */
    equals: function( fraction ) {
      return this.numerator === fraction.numerator && this.denominator === fraction.denominator;
    },

    /**
     * Returns whether this fraction has a value that is less than the provided fraction.
     * @public
     *
     * @param {Fraction} fraction
     * @returns {boolean}
     */
    isLessThan: function( fraction ) {
      assert && assert( fraction instanceof Fraction, 'fraction is not a Fraction: ' + fraction );

      // The more straightforward approach would be: this.getValue() < fraction.getValue().
      // But that uses floating-point operations and comparisons, which could result in a loss of precision.
      // https://github.com/phetsims/phetcommon/issues/43
      return SCRATCH_FRACTION.set( this ).subtract( fraction ).sign === -1;
    },

    /**
     * Gets the sign of the value.
     * @returns {number} see Util.sign
     * @public
     */
    get sign() {
      return Util.sign( this.getValue() );
    },

    /**
     * Returns the absolute value of this fraction.
     * @returns {Fraction}
     * @public
     */
    abs: function() {
      return new Fraction( Math.abs( this.numerator ), Math.abs( this.denominator ) );
    },

    /**
     * Sets the value of this fraction to the provided fraction.
     * @param {Fraction} value
     * @returns {Fraction} - Reference to this for chaining
     * @public
     */
    set: function( value ) {
      this.numerator = value.numerator;
      this.denominator = value.denominator;
      return this;
    },

    /**
     * Sets the value of this fraction to the sum of the two fractions:
     * numerator1 / denominator1 + numerator2 / denominator2
     * @param {number} numerator1
     * @param {number} denominator1
     * @param {number} numerator2
     * @param {number} denominator2
     * @returns {Fraction} - Reference to this
     * @public
     */
    setToSum: function( numerator1, denominator1, numerator2, denominator2 ) {
      assert && assert( Util.isInteger( numerator1 ), 'numerator1 must be an integer' );
      assert && assert( Util.isInteger( denominator1 ), 'denominator1 must be an integer' );
      assert && assert( Util.isInteger( numerator2 ), 'numerator2 must be an integer' );
      assert && assert( Util.isInteger( denominator2 ), 'denominator2 must be an integer' );

      var lcm = Util.lcm( denominator1, denominator2 );
      this.numerator = Util.roundSymmetric( numerator1 * lcm / denominator1 ) +
                       Util.roundSymmetric( numerator2 * lcm / denominator2 );
      this.denominator = lcm;
      return this;
    },

    /**
     * Adds the provided fraction into this fraction (mutates this fraction). The result is NOT reduced,
     * and has a denominator that is the least-common multiple of the 2 denominators.
     * @param {Fraction} value
     * @returns {Fraction} - Reference to this (for chaining)
     * @public
     */
    add: function( value ) {
      assert && assert( value instanceof Fraction, 'value is not a Fraction: ' + value );

      return this.setToSum( this.numerator, this.denominator, value.numerator, value.denominator );
    },

    /**
     * Adds a fraction to this fraction to create a new fraction.
     * The result is not reduced, and has a denominator that is the least-common multiple of the 2 denominators.
     * @param {Fraction} value
     * @returns {Fraction}
     * @public
     */
    plus: function( value ) {
      return this.copy().add( value );
    },

    /**
     * Subtracts the provided fraction from this fraction (mutates this fraction). The result is NOT reduced,
     * and has a denominator that is the least-common multiple of the 2 denominators.
     * @param {Fraction} value
     * @returns {Fraction} - Reference to this (for chaining)
     * @public
     */
    subtract: function( value ) {
      assert && assert( value instanceof Fraction, 'value is not a Fraction: ' + value );

      return this.setToSum( this.numerator, this.denominator, -value.numerator, value.denominator );
    },

    /**
     * Subtracts a fraction from this fraction to create a new fraction.
     * The result is not reduced, and has a denominator that is the least-common multiple of the 2 denominators.
     * @param {Fraction} value
     * @returns {Fraction}
     * @public
     */
    minus: function( value ) {
      return this.copy().subtract( value );
    },

    /**
     * Multiplies the provided fraction and this fraction, setting the result into this fraction (mutates).
     * The value is not reduced.
     * @param {Fraction} value
     * @returns {Fraction} - Reference to this (for chaining)
     * @public
     */
    multiply: function( value ) {
      assert && assert( value instanceof Fraction, 'value is not a Fraction: ' + value );

      this.numerator *= value.numerator;
      this.denominator *= value.denominator;
      return this;
    },

    /**
     * Multiplies this fraction by another fraction to create a new fraction.
     * The result is not reduced.
     * @param {Fraction} value
     * @returns {Fraction}
     * @public
     */
    times: function( value ) {
      return this.copy().multiply( value );
    },

    /**
     * Divides this fraction by the provided fraction, setting the result into this fraction (mutates).
     * The value is not reduced.
     * @param {Fraction} value
     * @returns {Fraction} - Reference to this (for chaining)
     * @public
     */
    divide: function( value ) {
      assert && assert( value instanceof Fraction, 'value is not a Fraction: ' + value );

      this.numerator *= value.denominator;
      this.denominator *= value.numerator;
      return this;
    },

    /**
     * Divides this fraction by another fraction to create a new fraction.
     * The result is not reduced.
     * @param {Fraction} value
     * @returns {Fraction}
     * @public
     */
    divided: function( value ) {
      return this.copy().divide( value );
    },

    /**
     * Convenience method.
     * Adds an integer value to this fraction to create a new fraction.
     * The result is not reduced, and the denominator is the same as the denominator of this fraction.
     * @param {number} value - integer
     * @returns {Fraction}
     * @public
     */
    plusInteger: function( value ) {
      assert && assert( Util.isInteger( value ), 'value is not an integer: ' + value );
      return new Fraction( this.numerator + ( value * this.denominator ), this.denominator );
    },

    /**
     * Convenience method.
     * Subtracts an integer value from this fraction to create a new fraction.
     * The result is not reduced, and the denominator is the same as the denominator of this fraction.
     * @param {number} value - integer
     * @returns {Fraction}
     * @public
     */
    minusInteger: function( value ) {
      assert && assert( Util.isInteger( value ), 'value is not an integer: ' + value );
      return new Fraction( this.numerator - ( value * this.denominator ), this.denominator );
    },

    /**
     * Convenience method.
     * Multiplies this fraction by an integer to create a new fraction.
     * The result is not reduced, and the denominator is the same as the denominator of this fraction.
     * @param {number} value
     * @returns {Fraction}
     * @public
     */
    timesInteger: function( value ) {
      assert && assert( Util.isInteger( value ), 'value is not an integer: ' + value );
      return new Fraction( this.numerator * value, this.denominator );
    },

    /**
     * Convenience method.
     * Divides this fraction by an integer to create a new fraction.
     * This operation affects the value and sign of the denominator only, and the result is not reduced.
     * Careful! Division by zero is allowed here.
     * @param {number} value - integer
     * @returns {Fraction}
     * @public
     */
    dividedInteger: function( value ) {
      assert && assert( Util.isInteger( value ), 'value is not an integer: ' + value );
      return new Fraction( this.numerator, this.denominator * value );
    }
  }, {

    /**
     * Convenience method for constructing a fraction from an integer.
     * @param {number} value - must be an integer
     * @returns {Fraction}
     * @public
     * @static
     */
    fromInteger: function( value ) {
      return new Fraction( value, 1 );
    }
  } );

  // Used to avoid GC - NOTE: Do NOT move in front of the constructor/inherit, as it is creating a copy of the type
  // defined.
  var SCRATCH_FRACTION = new Fraction( 1, 1 );

  return Fraction;
} );<|endoftext|>


<commit_before>const Promise = require('bluebird');

const connection = require('../../../database');
const formatTime = require('../helpers/formattime');

function randomQuote(parameters, message) {
  let count = 1;
  const channel = message.channel;
  if (parameters.length !== 0) {
    if (!isNaN(parameters[0])) {
      count = parameters[0] < 10 ? parameters[0] : 10;
    }
  }
  return new Promise((resolve, reject) => {
    connection.query(`CALL get_rands(${count}, ${channel.id})`, (err, result) => {
      if (err) return reject(err);
      let returnMessage = '';
      result.forEach((q, i) => {
        if (i + 1 === result.length) return;
        const quote = q[0];
        const date = new Date(quote.time);
        returnMessage += `${quote.username}: "${quote.message}" (${formatTime(date, false)})\n`;
      });
      resolve(returnMessage);
    });
  });
}

function searchPhrase(parameters, message) {
  if (parameters.length === 0) return;
  const phrase = parameters.join(' ');
  const finalPhrase = `%${phrase}%`;
  return new Promise((resolve, reject) => {
    connection.query('SELECT username, message, time FROM messages WHERE message LIKE ? and channelId = ?', [finalPhrase, message.channel.id], (err, result) => {
      if (err) return reject(err);
      if (result.length === 0) return (resolve(`No messages found containing phrase "${phrase}" in this channel.`));
      const rand = Math.floor(Math.random() * result.length);
      const quote = result[rand];
      const date = new Date(quote.time);
      resolve(`${quote.username}: "${quote.message}" (${formatTime(date, false)})\n`);
    });
  });
}

function phraseCount(parameters, message) {
  const channel = message.channel;
  if (parameters.length === 0) return
  const phrase = parameters.join(' ');
  const finalPhrase = `%${phrase}%`;
  return new Promise((resolve, reject) => {
    connection.query('SELECT count(*) FROM messages WHERE message LIKE ? and channelId = ?', [finalPhrase, message.channel.id], (err, result) => {
      if (err) return reject(err);
      return (resolve(`${result[0]['count(*)']}`));
    });
  });
}

function findLastOccurance(parameters, message) {
  if (parameters.length === 0) return;
  const phrase = parameters.join(' ');
  const finalPhrase = `%${phrase}%`;
  return new Promise((resolve, reject) => {
    connection.query('SELECT username, message, time FROM messages WHERE channelId = ? and message LIKE ? ORDER BY time DESC LIMIT 1', [message.channel.id, finalPhrase], (err, result) => {
      if (err) return reject(err);
      if (result.length === 0) return (resolve(`No messages found containing phrase "${phrase}" in this channel.`));
      const rand = Math.floor(Math.random() * result.length);
      const quote = result[rand];
      const date = new Date(quote.time);
      resolve(`${quote.username}: "${quote.message}" (${formatTime(date, false)})\n`);
    });
  });
}

module.exports = {
  quote: randomQuote,
  randomquote: randomQuote,
  phrase: searchPhrase,
  phrasecount: phraseCount,
  lastphrase: findLastOccurance,
  lastoccurance: findLastOccurance,
  last: findLastOccurance,
};
<commit_msg>find first occurance command<commit_after>const Promise = require('bluebird');

const connection = require('../../../database');
const formatTime = require('../helpers/formattime');

function randomQuote(parameters, message) {
  let count = 1;
  const channel = message.channel;
  if (parameters.length !== 0) {
    if (!isNaN(parameters[0])) {
      count = parameters[0] < 10 ? parameters[0] : 10;
    }
  }
  return new Promise((resolve, reject) => {
    connection.query(`CALL get_rands(${count}, ${channel.id})`, (err, result) => {
      if (err) return reject(err);
      let returnMessage = '';
      result.forEach((q, i) => {
        if (i + 1 === result.length) return;
        const quote = q[0];
        const date = new Date(quote.time);
        returnMessage += `${quote.username}: "${quote.message}" (${formatTime(date, false)})\n`;
      });
      resolve(returnMessage);
    });
  });
}

function searchPhrase(parameters, message) {
  if (parameters.length === 0) return;
  const phrase = parameters.join(' ');
  const finalPhrase = `%${phrase}%`;
  return new Promise((resolve, reject) => {
    connection.query('SELECT username, message, time FROM messages WHERE message LIKE ? and channelId = ?', [finalPhrase, message.channel.id], (err, result) => {
      if (err) return reject(err);
      if (result.length === 0) return (resolve(`No messages found containing phrase "${phrase}" in this channel.`));
      const rand = Math.floor(Math.random() * result.length);
      const quote = result[rand];
      const date = new Date(quote.time);
      resolve(`${quote.username}: "${quote.message}" (${formatTime(date, false)})\n`);
    });
  });
}

function phraseCount(parameters, message) {
  const channel = message.channel;
  if (parameters.length === 0) return
  const phrase = parameters.join(' ');
  const finalPhrase = `%${phrase}%`;
  return new Promise((resolve, reject) => {
    connection.query('SELECT count(*) FROM messages WHERE message LIKE ? and channelId = ?', [finalPhrase, message.channel.id], (err, result) => {
      if (err) return reject(err);
      return (resolve(`${result[0]['count(*)']}`));
    });
  });
}

// TODO: Fix copy pasterino code
function findFirstOccurance(parameters, message) {
  if (parameters.length === 0) return;
  const phrase = parameters.join(' ');
  const finalPhrase = `%${phrase}%`;
  return new Promise((resolve, reject) => {
    connection.query('SELECT username, message, time FROM messages WHERE channelId = ? and message LIKE ? ORDER BY time ASC LIMIT 1', [message.channel.id, finalPhrase], (err, result) => {
      if (err) return reject(err);
      if (result.length === 0) return (resolve(`No messages found containing phrase "${phrase}" in this channel.`));
      const date = new Date(result[0].time);
      resolve(`${result[0].username}: "${result[0].message}" (${formatTime(date, false)})\n`);
    });
  });
}

function findLastOccurance(parameters, message) {
  if (parameters.length === 0) return;
  const phrase = parameters.join(' ');
  const finalPhrase = `%${phrase}%`;
  return new Promise((resolve, reject) => {
    connection.query('SELECT username, message, time FROM messages WHERE channelId = ? and message LIKE ? ORDER BY time DESC LIMIT 1', [message.channel.id, finalPhrase], (err, result) => {
      if (err) return reject(err);
      if (result.length === 0) return (resolve(`No messages found containing phrase "${phrase}" in this channel.`));
      console.log(result);
      const date = new Date(result[0].time);
      resolve(`${result[0].username}: "${result[0].message}" (${formatTime(date, false)})\n`);
    });
  });
}

module.exports = {
  quote: randomQuote,
  randomquote: randomQuote,
  phrase: searchPhrase,
  phrasecount: phraseCount,
  last: findLastOccurance,
  lastphrase: findLastOccurance,
  lastoccurance: findLastOccurance,
  first: findFirstOccurance,
  firstphrase: findFirstOccurance,
  firstoccurance: findFirstOccurance,
};
<|endoftext|>


<commit_before>/**
 * https://www.hackerrank.com/challenges/two-characters/problem
 *
 * String t always consists of two distinct alternating characters.
 * For example, if string t's two distinct characters are x and y, then t could
 * be xyxyx or yxyxy but not xxyy or xyyx.
 *
 * You can convert some string s to string t by deleting characters from s.
 * When you delete a character from s, you must delete all occurrences of it in s.
 * For example, if s = abaacdabd and you delete the character a, then the string
 * becomes bcdbd.
 *
 * Given s, convert it to the longest possible string t. Then print the length
 * of string t on a new line; if no string t can be formed from s, print 0 instead.
 */
process.stdin.resume();
process.stdin.setEncoding('ascii');

var input_stdin = "";
var input_stdin_array = "";
var input_currentline = 0;

process.stdin.on('data', function (data) {
    input_stdin += data;
});

process.stdin.on('end', function () {
    input_stdin_array = input_stdin.split("\n");
    main();
});

function readLine() {
    return input_stdin_array[input_currentline++];
}

function removeBut(s, a, b) {
    let result = '';
    for (let i = 0; i < s.length; i++) {
        if (s.charAt(i) === a || s.charAt(i) === b) {
            result += s.charAt(i);
        }
    }

    return result;
}

/////////////// ignore above this line ////////////////////

function solution1(n, s) {
    let prev = '';
    let chars = '', removed = '';

    // beabeefeabzf
    for (let i = 0; i < n; i++) {
        let c = s[i];
        if (chars.indexOf(c) < 0 && removed.indexOf(c) < 0) {
            chars += c;
        }

        if (prev === s[i]) {
            chars = chars.replace(c, '');
            removed += c;
        }

        prev = c;
    }

    let best = 0;

    for (let i = 0; i < chars.length - 1; i++) {
        for (let j = i + 1; j < chars.length; j++) {
            let r = removeBut(s, chars.charAt(i), chars.charAt(j));

            let pattern = true;
            for (let k = 0; k < r.length - 1; k++) {
                if (r.charAt(k) === r.charAt(k + 1)) {
                    pattern = false;
                    break;
                }
            }

            if (pattern && r.length > best) {
                best = r.length;
            }
        }
    }

    return best;
}

function main() {
    var n = parseInt(readLine());
    var s = readLine();
    var result = solution1(n, s);
    process.stdout.write(""+result+"\n");
}
<commit_msg>Add 'Monte Carlo' solution for the two characters challenge<commit_after>/**
 * https://www.hackerrank.com/challenges/two-characters/problem
 *
 * String t always consists of two distinct alternating characters.
 * For example, if string t's two distinct characters are x and y, then t could
 * be xyxyx or yxyxy but not xxyy or xyyx.
 *
 * You can convert some string s to string t by deleting characters from s.
 * When you delete a character from s, you must delete all occurrences of it in s.
 * For example, if s = abaacdabd and you delete the character a, then the string
 * becomes bcdbd.
 *
 * Given s, convert it to the longest possible string t. Then print the length
 * of string t on a new line; if no string t can be formed from s, print 0 instead.
 */
process.stdin.resume();
process.stdin.setEncoding('ascii');

var input_stdin = "";
var input_stdin_array = "";
var input_currentline = 0;

process.stdin.on('data', function (data) {
    input_stdin += data;
});

process.stdin.on('end', function () {
    input_stdin_array = input_stdin.split("\n");
    main();
});

function readLine() {
    return input_stdin_array[input_currentline++];
}

function removeBut(s, a, b) {
    let result = '';
    for (let i = 0; i < s.length; i++) {
        if (s.charAt(i) === a || s.charAt(i) === b) {
            result += s.charAt(i);
        }
    }

    return result;
}

function getRandomInt(min, max) {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min)) + min;
}

/////////////// ignore above this line ////////////////////

// Kind of a Monte Carlo solution
// Passes 80-90% of the unit tests :)
function solution2(n, s) {
    let best = 0;
    let tested = [];
    let iter = 0;

    while (iter < 1000) {
        let a = -1, b = -1;
        while (a === b || tested.indexOf(a * 10 + b) > 0) {
            a = getRandomInt(0, n);
            b = getRandomInt(0, n);
        }
        tested.push(a * 10 + b);

        let r = removeBut(s, s.charAt(a), s.charAt(b));

        let pattern = true;
        for (let k = 0; k < r.length - 1; k++) {
            if (r.charAt(k) === r.charAt(k + 1)) {
                pattern = false;
                break;
            }
        }

        if (pattern && r.length > best) {
            best = r.length;
        }

        iter++;
    }

    return best;
}

function solution1(n, s) {
    let prev = '', chars = '', removed = '';

    // beabeefeabzf
    for (let i = 0; i < n; i++) {
        let c = s[i];
        if (chars.indexOf(c) < 0 && removed.indexOf(c) < 0) {
            chars += c;
        }

        if (prev === s[i]) {
            chars = chars.replace(c, '');
            removed += c;
        }

        prev = c;
    }

    let best = 0;

    for (let i = 0; i < chars.length - 1; i++) {
        for (let j = i + 1; j < chars.length; j++) {
            let r = removeBut(s, chars.charAt(i), chars.charAt(j));

            let pattern = true;
            for (let k = 0; k < r.length - 1; k++) {
                if (r.charAt(k) === r.charAt(k + 1)) {
                    pattern = false;
                    break;
                }
            }

            if (pattern && r.length > best) {
                best = r.length;
            }
        }
    }

    return best;
}

function main() {
    var n = parseInt(readLine());
    var s = readLine();
    var result = solution2(n, s);
    process.stdout.write(""+result+"\n");
}
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchLeaderBoardData } from '../actions/index'

// Import React Table
import ReactTable from 'react-table';
import 'react-table/react-table.css';

class LeaderBoardContainer extends Component {

  constructor(props) {
    super(props);
    this.state = {tableData: this.modifyTableData()}
  }

  modifyTableData() {
    let ownData = null;
    let ownIndex = 100;
    for(var i=0; i < this.props.leaderBoardData.length; i++) {
      if(this.props.leaderBoardData[i].user_id === 15653) {
        ownData = this.props.leaderBoardData[i];
        ownIndex = i;
      }
    }
    if(this.props.leaderBoardData.length > 9) {
      let data = this.props.leaderBoardData.slice(0,10);
      if(ownIndex > 9) data.push(ownData);
      return data;
    } else {
      return this.props.leaderBoardData.slice(0);
    }
  }

  componentDidMount() {
    if(this.props.leaderboardUpdated === true) {
      console.log('didMount fetches leaderboard');
      this.props.fetchLeaderboard(this.props.dashboard_token, this.props.courseId);
    }
  }

  componentWillReceiveProps(nextProps) {
    if(this.props.leaderboardUpdated === false && nextProps.leaderboardUpdated === true) {
      this.props.fetchLeaderboard(nextProps.dashboard_token, nextProps.courseId);
    }
    if(this.props.leaderBoardData !== nextProps.leaderBoardData) {
      this.setState({tableData: this.modifyTableData()})
    }
  }

  render() {
    const columns = [
      {
        columns: [
          {
            Header: "Sijoitus",
            accessor: "index",
            Cell: row =>{
              if(row.original.user_id === 15653) {
                return (

{row.value}.  [ohtu_dashboard]

                )
              }
              return(

{row.value}.

              )
              }

          },
          {
            Header: "Pisteet",
            accessor: "points",
            sortable: false
          }
        ]
      }
    ];

    return (
      <ReactTable
        getTrProps = {(state, rowInfo, column) => {
          if(rowInfo) {
            return {
              style: {
                background: (() => {
                  if(rowInfo.original.user_id === 15653) {
                    return 'rgba(0,255,0,0.5)'
                  } else if(rowInfo.index % 2 !== 0){
                    return 'rgb(240, 240, 240)'
                  } else {
                    return 'rgb(247,247,247)';
                  }
                })()
              }
            }
          } else {
            return {
              style: {
                background: 'initial'
              }
            }
          }
        }}
        data={this.state.chartData}
        columns={columns}
        showPagination={false}
        pageSizeOptions={[this.state.tableData.length]}
        defaultPageSize={this.state.tableData.length}
        className="-striped -highlight"
        defaultSorted={[
          {
            id: "points",
            desc: true
          },
          {
            id: "index",
            asc: true
          }
        ]}
      />
    );
  }
}

const mapStateToProps = state => {
  return {
    leaderBoardData: state.APIcalls.leaderBoardData,
    courseId : state.courseData.courseId,
    dashboard_token: state.APIcalls.dashboard_token,
    leaderboardUpdated: state.APIcalls.leaderboardUpdated
  };
};

const mapDispatchToProps = dispatch => {
  return {
    fetchLeaderboard: (token, courseId) => dispatch(fetchLeaderBoardData(token, courseId))
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(LeaderBoardContainer);
<commit_msg>refactored LeaderBoardContainer's modifyTableData method<commit_after>import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchLeaderBoardData } from '../actions/index'

// Import React Table
import ReactTable from 'react-table';
import 'react-table/react-table.css';

class LeaderBoardContainer extends Component {

  constructor(props) {
    super(props);
    this.state = {tableData: this.modifyTableData(this.props.leaderBoardData)}
  }

  modifyTableData(storeData) {
    let ownData = null;
    let ownIndex = 100;
    for(var i=0; i < storeData.length; i++) {
      if(storeData[i].user_id === 15653) {
        ownData = storeData[i];
        ownIndex = i;
      }
    }
    if(storeData.length > 9) {
      let data = storeData.slice(0,10);
      if(ownIndex > 9) data.push(ownData);
      return data;
    } else {
      return storeData.slice(0);
    }
  }

  componentDidMount() {
    if(this.props.leaderboardUpdated === true) {
      console.log('didMount fetches leaderboard');
      this.props.fetchLeaderboard(this.props.dashboard_token, this.props.courseId);
    }
  }

  componentWillReceiveProps(nextProps) {
    if(this.props.leaderboardUpdated === false && nextProps.leaderboardUpdated === true) {
      this.props.fetchLeaderboard(nextProps.dashboard_token, nextProps.courseId);
    }
    if(this.props.leaderBoardData !== nextProps.leaderBoardData) {
      this.setState({tableData: this.modifyTableData(nextProps.leaderBoardData)});
    }
  }

  render() {
    const columns = [
      {
        columns: [
          {
            Header: "Sijoitus",
            accessor: "index",
            Cell: row =>{
              if(row.original.user_id === 15653) {
                return (

{row.value}.  [ohtu_dashboard]

                )
              }
              return(

{row.value}.

              )
              }

          },
          {
            Header: "Pisteet",
            accessor: "points",
            sortable: false
          }
        ]
      }
    ];

    return (
      <ReactTable
        getTrProps = {(state, rowInfo, column) => {
          if(rowInfo) {
            return {
              style: {
                background: (() => {
                  if(rowInfo.original.user_id === 15653) {
                    return 'rgba(0,255,0,0.5)'
                  } else if(rowInfo.index % 2 !== 0){
                    return 'rgb(240, 240, 240)'
                  } else {
                    return 'rgb(247,247,247)';
                  }
                })()
              }
            }
          } else {
            return {
              style: {
                background: 'initial'
              }
            }
          }
        }}
        data={this.state.tableData}
        columns={columns}
        showPagination={false}
        pageSizeOptions={[this.state.tableData.length]}
        defaultPageSize={this.state.tableData.length}
        className="-striped -highlight"
        defaultSorted={[
          {
            id: "points",
            desc: true
          },
          {
            id: "index",
            asc: true
          }
        ]}
      />
    );
  }
}

const mapStateToProps = state => {
  return {
    leaderBoardData: state.APIcalls.leaderBoardData,
    courseId : state.courseData.courseId,
    dashboard_token: state.APIcalls.dashboard_token,
    leaderboardUpdated: state.APIcalls.leaderboardUpdated
  };
};

const mapDispatchToProps = dispatch => {
  return {
    fetchLeaderboard: (token, courseId) => dispatch(fetchLeaderBoardData(token, courseId))
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(LeaderBoardContainer);
<|endoftext|>


<commit_before>/*
 * Copyright [1999-2015] Wellcome Trust Sanger Institute and the EMBL-European Bioinformatics Institute
 * Copyright [2016] EMBL-European Bioinformatics Institute
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

(function($) {
  $.fn.new_table_loading = function(config,data) {
    return {
      generate: function() {
        return 'working';
      },
      go: function($table,$el) {
        $('.new_table_thinking',$table).hide();
      },
      flux: function($table,type,change) {
        var $el = $('.new_table_'+type+'ing',$table);
        if(change) { $el.show(); } else { $el.hide(); }
      },
      position: data.position
    };
  };

})(jQuery);
<commit_msg>Fix dipped column header.<commit_after>/*
 * Copyright [1999-2015] Wellcome Trust Sanger Institute and the EMBL-European Bioinformatics Institute
 * Copyright [2016] EMBL-European Bioinformatics Institute
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

(function($) {
  $.fn.new_table_loading = function(config,data) {
    return {
      generate: function() {
        return 'working';
      },
      go: function($table,$el) {
        $('.new_table_thinking',$table).hide();
      },
      flux: function($table,type,change) {
        var $el = $('.new_table_'+type+'ing',$table);
        if(change) { $el.show(); } else { $el.hide(); }
      },
      position: data.position,
      position_order: 1
    };
  };

})(jQuery);
<|endoftext|>


<commit_before>/*
 * This program is part of the OpenLMIS logistics management information system platform software.
 * Copyright © 2013 VillageReach
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
 * You should have received a copy of the GNU Affero General Public License along with this program.  If not, see http://www.gnu.org/licenses.  For additional information contact info@OpenLMIS.org.
 */

(function() {

    'use strict';

    angular
        .module('openlmis.requisitions')
        .controller('InitiateRnrController', InitiateRnrController);

    InitiateRnrController.$inject = ['$scope', 'messageService', 'facility', 'PeriodFactory', 'RequisitionService', '$state', 'DateUtils', 'Status', 'LoadingModalService', 'Notification'];

    function InitiateRnrController($scope, messageService, facility, PeriodFactory, RequisitionService, $state, DateUtils, Status, LoadingModalService, Notification) {

        $scope.emergency = false;

        $scope.$watch('selectedProgram.item', function() {
            $scope.loadPeriods();
        }, true);

        $scope.facilities =[];

        $scope.selectedType = 0;

        $scope.loadPeriods = loadPeriods;

        $scope.periodGridOptions = {
            data: 'periodGridData',
            canSelectRows: false,
            displayFooter: false,
            displaySelectionCheckbox: false,
            enableColumnResize: true,
            showColumnMenu: false,
            showFilter: false,
            enableSorting: false,
            columnDefs: [
                {
                    field: 'name',
                    displayName: messageService.get('label.periods')
                }, {
                    field: 'startDate',
                    displayName: messageService.get('period.header.startDate'),
                    type: 'date',
                    cellFilter: DateUtils.FILTER
                }, {
                    field: 'endDate',
                    displayName: messageService.get('period.header.endDate'),
                    type: 'date',
                    cellFilter: DateUtils.FILTER
                }, {
                    field: 'rnrStatus',
                    displayName: messageService.get('label.rnr.status')
                }, {
                    name: 'proceed',
                    displayName: '',
                    cellTemplate: 'requisitions/init-rnr-button.html'
                }
            ]
        };

        if (facility) {
            $scope.facilityDisplayName = facility.code + '-' + facility.name;
            $scope.selectedFacilityId = facility.id;
            $scope.programs = facility.supportedPrograms;
            if (_.isEmpty($scope.programs)) {
                $scope.error = messageService.get("msg.no.program.available");
            } else if ($scope.programs.length === 1) {
                $scope.selectedProgram = $scope.programs[0];
                $scope.loadPeriods();
            }
        } else {
            $scope.facilityDisplayName = messageService.get("label.none.assigned");
            $scope.error = messageService.get("error.rnr.user.facility.not.assigned");
        }

        $scope.programOptionMessage = function () {
            return $scope.programs === undefined || _.isEmpty($scope.programs) ? messageService.get("label.none.assigned") : messageService.get("label.select.program");
        };

        function loadPeriods() {
            $scope.periodGridData = [];
            if (!($scope.selectedProgram && $scope.selectedProgram.item  && $scope.selectedFacilityId)) {
                return;
            }
            LoadingModalService.open();
            PeriodFactory.get($scope.selectedProgram.item.id, $scope.selectedFacilityId, $scope.emergency).then
            (function(data) {
                if (data.length === 0) {
                    Notification.error('msg.no.period.available');
                } else {
                    $scope.periodGridData = data;
                    $scope.error = "";
                }
                data.forEach(function (period) {
                    if ($scope.emergency && (period.rnrStatus == Status.AUTHORIZED ||
                    period.rnrStatus == Status.APPROVED ||
                    period.rnrStatus == Status.RELEASED)) {
                        period.rnrStatus = messageService.get("msg.rnr.not.started");
                    }
                });
                LoadingModalService.close();
            }).catch(function() {
                Notification.error('msg.no.period.available');
                LoadingModalService.close();
            });
        };

        $scope.initRnr = function (selectedPeriod) {
            $scope.error = "";
            if (!selectedPeriod.rnrId ||
            selectedPeriod.rnrStatus == messageService.get("msg.rnr.not.started")){
                RequisitionService.initiate($scope.selectedFacilityId,
                $scope.selectedProgram.item.id,
                selectedPeriod.id,
                $scope.emergency).then(
                function (data) {
                    $state.go('requisitions.requisition', {
                        rnr: data.id
                    });
                }, function () {
                    Notification.error('error.requisition.not.initiated');
                });
            } else {
                $state.go('requisitions.requisition', {
                    rnr: selectedPeriod.rnrId
                });
            }
        };
    }
})();<commit_msg>OLMIS-1262 Documented InitRnR controller<commit_after>/*
 * This program is part of the OpenLMIS logistics management information system platform software.
 * Copyright © 2013 VillageReach
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
 * You should have received a copy of the GNU Affero General Public License along with this program.  If not, see http://www.gnu.org/licenses.  For additional information contact info@OpenLMIS.org.
 */

(function() {

    'use strict';

    /**
     * @ngdoc controller
     * @name openlmis.requisitions.InitiateRnrController
     * @description
     * Controller responsible for actions connected with displaying available periods and
     * initiating or navigating to an existing requisition.
     */
    angular
        .module('openlmis.requisitions')
        .controller('InitiateRnrController', InitiateRnrController);

    InitiateRnrController.$inject = ['$scope', 'messageService', 'facility', 'PeriodFactory', 'RequisitionService', '$state', 'DateUtils', 'Status', 'LoadingModalService', 'Notification'];

    function InitiateRnrController($scope, messageService, facility, PeriodFactory, RequisitionService, $state, DateUtils, Status, LoadingModalService, Notification) {

        /**
         * @ngdoc property
         * @name emergency
         * @propertyOf openlmis.requisitions.InitiateRnrController
         *
         * @description
         * Holds currently selected requisition type (standard/emergency)
         */
        $scope.emergency = false;

        $scope.$watch('selectedProgram.item', function() {
            $scope.loadPeriods();
        }, true);

        /**
         * @ngdoc property
         * @name facilities
         * @propertyOf openlmis.requisitions.InitiateRnrController
         *
         * @description
         * Holds available facilities based on the selected type and/or programs
         */
        $scope.facilities = [];

        /**
         * @ngdoc property
         * @name selectedType
         * @propertyOf openlmis.requisitions.InitiateRnrController
         *
         * @description
         * Holds currently selected facility selection type:
         *  0 - my facility
         *  1 - supervised facility
         */
        $scope.selectedType = 0;

        /**
         * @ngdoc property
         * @name periodGridOptions
         * @propertyOf openlmis.requisitions.InitiateRnrController
         *
         * @description
         * Holds configuration of the period grid
         */
        $scope.periodGridOptions = {
            data: 'periodGridData',
            canSelectRows: false,
            displayFooter: false,
            displaySelectionCheckbox: false,
            enableColumnResize: true,
            showColumnMenu: false,
            showFilter: false,
            enableSorting: false,
            columnDefs: [
                {
                    field: 'name',
                    displayName: messageService.get('label.periods')
                }, {
                    field: 'startDate',
                    displayName: messageService.get('period.header.startDate'),
                    type: 'date',
                    cellFilter: DateUtils.FILTER
                }, {
                    field: 'endDate',
                    displayName: messageService.get('period.header.endDate'),
                    type: 'date',
                    cellFilter: DateUtils.FILTER
                }, {
                    field: 'rnrStatus',
                    displayName: messageService.get('label.rnr.status')
                }, {
                    name: 'proceed',
                    displayName: '',
                    cellTemplate: 'requisitions/init-rnr-button.html'
                }
            ]
        };

        // Functions

        $scope.loadPeriods = loadPeriods;

        $scope.programOptionMessage = programOptionMessage;

        $scope.initRnr = initRnr;

        if (facility) {
            $scope.facilityDisplayName = facility.code + '-' + facility.name;
            $scope.selectedFacilityId = facility.id;
            $scope.programs = facility.supportedPrograms;
            if (_.isEmpty($scope.programs)) {
                $scope.error = messageService.get("msg.no.program.available");
            } else if ($scope.programs.length === 1) {
                $scope.selectedProgram = $scope.programs[0];
                $scope.loadPeriods();
            }
        } else {
            $scope.facilityDisplayName = messageService.get("label.none.assigned");
            $scope.error = messageService.get("error.rnr.user.facility.not.assigned");
        }

        /**
         * @ngdoc function
         * @name programOptionMessage
         * @methodOf openlmis.requisitions.InitiateRnrController
         *
         * @description
         * Determines a proper message for the programs dropdown, based on the presence of programs.
         *
         * @return {String} localized message
         */
        function programOptionMessage() {
            return $scope.programs === undefined || _.isEmpty($scope.programs) ? messageService.get("label.none.assigned") : messageService.get("label.select.program");
        };

        /**
         * @ngdoc function
         * @name loadPeriods
         * @methodOf openlmis.requisitions.InitiateRnrController
         *
         * @description
         * Responsible for displaying and updating a grid, containing available periods for the
         * selected program, facility and type. It will set an error message if no periods have
         * been found for the given parameters. It will also filter out periods for which there
         * already exists a requisition with an AUTHORIZED, APPROVED or RELEASED status.
         */
        function loadPeriods() {
            $scope.periodGridData = [];
            if (!($scope.selectedProgram && $scope.selectedProgram.item  && $scope.selectedFacilityId)) {
                return;
            }
            LoadingModalService.open();
            PeriodFactory.get($scope.selectedProgram.item.id, $scope.selectedFacilityId, $scope.emergency).then
            (function(data) {
                if (data.length === 0) {
                    Notification.error('msg.no.period.available');
                } else {
                    $scope.periodGridData = data;
                    $scope.error = "";
                }
                data.forEach(function (period) {
                    if ($scope.emergency && (period.rnrStatus == Status.AUTHORIZED ||
                    period.rnrStatus == Status.APPROVED ||
                    period.rnrStatus == Status.RELEASED)) {
                        period.rnrStatus = messageService.get("msg.rnr.not.started");
                    }
                });
                LoadingModalService.close();
            }).catch(function() {
                Notification.error('msg.no.period.available');
                LoadingModalService.close();
            });
        };

        /**
         * @ngdoc function
         * @name initRnr
         * @methodOf openlmis.requisitions.InitiateRnrController
         *
         * @description
         * Responsible for initiating and/or navigating to the requisition, based on the specified
         * period. If the provided period does not have a requisition associated with it, one
         * will be initiated for the currently selected facility, program, emergency status and
         * provided period. In case of a successful response, a redirect to the newly initiated
         * requisition is made. Otherwise an error about failed requisition initiate is shown. If
         * the provided period is already associated with a requisition, the function only
         * performs a redirect to that requisition.
         *
         * @param {Object} selectedPeriod  a period to initiate or proceed with the requisition for
         */
        function initRnr(selectedPeriod) {
            $scope.error = "";
            if (!selectedPeriod.rnrId ||
            selectedPeriod.rnrStatus == messageService.get("msg.rnr.not.started")){
                RequisitionService.initiate($scope.selectedFacilityId,
                $scope.selectedProgram.item.id,
                selectedPeriod.id,
                $scope.emergency).then(
                function (data) {
                    $state.go('requisitions.requisition', {
                        rnr: data.id
                    });
                }, function () {
                    Notification.error('error.requisition.not.initiated');
                });
            } else {
                $state.go('requisitions.requisition', {
                    rnr: selectedPeriod.rnrId
                });
            }
        };
    }
})();<|endoftext|>


<commit_before>const log = require('../util/logger.js')
const config = require('../config.js')
const dbOpsGuilds = require('../util/db/guilds.js')
const Translator = require('../structs/Translator.js')

module.exports = async (bot, message) => {
  const locale = message.content.split(' ')[1]
  try {
    let guildRss = await dbOpsGuilds.get(message.guild.id)
    const guildLocale = guildRss ? guildRss.locale : undefined
    const translate = Translator.createLocaleTranslator(guildLocale)
    const prefix = guildRss && guildRss.prefix ? guildRss.prefix : config.bot.prefix
    const localeList = Translator.getLocales()

    if (!locale) {
      return await message.channel.send(translate('commands.rsslocale.helpText', { prefix, localeList: localeList.join('`, `') }))
    }

    if (guildLocale === locale) {
      return await message.channel.send(translate('commands.rsslocale.alreadySet', { locale }))
    }

    if (locale !== 'reset' && !localeList.includes(locale)) {
      return await message.channel.send(translate('commands.rsslocale.setNone', { prefix, locale, localeList: localeList.join('`, `') }))
    }

    // Reset
    if (locale === 'reset') {
      if (!guildRss || !guildRss.locale) {
        return await message.channel.send(translate('commands.rsslocale.resetNone'))
      }
      delete guildRss.locale
      await dbOpsGuilds.update(guildRss)
      return await message.channel.send(translate('commands.rsslocale.resetSuccess', { locale: config.bot.locale }))
    }

    if (config.bot.locale === locale) {
      return await message.channel.send(translate('commands.rsslocale.resetNoDefault', { locale, prefix }))
    }

    if (!guildRss) guildRss = { id: message.guild.id, name: message.guild.name, locale }
    else guildRss.locale = locale

    await dbOpsGuilds.update(guildRss)
    await message.channel.send(Translator.translate('commands.rsslocale.setSuccess', locale, { locale }))
  } catch (err) {
    log.command.warning(`rsslocale`, message.guild, err)
    if (err.code !== 50013) message.channel.send(err.message).catch(err => log.command.warning('rsslocale 1', message.guild, err))
  }
}
<commit_msg>Remove defualt locale from locale list in rsslocale<commit_after>const log = require('../util/logger.js')
const config = require('../config.js')
const dbOpsGuilds = require('../util/db/guilds.js')
const Translator = require('../structs/Translator.js')

module.exports = async (bot, message) => {
  const locale = message.content.split(' ')[1]
  try {
    let guildRss = await dbOpsGuilds.get(message.guild.id)
    const guildLocale = guildRss ? guildRss.locale : undefined
    const translate = Translator.createLocaleTranslator(guildLocale)
    const prefix = guildRss && guildRss.prefix ? guildRss.prefix : config.bot.prefix
    const localeList = Translator.getLocales()

    localeList.splice(localeList.indexOf(config.bot.locale), 1)
    const printLocaleList = localeList.join('`, `')
    if (!locale) {
      return await message.channel.send(translate('commands.rsslocale.helpText', { prefix, localeList: printLocaleList }))
    }

    if (guildLocale === locale) {
      return await message.channel.send(translate('commands.rsslocale.alreadySet', { locale }))
    }

    if (locale !== 'reset' && !localeList.includes(locale)) {
      return await message.channel.send(translate('commands.rsslocale.setNone', { prefix, locale, localeList: printLocaleList }))
    }

    // Reset
    if (locale === 'reset') {
      if (!guildRss || !guildRss.locale) {
        return await message.channel.send(translate('commands.rsslocale.resetNone'))
      }
      delete guildRss.locale
      await dbOpsGuilds.update(guildRss)
      return await message.channel.send(Translator.translate('commands.rsslocale.resetSuccess', config.bot.locale, { locale: config.bot.locale }))
    }

    if (config.bot.locale === locale) {
      return await message.channel.send(translate('commands.rsslocale.resetNoDefault', { locale, prefix }))
    }

    if (!guildRss) guildRss = { id: message.guild.id, name: message.guild.name, locale }
    else guildRss.locale = locale

    await dbOpsGuilds.update(guildRss)
    await message.channel.send(Translator.translate('commands.rsslocale.setSuccess', locale, { locale }))
  } catch (err) {
    log.command.warning(`rsslocale`, message.guild, err)
    if (err.code !== 50013) message.channel.send(err.message).catch(err => log.command.warning('rsslocale 1', message.guild, err))
  }
}
<|endoftext|>


<commit_before>// Copyright 2014-2019, University of Colorado Boulder

/**
 * drag handler for objects that can be moved by the user, used to constrain objects to the play area and to prevent
 * them from being dragged through one another
 */
define( require => {
  'use strict';

  const energyFormsAndChanges = require( 'ENERGY_FORMS_AND_CHANGES/energyFormsAndChanges' );
  const DragListener = require( 'SCENERY/listeners/DragListener' );
  const Vector2 = require( 'DOT/Vector2' );

  class ThermalElementDragHandler extends DragListener {

    /**
     * @param {UserMovableModelElement} modelElement
     * @param {Node} screenViewChildNode - the node that will be used to convert pointer positions to global coordinates
     * @param {ModelViewTransform2} modelViewTransform
     * @param {function} constrainPosition
     * @param {BooleanProperty} simIsPlayingProperty
     */
    constructor(
      modelElement,
      screenViewChildNode,
      modelViewTransform,
      constrainPosition,
      simIsPlayingProperty
    ) {

      const dragStartOffset = new Vector2();
      let currentTarget = null;

      super( {

        // allow moving a finger (touch) across a screenViewChildNode to pick it up
        allowTouchSnag: true,

        start: event => {

          // make sure the sim is playing when an element is grabbed - this will resume the sim if it is paused
          simIsPlayingProperty.value = true;
          modelElement.userControlledProperty.set( true );
          const modelElementViewPosition = modelViewTransform.modelToViewPosition( modelElement.positionProperty.get() );
          currentTarget = event.currentTarget;
          const dragStartPosition = currentTarget.globalToParentPoint( event.pointer.point );
          dragStartOffset.setXY(
            dragStartPosition.x - modelElementViewPosition.x,
            dragStartPosition.y - modelElementViewPosition.y
          );
        },

        drag: event => {
          const dragPosition = currentTarget.globalToParentPoint( event.pointer.point );
          const modelElementViewPosition = dragPosition.minus( dragStartOffset );
          const modelElementPosition = modelViewTransform.viewToModelPosition( modelElementViewPosition );
          modelElement.positionProperty.set( constrainPosition( modelElement, modelElementPosition ) );
        },

        end: () => {
          modelElement.userControlledProperty.set( false );
          currentTarget = null;
        }
      } );
    }
  }

  return energyFormsAndChanges.register( 'ThermalElementDragHandler', ThermalElementDragHandler );
} );
<commit_msg>Made Vector2 constructor arguments required, see https://github.com/phetsims/dot/issues/85<commit_after>// Copyright 2014-2019, University of Colorado Boulder

/**
 * drag handler for objects that can be moved by the user, used to constrain objects to the play area and to prevent
 * them from being dragged through one another
 */
define( require => {
  'use strict';

  const energyFormsAndChanges = require( 'ENERGY_FORMS_AND_CHANGES/energyFormsAndChanges' );
  const DragListener = require( 'SCENERY/listeners/DragListener' );
  const Vector2 = require( 'DOT/Vector2' );

  class ThermalElementDragHandler extends DragListener {

    /**
     * @param {UserMovableModelElement} modelElement
     * @param {Node} screenViewChildNode - the node that will be used to convert pointer positions to global coordinates
     * @param {ModelViewTransform2} modelViewTransform
     * @param {function} constrainPosition
     * @param {BooleanProperty} simIsPlayingProperty
     */
    constructor(
      modelElement,
      screenViewChildNode,
      modelViewTransform,
      constrainPosition,
      simIsPlayingProperty
    ) {

      const dragStartOffset = new Vector2( 0, 0 );
      let currentTarget = null;

      super( {

        // allow moving a finger (touch) across a screenViewChildNode to pick it up
        allowTouchSnag: true,

        start: event => {

          // make sure the sim is playing when an element is grabbed - this will resume the sim if it is paused
          simIsPlayingProperty.value = true;
          modelElement.userControlledProperty.set( true );
          const modelElementViewPosition = modelViewTransform.modelToViewPosition( modelElement.positionProperty.get() );
          currentTarget = event.currentTarget;
          const dragStartPosition = currentTarget.globalToParentPoint( event.pointer.point );
          dragStartOffset.setXY(
            dragStartPosition.x - modelElementViewPosition.x,
            dragStartPosition.y - modelElementViewPosition.y
          );
        },

        drag: event => {
          const dragPosition = currentTarget.globalToParentPoint( event.pointer.point );
          const modelElementViewPosition = dragPosition.minus( dragStartOffset );
          const modelElementPosition = modelViewTransform.viewToModelPosition( modelElementViewPosition );
          modelElement.positionProperty.set( constrainPosition( modelElement, modelElementPosition ) );
        },

        end: () => {
          modelElement.userControlledProperty.set( false );
          currentTarget = null;
        }
      } );
    }
  }

  return energyFormsAndChanges.register( 'ThermalElementDragHandler', ThermalElementDragHandler );
} );
<|endoftext|>


<commit_before>import Routes from 'routes';
import MockData from './MockData';

function correctPath(path) {
  let uri = path.replace(/^\/?|\/?$/, '');
  let segments = uri.split('/');

  return '/' +
    segments
    .map(s => {
      let segment = s;
      if (segment.charAt(0) === '{' && segment.charAt(segment.length - 1) === '}') {
        segment = segment.slice(1, -1);
        return ':' + segment;
      }

      return segment;
    })
    .join('/');
}

// wrapped MockData to satisfy eslint's no funciton definitions inside of loops
function mock(schema) {
  return MockData(schema);
}

function generateResponse(potentialResponses) {
  for (let k in potentialResponses) {
    if (k === 'default') continue;

    let responseSchema = potentialResponses[k];
    let responseCode = parseInt(k, 10);
    if (responseCode > 199 && responseCode < 300) {
      return mock.bind(null, responseSchema);
    }
  }

  if (potentialResponses.default) {
    return mock.bind(null, potentialResponses.default);
  }
}

export default function ConfigureRouter(paths) {
  let router = new Routes();

  for (let pk in paths) {
    if (!paths.hasOwnProperty(pk)) continue;

    let path = paths[pk];
    let route = correctPath(pk);

    for (let mk in path) {
      if (!path.hasOwnProperty(mk)) continue;

      let method = path[mk];

      if (process.env.debug) {
        console.log('ADDING ROUTE: ', mk.toUpperCase() + ' ' + pk);
      }

      let respond = generateResponse(method.responses, pk);
      router.addRoute('/' + mk + route, respond);
    }
  }

  return router;
}
<commit_msg>remove wildcards<commit_after>import Routes from 'routes';
import MockData from './MockData';

function correctPath(path) {
  let uri = path.replace(/^\/?|\/?$/, '');
  let segments = uri.split('/');

  return '/' +
    segments
    .map(s => {
      let segment = s;
      if (segment.charAt(0) === '{' && segment.charAt(segment.length - 1) === '}') {
        segment = segment.slice(1, -1);
        segment = segment.replace(/(\-|\?|\*)/g, ''); //remove wildcards
        return ':' + segment;
      }

      return segment;
    })
    .join('/');
}

// wrapped MockData to satisfy eslint's no funciton definitions inside of loops
function mock(schema) {
  return MockData(schema);
}

function generateResponse(potentialResponses) {
  for (let k in potentialResponses) {
    if (k === 'default') continue;

    let responseSchema = potentialResponses[k];
    let responseCode = parseInt(k, 10);
    if (responseCode > 199 && responseCode < 300) {
      return mock.bind(null, responseSchema);
    }
  }

  if (potentialResponses.default) {
    return mock.bind(null, potentialResponses.default);
  }
}

export default function ConfigureRouter(paths) {
  let router = new Routes();

  for (let pk in paths) {
    if (!paths.hasOwnProperty(pk)) continue;

    let path = paths[pk];
    let route = correctPath(pk);

    for (let mk in path) {
      if (!path.hasOwnProperty(mk)) continue;

      let method = path[mk];

      if (process.env.debug) {
        console.log('ADDING ROUTE: ', mk.toUpperCase() + ' ' + pk);
      }

      let respond = generateResponse(method.responses, pk);
      router.addRoute('/' + mk + route, respond);
    }
  }

  return router;
}
<|endoftext|>


<commit_before>
'use strict'

const _ = require('lodash')
const config = require('../config')
const scriptures = require("../data/scriptures")

function getScripture(scriptures) {
	let num = Math.floor(Math.random() * scriptures.length)
	return scriptures.length
}

const msgDefaults = {
  response_type: 'in_channel',
  username: 'Stubot',
  icon_emoji: config('ICON_EMOJI')
}

let attachments = [
  {
    title: 'Stubot will retrieve a random scriptural thought for you.',
    color: '#2FA44F',
    text: "There are " + scriptures.length + "scriptures.",
    mrkdwn_in: ['text']
  },
]

const handler = (payload, res) => {
  let msg = _.defaults({
    channel: payload.channel_name,
    attachments: attachments
  }, msgDefaults)

  res.set('content-type', 'application/json')
  res.status(200).json(msg)
  return
}

module.exports = { pattern: /scripture/ig, handler: handler }
<commit_msg>Added count function.<commit_after>
'use strict'

const _ = require('lodash')
const fs = require('fs')
const config = require('../config')
const scriptures = require("../data/scriptures")

function scriptureCount(scriptures) {
	var scripture
	var count = 0

	for(scripture in scriptures) {
		count++
	}
	return count
}

function getScripture(scriptures) {
	let num = Math.floor(Math.random() * scriptures.length)
	return scriptures.length
}

const msgDefaults = {
  response_type: 'in_channel',
  username: 'Stubot',
  icon_emoji: config('ICON_EMOJI')
}

let attachments = [
  {
    title: 'Stubot will retrieve a random scriptural thought for you.',
    color: '#2FA44F',
    text: "There are " + scriptureCount(scriptures) + " scriptures.",
    mrkdwn_in: ['text']
  },
]

const handler = (payload, res) => {
  let msg = _.defaults({
    channel: payload.channel_name,
    attachments: attachments
  }, msgDefaults)

  res.set('content-type', 'application/json')
  res.status(200).json(msg)
  return
}

module.exports = { pattern: /scripture/ig, handler: handler }
<|endoftext|>