<commit_before>// Copyright 2013-2015, University of Colorado Boulder

/**
 * Horizontal slider.
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( function( require ) {
  'use strict';

  // modules
  var Dimension2 = require( 'DOT/Dimension2' );
  var HSliderThumb = require( 'SUN/HSliderThumb' );
  var HSliderTrack = require( 'SUN/HSliderTrack' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Input = require( 'SCENERY/input/Input' );
  var LinearFunction = require( 'DOT/LinearFunction' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Path = require( 'SCENERY/nodes/Path' );
  var Property = require( 'AXON/Property' );
  var Shape = require( 'KITE/Shape' );
  var sun = require( 'SUN/sun' );
  var Tandem = require( 'TANDEM/Tandem' );
  var TandemSimpleDragHandler = require( 'TANDEM/scenery/input/TandemSimpleDragHandler' );
  var Util = require( 'DOT/Util' );

  // phet-io modules
  var THSlider = require( 'ifphetio!PHET_IO/types/sun/THSlider' );

  /**
   * @param {Property.<number>} valueProperty
   * @param { {min:number, max:number} } range
   * @param {Object} [options]
   * @constructor
   */
  function HSlider( valueProperty, range, options ) {

    var self = this;
    Node.call( this );

    options = _.extend( {

      // track
      trackSize: new Dimension2( 100, 5 ),
      trackFillEnabled: 'white',
      trackFillDisabled: 'gray',
      trackStroke: 'black',
      trackLineWidth: 1,

      // {Node} optional thumb, replaces the default.
      // Client is responsible for highlighting, disabling and pointer areas.
      // The thumb will be centered in the track.
      thumbNode: null,

      // Options for the default thumb, ignored if thumbNode is set
      thumbSize: new Dimension2( 22, 45 ),
      thumbFillEnabled: 'rgb(50,145,184)',
      thumbFillHighlighted: 'rgb(71,207,255)',
      thumbFillDisabled: '#F0F0F0',
      thumbStroke: 'black',
      thumbLineWidth: 1,
      thumbCenterLineStroke: 'white',
      thumbTouchAreaXDilation: 11,
      thumbTouchAreaYDilation: 11,
      thumbMouseAreaXDilation: 0,
      thumbMouseAreaYDilation: 0,

      // ticks
      tickLabelSpacing: 6,
      majorTickLength: 25,
      majorTickStroke: 'black',
      majorTickLineWidth: 1,
      minorTickLength: 10,
      minorTickStroke: 'black',
      minorTickLineWidth: 1,

      // other
      cursor: 'pointer',
      enabledProperty: new Property( true ),
      enabledRangeProperty: new Property( range ), // controls the portion of the slider that is enabled
      snapValue: null, // if specified, slider will snap to this value on end drag
      startDrag: function() {}, // called when a drag sequence starts
      endDrag: function() {}, // called when a drag sequence ends
      constrainValue: function( value ) { return value; }, // called before valueProperty is set

      // phet-io
      tandem: Tandem.tandemRequired(),
      phetioType: THSlider
    }, options );

    // @public
    this.enabledProperty = options.enabledProperty;
    this.enabledRangeProperty = options.enabledRangeProperty;

    // @private options needed by prototype functions that add ticks
    this.tickOptions = _.pick( options, 'tickLabelSpacing',
      'majorTickLength', 'majorTickStroke', 'majorTickLineWidth',
      'minorTickLength', 'minorTickStroke', 'minorTickLineWidth' );

    // @private
    this._snapValue = options.snapValue;

    // @private ticks are added to these parents, so they are behind the knob
    this.majorTicksParent = new Node();
    this.minorTicksParent = new Node();
    this.addChild( this.majorTicksParent );
    this.addChild( this.minorTicksParent );

    // @private mapping between value and track position
    this.valueToPosition = new LinearFunction( range.min, range.max, 0, options.trackSize.width, true /* clamp */ );

    // snap to a value if value is within range, used by HSlider and HSliderTrack
    var snapToValue = function( value ) {
      if ( value <= range.max && value >= range.min ) {
        valueProperty.set( value );
      }
      else {
        throw new Error( 'value is out of range: ' + value );
      }
    };

    // @private track
    this.track = new HSliderTrack( valueProperty, this.valueToPosition, snapToValue, {

      // propagate options that are specific to HSliderTrack
      size: options.trackSize,
      fillEnabled: options.trackFillEnabled,
      fillDisabled: options.trackFillDisabled,
      stroke: options.trackStroke,
      lineWidth: options.trackLineWidth,
      enabledProperty: options.enabledProperty,
      startDrag: options.startDrag,
      endDrag: options.endDrag,
      snapValue: options.snapValue,
      constrainValue: options.constrainValue,

      // phet-io
      tandem: options.tandem.createTandem( 'track' )
    } );
    this.track.centerX = this.valueToPosition( ( range.max + range.min ) / 2 );
    this.addChild( this.track );

    // thumb
    var thumb = options.thumbNode || new HSliderThumb( this.enabledProperty, {

        // propagate options that are specific to HSliderThumb
        size: options.thumbSize,
        fillEnabled: options.thumbFillEnabled,
        fillHighlighted: options.thumbFillHighlighted,
        fillDisabled: options.thumbFillDisabled,
        stroke: options.thumbStroke,
        lineWidth: options.thumbLineWidth,
        centerLineStroke: options.thumbCenterLineStroke,
        tandem: options.tandem.createTandem( 'thumb' )
      } );

    // do this outside of options hash, so that it applied to both default and custom thumbs
    thumb.centerY = this.track.centerY;
    this.addChild( thumb );

    // touchArea for the default thumb. If a custom thumb is provided, the client is responsible for its touchArea.
    if ( !options.thumbNode && ( options.thumbTouchAreaXDilation || options.thumbTouchAreaYDilation ) ) {
      thumb.touchArea = thumb.localBounds.dilatedXY( options.thumbTouchAreaXDilation, options.thumbTouchAreaYDilation );
    }

    // mouseArea for the default thumb. If a custom thumb is provided, the client is responsible for its mouseArea.
    if ( !options.thumbNode && ( options.thumbMouseAreaXDilation || options.thumbMouseAreaYDilation ) ) {
      thumb.mouseArea = thumb.localBounds.dilatedXY( options.thumbMouseAreaXDilation, options.thumbMouseAreaYDilation );
    }

    // update value when thumb is dragged
    var clickXOffset = 0; // x-offset between initial click and thumb's origin
    var thumbInputListener = new TandemSimpleDragHandler( {

      tandem: options.tandem.createTandem( 'thumbInputListener' ),

      allowTouchSnag: true,

      start: function( event, trail ) {
        if ( self.enabledProperty.get() ) {
          options.startDrag();

          var transform = trail.subtrailTo( self ).getTransform();
          clickXOffset = transform.inversePosition2( event.pointer.point ).x - thumb.x;
        }
      },

      drag: function( event, trail ) {
        if ( self.enabledProperty.get() ) {
          var transform = trail.subtrailTo( self ).getTransform(); // we only want the transform to our parent
          var x = transform.inversePosition2( event.pointer.point ).x - clickXOffset;
          var newValue = self.valueToPosition.inverse( x );

          valueProperty.set( options.constrainValue( newValue ) );
        }
      },

      end: function() {
        if ( self.enabledProperty.get() ) {
          if ( typeof self._snapValue === 'number' ) {
            snapToValue( self._snapValue );
          }
          options.endDrag();
        }
      }
    } );
    thumb.addInputListener( thumbInputListener );

    //TODO This is experimental code. Decide how this affects data collection.
    // Keyboard accessibility
    thumb.addInputListener( {
      keydown: function( event, trail ) {
        if ( self.enabledProperty.get() ) {
          var keyCode = event.domEvent.keyCode;
          var delta = keyCode === Input.KEY_LEFT_ARROW || keyCode === Input.KEY_DOWN_ARROW ? -1 :
                      keyCode === Input.KEY_RIGHT_ARROW || keyCode === Input.KEY_UP_ARROW ? +1 :
                      0;
          var clampedValue = Util.clamp( valueProperty.get() + (range.max - range.min) * 0.1 * delta, range.min, range.max );
          valueProperty.set( options.constrainValue( clampedValue ) );
        }
      }
    } );

    // enable/disable
    var enabledObserver = function( enabled ) {
      self.cursor = self.enabledProperty.get() ? options.cursor : 'default';
      if ( !enabled ) {
        if ( thumbInputListener.dragging ) { thumbInputListener.endDrag(); }
      }
      self.pickable = enabled;
    };
    this.enabledProperty.link( enabledObserver ); // must be unlinked in disposeHSlider

    // update thumb location when value changes
    var valueObserver = function( value ) {
      thumb.centerX = self.valueToPosition( value );
    };
    valueProperty.link( valueObserver ); // must be unlinked in disposeHSlider

    // when the enabled range changes, the value to position linear function must change as well
    var enabledRangeObserver = function( enabledRange ) {

      assert && assert( enabledRange.min >= range.min && enabledRange.max <= range.max, 'enabledRange is out of range' );

      var initialValueToPosition = new LinearFunction( range.min, range.max, 0, options.trackSize.width, true /* clamp */ );
      var min = initialValueToPosition( enabledRange.min );
      var max = initialValueToPosition( enabledRange.max );

      // update the geometry of the enabled track
      self.track.updateEnabledTrackWidth( min, max );

      // update the function that maps value to position for the track and the slider
      self.valueToPosition = new LinearFunction( enabledRange.min, enabledRange.max, min, max, true /* clamp */ );
      self.track.valueToPosition = self.valueToPosition;

      // clamp the value to the enabled range if it changes
      valueProperty.set( Util.clamp( valueProperty.value, enabledRange.min, enabledRange.max ) );
    };
    this.enabledRangeProperty.link( enabledRangeObserver ); // needs to be unlinked in dispose function

    // @private Called by dispose
    this.disposeHSlider = function() {
      thumb.dispose && thumb.dispose(); // in case a custom thumb is provided via options.thumbNode that doesn't implement dispose
      self.track.dispose();
      valueProperty.unlink( valueObserver );
      self.enabledRangeProperty.unlink( enabledRangeObserver );
      self.enabledProperty.unlink( enabledObserver );

      thumbInputListener.dispose();
    };

    this.mutate( options );
  }

  sun.register( 'HSlider', HSlider );

  inherit( Node, HSlider, {

    // @public - ensures that this object is eligible for GC
    dispose: function() {
      this.disposeHSlider();
    },

    /**
     * Adds a major tick mark.
     * @param {number} value
     * @param {Node} [label] optional
     * @public
     */
    addMajorTick: function( value, label ) {
      this.addTick( this.majorTicksParent, value, label,
        this.tickOptions.majorTickLength, this.tickOptions.majorTickStroke, this.tickOptions.majorTickLineWidth );
    },

    /**
     * Adds a minor tick mark.
     * @param {number} value
     * @param {Node} [label] optional
     * @public
     */
    addMinorTick: function( value, label ) {
      this.addTick( this.minorTicksParent, value, label,
        this.tickOptions.minorTickLength, this.tickOptions.minorTickStroke, this.tickOptions.minorTickLineWidth );
    },

    /*
     * Adds a tick mark above the track.
     * @param {Node} parent
     * @param {number} value
     * @param {Node} [label] optional
     * @param {number} length
     * @param {number} stroke
     * @param {number} lineWidth
     * @private
     */
    addTick: function( parent, value, label, length, stroke, lineWidth ) {
      var labelX = this.valueToPosition( value );
      // ticks
      var tick = new Path( new Shape()
          .moveTo( labelX, this.track.top )
          .lineTo( labelX, this.track.top - length ),
        { stroke: stroke, lineWidth: lineWidth } );
      parent.addChild( tick );
      // label
      if ( label ) {
        parent.addChild( label );
        label.centerX = tick.centerX;
        label.bottom = tick.top - this.tickOptions.tickLabelSpacing;
      }
    },

    // @public
    setEnabled: function( enabled ) { this.enabledProperty.value = enabled; },
    set enabled( value ) { this.setEnabled( value ); },

    // @public
    getEnabled: function() { return this.enabledProperty.value; },
    get enabled() { return this.getEnabled(); },

    // @public
    setEnabledRange: function( enabledRange ) { this.enabledRangeProperty.value = enabledRange; },
    set enabledRange( range ) { this.setEnabledRange( range ); },

    // @public
    getEnabledRange: function() { return this.enabledRangeProperty.value; },
    get enabledRange() { return this.getEnabledRange(); },

    // @public
    setSnapValue: function( snapValue ) {
      this._snapValue = snapValue;
      this.track.snapValue = snapValue;
    },
    set snapValue( snapValue ) { this.setSnapValue( snapValue ); },

    // @public
    getSnapValue: function() { return this._snapValue; },
    get snapValue() { return this.getSnapValue(); },

    // @public - Sets visibility of major ticks.
    setMajorTicksVisible: function( visible ) {
      this.majorTicksParent.visible = visible;
    },
    set majorTicksVisible( value ) { this.setMajorTicksVisible( value ); },

    // @public - Gets visibility of major ticks.
    getMajorTicksVisible: function() {
      return this.majorTicksParent.visible;
    },
    get majorTicksVisible() { return this.getMajorTicksVisible(); },

    // @public - Sets visibility of minor ticks.
    setMinorTicksVisible: function( visible ) {
      this.minorTicksParent.visible = visible;
    },
    set minorTicksVisible( value ) { this.setMinorTicksVisible( value ); },

    // @public - Gets visibility of minor ticks.
    getMinorTicksVisible: function() {
      return this.minorTicksParent.visible;
    },
    get minorTicksVisible() { return this.getMinorTicksVisible(); }
  } );

  return HSlider;
} );<commit_msg>Added missing dispose call, see https://github.com/phetsims/scenery/issues/603<commit_after>// Copyright 2013-2015, University of Colorado Boulder

/**
 * Horizontal slider.
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( function( require ) {
  'use strict';

  // modules
  var Dimension2 = require( 'DOT/Dimension2' );
  var HSliderThumb = require( 'SUN/HSliderThumb' );
  var HSliderTrack = require( 'SUN/HSliderTrack' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Input = require( 'SCENERY/input/Input' );
  var LinearFunction = require( 'DOT/LinearFunction' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Path = require( 'SCENERY/nodes/Path' );
  var Property = require( 'AXON/Property' );
  var Shape = require( 'KITE/Shape' );
  var sun = require( 'SUN/sun' );
  var Tandem = require( 'TANDEM/Tandem' );
  var TandemSimpleDragHandler = require( 'TANDEM/scenery/input/TandemSimpleDragHandler' );
  var Util = require( 'DOT/Util' );

  // phet-io modules
  var THSlider = require( 'ifphetio!PHET_IO/types/sun/THSlider' );

  /**
   * @param {Property.<number>} valueProperty
   * @param { {min:number, max:number} } range
   * @param {Object} [options]
   * @constructor
   */
  function HSlider( valueProperty, range, options ) {

    var self = this;
    Node.call( this );

    options = _.extend( {

      // track
      trackSize: new Dimension2( 100, 5 ),
      trackFillEnabled: 'white',
      trackFillDisabled: 'gray',
      trackStroke: 'black',
      trackLineWidth: 1,

      // {Node} optional thumb, replaces the default.
      // Client is responsible for highlighting, disabling and pointer areas.
      // The thumb will be centered in the track.
      thumbNode: null,

      // Options for the default thumb, ignored if thumbNode is set
      thumbSize: new Dimension2( 22, 45 ),
      thumbFillEnabled: 'rgb(50,145,184)',
      thumbFillHighlighted: 'rgb(71,207,255)',
      thumbFillDisabled: '#F0F0F0',
      thumbStroke: 'black',
      thumbLineWidth: 1,
      thumbCenterLineStroke: 'white',
      thumbTouchAreaXDilation: 11,
      thumbTouchAreaYDilation: 11,
      thumbMouseAreaXDilation: 0,
      thumbMouseAreaYDilation: 0,

      // ticks
      tickLabelSpacing: 6,
      majorTickLength: 25,
      majorTickStroke: 'black',
      majorTickLineWidth: 1,
      minorTickLength: 10,
      minorTickStroke: 'black',
      minorTickLineWidth: 1,

      // other
      cursor: 'pointer',
      enabledProperty: new Property( true ),
      enabledRangeProperty: new Property( range ), // controls the portion of the slider that is enabled
      snapValue: null, // if specified, slider will snap to this value on end drag
      startDrag: function() {}, // called when a drag sequence starts
      endDrag: function() {}, // called when a drag sequence ends
      constrainValue: function( value ) { return value; }, // called before valueProperty is set

      // phet-io
      tandem: Tandem.tandemRequired(),
      phetioType: THSlider
    }, options );

    // @public
    this.enabledProperty = options.enabledProperty;
    this.enabledRangeProperty = options.enabledRangeProperty;

    // @private options needed by prototype functions that add ticks
    this.tickOptions = _.pick( options, 'tickLabelSpacing',
      'majorTickLength', 'majorTickStroke', 'majorTickLineWidth',
      'minorTickLength', 'minorTickStroke', 'minorTickLineWidth' );

    // @private
    this._snapValue = options.snapValue;

    // @private ticks are added to these parents, so they are behind the knob
    this.majorTicksParent = new Node();
    this.minorTicksParent = new Node();
    this.addChild( this.majorTicksParent );
    this.addChild( this.minorTicksParent );

    // @private mapping between value and track position
    this.valueToPosition = new LinearFunction( range.min, range.max, 0, options.trackSize.width, true /* clamp */ );

    // snap to a value if value is within range, used by HSlider and HSliderTrack
    var snapToValue = function( value ) {
      if ( value <= range.max && value >= range.min ) {
        valueProperty.set( value );
      }
      else {
        throw new Error( 'value is out of range: ' + value );
      }
    };

    // @private track
    this.track = new HSliderTrack( valueProperty, this.valueToPosition, snapToValue, {

      // propagate options that are specific to HSliderTrack
      size: options.trackSize,
      fillEnabled: options.trackFillEnabled,
      fillDisabled: options.trackFillDisabled,
      stroke: options.trackStroke,
      lineWidth: options.trackLineWidth,
      enabledProperty: options.enabledProperty,
      startDrag: options.startDrag,
      endDrag: options.endDrag,
      snapValue: options.snapValue,
      constrainValue: options.constrainValue,

      // phet-io
      tandem: options.tandem.createTandem( 'track' )
    } );
    this.track.centerX = this.valueToPosition( ( range.max + range.min ) / 2 );
    this.addChild( this.track );

    // thumb
    var thumb = options.thumbNode || new HSliderThumb( this.enabledProperty, {

        // propagate options that are specific to HSliderThumb
        size: options.thumbSize,
        fillEnabled: options.thumbFillEnabled,
        fillHighlighted: options.thumbFillHighlighted,
        fillDisabled: options.thumbFillDisabled,
        stroke: options.thumbStroke,
        lineWidth: options.thumbLineWidth,
        centerLineStroke: options.thumbCenterLineStroke,
        tandem: options.tandem.createTandem( 'thumb' )
      } );

    // do this outside of options hash, so that it applied to both default and custom thumbs
    thumb.centerY = this.track.centerY;
    this.addChild( thumb );

    // touchArea for the default thumb. If a custom thumb is provided, the client is responsible for its touchArea.
    if ( !options.thumbNode && ( options.thumbTouchAreaXDilation || options.thumbTouchAreaYDilation ) ) {
      thumb.touchArea = thumb.localBounds.dilatedXY( options.thumbTouchAreaXDilation, options.thumbTouchAreaYDilation );
    }

    // mouseArea for the default thumb. If a custom thumb is provided, the client is responsible for its mouseArea.
    if ( !options.thumbNode && ( options.thumbMouseAreaXDilation || options.thumbMouseAreaYDilation ) ) {
      thumb.mouseArea = thumb.localBounds.dilatedXY( options.thumbMouseAreaXDilation, options.thumbMouseAreaYDilation );
    }

    // update value when thumb is dragged
    var clickXOffset = 0; // x-offset between initial click and thumb's origin
    var thumbInputListener = new TandemSimpleDragHandler( {

      tandem: options.tandem.createTandem( 'thumbInputListener' ),

      allowTouchSnag: true,

      start: function( event, trail ) {
        if ( self.enabledProperty.get() ) {
          options.startDrag();

          var transform = trail.subtrailTo( self ).getTransform();
          clickXOffset = transform.inversePosition2( event.pointer.point ).x - thumb.x;
        }
      },

      drag: function( event, trail ) {
        if ( self.enabledProperty.get() ) {
          var transform = trail.subtrailTo( self ).getTransform(); // we only want the transform to our parent
          var x = transform.inversePosition2( event.pointer.point ).x - clickXOffset;
          var newValue = self.valueToPosition.inverse( x );

          valueProperty.set( options.constrainValue( newValue ) );
        }
      },

      end: function() {
        if ( self.enabledProperty.get() ) {
          if ( typeof self._snapValue === 'number' ) {
            snapToValue( self._snapValue );
          }
          options.endDrag();
        }
      }
    } );
    thumb.addInputListener( thumbInputListener );

    //TODO This is experimental code. Decide how this affects data collection.
    // Keyboard accessibility
    thumb.addInputListener( {
      keydown: function( event, trail ) {
        if ( self.enabledProperty.get() ) {
          var keyCode = event.domEvent.keyCode;
          var delta = keyCode === Input.KEY_LEFT_ARROW || keyCode === Input.KEY_DOWN_ARROW ? -1 :
                      keyCode === Input.KEY_RIGHT_ARROW || keyCode === Input.KEY_UP_ARROW ? +1 :
                      0;
          var clampedValue = Util.clamp( valueProperty.get() + (range.max - range.min) * 0.1 * delta, range.min, range.max );
          valueProperty.set( options.constrainValue( clampedValue ) );
        }
      }
    } );

    // enable/disable
    var enabledObserver = function( enabled ) {
      self.cursor = self.enabledProperty.get() ? options.cursor : 'default';
      if ( !enabled ) {
        if ( thumbInputListener.dragging ) { thumbInputListener.endDrag(); }
      }
      self.pickable = enabled;
    };
    this.enabledProperty.link( enabledObserver ); // must be unlinked in disposeHSlider

    // update thumb location when value changes
    var valueObserver = function( value ) {
      thumb.centerX = self.valueToPosition( value );
    };
    valueProperty.link( valueObserver ); // must be unlinked in disposeHSlider

    // when the enabled range changes, the value to position linear function must change as well
    var enabledRangeObserver = function( enabledRange ) {

      assert && assert( enabledRange.min >= range.min && enabledRange.max <= range.max, 'enabledRange is out of range' );

      var initialValueToPosition = new LinearFunction( range.min, range.max, 0, options.trackSize.width, true /* clamp */ );
      var min = initialValueToPosition( enabledRange.min );
      var max = initialValueToPosition( enabledRange.max );

      // update the geometry of the enabled track
      self.track.updateEnabledTrackWidth( min, max );

      // update the function that maps value to position for the track and the slider
      self.valueToPosition = new LinearFunction( enabledRange.min, enabledRange.max, min, max, true /* clamp */ );
      self.track.valueToPosition = self.valueToPosition;

      // clamp the value to the enabled range if it changes
      valueProperty.set( Util.clamp( valueProperty.value, enabledRange.min, enabledRange.max ) );
    };
    this.enabledRangeProperty.link( enabledRangeObserver ); // needs to be unlinked in dispose function

    // @private Called by dispose
    this.disposeHSlider = function() {
      thumb.dispose && thumb.dispose(); // in case a custom thumb is provided via options.thumbNode that doesn't implement dispose
      self.track.dispose();
      valueProperty.unlink( valueObserver );
      self.enabledRangeProperty.unlink( enabledRangeObserver );
      self.enabledProperty.unlink( enabledObserver );

      thumbInputListener.dispose();
    };

    this.mutate( options );
  }

  sun.register( 'HSlider', HSlider );

  inherit( Node, HSlider, {

    // @public - ensures that this object is eligible for GC
    dispose: function() {
      this.disposeHSlider();
      Node.prototype.dispose.call( this );
    },

    /**
     * Adds a major tick mark.
     * @param {number} value
     * @param {Node} [label] optional
     * @public
     */
    addMajorTick: function( value, label ) {
      this.addTick( this.majorTicksParent, value, label,
        this.tickOptions.majorTickLength, this.tickOptions.majorTickStroke, this.tickOptions.majorTickLineWidth );
    },

    /**
     * Adds a minor tick mark.
     * @param {number} value
     * @param {Node} [label] optional
     * @public
     */
    addMinorTick: function( value, label ) {
      this.addTick( this.minorTicksParent, value, label,
        this.tickOptions.minorTickLength, this.tickOptions.minorTickStroke, this.tickOptions.minorTickLineWidth );
    },

    /*
     * Adds a tick mark above the track.
     * @param {Node} parent
     * @param {number} value
     * @param {Node} [label] optional
     * @param {number} length
     * @param {number} stroke
     * @param {number} lineWidth
     * @private
     */
    addTick: function( parent, value, label, length, stroke, lineWidth ) {
      var labelX = this.valueToPosition( value );
      // ticks
      var tick = new Path( new Shape()
          .moveTo( labelX, this.track.top )
          .lineTo( labelX, this.track.top - length ),
        { stroke: stroke, lineWidth: lineWidth } );
      parent.addChild( tick );
      // label
      if ( label ) {
        parent.addChild( label );
        label.centerX = tick.centerX;
        label.bottom = tick.top - this.tickOptions.tickLabelSpacing;
      }
    },

    // @public
    setEnabled: function( enabled ) { this.enabledProperty.value = enabled; },
    set enabled( value ) { this.setEnabled( value ); },

    // @public
    getEnabled: function() { return this.enabledProperty.value; },
    get enabled() { return this.getEnabled(); },

    // @public
    setEnabledRange: function( enabledRange ) { this.enabledRangeProperty.value = enabledRange; },
    set enabledRange( range ) { this.setEnabledRange( range ); },

    // @public
    getEnabledRange: function() { return this.enabledRangeProperty.value; },
    get enabledRange() { return this.getEnabledRange(); },

    // @public
    setSnapValue: function( snapValue ) {
      this._snapValue = snapValue;
      this.track.snapValue = snapValue;
    },
    set snapValue( snapValue ) { this.setSnapValue( snapValue ); },

    // @public
    getSnapValue: function() { return this._snapValue; },
    get snapValue() { return this.getSnapValue(); },

    // @public - Sets visibility of major ticks.
    setMajorTicksVisible: function( visible ) {
      this.majorTicksParent.visible = visible;
    },
    set majorTicksVisible( value ) { this.setMajorTicksVisible( value ); },

    // @public - Gets visibility of major ticks.
    getMajorTicksVisible: function() {
      return this.majorTicksParent.visible;
    },
    get majorTicksVisible() { return this.getMajorTicksVisible(); },

    // @public - Sets visibility of minor ticks.
    setMinorTicksVisible: function( visible ) {
      this.minorTicksParent.visible = visible;
    },
    set minorTicksVisible( value ) { this.setMinorTicksVisible( value ); },

    // @public - Gets visibility of minor ticks.
    getMinorTicksVisible: function() {
      return this.minorTicksParent.visible;
    },
    get minorTicksVisible() { return this.getMinorTicksVisible(); }
  } );

  return HSlider;
} );<|endoftext|>


<commit_before>import React from 'react'
import {Link} from 'react-router'

const Landing = React.createClass({
  render () {
    return (

svideo

        <input type='text' placeholder='Search' />
        <Link to='/search'>or Browse All</Link>

      )
  }
})

export default Landing
<commit_msg>pass state from redux as props to Landing<commit_after>import React from 'react'
import {Link} from 'react-router'

import { connect } from 'react-redux'

const { string } = React.PropTypes

const Landing = React.createClass({
  propTypes: {
    searchTerm: string
  },
  render () {
    return (

svideo

        <input value={this.props.searchTerm} type='text' placeholder='Search' />
        <Link to='/search'>or Browse All</Link>

      )
  }
})

const mapStateToProps = (state) => {
  return {
    searchTerm: state.searchTerm
  }
}

export default connect(mapStateToProps)(Landing)
<|endoftext|>


<commit_before>/**
 * Manager.js
 *
 * @param  {Object} window    Window
 * @param  {[type]} factory [description]
 */
( function ( window, factory ) {

    'use strict';

    if ( typeof define === 'function' && define.amd ) {

        define( [
            'jquery',
            './Util',
            './Config',
            './Ajax',
        ], function ( $, Util, Config, Ajax ) {
            return factory( window, $, Util, Config, Ajax );
        } );

    } else if ( typeof exports === 'object' ) {

        module.exports = factory(
            window,
            require( 'jquery' ),
            require( './Util' ),
            require( './Config' ),
            require( './Ajax' )
        );

    } else {

        window.StateManager = window.StateManager || {};

        window.StateManager.Manager = factory(
            window,
            window.jQuery,
            window.StateManager.Util,
            window.StateManager.Config,
            window.StateManager.Ajax
        );

    }

} ( window, function ( window, $, Util, Config, Ajax ) {

    'use strict';

    // define any private variables
    var name = 'Manager',
        debugEnabled = true,
        debug = debugEnabled ? Util.debug : function () {},
        initialized = false,
        history = null,
        mode = 'traditional', // will either be 'dynamic' or 'traditional'
        $contentHolder,
        $window = $( window ),
        $body = $( 'body' ),
        currentPageConfig = {},
        prefetchCache = {
            list: [],
            limit: null
        },
        ajaxCache = {
            list: [],
            limit: null
        },
        ajaxQueue = []
    ;

    //////////////////////////////////////////////////////////////////////////////////////

    function init() {

        if ( initialized ) {
            return;
        }

        prefetchCache.limit = Config.get( 'prefetchCacheLimit' );
        ajaxCache.limit = Config.get( 'ajaxCacheLimit' );

        $contentHolder = $( Config.get( 'content' ) ).first();

        if ( $contentHolder.length < 1 ) {
            return;
        }

        initHistory();

        initState({
            isInitLoad: true
        });

        ajaxEventListener();

        initialized = true;

    }

    /**
     * Set up history object and add popstate event listener
     */
    function initHistory() {

        // set up our private alias to the history.js adapter
        history = window.history;

        mode = Util.getMode();

        if ( mode === 'traditional' ) {
            return;
        }

        Ajax.ajaxifyLinks( $body );

        // bind to statechanges
        $window.on( 'popstate', function () {

            gotoUrl(
                history.state.url,
                {}
            );

            $window.trigger( 'StateManager.StateChange' );

        } );

    }

    /**
     * Initializes whatever state has been loaded
     * (either on page load or on a history push.)
     *
     * @param  {Object} options
     */
    function initState( options ) {

        var isInitLoad = false,
            stateInfo = history.state,
            // pageConfig = $( Config.get( 'content' ) ).data( 'config' ),
            pageTitle = 'title' in options ? options.title : document.title
        ;

        if ( typeof options !== 'undefined' && typeof options.isInitLoad !== 'undefined' ) {
            isInitLoad = options.isInitLoad
        }

        // if ( typeof pageConfig === 'undefined' ) {
        //     return;
        // }

        // if ( pageConfig === null ) {
        //     return;
        // }

        // check to see if this page relies on any custom body classes
        // if ( typeof pageConfig.bodyClass !== 'undefined' ) {
        //     $body.addClass( pageConfig.bodyClass );
        // }

        Util.setDocumentTitle( pageTitle );

        if ( ! isInitLoad ) {
            $window.trigger(
                'EventTrackAjax.RecordPageview',
                {
                    url: stateInfo.url,
                    title: pageTitle
                }
            );
        }

        // update currentPageConfig
        // currentPageConfig = pageConfig;

        prefetchUpcomingUrls();

        $window.trigger( 'StateManager.AfterInitState' );

    }

    /**
     * Loop through anchor tags with data-prefetch added
     */
    function prefetchUpcomingUrls() {

        if ( mode !== 'dynamic' ) {
            return false;
        }

        var currentState = history.state;

        // stagger prefetch of additional URLs
        $( 'a[data-prefetch]' ).each( function ( index ) {

            // if ( index > prefetchCache.limit ) {
            //     return false;
            // }

            var thisHref = Util.fullyQualifyUrl( $( this ).attr( 'href' ) );

            // make sure we don't reload the page we're on
            if ( thisHref !== currentState.url ) {
                setTimeout( function () {
                    prefetchUrl( thisHref );
                }, 50 * ( index + 1 ) );
            }

        });
    }

    /**
     * Inserts url data to the DOM. Called by gotoUrl().
     *
     * @param  {Object} data
     * @param  {Object} options
     */
    function renderUrl( data ) {

        // drop in image_box HTML
        $contentHolder.html( data.data );

        Ajax.ajaxifyLinks( $contentHolder );

        initState( data );

    }

    /**
     * Toggles whether we're waiting for content to load.
     *
     * @param  {Boolean} isLoading
     */
    function toggleLoading( isLoading ) {

        if ( isLoading ) {

            // reveal loading state
            $window.trigger( 'StateManager.LoadingReveal' );

        } else {

            // hide loading state
            $window.trigger( 'StateManager.LoadingComplete' );

        }

    }

    /**
     * Handles loading of a particular url, then moves along to rendering.
     *
     * @param  {String} url
     * @param  {Object} options
     */
    function gotoUrl( url, options ) {

        // set empty options if they don't exist
        if ( typeof options === 'undefined' ) {
            options = {};
        }

        var thisUrl = url,
            thisOptions = options,
            data = getUrlData({
                url: thisUrl,
                afterAjaxLoad: function ( data ) {
                    // this function only fires if we need to wait for
                    // an ajax load.

                    // record what the last url had been
                    var lastUrlInQueue = ajaxQueue[ ajaxQueue.length - 1 ].url;

                    removeUrlFromAjaxQueue( thisUrl );

                    // save the new data to the cache
                    saveCacheData( ajaxCache, thisUrl, data );

                    // only proceed if this was the last url in the queue
                    if ( lastUrlInQueue == thisUrl ) {

                        // now that we have the data, recall gotoUrl
                        gotoUrl( thisUrl, thisOptions );

                    } else {
                        debug( '******* still loading: ' + lastUrlInQueue );
                    }
                }
            } )
        ;

        // did we get data back, or are we waiting on an ajax request to be completed?
        if ( typeof data.loading !== 'undefined' && data.loading ) {

            toggleLoading( true );

            return false;

        }

        // if we reached this point, we have the data we need and can proceed.
        toggleLoading( false );

        renderUrl( data );

    }

    /**
     * Returns html data for a particular url. This data may be cached already. If not
     *       we make an AJAX call to load the data.
     *
     * @param  {Object} options Includes: url, isPrefetch
     * @return {Object}         Trigger the loading function
     */
    function getUrlData( options ) {

        var thisUrl = options.url,
            trackProgress = true,
            data
        ;

        if ( data = checkCacheForData( ajaxCache.list, options.url ) ) {
            return data;
        }

        if ( data = checkCacheForData( prefetchCache.list, options.url ) ) {
            return data;
        }

        if ( data = checkCacheForData( ajaxQueue, options.url ) ) {
            return {
                loading: true
            };
        }

        // Disable tracking progress if this is a prefetch request
        if ( options.isPrefetch ) {
            trackProgress = false;
        }

        ajaxQueue.push({ url: thisUrl });

        // if we reach this point, the data wasn't in the cache. make ajax request.
        Ajax.loadAjax({
            url: thisUrl,
            dataType: 'html',
            trackProgress: trackProgress,
            success: options.afterAjaxLoad,
            error: function () {

            }
        });

        return {
            loading: true
        };

    }

    /**
     * Prefetches URLs we think the user is likely to load in the cache.
     *
     * @param  {String} url Marker to decide which pages should be cached
     */
    function prefetchUrl( url ) {

        if ( mode === 'traditional' ) {
            return;
        }

        // no, let's make the request
        getUrlData({
            url: url,
            isPrefetch: true,
            afterAjaxLoad: function ( data ) {
                removeUrlFromAjaxQueue( url );
                saveCacheData( prefetchCache, url, data );
            }
        });
    }

    /**
     * Check supplied cache array for a match against the URI
     *
     * @param  {Array} cacheList  prefetch, ajax, or ajaxQueue cache
     * @param  {String} url       used to identify the correct data in the loop
     * @return {Object}           cacheList data if present
     * @return {Boolean}          false if no data in cache
     */
    function checkCacheForData( cacheList, url ) {

        if ( cacheList.length > 0 ) {
            for ( var i = 0; i < cacheList.length; i++ ) {
                if ( cacheList[i].url === url ) {
                    return cacheList[i];
                }
            }
        }

        return false;

    }

    /**
     * A function for passing different cache arrays with url and data to save
     *
     * @param  {Array} cacheType  prefetch or ajax cache
     * @param  {String} url       Page URI to cache
     * @param  {String} data      Data from page to be cached, it get's parsed first
     */
    function saveCacheData( cacheType, url, data ) {

        var cacheObj = {
            url: url,
            data: Ajax.parseHtml( data )
        };

        cacheType.list.push( cacheObj );

        // check if cacheType has grown too large
        if ( cacheType.list.length > cacheType.limit ) {
            // remove the oldest data
            debug( 'over cache limit of ' + cacheType.limit + ', removing oldest data' );

            cacheType.list = $.grep( cacheType.list, function ( element, index ) {
                return index !== 0;
            } );

        }

    }

    /**
     * Loop through the queue and remove the url from the array
     *
     * @param  {String} url  string to remove from the queue
     */
    function removeUrlFromAjaxQueue( url ) {

        // remove url from ajaxQueue
        ajaxQueue = $.grep( ajaxQueue, function ( element, index ) {
            return element.url !== url;
        } );

    }

    /**
     * Add any Listeners to avoid exposing functions
     */
    function ajaxEventListener() {

        $window.on( 'StateManager.GotoUrl', function ( event, url ) {

            gotoUrl( url, {} );

        } );

    }

    //////////////////////////////////////////////////////////////////////////////////////

    return {
        init: init
    };

} ) );<commit_msg>Styling.<commit_after>/**
 * Manager.js
 *
 * @param  {Object} window    Window
 * @param  {[type]} factory [description]
 */
( function ( window, factory ) {

    'use strict';

    if ( typeof define === 'function' && define.amd ) {

        define( [
            'jquery',
            './Util',
            './Config',
            './Ajax',
        ], function ( $, Util, Config, Ajax ) {
            return factory( window, $, Util, Config, Ajax );
        } );

    } else if ( typeof exports === 'object' ) {

        module.exports = factory(
            window,
            require( 'jquery' ),
            require( './Util' ),
            require( './Config' ),
            require( './Ajax' )
        );

    } else {

        window.StateManager = window.StateManager || {};

        window.StateManager.Manager = factory(
            window,
            window.jQuery,
            window.StateManager.Util,
            window.StateManager.Config,
            window.StateManager.Ajax
        );

    }

} ( window, function ( window, $, Util, Config, Ajax ) {

    'use strict';

    // define any private variables
    var name = 'Manager',
        debugEnabled = true,
        debug = debugEnabled ? Util.debug : function () {},
        initialized = false,
        history = null,
        mode = 'traditional', // will either be 'dynamic' or 'traditional'
        $contentHolder,
        $window = $( window ),
        $body = $( 'body' ),
        currentPageConfig = {},
        prefetchCache = {
            list: [],
            limit: null
        },
        ajaxCache = {
            list: [],
            limit: null
        },
        ajaxQueue = []
    ;

    //////////////////////////////////////////////////////////////////////////////////////

    function init() {

        if ( initialized ) {
            return;
        }

        prefetchCache.limit = Config.get( 'prefetchCacheLimit' );
        ajaxCache.limit = Config.get( 'ajaxCacheLimit' );

        $contentHolder = $( Config.get( 'content' ) ).first();

        if ( $contentHolder.length < 1 ) {
            return;
        }

        initHistory();

        initState({
            isInitLoad: true
        });

        ajaxEventListener();

        initialized = true;

    }

    /**
     * Set up history object and add popstate event listener
     */
    function initHistory() {

        // set up our private alias to the history.js adapter
        history = window.history;

        mode = Util.getMode();

        if ( mode === 'traditional' ) {
            return;
        }

        Ajax.ajaxifyLinks( $body );

        // bind to statechanges
        $window.on( 'popstate', function () {

            gotoUrl(
                history.state.url,
                {}
            );

            $window.trigger( 'StateManager.StateChange' );

        } );

    }

    /**
     * Initializes whatever state has been loaded
     * (either on page load or on a history push.)
     *
     * @param  {Object} options
     */
    function initState( options ) {

        var isInitLoad = false,
            stateInfo = history.state,
            // pageConfig = $( Config.get( 'content' ) ).data( 'config' ),
            pageTitle = 'title' in options ? options.title : document.title
        ;

        if ( typeof options !== 'undefined' && typeof options.isInitLoad !== 'undefined' ) {
            isInitLoad = options.isInitLoad
        }

        // if ( typeof pageConfig === 'undefined' ) {
        //     return;
        // }

        // if ( pageConfig === null ) {
        //     return;
        // }

        // check to see if this page relies on any custom body classes
        // if ( typeof pageConfig.bodyClass !== 'undefined' ) {
        //     $body.addClass( pageConfig.bodyClass );
        // }

        Util.setDocumentTitle( pageTitle );

        if ( ! isInitLoad ) {
            $window.trigger(
                'EventTrackAjax.RecordPageview',
                {
                    url: stateInfo.url,
                    title: pageTitle
                }
            );
        }

        // update currentPageConfig
        // currentPageConfig = pageConfig;

        prefetchUpcomingUrls();

        $window.trigger( 'StateManager.AfterInitState' );

    }

    /**
     * Loop through anchor tags with data-prefetch added
     */
    function prefetchUpcomingUrls() {

        if ( mode !== 'dynamic' ) {
            return false;
        }

        var currentState = history.state;

        // stagger prefetch of additional URLs
        $( 'a[data-prefetch]' ).each( function ( index ) {

            // if ( index > prefetchCache.limit ) {
            //     return false;
            // }

            var thisHref = Util.fullyQualifyUrl( $( this ).attr( 'href' ) );

            // make sure we don't reload the page we're on
            if ( thisHref !== currentState.url ) {
                setTimeout( function () {
                    prefetchUrl( thisHref );
                }, 50 * ( index + 1 ) );
            }

        });
    }

    /**
     * Inserts url data to the DOM. Called by gotoUrl().
     *
     * @param  {Object} data
     * @param  {Object} options
     */
    function renderUrl( data ) {

        // drop in image_box HTML
        $contentHolder.html( data.data );

        Ajax.ajaxifyLinks( $contentHolder );

        initState( data );

    }

    /**
     * Toggles whether we're waiting for content to load.
     *
     * @param  {Boolean} isLoading
     */
    function toggleLoading( isLoading ) {

        if ( isLoading ) {

            // reveal loading state
            $window.trigger( 'StateManager.LoadingReveal' );

        } else {

            // hide loading state
            $window.trigger( 'StateManager.LoadingComplete' );

        }

    }

    /**
     * Handles loading of a particular url, then moves along to rendering.
     *
     * @param  {String} url
     * @param  {Object} options
     */
    function gotoUrl( url, options ) {

        // set empty options if they don't exist
        if ( typeof options === 'undefined' ) {
            options = {};
        }

        var thisUrl = url,
            thisOptions = options,
            data = getUrlData({
                url: thisUrl,
                afterAjaxLoad: function ( data ) {
                    // this function only fires if we need to wait for
                    // an ajax load.

                    // record what the last url had been
                    var lastUrlInQueue = ajaxQueue[ ajaxQueue.length - 1 ].url;

                    removeUrlFromAjaxQueue( thisUrl );

                    // save the new data to the cache
                    saveCacheData( ajaxCache, thisUrl, data );

                    // only proceed if this was the last url in the queue
                    if ( lastUrlInQueue === thisUrl ) {

                        // now that we have the data, recall gotoUrl
                        gotoUrl( thisUrl, thisOptions );

                    } else {
                        debug( '******* still loading: ' + lastUrlInQueue );
                    }
                }
            } )
        ;

        // did we get data back, or are we waiting on an ajax request to be completed?
        if ( typeof data.loading !== 'undefined' && data.loading ) {

            toggleLoading( true );

            return false;

        }

        // if we reached this point, we have the data we need and can proceed.
        toggleLoading( false );

        renderUrl( data );

    }

    /**
     * Returns html data for a particular url. This data may be cached already. If not
     *       we make an AJAX call to load the data.
     *
     * @param  {Object} options Includes: url, isPrefetch
     * @return {Object}         Trigger the loading function
     */
    function getUrlData( options ) {

        var thisUrl = options.url,
            trackProgress = true,
            data
        ;

        if ( data = checkCacheForData( ajaxCache.list, options.url ) ) {
            return data;
        }

        if ( data = checkCacheForData( prefetchCache.list, options.url ) ) {
            return data;
        }

        if ( data = checkCacheForData( ajaxQueue, options.url ) ) {
            return {
                loading: true
            };
        }

        // Disable tracking progress if this is a prefetch request
        if ( options.isPrefetch ) {
            trackProgress = false;
        }

        ajaxQueue.push({ url: thisUrl });

        // if we reach this point, the data wasn't in the cache. make ajax request.
        Ajax.loadAjax({
            url: thisUrl,
            dataType: 'html',
            trackProgress: trackProgress,
            success: options.afterAjaxLoad,
            error: function () {

            }
        });

        return {
            loading: true
        };

    }

    /**
     * Prefetches URLs we think the user is likely to load in the cache.
     *
     * @param {String} url Marker to decide which pages should be cached
     */
    function prefetchUrl( url ) {

        if ( mode === 'traditional' ) {
            return;
        }

        // no, let's make the request
        getUrlData({
            url: url,
            isPrefetch: true,
            afterAjaxLoad: function ( data ) {
                removeUrlFromAjaxQueue( url );
                saveCacheData( prefetchCache, url, data );
            }
        });
    }

    /**
     * Check supplied cache array for a match against the URI
     *
     * @param  {Array} cacheList  prefetch, ajax, or ajaxQueue cache
     * @param  {String} url       used to identify the correct data in the loop
     * @return {Object|Boolean}   cacheList data if present or false
     */
    function checkCacheForData( cacheList, url ) {

        if ( cacheList.length > 0 ) {
            for ( var i = 0; i < cacheList.length; i++ ) {
                if ( cacheList[i].url === url ) {
                    return cacheList[i];
                }
            }
        }

        return false;

    }

    /**
     * A function for passing different cache arrays with url and data to save
     *
     * @param  {Array} cacheType  prefetch or ajax cache
     * @param  {String} url       Page URI to cache
     * @param  {String} data      Data from page to be cached, it get's parsed first
     */
    function saveCacheData( cacheType, url, data ) {

        var cacheObj = {
            url: url,
            data: Ajax.parseHtml( data )
        };

        cacheType.list.push( cacheObj );

        // check if cacheType has grown too large
        if ( cacheType.list.length > cacheType.limit ) {
            // remove the oldest data
            debug( 'over cache limit of ' + cacheType.limit + ', removing oldest data' );

            cacheType.list = $.grep( cacheType.list, function ( element, index ) {
                return index !== 0;
            } );

        }

    }

    /**
     * Loop through the queue and remove the url from the array
     *
     * @param  {String} url  string to remove from the queue
     */
    function removeUrlFromAjaxQueue( url ) {

        // remove url from ajaxQueue
        ajaxQueue = $.grep( ajaxQueue, function ( element, index ) {
            return element.url !== url;
        } );

    }

    /**
     * Add any Listeners to avoid exposing functions
     */
    function ajaxEventListener() {

        $window.on( 'StateManager.GotoUrl', function ( event, url ) {

            gotoUrl( url, {} );

        } );

    }

    //////////////////////////////////////////////////////////////////////////////////////

    return {
        init: init
    };

} ) );<|endoftext|>


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

/**
 * Return an object of data about the simulation and the browser
 * much of the code was largely copied and expanded on from SimTroubleshootPage.html in the website repo. Note that
 * key names in the info object are used by the PhET-iO API, do not change without great consideration.
 *
 * @author Michael Kauzmann (PhET Interactive Simulations)
 */

import Utils from '../../scenery/js/util/Utils.js';
import PhetioObject from '../../tandem/js/PhetioObject.js';
import Tandem from '../../tandem/js/Tandem.js';
import IOType from '../../tandem/js/types/IOType.js';
import joist from './joist.js';
import packageJSON from './packageJSON.js';

class SimInfo extends PhetioObject {

  constructor( sim ) {
    super( {
      tandem: Tandem.GENERAL_MODEL.createTandem( 'simInfo' ),
      phetioType: SimInfo.SimInfoIO,
      phetioReadOnly: true,
      phetioDocumentation: 'A collection of data about the runtime and simulation. Available in the simStarted PhET-iO ' +
                           'data stream event, as well as on demand in the PhET-iO state.'
    } );

    assert && assert( Array.isArray( sim.screens ), 'screens should be set and an array' );

    // @public (SimInfoIO)
    this.info = {};

    // globals
    this.putInfo( 'randomSeed', window.phet.chipper.queryParameters.randomSeed );

    // Some data values change from run to run and should not be recorded for purposes of PhET-iO API generation or
    // comparison
    if ( !Tandem.API_GENERATION ) {
      this.putInfo( 'url', window.location.href );
      this.putInfo( 'userAgent', window.navigator.userAgent );
    }

    this.putInfo( 'language', window.navigator.language );
    this.putInfo( 'window', `${window.innerWidth}x${window.innerHeight}` );
    this.putInfo( 'referrer', document.referrer );

    // from Scenery Utils
    this.putInfo( 'checkIE11StencilSupport', Utils.checkIE11StencilSupport() );
    if ( phet.chipper.queryParameters.webgl ) {
      this.putInfo( 'isWebGLSupported', Utils.isWebGLSupported );
    }

    let canvas;
    let context;
    let backingStorePixelRatio;

    try {
      canvas = document.createElement( 'canvas' );
      context = canvas.getContext( '2d' );
      backingStorePixelRatio = Utils.backingStorePixelRatio( context );
    }
    catch( e ) {} // eslint-disable-line

    this.putInfo( 'pixelRatio', `${window.devicePixelRatio || 1}/${backingStorePixelRatio}` );

    const flags = [];
    if ( window.navigator.pointerEnabled ) { flags.push( 'pointerEnabled' ); }
    if ( window.navigator.msPointerEnabled ) { flags.push( 'msPointerEnabled' ); }
    if ( !window.navigator.onLine ) { flags.push( 'offline' ); }
    if ( ( window.devicePixelRatio || 1 ) / backingStorePixelRatio !== 1 ) { flags.push( 'pixelRatioScaling' ); }
    this.putInfo( 'flags', flags.join( ', ' ) );

    canvas = null; // dispose only reference

    // from Sim.js
    this.putInfo( 'simName', sim.simNameProperty.value );
    this.putInfo( 'simVersion', sim.version );
    this.putInfo( 'repoName', packageJSON.name );
    this.putInfo( 'screens', sim.screens.map( screen => {
      const screenObject = {

        // likely null for single screen sims, so use the sim name as a default
        name: screen.nameProperty.value || sim.simNameProperty.value
      };
      if ( Tandem.PHET_IO_ENABLED ) {
        screenObject.phetioID = screen.tandem.phetioID;
      }
      return screenObject;
    } ) );

    // From PhET-iO code
    if ( Tandem.PHET_IO_ENABLED ) {
      this.putInfo( 'screenPropertyValue', sim.screenProperty.value.tandem.phetioID );
      this.putInfo( 'wrapperMetadata', phet.preloads.phetio.simStartedMetadata );
      this.putInfo( 'dataStreamVersion', phet.phetio.dataStream.VERSION );
      this.putInfo( 'phetioCommandProcessorProtocol', phet.phetio.phetioCommandProcessor.PHET_IO_PROTOCOL );
    }
  }

  /**
   * @private
   * @param {string} key
   * @param {*} value
   */
  putInfo( key, value ) {
    if ( value === undefined ) {
      value = '{{undefined}}';
    }
    assert && assert( !this.info.hasOwnProperty( key ), `key already defined: ${key}` );
    this.info[ key ] = value;
  }
}

// @private
SimInfo.SimInfoIO = new IOType( 'SimInfoIO', {
  valueType: SimInfo,
  toStateObject: simInfo => simInfo.info
} );

joist.register( 'SimInfo', SimInfo );
export default SimInfo;<commit_msg>Exclude values from initial state during phet-io API generation, see https://github.com/phetsims/phet-io/issues/1776<commit_after>// Copyright 2018-2020, University of Colorado Boulder

/**
 * Return an object of data about the simulation and the browser
 * much of the code was largely copied and expanded on from SimTroubleshootPage.html in the website repo. Note that
 * key names in the info object are used by the PhET-iO API, do not change without great consideration.
 *
 * @author Michael Kauzmann (PhET Interactive Simulations)
 */

import Utils from '../../scenery/js/util/Utils.js';
import PhetioObject from '../../tandem/js/PhetioObject.js';
import Tandem from '../../tandem/js/Tandem.js';
import IOType from '../../tandem/js/types/IOType.js';
import joist from './joist.js';
import packageJSON from './packageJSON.js';

class SimInfo extends PhetioObject {

  constructor( sim ) {
    super( {
      tandem: Tandem.GENERAL_MODEL.createTandem( 'simInfo' ),
      phetioType: SimInfo.SimInfoIO,
      phetioReadOnly: true,
      phetioDocumentation: 'A collection of data about the runtime and simulation. Available in the simStarted PhET-iO ' +
                           'data stream event, as well as on demand in the PhET-iO state.'
    } );

    assert && assert( Array.isArray( sim.screens ), 'screens should be set and an array' );

    // @public (SimInfoIO)
    this.info = {};

    // globals

    this.putInfo( 'language', window.navigator.language );

    // from Scenery Utils
    this.putInfo( 'checkIE11StencilSupport', Utils.checkIE11StencilSupport() );
    if ( phet.chipper.queryParameters.webgl ) {
      this.putInfo( 'isWebGLSupported', Utils.isWebGLSupported );
    }

    let canvas;
    let context;
    let backingStorePixelRatio;

    try {
      canvas = document.createElement( 'canvas' );
      context = canvas.getContext( '2d' );
      backingStorePixelRatio = Utils.backingStorePixelRatio( context );
    }
    catch( e ) {} // eslint-disable-line

    const flags = [];
    if ( window.navigator.pointerEnabled ) { flags.push( 'pointerEnabled' ); }
    if ( window.navigator.msPointerEnabled ) { flags.push( 'msPointerEnabled' ); }
    if ( !window.navigator.onLine ) { flags.push( 'offline' ); }
    if ( ( window.devicePixelRatio || 1 ) / backingStorePixelRatio !== 1 ) { flags.push( 'pixelRatioScaling' ); }

    canvas = null; // dispose only reference

    // from Sim.js
    this.putInfo( 'simName', sim.simNameProperty.value );
    this.putInfo( 'simVersion', sim.version );
    this.putInfo( 'repoName', packageJSON.name );
    this.putInfo( 'screens', sim.screens.map( screen => {
      const screenObject = {

        // likely null for single screen sims, so use the sim name as a default
        name: screen.nameProperty.value || sim.simNameProperty.value
      };
      if ( Tandem.PHET_IO_ENABLED ) {
        screenObject.phetioID = screen.tandem.phetioID;
      }
      return screenObject;
    } ) );

    // Some data values change from run to run and should not be recorded for purposes of PhET-iO API generation or
    // comparison
    if ( !Tandem.API_GENERATION ) {
      this.putInfo( 'randomSeed', window.phet.chipper.queryParameters.randomSeed );
      this.putInfo( 'url', window.location.href );
      this.putInfo( 'userAgent', window.navigator.userAgent );
      this.putInfo( 'window', `${window.innerWidth}x${window.innerHeight}` );
      this.putInfo( 'referrer', document.referrer );
      this.putInfo( 'flags', flags.join( ', ' ) );
      this.putInfo( 'pixelRatio', `${window.devicePixelRatio || 1}/${backingStorePixelRatio}` );
    }

    // From PhET-iO code
    if ( Tandem.PHET_IO_ENABLED ) {
      this.putInfo( 'screenPropertyValue', sim.screenProperty.value.tandem.phetioID );
      this.putInfo( 'wrapperMetadata', phet.preloads.phetio.simStartedMetadata );
      this.putInfo( 'dataStreamVersion', phet.phetio.dataStream.VERSION );
      this.putInfo( 'phetioCommandProcessorProtocol', phet.phetio.phetioCommandProcessor.PHET_IO_PROTOCOL );
    }
  }

  /**
   * @private
   * @param {string} key
   * @param {*} value
   */
  putInfo( key, value ) {
    if ( value === undefined ) {
      value = '{{undefined}}';
    }
    assert && assert( !this.info.hasOwnProperty( key ), `key already defined: ${key}` );
    this.info[ key ] = value;
  }
}

// @private
SimInfo.SimInfoIO = new IOType( 'SimInfoIO', {
  valueType: SimInfo,
  toStateObject: simInfo => simInfo.info
} );

joist.register( 'SimInfo', SimInfo );
export default SimInfo;<|endoftext|>


<commit_before>function showCar1()
{

    document.getElementById("car").style.visibility = "hidden";
    document.getElementById("btnCar1").style.visibility = "hidden";
    document.getElementById("btnCar2").style.visibility = "visible";
    document.getElementById("car2").style.visibility = "visible";
    document.getElementById("top").style.visibility = "hidden";
}

function showCar2()
{

    document.getElementById("car2").style.visibility = "hidden";
    document.getElementById("btnCar2").style.visibility = "hidden";
    document.getElementById("car3").style.visibility = "visible";

}

function showTop()
{
    document.getElementById("car3").style.visibility = "hidden";
    document.getElementById("top").style.visibility = "visible";
}

function showMsg()
{
    alert("This Person has Requested a Call before you can see the video .. Please dial this number +91-9650430016. India ka no. hai T-Mobile se matt dial krna .. koi apna phone dedo isko!!!");
}

function sampleCheck()
{
    var answer = document.getElementById("sampleA").value;
    if (answer.toLowerCase() == "popo")
    {
        $("#sampleVideo").modal();
    }
    else
    {
        document.getElementById("incorrectAnswer").src = "../img/emb/"+generateRandom()+".jpg";
        $("#sampleImgPusph").modal();
        document.getElementById("msg").innerHTML = "Are you sure he calls you "+answer;
    }
}

//Vishu - kutta
function a1Check()
{
    var answer = document.getElementById("a1").value;
    if (answer.toLowerCase() == "zeher")
    {
        $("#q1v").modal();
    }
    else
    {
        document.getElementById("incorrectAnswer1").src = "../img/emb/"+generateRandom()+".jpg";
        $("#i1").modal();
        document.getElementById("msg").innerHTML = "Are you sure you call him/her "+answer;
    }
}

//Amit - Amitwaa
function a2Check()
{
    var answer = document.getElementById("a2").value;
    if (answer.toLowerCase() == "banddar")
    {
        $("#q2v").modal();
    }
    else
    {
        document.getElementById("incorrectAnswer2").src = "../img/emb/"+generateRandom()+".jpg";
        $("#i2").modal();
        document.getElementById("msg").innerHTML = "Are you sure you call him/her "+answer;
    }
}

//rishabh
function a3Check()
{
    var answer = document.getElementById("a3").value;
    if (answer.toLowerCase() == "dukh")
    {
        $("#q3v").modal();
    }
    else
    {
        document.getElementById("incorrectAnswer3").src = "../img/emb/"+generateRandom()+".jpg";
        $("#i3").modal();
        document.getElementById("msg").innerHTML = "Are you sure you call him/her "+answer;
    }
}

//manna
function a4Check()
{
    var answer = document.getElementById("a4").value;
    if (answer.toLowerCase() == "bhakt")
    {
        showMsg();
        $("#q4v").modal();
    }
    else
    {
        document.getElementById("incorrectAnswer4").src = "../img/emb/"+generateRandom()+".jpg";
        $("#i4").modal();
        document.getElementById("msg").innerHTML = "Are you sure you call him/her "+answer;
    }
}

//Shushi
function a5Check()
{
    var answer = document.getElementById("a5").value;
    if (answer.toLowerCase() == "kai zala")
    {
        $("#q5v").modal();
    }
    else
    {
        document.getElementById("incorrectAnswer5").src = "../img/emb/"+generateRandom()+".jpg";
        $("#i5").modal();
        document.getElementById("msg").innerHTML = "Are you sure you call him/her "+answer;
    }
}

//Saurabh
function a6Check()
{
    var answer = document.getElementById("a6").value;
    if (answer.toLowerCase() == "faraki")
    {
        $("#q6v").modal();
    }
    else
    {
        document.getElementById("incorrectAnswer6").src = "../img/emb/"+generateRandom()+".jpg";
        $("#i6").modal();
        document.getElementById("msg").innerHTML = "Are you sure you call him/her "+answer;
    }
}

//Shivam - pati
function a7Check()
{
    var answer = document.getElementById("a7").value;
    if (answer.toLowerCase() == "pati")
    {
        $("#q7v").modal();
    }
    else
    {
        document.getElementById("incorrectAnswer7").src = "../img/emb/"+generateRandom()+".jpg";
        $("#i7").modal();
        document.getElementById("msg").innerHTML = "Are you sure you call him/her "+answer;
    }
}

//Shalin
function a8Check()
{
    var answer = document.getElementById("a8").value;
    if (answer.toLowerCase() == "hate you")
    {
        $("#q8v").modal();
    }
    else
    {
        document.getElementById("incorrectAnswer8").src = "../img/emb/"+generateRandom()+".jpg";
        $("#i8").modal();
        document.getElementById("msg").innerHTML = "Are you sure you call him/her "+answer;
    }
}

//Pooja - cheese cake
function a9Check()
{
    var answer = document.getElementById("a9").value;
    if (answer.toLowerCase() == "cheesecake")
    {
        $("#q9v").modal();
    }
    else
    {
        document.getElementById("incorrectAnswer9").src = "../img/emb/"+generateRandom()+".jpg";
        $("#i9").modal();
        document.getElementById("msg").innerHTML = "Are you sure you call him/her "+answer;
    }
}

function generateRandom(){
                var num = Math.floor((Math.random() * 25) + 1);
                return num;
            }

<commit_msg>Update answers.js<commit_after>function showCar1()
{

    document.getElementById("car").style.visibility = "hidden";
    document.getElementById("btnCar1").style.visibility = "hidden";
    document.getElementById("btnCar2").style.visibility = "visible";
    document.getElementById("car2").style.visibility = "visible";
    document.getElementById("top").style.visibility = "hidden";
}

function showCar2()
{

    document.getElementById("car2").style.visibility = "hidden";
    document.getElementById("btnCar2").style.visibility = "hidden";
    document.getElementById("car3").style.visibility = "visible";

}

function showTop()
{
    document.getElementById("car3").style.visibility = "hidden";
    document.getElementById("top").style.visibility = "visible";
}

function showMsg()
{
    alert("This Person has Requested a Call before you can see the video .. Please dial this number +91-9650430016. India ka no. hai T-Mobile se matt dial krna .. koi apna phone dedo isko!!!");
}

function sampleCheck()
{
    var answer = document.getElementById("sampleA").value;
    if (answer.toLowerCase() == "popo")
    {
        $("#sampleVideo").modal();
    }
    else
    {
        document.getElementById("incorrectAnswer").src = "../img/emb/"+generateRandom()+".jpg";
        $("#sampleImgPusph").modal();
        document.getElementById("msg").innerHTML = "Are you sure he calls you "+answer;
    }
}

//Vishu - kutta
function a1Check()
{
    var answer = document.getElementById("a1").value;
    if (answer.toLowerCase() == "zeher")
    {
        $("#q1v").modal();
    }
    else
    {
        document.getElementById("incorrectAnswer1").src = "../img/emb/"+generateRandom()+".jpg";
        $("#i1").modal();
        document.getElementById("msg").innerHTML = "Are you sure you call him/her "+answer;
    }
}

//Amit - Amitwaa
function a2Check()
{
    var answer = document.getElementById("a2").value;
    if (answer.toLowerCase() == "banddar")
    {
        $("#q2v").modal();
    }
    else
    {
        document.getElementById("incorrectAnswer2").src = "../img/emb/"+generateRandom()+".jpg";
        $("#i2").modal();
        document.getElementById("msg").innerHTML = "Are you sure you call him/her "+answer;
    }
}

//rishabh
function a3Check()
{
    var answer = document.getElementById("a3").value;
    if (answer.toLowerCase() == "dukh")
    {
        $("#q3v").modal();
    }
    else
    {
        document.getElementById("incorrectAnswer3").src = "../img/emb/"+generateRandom()+".jpg";
        $("#i3").modal();
        document.getElementById("msg").innerHTML = "Are you sure you call him/her "+answer;
    }
}

//manna
function a4Check()
{
    var answer = document.getElementById("a4").value;
    if (answer.toLowerCase() == "bhakt")
    {
        showMsg();
        $("#q4v").modal();
    }
    else
    {
        document.getElementById("incorrectAnswer4").src = "../img/emb/"+generateRandom()+".jpg";
        $("#i4").modal();
        document.getElementById("msg").innerHTML = "Are you sure you call him/her "+answer;
    }
}

//Shushi
function a5Check()
{
    var answer = document.getElementById("a5").value;
    if (answer.toLowerCase() == "kai zala")
    {
        $("#q5v").modal();
    }
    else
    {
        document.getElementById("incorrectAnswer5").src = "../img/emb/"+generateRandom()+".jpg";
        $("#i5").modal();
        document.getElementById("msg").innerHTML = "Are you sure you call him/her "+answer;
    }
}

//Saurabh
function a6Check()
{
    var answer = document.getElementById("a6").value;
    if (answer.toLowerCase() == "faraki")
    {
        $("#q6v").modal();
    }
    else
    {
        document.getElementById("incorrectAnswer6").src = "../img/emb/"+generateRandom()+".jpg";
        $("#i6").modal();
        document.getElementById("msg").innerHTML = "Are you sure you call him/her "+answer;
    }
}

//Shivam - pati
function a7Check()
{
    var answer = document.getElementById("a7").value;
    if (answer.toLowerCase() == "shivam")
    {
        $("#q7v").modal();
    }
    else
    {
        document.getElementById("incorrectAnswer7").src = "../img/emb/"+generateRandom()+".jpg";
        $("#i7").modal();
        document.getElementById("msg").innerHTML = "Are you sure you call him/her "+answer;
    }
}

//Shalin
function a8Check()
{
    var answer = document.getElementById("a8").value;
    if (answer.toLowerCase() == "hate you")
    {
        $("#q8v").modal();
    }
    else
    {
        document.getElementById("incorrectAnswer8").src = "../img/emb/"+generateRandom()+".jpg";
        $("#i8").modal();
        document.getElementById("msg").innerHTML = "Are you sure you call him/her "+answer;
    }
}

//Pooja - cheese cake
function a9Check()
{
    var answer = document.getElementById("a9").value;
    if (answer.toLowerCase() == "cheesecake")
    {
        $("#q9v").modal();
    }
    else
    {
        document.getElementById("incorrectAnswer9").src = "../img/emb/"+generateRandom()+".jpg";
        $("#i9").modal();
        document.getElementById("msg").innerHTML = "Are you sure you call him/her "+answer;
    }
}

function generateRandom(){
                var num = Math.floor((Math.random() * 25) + 1);
                return num;
            }

<|endoftext|>


<commit_before>/*!
 * avgrund 0.1
 * http://lab.hakim.se/avgrund
 * MIT licensed
 *
 * Copyright (C) 2012 Hakim El Hattab, http://hakim.se
 */
var Avgrund = (function(){

	var container = document.documentElement,
		popup = document.querySelector('.avgrund-popup-animate'),
		cover = document.querySelector( '.avgrund-cover' ),
		currentState = null;
	container.classList.add('avgrund-ready');

	// Deactivate on ESC
	function onDocumentKeyUp( event ) {
		if( event.keyCode === 27 ) {
			deactivate();
		}
	}

	// Deactivate on click outside
	function onDocumentClick( event ) {
		if( event.target === cover ) {
			deactivate();
		}
	}

	function activate( state ) {
		document.addEventListener( 'keyup', onDocumentKeyUp, false );
		document.addEventListener( 'click', onDocumentClick, false );
		document.addEventListener( 'touchstart', onDocumentClick, false );

		popup.classList.remove(currentState);
		popup.classList.add('no-transition');
		if(state)
			popup.classList.add(state);

		setTimeout( function() {
			popup.classList.remove('no-transition');
			container.classList.add('avgrund-active');
		}, 0 );

		currentState = state;
	}

	function deactivate() {
		document.removeEventListener( 'keyup', onDocumentKeyUp, false );
		document.removeEventListener( 'click', onDocumentClick, false );
		document.removeEventListener( 'touchstart', onDocumentClick, false );

		container.classList.remove('avgrund-active');
		popup.classList.remove('avgrund-popup-animate');
	}

	function disableBlur() {
		document.documentElement.classList.add('no-blur');
	}

	function show(selector){
		popup = document.querySelector( selector );
		popup.classList.add('avgrund-popup-animate');
		activate();
		return this;
	}
	function hide() {
		deactivate();
	}

	return {
		activate: activate,
		deactivate: deactivate,
		disableBlur: disableBlur,
		show: show,
		hide: hide
	}

})();
<commit_msg>Create avgrund.js<commit_after>/*!
 * avgrund 0.1
 * http://lab.hakim.se/avgrund
 * MIT licensed
 *
 * Copyright (C) 2012 Hakim El Hattab, http://hakim.se
 */
var Avgrund = (function(){

	var container = document.documentElement,
		popup = document.querySelector('.avgrund-popup-animate'),
		cover = document.querySelector('.avgrund-cover'),
		currentState = null;
	container.classList.add('avgrund-ready');

	// Deactivate on ESC
	function onDocumentKeyUp(event) {
		if(event.keyCode === 27) {
			deactivate();
		}
	}

	// Deactivate on click outside
	function onDocumentClick(event) {
		if(event.target === cover) {
			deactivate();
		}
	}

	function activate(state) {
		document.addEventListener('keyup', onDocumentKeyUp, false);
		document.addEventListener('click', onDocumentClick, false);
		document.addEventListener('touchstart', onDocumentClick, false);

		popup.classList.remove(currentState);
		popup.classList.add('no-transition');
		if(state)
			popup.classList.add(state);

		setTimeout(function() {
			popup.classList.remove('no-transition');
			container.classList.add('avgrund-active');
		}, 0);

		currentState = state;
	}

	function deactivate() {
		document.removeEventListener('keyup', onDocumentKeyUp, false);
		document.removeEventListener('click', onDocumentClick, false);
		document.removeEventListener('touchstart', onDocumentClick, false);

		container.classList.remove('avgrund-active');
		popup.classList.remove('avgrund-popup-animate');
	}

	function disableBlur() {
		document.documentElement.classList.add('no-blur');
	}

	function show(selector){
		popup = document.querySelector(selector);
		popup.classList.add('avgrund-popup-animate');
		activate();
		return this;
	}
	function hide() {
		deactivate();
	}

	return {
		activate: activate,
		deactivate: deactivate,
		disableBlur: disableBlur,
		show: show,
		hide: hide
	}

})();
<|endoftext|>


<commit_before>// Andoni Garcia's Markov Babbler in JS. 2014

var TABLE = new htable(51);

// =====================================================================
// ====================== Hash Table Structs  ==========================
// =====================================================================

// My general "hash" function. Just assigns a number to the each word
// that is "somewhat" unique. THIS FUNCTION DOES NOT preserve properties
// like backtracking resistance or collision resistance.
function hashFn(word){
	var res = 17;
	for(var i = 0; i < word.length; i++){
		var tmp = word.charCodeAt(i) * 31;
		tmp *= 23;
		res += tmp;
	}
	return res;
}

function list(word){
	this.word = word;
	this.count = 1;
	this.nextWord = undefined;
}

function entry(word){
	this.word = word;
	this.count = 1;
	this.nextWord = undefined;
}

function bucket(entry){
	this.e = entry;
	this.nextBucket = undefined;
}

function htable(nBucks){
	var bucks = [];
	for(var i = 0; i < nBucks; i++){
		bucks.push(undefined);
	}

	this.nBuckets = nBucks;
	this.buckets = bucks;
	this.firstWords = [];
}

// =====================================================================
// ====================== Membership Testing ===========================
// =====================================================================

function bucketMem(s, b){
	var tmp = b;
	while(tmp != undefined && tmp != null){
		if(tmp.e.word === s)
			return true;
		tmp = tmp.nextBucket;
	}
	return false;
}

function listMem(s, l){
	var tmp = l;
	while(tmp != undefined && tmp != null){
		if(tmp.word === s)
			return true;
		tmp = tmp.nextWord
	}
	return false;
}

function htableMem(s){
	var nBucks = TABLE.nBuckets;
	var hash = hashFn(s);
	var whichBucket = hash % nBucks;
	return bucketMem(s, TABLE.buckets[whichBucket]);
}

// =====================================================================
// ====================== Insertion Functions ==========================
// =====================================================================

function isFirstWord(s){
	var firstChar = s.charCodeAt(0);
	if(65 <= firstChar && firstChar <= 90)
		return true;
	return false;
}

function endOfSent(s){
	var lastChar = s.charAt(s.length - 1);
	if(lastChar === "." || lastChar === "?" || lastChar === "!")
		return true;
	return false;
}

// Checks that at least 1 character in the String is printable
function isPrintable(s){
	for(var i = 0; i < s.length; i++){
		var c = s.charCodeAt(i);
		if((48 <= c && c <= 57) || (65 <= c && c <= 90) ||
			(97 <= c && c <= 122) || c === 45 || c === 39)
			return true;
	}
	return false;
}

function strCleanup(s, bool){
	var newStr = "";
	for(var i = 0; i < s.length; i++){
		var c = s.charCodeAt(i);
		var d = s.charAt(i);
		if(bool && i === (s.length - 1)){
			if(d === "." || d === "?" || d === "!"){
				newStr += d;
				continue;
			}
		}
		if((48 <= c && c <= 57) || (65 <= c && c <= 90) || (97 <= c && c <= 122) || c === 45 || c === 39)
			newStr += d;
	}
	return newStr;
}

function htableInsert(s, nextW){
	// Add to firstWord list
	if(isFirstWord(s))
		TABLE.firstWords.push(s);

	// Adds to the appropriate place in the table
	var a = TABLE.nBuckets;
	var b = hashFn(s);
	var hash = b % a;

	var curr = TABLE.buckets[hash];
	// If the bucket already contains the current word
	if(bucketMem(s, curr)){
		// Finds the appropriate entry
		while(curr.e.word !== s)
			curr = curr.nextBucket;
		var ent = curr.e;
		// Increments the entry's count
		ent.count++;

		// If the entry already contains the next word
		if(listMem(nextW, ent.nextWord)){
			var nextWd = ent.nextWord;
			// Finds the appropriate list
			while(nextWd.word !== nextW)
				nextWd = nextWd.nextWord;
			// Increments the list's count
			nextWd.count++;
			return;
		// The entry does not contain the word
		} else {
			var newL = new list(nextW);
			newL.nextWord = ent.nextWord;
			ent.nextWord = newL;
			return;
		}
	// The bucket does not contain the current word
	} else {
		var lnew = new list(nextW);
		var enew = new entry(s);
		enew.nextWord = lnew;
		var bnew = new bucket(enew);
		bnew.nextBucket = curr;
		TABLE.buckets[hash] = bnew;
		return;
	}
}

// Treats a "file" as a giant array of words
function insertFile(upload){
	var currentWord, nextWord;
	var end = "EOS";
	var ct = 0;
	var maxlen = upload.length;

	// A function to get the next printable word
	function getNextWord(){
		if(ct >= maxlen)
			return "EOS";
		word = upload[ct];
		ct++;
		while(!isPrintable(word) && ct < maxlen){
			word = upload[ct];
			ct++;
		}
		return word;

	};

	// The insertion algorithm
	currentWord = getNextWord();
	nextWord = getNextWord();
	while(ct < maxlen){
		if(endOfSent(currentWord)){
			var tmp = strCleanup(currentWord, true);
			htableInsert(tmp, end);
		} else {
			var tmp1 = strCleanup(currentWord, false);
			var tmp2 = strCleanup(currentWord, false);
			htableInsert(tmp1, tmp2);
		}
		currentWord = nextWord;
		nextWord = getNextWord();
	}

	// Handling the end case
	var tmp3 = strCleanup(currentWord, true);
	htableInsert(tmp3, end);
	return;
}

// =====================================================================
// ====================== Babbling Functions ===========================
// =====================================================================

function nextWord(e){
	var randNum = Math.floor(Math.random() * e.count);
	var list = e.nextWord;
	while(list != undefined){
		randNum -= list.count;
		if(randNum <= 0)
			return list.word;
		list = list.nextWord;
	}
	return;
}

function firstWord(){
	var randNum = Math.floor(Math.random() * TABLE.firstWords.length);
	return TABLE.firstWords[randNum];
}

function htableSearch(s){
	var a = TABLE.nBuckets;
	var b = hashFn(s);
	var c = (b % a);
	var bucks = TABLE.buckets[c];
	if(htableMem(s)){
		while(bucks.e.word !== s)
			bucks = bucks.nextBucket;
		return bucks.e;
	}
	return undefined;
}

function sentence(){
	var sent = [];

	var words = Math.floor(Math.random() * 25) + 3;

	//Creates the sentence
	var first = firstWord();
	var lastWord = first;
	var e = htableSearch(first);
	while(words !== 0){
		sent.push(e.word);
		if(words > 0)
			sent.push(" ");
		var nxt = nextWord(e);
		lastWord = nxt;
		if(nxt === "EOS")
			break;
		e = htableSearch(nxt);
		if(e == undefined)
			break;
		words--;
	}
	sent.pop();
	if(!(endOfSent(lastWord)))
		sent.push(".");
	return sent.join("");
}

function paragraph(len){
	var par = [];
	par.push("\t");
	while(len !== 0){
		par.push(sentence());
		par.push(" ");
		len--;
	}
	return par.join("");
}

function babble(pars, sents){
	var bab = [];
	while(pars !== 0){
		bab.push(paragraph(sents));
		bab.push("\n");
		pars--;
	}
	return bab;
}<commit_msg>Everything is its own next word...<commit_after>// Andoni Garcia's Markov Babbler in JS. 2014

var TABLE = new htable(51);

// =====================================================================
// ====================== Hash Table Structs  ==========================
// =====================================================================

// My general "hash" function. Just assigns a number to the each word
// that is "somewhat" unique. THIS FUNCTION DOES NOT preserve properties
// like backtracking resistance or collision resistance.
function hashFn(word){
	var res = 17;
	for(var i = 0; i < word.length; i++){
		var tmp = word.charCodeAt(i) * 31;
		tmp *= 23;
		res += tmp;
	}
	return res;
}

function list(word){
	this.word = word;
	this.count = 1;
	this.nextWord = undefined;
}

function entry(word){
	this.word = word;
	this.count = 1;
	this.nextWord = undefined;
}

function bucket(entry){
	this.e = entry;
	this.nextBucket = undefined;
}

function htable(nBucks){
	var bucks = [];
	for(var i = 0; i < nBucks; i++){
		bucks.push(undefined);
	}

	this.nBuckets = nBucks;
	this.buckets = bucks;
	this.firstWords = [];
}

// =====================================================================
// ====================== Membership Testing ===========================
// =====================================================================

function bucketMem(s, b){
	var tmp = b;
	while(tmp != undefined && tmp != null){
		if(tmp.e.word === s)
			return true;
		tmp = tmp.nextBucket;
	}
	return false;
}

function listMem(s, l){
	var tmp = l;
	while(tmp != undefined && tmp != null){
		if(tmp.word === s)
			return true;
		tmp = tmp.nextWord
	}
	return false;
}

function htableMem(s){
	var nBucks = TABLE.nBuckets;
	var hash = hashFn(s);
	var whichBucket = hash % nBucks;
	return bucketMem(s, TABLE.buckets[whichBucket]);
}

// =====================================================================
// ====================== Insertion Functions ==========================
// =====================================================================

function isFirstWord(s){
	var firstChar = s.charCodeAt(0);
	if(65 <= firstChar && firstChar <= 90)
		return true;
	return false;
}

function endOfSent(s){
	var lastChar = s.charAt(s.length - 1);
	if(lastChar === "." || lastChar === "?" || lastChar === "!")
		return true;
	return false;
}

// Checks that at least 1 character in the String is printable
function isPrintable(s){
	for(var i = 0; i < s.length; i++){
		var c = s.charCodeAt(i);
		if((48 <= c && c <= 57) || (65 <= c && c <= 90) ||
			(97 <= c && c <= 122) || c === 45 || c === 39)
			return true;
	}
	return false;
}

function strCleanup(s, bool){
	var newStr = "";
	for(var i = 0; i < s.length; i++){
		var c = s.charCodeAt(i);
		var d = s.charAt(i);
		if(bool && i === (s.length - 1)){
			if(d === "." || d === "?" || d === "!"){
				newStr += d;
				continue;
			}
		}
		if((48 <= c && c <= 57) || (65 <= c && c <= 90) || (97 <= c && c <= 122) || c === 45 || c === 39)
			newStr += d;
	}
	return newStr;
}

function htableInsert(s, nextW){
	// Add to firstWord list
	if(isFirstWord(s))
		TABLE.firstWords.push(s);

	// Adds to the appropriate place in the table
	var a = TABLE.nBuckets;
	var b = hashFn(s);
	var hash = b % a;

	var curr = TABLE.buckets[hash];
	// If the bucket already contains the current word
	if(bucketMem(s, curr)){
		// Finds the appropriate entry
		while(curr.e.word !== s)
			curr = curr.nextBucket;
		var ent = curr.e;
		// Increments the entry's count
		ent.count++;

		// If the entry already contains the next word
		if(listMem(nextW, ent.nextWord)){
			var nextWd = ent.nextWord;
			// Finds the appropriate list
			while(nextWd.word !== nextW)
				nextWd = nextWd.nextWord;
			// Increments the list's count
			nextWd.count++;
			return;
		// The entry does not contain the word
		} else {
			var newL = new list(nextW);
			newL.nextWord = ent.nextWord;
			ent.nextWord = newL;
			return;
		}
	// The bucket does not contain the current word
	} else {
		var lnew = new list(nextW);
		var enew = new entry(s);
		enew.nextWord = lnew;
		var bnew = new bucket(enew);
		bnew.nextBucket = curr;
		TABLE.buckets[hash] = bnew;
		return;
	}
}

// Treats a "file" as a giant array of words
function insertFile(upload){
	var currentWord, nextWord;
	var end = "EOS";
	var ct = 0;
	var maxlen = upload.length;

	// A function to get the next printable word
	function getNextWord(){
		if(ct >= maxlen)
			return "EOS";
		var word = upload[ct++];
		while(!isPrintable(word) && ct < maxlen){
			word = upload[ct++];
		}
		return word;
	}

	// The insertion algorithm
	currentWord = getNextWord();
	nextWord = getNextWord();
	while(ct < maxlen){
		if(endOfSent(currentWord)){
			var tmp = strCleanup(currentWord, true);
			htableInsert(tmp, end);
		} else {
			var tmp1 = strCleanup(currentWord, false);
			var tmp2 = strCleanup(currentWord, false);
			htableInsert(tmp1, tmp2);
		}
		currentWord = nextWord;
		nextWord = getNextWord();
	}

	// Handling the end case
	var tmp3 = strCleanup(currentWord, true);
	htableInsert(tmp3, end);
	return;
}

// =====================================================================
// ====================== Babbling Functions ===========================
// =====================================================================

function nextWord(e){
	var randNum = Math.floor(Math.random() * e.count);
	var list = e.nextWord;
	while(list != undefined){
		randNum -= list.count;
		if(randNum <= 0)
			return list.word;
		list = list.nextWord;
	}
	return;
}

function firstWord(){
	var randNum = Math.floor(Math.random() * TABLE.firstWords.length);
	return TABLE.firstWords[randNum];
}

function htableSearch(s){
	var a = TABLE.nBuckets;
	var b = hashFn(s);
	var c = (b % a);
	var bucks = TABLE.buckets[c];
	if(htableMem(s)){
		while(bucks.e.word !== s)
			bucks = bucks.nextBucket;
		return bucks.e;
	}
	return undefined;
}

function sentence(){
	var sent = [];

	var words = Math.floor(Math.random() * 25) + 3;

	//Creates the sentence
	var first = firstWord();
	var lastWord = first;
	var e = htableSearch(first);
	while(words !== 0){
		sent.push(e.word);
		if(words > 0)
			sent.push(" ");
		var nxt = nextWord(e);
		lastWord = nxt;
		if(nxt === "EOS")
			break;
		e = htableSearch(nxt);
		if(e == undefined)
			break;
		words--;
	}
	sent.pop();
	if(!(endOfSent(lastWord)))
		sent.push(".");
	return sent.join("");
}

function paragraph(len){
	var par = [];
	par.push("\t");
	while(len !== 0){
		par.push(sentence());
		par.push(" ");
		len--;
	}
	return par.join("");
}

function babble(pars, sents){
	var bab = [];
	while(pars !== 0){
		bab.push(paragraph(sents));
		bab.push("\n");
		pars--;
	}
	return bab;
}<|endoftext|>


<commit_before>var bootbox = bootbox || (function() {
    var that = {};

    that.alert = function(str, cb, okStr) {
        if (okStr == null) {
            okStr = "OK";
        }
        if (typeof cb === 'undefined') {
            cb = null;
        }
        that.dialog(str, {
            "label": okStr,
            "callback": cb
        }, {
            "onEscape": cb
        });

    };

    that.confirm = function(str, cb, okStr, cancelStr) {
        if (okStr == null) {
            okStr = "OK";
        }
        if (cancelStr == null) {
            cancelStr = "Cancel";
        }
        that.dialog(str, [{
            "label": cancelStr,
            "callback": function() {
                cb(false);
            }
        }, {
            "label": okStr,
            "callback": function() {
                cb(true);
            }
        }]);
    }

    that.dialog = function(str, handlers, options) {
        var hideSource = null;
        var buttons = "";
        var callbacks = [];
        var options = options || {};

        // check for single object and convert to array if necessary
        if (typeof handlers.length == 'undefined') {
            handlers = [handlers];
        }

        var i = handlers.length;
        while (i--) {
            var label = null;
            var _class = null;
            var callback = null;

            if (typeof handlers[i].label == 'undefined' &&
                typeof handlers[i].class == 'undefined' &&
                typeof handlers[i].callback == 'undefined') {
                // if we've got nothing we expect, check for condensed format
                var propCount = 0;      // condensed will only match if this == 1
                var property = null;    // save the last property we found
                for (var j in handlers[i]) {
                    property = j;
                    propCount ++;
                }

                if (propCount == 1 && typeof handlers[i][j] == 'function') {
                    // matches condensed format of label -> function
                    handlers[i].label = property;
                    handlers[i].callback = handlers[i][j];
                }
            }

            if (typeof handlers[i].callback == 'function') {
                callback = handlers[i].callback;
            }

            if (handlers[i].class) {
                _class = handlers[i].class;
            } else if (i == handlers.length -1 == handlers.length == 2) {
                _class = 'primary';
            } else if (i == 0 && handlers.length == 2) {
                _class = 'danger';
            }

            if (handlers[i].label) {
                label = handlers[i].label;
            } else {
                label = "Option "+(i+1);
            }

            buttons += ""+label+"";

            callbacks[i] = callback;
        }

        var div = $([
            "
",
                "
",
                    str,
                "
",
                "
",
                    buttons,
                "
",
            "
"
        ].join("\n"));

        div.bind('hidden', function() {
            div.remove();
        });

        div.bind('hide', function() {
            if (hideSource == 'escape' &&
                typeof options.onEscape == 'function') {
                options.onEscape();
            }
        });

        // hook into the modal's keyup trigger to check for the escape key
        $(document).bind('keyup.modal', function ( e ) {
            if (e.which == 27) {
                hideSource = 'escape';
            }
        });

        // well, *if* we have a primary - give the last dom element (first displayed) focus
        div.bind('shown', function() {
            $("a.primary:last", div).focus();
        });

        $("a", div).click(function(e) {
            e.preventDefault();
            hideSource = 'button';
            div.modal("hide");
            var handler = $(this).data("handler");
            var cb = callbacks[handler];
            if (typeof cb == 'function') {
                cb();
            }
        });

        if (options.keyboard == null) {
            options.keyboard = (typeof options.onEscape == 'function');
        }
        div.modal({
            "backdrop" : options.backdrop || "static",
            "show"     : options.show || true,
            "keyboard" : options.keyboard
        });

        $("body").append(div);
    }

    return that;
})();
<commit_msg>bugfix to primary button detection logic<commit_after>var bootbox = bootbox || (function() {
    var that = {};

    that.alert = function(str, cb, okStr) {
        if (okStr == null) {
            okStr = "OK";
        }
        if (typeof cb === 'undefined') {
            cb = null;
        }
        that.dialog(str, {
            "label": okStr,
            "callback": cb
        }, {
            "onEscape": cb
        });

    };

    that.confirm = function(str, cb, okStr, cancelStr) {
        if (okStr == null) {
            okStr = "OK";
        }
        if (cancelStr == null) {
            cancelStr = "Cancel";
        }
        that.dialog(str, [{
            "label": cancelStr,
            "callback": function() {
                cb(false);
            }
        }, {
            "label": okStr,
            "callback": function() {
                cb(true);
            }
        }]);
    }

    that.dialog = function(str, handlers, options) {
        var hideSource = null;
        var buttons = "";
        var callbacks = [];
        var options = options || {};

        // check for single object and convert to array if necessary
        if (typeof handlers.length == 'undefined') {
            handlers = [handlers];
        }

        var i = handlers.length;
        while (i--) {
            var label = null;
            var _class = null;
            var callback = null;

            if (typeof handlers[i].label == 'undefined' &&
                typeof handlers[i].class == 'undefined' &&
                typeof handlers[i].callback == 'undefined') {
                // if we've got nothing we expect, check for condensed format
                var propCount = 0;      // condensed will only match if this == 1
                var property = null;    // save the last property we found
                for (var j in handlers[i]) {
                    property = j;
                    propCount ++;
                }

                if (propCount == 1 && typeof handlers[i][j] == 'function') {
                    // matches condensed format of label -> function
                    handlers[i].label = property;
                    handlers[i].callback = handlers[i][j];
                }
            }

            if (typeof handlers[i].callback == 'function') {
                callback = handlers[i].callback;
            }

            if (handlers[i].class) {
                _class = handlers[i].class;
            } else if (i == handlers.length -1 && handlers.length == 2) {
                _class = 'primary';
            } else if (i == 0 && handlers.length == 2) {
                _class = 'danger';
            }

            if (handlers[i].label) {
                label = handlers[i].label;
            } else {
                label = "Option "+(i+1);
            }

            buttons += ""+label+"";

            callbacks[i] = callback;
        }

        var div = $([
            "
",
                "
",
                    str,
                "
",
                "
",
                    buttons,
                "
",
            "
"
        ].join("\n"));

        div.bind('hidden', function() {
            div.remove();
        });

        div.bind('hide', function() {
            if (hideSource == 'escape' &&
                typeof options.onEscape == 'function') {
                options.onEscape();
            }
        });

        // hook into the modal's keyup trigger to check for the escape key
        $(document).bind('keyup.modal', function ( e ) {
            if (e.which == 27) {
                hideSource = 'escape';
            }
        });

        // well, *if* we have a primary - give the last dom element (first displayed) focus
        div.bind('shown', function() {
            $("a.primary:last", div).focus();
        });

        $("a", div).click(function(e) {
            e.preventDefault();
            hideSource = 'button';
            div.modal("hide");
            var handler = $(this).data("handler");
            var cb = callbacks[handler];
            if (typeof cb == 'function') {
                cb();
            }
        });

        if (options.keyboard == null) {
            options.keyboard = (typeof options.onEscape == 'function');
        }
        div.modal({
            "backdrop" : options.backdrop || "static",
            "show"     : options.show || true,
            "keyboard" : options.keyboard
        });

        $("body").append(div);
    }

    return that;
})();
<|endoftext|>