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

/**
 * Demonstration of misc scenery-phet UI components
 *
 * @author Sam Reid
 * @author Chris Malley
 */
define( function( require ) {
  'use strict';

  // modules
  var BracketNode = require( 'SCENERY_PHET/BracketNode' );
  var CheckBox = require( 'SUN/CheckBox' );
  var ComboBox = require( 'SUN/ComboBox' );
  var ConductivityTesterNode = require( 'SCENERY_PHET/ConductivityTesterNode' );
  var Dimension2 = require( 'DOT/Dimension2' );
  var EyeDropperNode = require( 'SCENERY_PHET/EyeDropperNode' );
  var FaucetNode = require( 'SCENERY_PHET/FaucetNode' );
  var HSlider = require( 'SUN/HSlider' );
  var inherit = require( 'PHET_CORE/inherit' );
  var ProbeNode = require( 'SCENERY_PHET/ProbeNode' );
  var MeasuringTape = require( 'SCENERY_PHET/MeasuringTape' );
  var ModelViewTransform2 = require( 'PHETCOMMON/view/ModelViewTransform2' );
  var MovableDragHandler = require( 'SCENERY_PHET/input/MovableDragHandler' );
  var Node = require( 'SCENERY/nodes/Node' );
  var NumberPicker = require( 'SCENERY_PHET/NumberPicker' );
  var Path = require( 'SCENERY/nodes/Path' );
  var PhetFont = require( 'SCENERY_PHET/PhetFont' );
  var Property = require( 'AXON/Property' );
  var PropertySet = require( 'AXON/PropertySet' );
  var Range = require( 'DOT/Range' );
  var RulerNode = require( 'SCENERY_PHET/RulerNode' );
  var ScreenView = require( 'JOIST/ScreenView' );
  var Shape = require( 'KITE/Shape' );
  var StarNode = require( 'SCENERY_PHET/StarNode' );
  var Text = require( 'SCENERY/nodes/Text' );
  var ThermometerNode = require( 'SCENERY_PHET/ThermometerNode' );
  var VBox = require( 'SCENERY/nodes/VBox' );
  var Vector2 = require( 'DOT/Vector2' );
  var WavelengthSlider = require( 'SCENERY_PHET/WavelengthSlider' );
  var VisibleColor = require( 'SCENERY_PHET/VisibleColor' );

  function ComponentsView() {

    var thisView = this;
    ScreenView.call( this );

    // To add a demo, create an entry here.
    var demos = [
      { label: 'BracketNode', node: demoBracketNode( this.layoutBounds ) },
      { label: 'ConductivityTesterNode', node: demoConductivityTesterNode( this.layoutBounds ) },
      { label: 'EyeDropperNode', node: demoEyeDropperNode( this.layoutBounds ) },
      { label: 'FaucetNode', node: demoFaucetNode( this.layoutBounds ) },
      { label: 'MeasuringTape', node: demoMeasuringTape( this.layoutBounds ) },
      { label: 'NumberPicker', node: demoNumberPicker( this.layoutBounds ) },
      { label: 'ProbeNode', node: demoProbeNode( this.layoutBounds ) },
      { label: 'RulerNode', node: demoRulerNode( this.layoutBounds ) },
      { label: 'StarNode', node: demoStarNode( this.layoutBounds ) },
      { label: 'ThermometerNode', node: demoTemperatureNode( this.layoutBounds ) }
    ];

    // Sort the demos by label, so that they appear in the combo box in alphabetical order
    demos = _.sortBy( demos, function( demo ) {
      return demo.label;
    } );

    var comboBoxItems = [];

    demos.forEach( function( demo ) {

      // add demo to the combo box
      comboBoxItems.push( ComboBox.createItem( new Text( demo.label, { font: new PhetFont( 20 ) } ), demo.node ) );

      // add demo to the scenegraph
      thisView.addChild( demo.node );

      // demo is invisible until selected via the combo box
      demo.node.visible = false;
    } );

    // Parent for the combo box popup list
    var listParent = new Node();
    this.addChild( listParent );

    // Combo box for selecting which component to view
    var selectedDemoProperty = new Property( demos[ 0 ].node );
    var comboBox = new ComboBox( comboBoxItems, selectedDemoProperty, listParent, {
      buttonFill: 'rgb( 218, 236, 255 )',
      top: 20,
      left: 20
    } );
    this.addChild( comboBox );

    // Make the selected demo visible
    selectedDemoProperty.link( function( demo, oldDemo ) {
      if ( oldDemo ) { oldDemo.visible = false; }
      demo.visible = true;
    } );
  }

  // Creates a demo for BracketNode
  var demoBracketNode = function( layoutBounds ) {
    return new BracketNode( {
      orientation: 'left',
      bracketTipLocation: 0.75,
      labelNode: new Text( 'bracket', { font: new PhetFont( 20 ) } ),
      spacing: 10,
      center: layoutBounds.center
    } );
  };

  // Creates a demo for ConductivityTesterNode
  var demoConductivityTesterNode = function( layoutBounds ) {

    var brightnessProperty = new Property( 0 ); // 0-1
    var testerLocationProperty = new Property( new Vector2( 0, 0 ) );
    var positiveProbeLocationProperty = new Property( new Vector2( testerLocationProperty.get().x + 140, testerLocationProperty.get().y + 100 ) );
    var negativeProbeLocationProperty = new Property( new Vector2( testerLocationProperty.get().x - 40, testerLocationProperty.get().y + 100 ) );

    var conductivityTesterNode = new ConductivityTesterNode( brightnessProperty,
      testerLocationProperty, positiveProbeLocationProperty, negativeProbeLocationProperty, {
        modelViewTransform: ModelViewTransform2.createOffsetScaleMapping( layoutBounds.center, 1 ), // move model origin to screen's center
        positiveProbeFill: 'orange',
        cursor: 'pointer'
      }
    );
    conductivityTesterNode.addInputListener( new MovableDragHandler( testerLocationProperty ) );

    // brightness slider
    var brightnessSlider = new HSlider( brightnessProperty, { min: 0, max: 1 }, {
      trackSize: new Dimension2( 200, 5 ),
      thumbSize: new Dimension2( 25, 45 ),
      thumbFillEnabled: 'orange',
      thumbFillHighlighted: 'rgb( 255, 210, 0 )',
      thumbCenterLineStroke: 'black',
      left: layoutBounds.centerX,
      bottom: conductivityTesterNode.top - 50
    } );

    // short-circuit check box
    var shortCircuitProperty = new Property( false );
    shortCircuitProperty.link( function( shortCircuit ) {
      conductivityTesterNode.shortCircuit = shortCircuit;
    } );
    var shortCircuitCheckBox = new CheckBox( new Text( 'short circuit', { font: new PhetFont( 20 ) } ), shortCircuitProperty, {
      left: brightnessSlider.left,
      bottom: brightnessSlider.top - 50
    } );

    return new Node( {
      children: [ conductivityTesterNode, brightnessSlider, shortCircuitCheckBox ],
      center: layoutBounds.center
    } );
  };

  // Creates a demo for EyeDropperNode
  var demoEyeDropperNode = function( layoutBounds ) {

    var dropperNode = new EyeDropperNode( {
      fluidColor: 'purple',
      center: layoutBounds.center
    } );

    dropperNode.dispensingProperty.lazyLink( function( dispensing ) {
      console.log( 'dropper ' + ( dispensing ? 'dispensing' : 'not dispensing' ) );
    } );

    return dropperNode;
  };

  // Creates a demo for FaucetNode
  var demoFaucetNode = function( layoutBounds ) {

    var fluidRateProperty = new Property( 0 );
    var faucetEnabledProperty = new Property( true );

    var faucetNode = new FaucetNode( 10, fluidRateProperty, faucetEnabledProperty );

    var faucetEnabledCheckBox = new CheckBox( new Text( 'faucet enabled', { font: new PhetFont( 20 ) } ), faucetEnabledProperty, {
      left: faucetNode.left,
      bottom: faucetNode.top - 20
    } );

    return new Node( {
      children: [ faucetNode, faucetEnabledCheckBox ],
      center: layoutBounds.center
    } );
  };

  // Creates a demo for ProbeNode
  var demoProbeNode = function( layoutBounds ) {

    var demoParent = new Node();

    // Layer for the light sensor node.  The node will be destroyed and re-created when its parameters change
    var probeNodeLayer = new Node();

    // Model properties that describe the sensor
    var propertySet = new PropertySet( {
      radius: ProbeNode.DEFAULTS.radius,
      handleWidth: ProbeNode.DEFAULTS.handleWidth,
      handleHeight: ProbeNode.DEFAULTS.handleHeight,
      handleCornerRadius: ProbeNode.DEFAULTS.handleCornerRadius
    } );

    var wavelengthProperty = new Property( 450 );

    // Only switch to the wavelength slider after it has been changed once
    var useWavelength = false;
    wavelengthProperty.lazyLink( function() {
      useWavelength = true;
    } );

    // When the model properties change, update the sensor node
    var updateLightSensor = function() {
      probeNodeLayer.removeAllChildren();
      probeNodeLayer.addChild( new ProbeNode( {

        // default to the default color, but allow it to be overriden with the wavelength slider
        color: useWavelength ? VisibleColor.wavelengthToColor( wavelengthProperty.value ) : ProbeNode.DEFAULTS.color,
        radius: propertySet.radius,
        x: layoutBounds.centerX,
        y: layoutBounds.centerY,
        handleWidth: propertySet.handleWidth,
        handleHeight: propertySet.handleHeight,
        handleCornerRadius: propertySet.handleCornerRadius
      } ) );
    };
    propertySet.radiusProperty.link( updateLightSensor );
    propertySet.handleWidthProperty.link( updateLightSensor );
    propertySet.handleHeightProperty.link( updateLightSensor );
    propertySet.handleCornerRadiusProperty.link( updateLightSensor );
    wavelengthProperty.link( updateLightSensor );
    demoParent.addChild( probeNodeLayer );

    // Show a cross hairs in the middle of the screen so that we can verify that the sensor's origin is correct.
    demoParent.addChild( new Path( new Shape()
      .moveTo( layoutBounds.left, layoutBounds.centerY )
      .lineTo( layoutBounds.right, layoutBounds.centerY )
      .moveTo( layoutBounds.centerX, layoutBounds.top )
      .lineTo( layoutBounds.centerX, layoutBounds.bottom ), {
      stroke: 'black',
      lineWidth: 0.5
    } ) );

    var textLabel = function( text ) {
      return new Text( text, { font: new PhetFont( 12 ) } );
    };
    // Controls
    demoParent.addChild( new VBox( {
      resize: false, // Don't readjust the size when the slider knob moves all the way to the right
      spacing: 5,
      children: [
        textLabel( 'Radius' ),
        new HSlider( propertySet.radiusProperty, { min: 1, max: ProbeNode.DEFAULTS.radius * 2 } ),

        textLabel( 'Handle Width' ),
        new HSlider( propertySet.handleWidthProperty, { min: 1, max: ProbeNode.DEFAULTS.handleWidth * 2 } ),

        textLabel( 'Handle Height' ),
        new HSlider( propertySet.handleHeightProperty, { min: 1, max: ProbeNode.DEFAULTS.handleHeight * 2 } ),

        textLabel( 'Handle Corner Radius' ),
        new HSlider( propertySet.handleCornerRadiusProperty, {
          min: 1,
          max: ProbeNode.DEFAULTS.handleCornerRadius * 2
        } ),

        textLabel( 'Wavelength' ),
        new WavelengthSlider( wavelengthProperty )
      ],
      left: 50,
      bottom: layoutBounds.maxY - 50
    } ) );

    return demoParent;
  };

  // Creates a demo for MeasuringTape
  var demoMeasuringTape = function( layoutBounds ) {

    var measuringTapeUnitsProperty = new Property( { name: 'meters', multiplier: 1 } );

    return new MeasuringTape( measuringTapeUnitsProperty, new Property( true ), {
      textColor: 'black',
      dragBounds: layoutBounds,
      basePositionProperty: new Property( new Vector2( layoutBounds.centerX, layoutBounds.centerY ) ),
      tipPositionProperty: new Property( new Vector2( layoutBounds.centerX + 100, layoutBounds.centerY ) )
    } );
  };

  // Creates a demo for NumberPicker
  var demoNumberPicker = function( layoutBounds ) {
    return new NumberPicker( new Property( 0 ), new Property( new Range( -10, 10 ) ), {
      font: new PhetFont( 40 ),
      center: layoutBounds.center
    } );
  };

  // Creates a demo for RulerNode
  var demoRulerNode = function( layoutBounds ) {

    var rulerLength = 500;
    var majorTickWidth = 50;
    var majorTickLabels = [];
    var numberOfTicks = Math.floor( rulerLength / majorTickWidth ) + 1;
    for ( var i = 0; i < numberOfTicks; i++ ) {
      majorTickLabels[ i ] = '' + ( i * majorTickWidth );
    }

    return new RulerNode( rulerLength, 0.15 * rulerLength, majorTickWidth, majorTickLabels, 'm', {
      insetsWidth: 25,
      minorTicksPerMajorTick: 4,
      center: layoutBounds.center
    } );
  };

  // Creates a demo for StarNode
  var demoStarNode = function( layoutBounds ) {

    var starValueProperty = new Property( 1 );

    var starSlider = new HSlider( starValueProperty, { min: 0, max: 1 }, {
      thumbSize: new Dimension2( 25, 50 ),
      thumbFillHighlighted: 'yellow',
      thumbFillEnabled: 'rgb(220,220,0)',
      thumbCenterLineStroke: 'black'
    } );

    var starNodeContainer = new Node( {
      children: [ new StarNode() ],
      top: starSlider.bottom + 30,
      right: starSlider.right
    } );

    /*
     * Fill up a star by creating new StarNodes dynamically.
     * Shouldn't be a problem for sims since stars are relatively static.
     * Stars should be rewritten if they need to support smooth dynamic filling (may require mutable kite paths).
     */
    starValueProperty.link( function( value ) {
      starNodeContainer.children = [
        new StarNode( {
          value: value,
          outerRadius: 30,
          innerRadius: 15
        } )
      ];
    } );

    return new Node( {
      children: [ starNodeContainer, starSlider ],
      center: layoutBounds.center
    } );
  };

  // Creates a demo for ThermometerNode
  var demoTemperatureNode = function( layoutBounds ) {

    var temperatureProperty = new Property( 50 );

    var thermometer = new ThermometerNode( 0, 100, temperatureProperty, {
      bulbDiameter: 100,
      tubeWidth: 60,
      tubeHeight: 200,
      glassThickness: 6,
      backgroundFill: 'yellow'
    } );

    var temperatureSlider = new HSlider( temperatureProperty, { min: 0, max: 100 }, {
      trackSize: new Dimension2( 200, 5 ),
      thumbSize: new Dimension2( 25, 50 ),
      thumbFillHighlighted: 'red',
      thumbFillEnabled: 'rgb(158,35,32)'
    } );
    temperatureSlider.rotation = -Math.PI / 2;
    temperatureSlider.right = thermometer.left - 50;
    temperatureSlider.centerY = thermometer.centerY;

    return new Node( {
      children: [ thermometer, temperatureSlider ],
      center: layoutBounds.center
    } );
  };

  return inherit( ScreenView, ComponentsView );
} );<commit_msg>#165 updateLightSensor -> updateProbe in demo<commit_after>// Copyright 2002-2014, University of Colorado Boulder

/**
 * Demonstration of misc scenery-phet UI components
 *
 * @author Sam Reid
 * @author Chris Malley
 */
define( function( require ) {
  'use strict';

  // modules
  var BracketNode = require( 'SCENERY_PHET/BracketNode' );
  var CheckBox = require( 'SUN/CheckBox' );
  var ComboBox = require( 'SUN/ComboBox' );
  var ConductivityTesterNode = require( 'SCENERY_PHET/ConductivityTesterNode' );
  var Dimension2 = require( 'DOT/Dimension2' );
  var EyeDropperNode = require( 'SCENERY_PHET/EyeDropperNode' );
  var FaucetNode = require( 'SCENERY_PHET/FaucetNode' );
  var HSlider = require( 'SUN/HSlider' );
  var inherit = require( 'PHET_CORE/inherit' );
  var ProbeNode = require( 'SCENERY_PHET/ProbeNode' );
  var MeasuringTape = require( 'SCENERY_PHET/MeasuringTape' );
  var ModelViewTransform2 = require( 'PHETCOMMON/view/ModelViewTransform2' );
  var MovableDragHandler = require( 'SCENERY_PHET/input/MovableDragHandler' );
  var Node = require( 'SCENERY/nodes/Node' );
  var NumberPicker = require( 'SCENERY_PHET/NumberPicker' );
  var Path = require( 'SCENERY/nodes/Path' );
  var PhetFont = require( 'SCENERY_PHET/PhetFont' );
  var Property = require( 'AXON/Property' );
  var PropertySet = require( 'AXON/PropertySet' );
  var Range = require( 'DOT/Range' );
  var RulerNode = require( 'SCENERY_PHET/RulerNode' );
  var ScreenView = require( 'JOIST/ScreenView' );
  var Shape = require( 'KITE/Shape' );
  var StarNode = require( 'SCENERY_PHET/StarNode' );
  var Text = require( 'SCENERY/nodes/Text' );
  var ThermometerNode = require( 'SCENERY_PHET/ThermometerNode' );
  var VBox = require( 'SCENERY/nodes/VBox' );
  var Vector2 = require( 'DOT/Vector2' );
  var WavelengthSlider = require( 'SCENERY_PHET/WavelengthSlider' );
  var VisibleColor = require( 'SCENERY_PHET/VisibleColor' );

  function ComponentsView() {

    var thisView = this;
    ScreenView.call( this );

    // To add a demo, create an entry here.
    var demos = [
      { label: 'BracketNode', node: demoBracketNode( this.layoutBounds ) },
      { label: 'ConductivityTesterNode', node: demoConductivityTesterNode( this.layoutBounds ) },
      { label: 'EyeDropperNode', node: demoEyeDropperNode( this.layoutBounds ) },
      { label: 'FaucetNode', node: demoFaucetNode( this.layoutBounds ) },
      { label: 'MeasuringTape', node: demoMeasuringTape( this.layoutBounds ) },
      { label: 'NumberPicker', node: demoNumberPicker( this.layoutBounds ) },
      { label: 'ProbeNode', node: demoProbeNode( this.layoutBounds ) },
      { label: 'RulerNode', node: demoRulerNode( this.layoutBounds ) },
      { label: 'StarNode', node: demoStarNode( this.layoutBounds ) },
      { label: 'ThermometerNode', node: demoTemperatureNode( this.layoutBounds ) }
    ];

    // Sort the demos by label, so that they appear in the combo box in alphabetical order
    demos = _.sortBy( demos, function( demo ) {
      return demo.label;
    } );

    var comboBoxItems = [];

    demos.forEach( function( demo ) {

      // add demo to the combo box
      comboBoxItems.push( ComboBox.createItem( new Text( demo.label, { font: new PhetFont( 20 ) } ), demo.node ) );

      // add demo to the scenegraph
      thisView.addChild( demo.node );

      // demo is invisible until selected via the combo box
      demo.node.visible = false;
    } );

    // Parent for the combo box popup list
    var listParent = new Node();
    this.addChild( listParent );

    // Combo box for selecting which component to view
    var selectedDemoProperty = new Property( demos[ 0 ].node );
    var comboBox = new ComboBox( comboBoxItems, selectedDemoProperty, listParent, {
      buttonFill: 'rgb( 218, 236, 255 )',
      top: 20,
      left: 20
    } );
    this.addChild( comboBox );

    // Make the selected demo visible
    selectedDemoProperty.link( function( demo, oldDemo ) {
      if ( oldDemo ) { oldDemo.visible = false; }
      demo.visible = true;
    } );
  }

  // Creates a demo for BracketNode
  var demoBracketNode = function( layoutBounds ) {
    return new BracketNode( {
      orientation: 'left',
      bracketTipLocation: 0.75,
      labelNode: new Text( 'bracket', { font: new PhetFont( 20 ) } ),
      spacing: 10,
      center: layoutBounds.center
    } );
  };

  // Creates a demo for ConductivityTesterNode
  var demoConductivityTesterNode = function( layoutBounds ) {

    var brightnessProperty = new Property( 0 ); // 0-1
    var testerLocationProperty = new Property( new Vector2( 0, 0 ) );
    var positiveProbeLocationProperty = new Property( new Vector2( testerLocationProperty.get().x + 140, testerLocationProperty.get().y + 100 ) );
    var negativeProbeLocationProperty = new Property( new Vector2( testerLocationProperty.get().x - 40, testerLocationProperty.get().y + 100 ) );

    var conductivityTesterNode = new ConductivityTesterNode( brightnessProperty,
      testerLocationProperty, positiveProbeLocationProperty, negativeProbeLocationProperty, {
        modelViewTransform: ModelViewTransform2.createOffsetScaleMapping( layoutBounds.center, 1 ), // move model origin to screen's center
        positiveProbeFill: 'orange',
        cursor: 'pointer'
      }
    );
    conductivityTesterNode.addInputListener( new MovableDragHandler( testerLocationProperty ) );

    // brightness slider
    var brightnessSlider = new HSlider( brightnessProperty, { min: 0, max: 1 }, {
      trackSize: new Dimension2( 200, 5 ),
      thumbSize: new Dimension2( 25, 45 ),
      thumbFillEnabled: 'orange',
      thumbFillHighlighted: 'rgb( 255, 210, 0 )',
      thumbCenterLineStroke: 'black',
      left: layoutBounds.centerX,
      bottom: conductivityTesterNode.top - 50
    } );

    // short-circuit check box
    var shortCircuitProperty = new Property( false );
    shortCircuitProperty.link( function( shortCircuit ) {
      conductivityTesterNode.shortCircuit = shortCircuit;
    } );
    var shortCircuitCheckBox = new CheckBox( new Text( 'short circuit', { font: new PhetFont( 20 ) } ), shortCircuitProperty, {
      left: brightnessSlider.left,
      bottom: brightnessSlider.top - 50
    } );

    return new Node( {
      children: [ conductivityTesterNode, brightnessSlider, shortCircuitCheckBox ],
      center: layoutBounds.center
    } );
  };

  // Creates a demo for EyeDropperNode
  var demoEyeDropperNode = function( layoutBounds ) {

    var dropperNode = new EyeDropperNode( {
      fluidColor: 'purple',
      center: layoutBounds.center
    } );

    dropperNode.dispensingProperty.lazyLink( function( dispensing ) {
      console.log( 'dropper ' + ( dispensing ? 'dispensing' : 'not dispensing' ) );
    } );

    return dropperNode;
  };

  // Creates a demo for FaucetNode
  var demoFaucetNode = function( layoutBounds ) {

    var fluidRateProperty = new Property( 0 );
    var faucetEnabledProperty = new Property( true );

    var faucetNode = new FaucetNode( 10, fluidRateProperty, faucetEnabledProperty );

    var faucetEnabledCheckBox = new CheckBox( new Text( 'faucet enabled', { font: new PhetFont( 20 ) } ), faucetEnabledProperty, {
      left: faucetNode.left,
      bottom: faucetNode.top - 20
    } );

    return new Node( {
      children: [ faucetNode, faucetEnabledCheckBox ],
      center: layoutBounds.center
    } );
  };

  // Creates a demo for ProbeNode
  var demoProbeNode = function( layoutBounds ) {

    var demoParent = new Node();

    // Layer for the light sensor node.  The node will be destroyed and re-created when its parameters change
    var probeNodeLayer = new Node();

    // Model properties that describe the sensor
    var propertySet = new PropertySet( {
      radius: ProbeNode.DEFAULTS.radius,
      handleWidth: ProbeNode.DEFAULTS.handleWidth,
      handleHeight: ProbeNode.DEFAULTS.handleHeight,
      handleCornerRadius: ProbeNode.DEFAULTS.handleCornerRadius
    } );

    var wavelengthProperty = new Property( 450 );

    // Only switch to the wavelength slider after it has been changed once
    var useWavelength = false;
    wavelengthProperty.lazyLink( function() {
      useWavelength = true;
    } );

    // When the model properties change, update the sensor node
    var updateProbe = function() {
      probeNodeLayer.removeAllChildren();
      probeNodeLayer.addChild( new ProbeNode( {

        // default to the default color, but allow it to be overriden with the wavelength slider
        color: useWavelength ? VisibleColor.wavelengthToColor( wavelengthProperty.value ) : ProbeNode.DEFAULTS.color,
        radius: propertySet.radius,
        x: layoutBounds.centerX,
        y: layoutBounds.centerY,
        handleWidth: propertySet.handleWidth,
        handleHeight: propertySet.handleHeight,
        handleCornerRadius: propertySet.handleCornerRadius
      } ) );
    };
    propertySet.radiusProperty.link( updateProbe );
    propertySet.handleWidthProperty.link( updateProbe );
    propertySet.handleHeightProperty.link( updateProbe );
    propertySet.handleCornerRadiusProperty.link( updateProbe );
    wavelengthProperty.link( updateProbe );
    demoParent.addChild( probeNodeLayer );

    // Show a cross hairs in the middle of the screen so that we can verify that the sensor's origin is correct.
    demoParent.addChild( new Path( new Shape()
      .moveTo( layoutBounds.left, layoutBounds.centerY )
      .lineTo( layoutBounds.right, layoutBounds.centerY )
      .moveTo( layoutBounds.centerX, layoutBounds.top )
      .lineTo( layoutBounds.centerX, layoutBounds.bottom ), {
      stroke: 'black',
      lineWidth: 0.5
    } ) );

    var textLabel = function( text ) {
      return new Text( text, { font: new PhetFont( 12 ) } );
    };
    // Controls
    demoParent.addChild( new VBox( {
      resize: false, // Don't readjust the size when the slider knob moves all the way to the right
      spacing: 5,
      children: [
        textLabel( 'Radius' ),
        new HSlider( propertySet.radiusProperty, { min: 1, max: ProbeNode.DEFAULTS.radius * 2 } ),

        textLabel( 'Handle Width' ),
        new HSlider( propertySet.handleWidthProperty, { min: 1, max: ProbeNode.DEFAULTS.handleWidth * 2 } ),

        textLabel( 'Handle Height' ),
        new HSlider( propertySet.handleHeightProperty, { min: 1, max: ProbeNode.DEFAULTS.handleHeight * 2 } ),

        textLabel( 'Handle Corner Radius' ),
        new HSlider( propertySet.handleCornerRadiusProperty, {
          min: 1,
          max: ProbeNode.DEFAULTS.handleCornerRadius * 2
        } ),

        textLabel( 'Wavelength' ),
        new WavelengthSlider( wavelengthProperty )
      ],
      left: 50,
      bottom: layoutBounds.maxY - 50
    } ) );

    return demoParent;
  };

  // Creates a demo for MeasuringTape
  var demoMeasuringTape = function( layoutBounds ) {

    var measuringTapeUnitsProperty = new Property( { name: 'meters', multiplier: 1 } );

    return new MeasuringTape( measuringTapeUnitsProperty, new Property( true ), {
      textColor: 'black',
      dragBounds: layoutBounds,
      basePositionProperty: new Property( new Vector2( layoutBounds.centerX, layoutBounds.centerY ) ),
      tipPositionProperty: new Property( new Vector2( layoutBounds.centerX + 100, layoutBounds.centerY ) )
    } );
  };

  // Creates a demo for NumberPicker
  var demoNumberPicker = function( layoutBounds ) {
    return new NumberPicker( new Property( 0 ), new Property( new Range( -10, 10 ) ), {
      font: new PhetFont( 40 ),
      center: layoutBounds.center
    } );
  };

  // Creates a demo for RulerNode
  var demoRulerNode = function( layoutBounds ) {

    var rulerLength = 500;
    var majorTickWidth = 50;
    var majorTickLabels = [];
    var numberOfTicks = Math.floor( rulerLength / majorTickWidth ) + 1;
    for ( var i = 0; i < numberOfTicks; i++ ) {
      majorTickLabels[ i ] = '' + ( i * majorTickWidth );
    }

    return new RulerNode( rulerLength, 0.15 * rulerLength, majorTickWidth, majorTickLabels, 'm', {
      insetsWidth: 25,
      minorTicksPerMajorTick: 4,
      center: layoutBounds.center
    } );
  };

  // Creates a demo for StarNode
  var demoStarNode = function( layoutBounds ) {

    var starValueProperty = new Property( 1 );

    var starSlider = new HSlider( starValueProperty, { min: 0, max: 1 }, {
      thumbSize: new Dimension2( 25, 50 ),
      thumbFillHighlighted: 'yellow',
      thumbFillEnabled: 'rgb(220,220,0)',
      thumbCenterLineStroke: 'black'
    } );

    var starNodeContainer = new Node( {
      children: [ new StarNode() ],
      top: starSlider.bottom + 30,
      right: starSlider.right
    } );

    /*
     * Fill up a star by creating new StarNodes dynamically.
     * Shouldn't be a problem for sims since stars are relatively static.
     * Stars should be rewritten if they need to support smooth dynamic filling (may require mutable kite paths).
     */
    starValueProperty.link( function( value ) {
      starNodeContainer.children = [
        new StarNode( {
          value: value,
          outerRadius: 30,
          innerRadius: 15
        } )
      ];
    } );

    return new Node( {
      children: [ starNodeContainer, starSlider ],
      center: layoutBounds.center
    } );
  };

  // Creates a demo for ThermometerNode
  var demoTemperatureNode = function( layoutBounds ) {

    var temperatureProperty = new Property( 50 );

    var thermometer = new ThermometerNode( 0, 100, temperatureProperty, {
      bulbDiameter: 100,
      tubeWidth: 60,
      tubeHeight: 200,
      glassThickness: 6,
      backgroundFill: 'yellow'
    } );

    var temperatureSlider = new HSlider( temperatureProperty, { min: 0, max: 100 }, {
      trackSize: new Dimension2( 200, 5 ),
      thumbSize: new Dimension2( 25, 50 ),
      thumbFillHighlighted: 'red',
      thumbFillEnabled: 'rgb(158,35,32)'
    } );
    temperatureSlider.rotation = -Math.PI / 2;
    temperatureSlider.right = thermometer.left - 50;
    temperatureSlider.centerY = thermometer.centerY;

    return new Node( {
      children: [ thermometer, temperatureSlider ],
      center: layoutBounds.center
    } );
  };

  return inherit( ScreenView, ComponentsView );
} );<|endoftext|>


<commit_before>
/*
 * jshint forin:true, noarg:true, noempty:true, eqeqeq:true, bitwise:true, strict:true, undef:true, unused:true,
 * curly:true, browser:true, indent:4, maxerr:50, newcap:true
 *
 * Author:     Ryan Faulkner
 * Date:       2013-06-10
 * File:       chart.js
 *
 * Defines the chart object for ydash.
 *
 */

"use strict";

// Chart dimensions
var WIDTH = 640;
var HEIGHT = 300;

/**
 * Create chart elements based on Rickshaw library.
 *
 * @param id            - Chart id.
 * @param series_data   - [{data: [{x: <x>, y: <y>},+] color: <color>, name: <name>},+]
 * @param render_type   - Rickshaw render type of the plot.
 *
 */
function chartFactory(/* int */ id,
                      /* Array */ series_data,
                      /* String */ render_type) {

    return new Chart(id, series_data, render_type).
        buildGraph().
        buildSlider().
        buildHoverDetail().
        buildAxes().
        buildLegend();
}

/**
 * Create chart elements based on Rickshaw library.
 *
 * @param id            - Chart id.
 * @param series_data   - [{data: [{x: <x>, y: <y>},+] color: <color>, name: <name>},+]
 * @param render_type   - Rickshaw render type of the plot.
 *
 */
function Chart(/* int */ id,
               /* Array */ series_data,
               /* Array */ render_type) {

    this.id = id;
    this.series_data = series_data;
    this.render_type = render_type;

    this.buildGraph = function (args) {

        if (args === undefined) {
            args = {};
        }
        var minVal =  args['min'] != undefined ? args.min : 0;

        this.graph = new Rickshaw.Graph( {
            element: document.querySelector("#chart" + this.id),
            width: WIDTH,
            height: HEIGHT,
            renderer: this.render_type,
            preserve: true,
            series: this.series_data,
            min: minVal
        } );
        this.graph.render();
        return this;
    };

    this.buildSlider = function () {
        this.slider = new Rickshaw.Graph.RangeSlider({
            graph: this.graph,
            element: $('#slider' + this.id)
        });
        return this;
    };

    this.buildHoverDetail = function () {
        this.hoverDetail = new Rickshaw.Graph.HoverDetail( {
            graph: this.graph
        });
        return this;
    };

    this.buildAxes = function () {
        this.x_axis = new Rickshaw.Graph.Axis.Time( { graph: this.graph } );
        this.x_axis.render();

        this.y_axis = new Rickshaw.Graph.Axis.Y( {
            graph: this.graph,
            orientation: 'left',
            tickFormat: Rickshaw.Fixtures.Number.formatKMBT,
            element: document.getElementById('y_axis' + this.id)
        } );
        this.y_axis.render();
        return this;
    };

    this.buildLegend = function () {

        this.legend = new Rickshaw.Graph.Legend({
            graph: this.graph,
            element: document.querySelector('#legend' + this.id)
        });

        this.shelving = new Rickshaw.Graph.Behavior.Series.Toggle({
            graph: this.graph,
            legend: this.legend
        });

        this.highlighter = new Rickshaw.Graph.Behavior.Series.Highlight({
            graph: this.graph,
            legend: this.legend
        });

        this.order = new Rickshaw.Graph.Behavior.Series.Order({
            graph: this.graph,
            legend: this.legend
        });
        return this;
    };

    /*
     * Create a CSV from the series data.
     *
     * @param series_data   - [{data: [{x: <x>, y: <y>},+] color: <color>, name: <name>},+]
     */
    this.getCSV = function () {
        var i,j;
        var out = "name,x,y\n";
        for (i = 0; i < this.series_data.length; i++) {
            for (j = 0; j < this.series_data[i].data.length; j++) {
                out += [this.series_data[i].name,
                    this.series_data[i].data[j].x,
                    this.series_data[i].data[j].y].join(',') + "\n";
            }
        }
        return out;
    };

    return this;
}<commit_msg>mod. chart constructor accepts custom width/height.<commit_after>
/*
 * jshint forin:true, noarg:true, noempty:true, eqeqeq:true, bitwise:true, strict:true, undef:true, unused:true,
 * curly:true, browser:true, indent:4, maxerr:50, newcap:true
 *
 * Author:     Ryan Faulkner
 * Date:       2013-06-10
 * File:       chart.js
 *
 * Defines the chart object for ydash.
 *
 */

"use strict";

// Chart dimensions
var WIDTH = 640;
var HEIGHT = 300;

/**
 * Create chart elements based on Rickshaw library.
 *
 * @param id            - Chart id.
 * @param series_data   - [{data: [{x: <x>, y: <y>},+] color: <color>, name: <name>},+]
 * @param render_type   - Rickshaw render type of the plot.
 *
 */
function chartFactory(/* int */ id,
                      /* Array */ series_data,
                      /* String */ render_type) {

    return new Chart(id, series_data, render_type).
        buildGraph().
        buildSlider().
        buildHoverDetail().
        buildAxes().
        buildLegend();
}

/**
 * Create chart elements based on Rickshaw library.
 *
 * @param id            - Chart id.
 * @param series_data   - [{data: [{x: <x>, y: <y>},+] color: <color>, name: <name>},+]
 * @param render_type   - Rickshaw render type of the plot.
 * @param width   - Chart width (OPTIONAL).
 * @param height   - Chart height (OPTIONAL).
 *
 */
function Chart(/* int */ id,
               /* Array */ series_data,
               /* Array */ render_type,
               /* int */ width,
               /* int */ height) {

    if(typeof(width)==='undefined') width = WIDTH;
    if(typeof(height)==='undefined') height = HEIGHT;

    this.id = id;
    this.series_data = series_data;
    this.render_type = render_type;

    this.buildGraph = function (args) {

        if (args === undefined) {
            args = {};
        }
        var minVal =  args['min'] != undefined ? args.min : 0;

        this.graph = new Rickshaw.Graph( {
            element: document.querySelector("#chart" + this.id),
            width: width,
            height: height,
            renderer: this.render_type,
            preserve: true,
            series: this.series_data,
            min: minVal
        } );
        this.graph.render();
        return this;
    };

    this.buildSlider = function () {
        this.slider = new Rickshaw.Graph.RangeSlider({
            graph: this.graph,
            element: $('#slider' + this.id)
        });
        return this;
    };

    this.buildHoverDetail = function () {
        this.hoverDetail = new Rickshaw.Graph.HoverDetail( {
            graph: this.graph
        });
        return this;
    };

    this.buildAxes = function () {
        this.x_axis = new Rickshaw.Graph.Axis.Time( { graph: this.graph } );
        this.x_axis.render();

        this.y_axis = new Rickshaw.Graph.Axis.Y( {
            graph: this.graph,
            orientation: 'left',
            tickFormat: Rickshaw.Fixtures.Number.formatKMBT,
            element: document.getElementById('y_axis' + this.id)
        } );
        this.y_axis.render();
        return this;
    };

    this.buildLegend = function () {

        this.legend = new Rickshaw.Graph.Legend({
            graph: this.graph,
            element: document.querySelector('#legend' + this.id)
        });

        this.shelving = new Rickshaw.Graph.Behavior.Series.Toggle({
            graph: this.graph,
            legend: this.legend
        });

        this.highlighter = new Rickshaw.Graph.Behavior.Series.Highlight({
            graph: this.graph,
            legend: this.legend
        });

        this.order = new Rickshaw.Graph.Behavior.Series.Order({
            graph: this.graph,
            legend: this.legend
        });
        return this;
    };

    /*
     * Create a CSV from the series data.
     *
     * @param series_data   - [{data: [{x: <x>, y: <y>},+] color: <color>, name: <name>},+]
     */
    this.getCSV = function () {
        var i,j;
        var out = "name,x,y\n";
        for (i = 0; i < this.series_data.length; i++) {
            for (j = 0; j < this.series_data[i].data.length; j++) {
                out += [this.series_data[i].name,
                    this.series_data[i].data[j].x,
                    this.series_data[i].data[j].y].join(',') + "\n";
            }
        }
        return out;
    };

    return this;
}<|endoftext|>


<commit_before>var modConstants = require('module.constants');

var modCommon = {

  getFatigue: function(creep){
    var body = creep.body;
    var nonMoveCount = 0;
    var moveCount = 0;
    var total = 0;
    for(var limb in body){
      if(limb.type === MOVE){
        moveCount++;
        total++;
      }else{
        nonMoveCount++;
        total++;
      }
    }
    return 2*(nonMoveCount * 0.5 - moveCount);

  },

  distTo: function(creep, pos){
    var x = creep.pos.x - pos.x;
    var y = creep.pos.y - pos.y;
    var xSquared = x * x;
    var ySquared = y * y;
    var root = xSquared + ySquared;
    var dist = Math.sqrt(root);
    return dist;
  },

  //Gets energy from availible locations, including sources
  //if it can self harvest but at a lower priority
  getEn: function(creep){
    var maxTicks = 50;
    //Priority 1 is dropped energy, since it detiorates
    //TODO find why creeps will pick up compounds
    var dropped = creep.pos.findClosestByPath(FIND_DROPPED_ENERGY);
    if(dropped && dropped.resourceType === RESOURCE_ENERGY){
      var dist;
      var fat;
      var worth = 2;
      dist = this.distTo(creep, dropped.pos);
      fat = this.getFatigue(creep);
      worth = (dist * fat) / maxTicks;
      if(dropped && worth<=1){
        if(creep.pickup(dropped)== ERR_NOT_IN_RANGE){
          modCommon.move(creep,dropped.pos);
        }else{
          creep.memory.path = null;
        }
      }
    }else{
      //Next priority is the closest container or storage
      var storage = creep.pos.findClosestByPath(FIND_STRUCTURES, {
        filter: (object)=>((object.structureType === STRUCTURE_CONTAINER) || (object.structureType === STRUCTURE_STORAGE)) && (object.store[RESOURCE_ENERGY] > creep.carryCapacity)
      });
      if(storage!==null){
        var getEnergy = creep.withdraw(storage, RESOURCE_ENERGY, creep.carryCapacity-creep.carry);
        if(getEnergy===ERR_NOT_IN_RANGE) {
            modCommon.move(creep, storage);
        }else{
          creep.memory.path = null;
        }
      //Finally, the creep will harvest if it can
      }else if(creep.memory.selfHarvest){
        var sources = creep.pos.findClosestByPath(FIND_SOURCES);
        if(creep.harvest(sources[0]) == ERR_NOT_IN_RANGE) {
          modCommon.move(creep, sources);
        }else{
          creep.memory.path = null;
        }
      }
    }
  },

  stillToFix:function(object){
    //Priority
    var brokenRoad = object.structureType ===STRUCTURE_ROAD && (object.hits < 3000);
    var brokenRamp = object.structureType ===STRUCTURE_RAMPART && (object.hits < 5000)&& (object.hitsMax-object.hits>0);
    var brokenCont = object.structureType ===STRUCTURE_CONTAINER && (object.hits < 100000);
    var brokenWall = object.structureType ===STRUCTURE_WALL && (object.hits < 5000) && (object.hitsMax-object.hits>0);
    //Priority 2
    var brokenRamp2 = object.structureType ===STRUCTURE_RAMPART && (object.hits < (500*modifier+buffer))&& (object.hitsMax-object.hits>0);
    //Lowest Priority
    var brokenWall2 = object.structureType ===STRUCTURE_WALL && (object.hits < (500*modifier+modConstants.structBuffer)) && (object.hitsMax-object.hits>0);

    if(room.storage.store.energy < modConstants.roomEnergyBuffer){
      return brokenRoad || brokenRamp || brokenCont || brokenWall;
    }else if(fixeArr.length>0){
      return brokenRamp2;
    }else {
      return brokenWall2;
    }
    return false;
  },

  //Method to find the next structure to repair, shared by repair creeps and towers
  findToFixArr: function(room){
    var controlLvl = room.controller.level;
    var modifier = Math.max(Math.pow(10,controlLvl-3),10);
    var buffer = modConstants.structBuffer;

    var fixeArrPriority = room.find(FIND_STRUCTURES, {filter: function(object){
      var brokenRoad = object.structureType == STRUCTURE_ROAD && (object.hits < 3000);
      var brokenRamp = object.structureType == STRUCTURE_RAMPART && (object.hits < 5000)&& (object.hitsMax-object.hits>0);
      var brokenCont = object.structureType == STRUCTURE_CONTAINER && (object.hits < 100000);
      var brokenWall = object.structureType == STRUCTURE_WALL && (object.hits < 5000) && (object.hitsMax-object.hits>0);
      return brokenRoad || brokenRamp || brokenCont || brokenWall;
    }});

    var fixeArr = room.find(FIND_STRUCTURES, {filter: function(object){
      var brokenRamp = object.structureType ===STRUCTURE_RAMPART && (object.hits < (500*modifier+buffer))&& (object.hitsMax-object.hits>0);
      return brokenRamp;
    }});

    var fixeArr2 = room.find(FIND_STRUCTURES, {filter: function(object){
      var brokenWall = object.structureType ===STRUCTURE_WALL && (object.hits < (500*modifier+modConstants.structBuffer)) && (object.hitsMax-object.hits>0);
      return brokenWall;
    }});

    if((room.storage && room.storage.store.energy < modConstants.roomEnergyBuffer) || fixeArrPriority.length>0){
      return fixeArrPriority;
    }else if(fixeArr.length>0){
      return fixeArr;
    }else {
      return fixeArr2;
    }
    return NULL;
  },

  findToFortify: function(room){
    // use  '|| object.structureType ===STRUCTURE_RAMPART' ?
    var fortArr = room.find(FIND_MY_STRUCTURES, {filter: function(object){
      return (object.structureType ===STRUCTURE_WALL || object.structureType === STRUCTURE_RAMPART) && (object.hits < 100000) && (object.hitsMax-object.hits>0);
    }});

    return fortArr;
  },

  //Function to run away and hide
  retreat: function(creep){
    this.move(creep, creep.room.controller.pos);
    creep.say("HELP ME!");
  },

  //Function to move useing a stored path
  move:function(creep,pos){
    var opts = {};
    var posStr = pos.roomName+":"+pos.x+","+pos.y;
    opts.ignoreCreeps = false;
    opts.serialize = true;
    var emptyPath = false;
    var creepPath = creep.memory.path;
    if(!creepPath || creep.memory.dest != posStr){
        creep.memory.path = creep.pos.findPathTo(pos, opts);
        creep.memory.dest = posStr;
    }
    var result = creep.moveByPath(creep.memory.path);
    if(result != OK){
      creep.memory.path = null;
    }
    return result;
  },

  playerAttack:function(allCreepList){
    //priority Targets
    var pTargets = _.filter(allCreepList, (creep) => !creep.my);
    var attackers = [];
    for(var creepName in pTargets){
      var owner = pTargets[creepName].owner;
      var bodies = pTargets[creepName].body;
      var justAttack = _.filter(bodies, (part)=>(part.type==ATTACK || part.type==RANGED_ATTACK));
      if(!attackers.includes(owner))
        attackers.push(owner);
    }
    if(attackers.length > 0){
      return attackers[0]; //TODO turn this into a string of all attackers;
    }else{
      return null;
    }
  },

  findInjured:function(allCreepList){
    var hTargets = _.filter(allCreepList, (creep) => creep.hits<creep.hitsMax && creep.owner.username === "PCarton");
    //TODO sort by a priority
    return hTargets;
  },

  whatCarry:function(creep){
    var resourceType;

    var creepCarry = creep.carry;
    if(creepCarry.energy>0){
      resourceType = RESOURCE_ENERGY;
    }else if(creepCarry.power>0){
      resourceType = RESOURCE_POWER;
    }else if(creepCarry.H>0){
      resourceType = RESOURCE_HYDROGEN;
    }else if(creepCarry.O>0){
      resourceType = RESOURCE_OXYGEN;
    }else if(creepCarry.U>0){
      resourceType = RESOURCE_UTRIUM;
    }else if(creepCarry.L>0){
      resourceType = RESOURCE_LEMERGIUM;
    }else if(creepCarry.K>0){
      resourceType = RESOURCE_KEANIUM;
    }else if(creepCarry.Z>0){
      resourceType = RESOURCE_ZYNTHIUM;
    }else if(creepCarry.X>0){
      resourceType = RESOURCE_CATALYST;
    }else if(creepCarry.G>0){
      resourceType = RESOURCE_GHODIUM;
    }else{
      resourceType = RESOURCE_ENERGY;
    }

    return resourceType;
  },

  whatStore:function(struct){
    var resourceType;

    var structStore = struct.store;
    if(structStore.power>0){
      resourceType = RESOURCE_POWER;
    }else if(structStore.H>0){
      resourceType = RESOURCE_HYDROGEN;
    }else if(structStore.O>0){
      resourceType = RESOURCE_OXYGEN;
    }else if(structStore.U>0){
      resourceType = RESOURCE_UTRIUM;
    }else if(structStore.L>0){
      resourceType = RESOURCE_LEMERGIUM;
    }else if(structStore.K>0){
      resourceType = RESOURCE_KEANIUM;
    }else if(structStore.Z>0){
      resourceType = RESOURCE_ZYNTHIUM;
    }else if(structStore.X>0){
      resourceType = RESOURCE_CATALYST;
    }else if(structStore.G>0){
      resourceType = RESOURCE_GHODIUM;
    }else{
      resourceType = RESOURCE_ENERGY;
    }

    return resourceType;
  },

  getResourceCount:function(storeObj, resourceType){
    var count;
    switch(resourceType){
      case RESOURCE_ENERGY:
        count = storeObj.energy;
        break;
      case RESOURCE_POWER:
        count = storeObj.power;
        break;
      case RESOURCE_HYDROGEN:
        count = storeObj.H;
        break;
      case RESOURCE_OXYGEN:
        count = storeObj.O;
        break;
      case RESOURCE_UTRIUM:
        count = storeObj.U;
        break;
      case RESOURCE_LEMERGIUM:
        count = storeObj.L;
        break;
      case RESOURCE_KEANIUM:
        count = storeObj.K;
        break;
      case RESOURCE_ZYNTHIUM:
        count = storeObj.Z;
        break;
      case RESOURCE_CATALYST:
        count = storeObj.X;
        break;
      case RESOURCE_GHODIUM:
        count = storeObj.G;
        break;
      default:
        count = 0;
    }
    return count;
  },
  //TODO Emergency upgrade logic

  linkRoomAtTick:function(room,tick,msg){
    //Disables the autolinking
    //See http://support.screeps.com/hc/en-us/community/posts/206652879-Email-links-broken
    let roomName = room.name.replace(/^\w/,"&#"+room.name.charCodeAt(0)+";");

    var link = "http://screeps.com/a/#!/history/"+roomName+"?t="+tick;
    msg = "Room>"+roomName+":"+msg+"@"+tick;
    return ""+msg+"";
  }

};

module.exports = modCommon;
<commit_msg>stoped recalculating paths on fatigue moves<commit_after>var modConstants = require('module.constants');

var modCommon = {

  getFatigue: function(creep){
    var body = creep.body;
    var nonMoveCount = 0;
    var moveCount = 0;
    var total = 0;
    for(var limb in body){
      if(limb.type === MOVE){
        moveCount++;
        total++;
      }else{
        nonMoveCount++;
        total++;
      }
    }
    return 2*(nonMoveCount * 0.5 - moveCount);

  },

  distTo: function(creep, pos){
    var x = creep.pos.x - pos.x;
    var y = creep.pos.y - pos.y;
    var xSquared = x * x;
    var ySquared = y * y;
    var root = xSquared + ySquared;
    var dist = Math.sqrt(root);
    return dist;
  },

  //Gets energy from availible locations, including sources
  //if it can self harvest but at a lower priority
  getEn: function(creep){
    var maxTicks = 50;
    //Priority 1 is dropped energy, since it detiorates
    //TODO find why creeps will pick up compounds
    var dropped = creep.pos.findClosestByPath(FIND_DROPPED_ENERGY);
    if(dropped && dropped.resourceType === RESOURCE_ENERGY){
      var dist;
      var fat;
      var worth = 2;
      dist = this.distTo(creep, dropped.pos);
      fat = this.getFatigue(creep);
      worth = (dist * fat) / maxTicks;
      if(dropped && worth<=1){
        if(creep.pickup(dropped)== ERR_NOT_IN_RANGE){
          modCommon.move(creep,dropped.pos);
        }else{
          creep.memory.path = null;
        }
      }
    }else{
      //Next priority is the closest container or storage
      var storage = creep.pos.findClosestByPath(FIND_STRUCTURES, {
        filter: (object)=>((object.structureType === STRUCTURE_CONTAINER) || (object.structureType === STRUCTURE_STORAGE)) && (object.store[RESOURCE_ENERGY] > creep.carryCapacity)
      });
      if(storage!==null){
        var getEnergy = creep.withdraw(storage, RESOURCE_ENERGY, creep.carryCapacity-creep.carry);
        if(getEnergy===ERR_NOT_IN_RANGE) {
            modCommon.move(creep, storage);
        }else{
          creep.memory.path = null;
        }
      //Finally, the creep will harvest if it can
      }else if(creep.memory.selfHarvest){
        var sources = creep.pos.findClosestByPath(FIND_SOURCES);
        if(creep.harvest(sources[0]) == ERR_NOT_IN_RANGE) {
          modCommon.move(creep, sources);
        }else{
          creep.memory.path = null;
        }
      }
    }
  },

  stillToFix:function(object){
    //Priority
    var brokenRoad = object.structureType ===STRUCTURE_ROAD && (object.hits < 3000);
    var brokenRamp = object.structureType ===STRUCTURE_RAMPART && (object.hits < 5000)&& (object.hitsMax-object.hits>0);
    var brokenCont = object.structureType ===STRUCTURE_CONTAINER && (object.hits < 100000);
    var brokenWall = object.structureType ===STRUCTURE_WALL && (object.hits < 5000) && (object.hitsMax-object.hits>0);
    //Priority 2
    var brokenRamp2 = object.structureType ===STRUCTURE_RAMPART && (object.hits < (500*modifier+buffer))&& (object.hitsMax-object.hits>0);
    //Lowest Priority
    var brokenWall2 = object.structureType ===STRUCTURE_WALL && (object.hits < (500*modifier+modConstants.structBuffer)) && (object.hitsMax-object.hits>0);

    if(room.storage.store.energy < modConstants.roomEnergyBuffer){
      return brokenRoad || brokenRamp || brokenCont || brokenWall;
    }else if(fixeArr.length>0){
      return brokenRamp2;
    }else {
      return brokenWall2;
    }
    return false;
  },

  //Method to find the next structure to repair, shared by repair creeps and towers
  findToFixArr: function(room){
    var controlLvl = room.controller.level;
    var modifier = Math.max(Math.pow(10,controlLvl-3),10);
    var buffer = modConstants.structBuffer;

    var fixeArrPriority = room.find(FIND_STRUCTURES, {filter: function(object){
      var brokenRoad = object.structureType == STRUCTURE_ROAD && (object.hits < 3000);
      var brokenRamp = object.structureType == STRUCTURE_RAMPART && (object.hits < 5000)&& (object.hitsMax-object.hits>0);
      var brokenCont = object.structureType == STRUCTURE_CONTAINER && (object.hits < 100000);
      var brokenWall = object.structureType == STRUCTURE_WALL && (object.hits < 5000) && (object.hitsMax-object.hits>0);
      return brokenRoad || brokenRamp || brokenCont || brokenWall;
    }});

    var fixeArr = room.find(FIND_STRUCTURES, {filter: function(object){
      var brokenRamp = object.structureType ===STRUCTURE_RAMPART && (object.hits < (500*modifier+buffer))&& (object.hitsMax-object.hits>0);
      return brokenRamp;
    }});

    var fixeArr2 = room.find(FIND_STRUCTURES, {filter: function(object){
      var brokenWall = object.structureType ===STRUCTURE_WALL && (object.hits < (500*modifier+modConstants.structBuffer)) && (object.hitsMax-object.hits>0);
      return brokenWall;
    }});

    if((room.storage && room.storage.store.energy < modConstants.roomEnergyBuffer) || fixeArrPriority.length>0){
      return fixeArrPriority;
    }else if(fixeArr.length>0){
      return fixeArr;
    }else {
      return fixeArr2;
    }
    return NULL;
  },

  findToFortify: function(room){
    // use  '|| object.structureType ===STRUCTURE_RAMPART' ?
    var fortArr = room.find(FIND_MY_STRUCTURES, {filter: function(object){
      return (object.structureType ===STRUCTURE_WALL || object.structureType === STRUCTURE_RAMPART) && (object.hits < 100000) && (object.hitsMax-object.hits>0);
    }});

    return fortArr;
  },

  //Function to run away and hide
  retreat: function(creep){
    this.move(creep, creep.room.controller.pos);
    creep.say("HELP ME!");
  },

  //Function to move useing a stored path
  move:function(creep,pos){
    var opts = {};
    var posStr = pos.roomName+":"+pos.x+","+pos.y;
    opts.ignoreCreeps = false;
    opts.serialize = true;
    var emptyPath = false;
    var creepPath = creep.memory.path;
    if(!creepPath || creep.memory.dest != posStr){
        creep.memory.path = creep.pos.findPathTo(pos, opts);
        creep.memory.dest = posStr;
    }
    var result = creep.moveByPath(creep.memory.path);
    if(result != OK && result != ERR_TIRED){
      creep.memory.path = null;
    }
    return result;
  },

  playerAttack:function(allCreepList){
    //priority Targets
    var pTargets = _.filter(allCreepList, (creep) => !creep.my);
    var attackers = [];
    for(var creepName in pTargets){
      var owner = pTargets[creepName].owner;
      var bodies = pTargets[creepName].body;
      var justAttack = _.filter(bodies, (part)=>(part.type==ATTACK || part.type==RANGED_ATTACK));
      if(!attackers.includes(owner))
        attackers.push(owner);
    }
    if(attackers.length > 0){
      return attackers[0]; //TODO turn this into a string of all attackers;
    }else{
      return null;
    }
  },

  findInjured:function(allCreepList){
    var hTargets = _.filter(allCreepList, (creep) => creep.hits<creep.hitsMax && creep.owner.username === "PCarton");
    //TODO sort by a priority
    return hTargets;
  },

  whatCarry:function(creep){
    var resourceType;

    var creepCarry = creep.carry;
    if(creepCarry.energy>0){
      resourceType = RESOURCE_ENERGY;
    }else if(creepCarry.power>0){
      resourceType = RESOURCE_POWER;
    }else if(creepCarry.H>0){
      resourceType = RESOURCE_HYDROGEN;
    }else if(creepCarry.O>0){
      resourceType = RESOURCE_OXYGEN;
    }else if(creepCarry.U>0){
      resourceType = RESOURCE_UTRIUM;
    }else if(creepCarry.L>0){
      resourceType = RESOURCE_LEMERGIUM;
    }else if(creepCarry.K>0){
      resourceType = RESOURCE_KEANIUM;
    }else if(creepCarry.Z>0){
      resourceType = RESOURCE_ZYNTHIUM;
    }else if(creepCarry.X>0){
      resourceType = RESOURCE_CATALYST;
    }else if(creepCarry.G>0){
      resourceType = RESOURCE_GHODIUM;
    }else{
      resourceType = RESOURCE_ENERGY;
    }

    return resourceType;
  },

  whatStore:function(struct){
    var resourceType;

    var structStore = struct.store;
    if(structStore.power>0){
      resourceType = RESOURCE_POWER;
    }else if(structStore.H>0){
      resourceType = RESOURCE_HYDROGEN;
    }else if(structStore.O>0){
      resourceType = RESOURCE_OXYGEN;
    }else if(structStore.U>0){
      resourceType = RESOURCE_UTRIUM;
    }else if(structStore.L>0){
      resourceType = RESOURCE_LEMERGIUM;
    }else if(structStore.K>0){
      resourceType = RESOURCE_KEANIUM;
    }else if(structStore.Z>0){
      resourceType = RESOURCE_ZYNTHIUM;
    }else if(structStore.X>0){
      resourceType = RESOURCE_CATALYST;
    }else if(structStore.G>0){
      resourceType = RESOURCE_GHODIUM;
    }else{
      resourceType = RESOURCE_ENERGY;
    }

    return resourceType;
  },

  getResourceCount:function(storeObj, resourceType){
    var count;
    switch(resourceType){
      case RESOURCE_ENERGY:
        count = storeObj.energy;
        break;
      case RESOURCE_POWER:
        count = storeObj.power;
        break;
      case RESOURCE_HYDROGEN:
        count = storeObj.H;
        break;
      case RESOURCE_OXYGEN:
        count = storeObj.O;
        break;
      case RESOURCE_UTRIUM:
        count = storeObj.U;
        break;
      case RESOURCE_LEMERGIUM:
        count = storeObj.L;
        break;
      case RESOURCE_KEANIUM:
        count = storeObj.K;
        break;
      case RESOURCE_ZYNTHIUM:
        count = storeObj.Z;
        break;
      case RESOURCE_CATALYST:
        count = storeObj.X;
        break;
      case RESOURCE_GHODIUM:
        count = storeObj.G;
        break;
      default:
        count = 0;
    }
    return count;
  },
  //TODO Emergency upgrade logic

  linkRoomAtTick:function(room,tick,msg){
    //Disables the autolinking
    //See http://support.screeps.com/hc/en-us/community/posts/206652879-Email-links-broken
    let roomName = room.name.replace(/^\w/,"&#"+room.name.charCodeAt(0)+";");

    var link = "http://screeps.com/a/#!/history/"+roomName+"?t="+tick;
    msg = "Room>"+roomName+":"+msg+"@"+tick;
    return ""+msg+"";
  }

};

module.exports = modCommon;
<|endoftext|>


<commit_before>// Based on https://github.com/joelburget/react-live-editor/blob/master/live-compile.jsx

import React, { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom';
import babel from 'babel-core/browser';
import Wrapper from 'rsg-components/Wrapper';

import s from './Preview.css';

export default class Preview extends Component {
	static propTypes = {
		code: PropTypes.string.isRequired,
		evalInContext: PropTypes.func.isRequired,
	}

	constructor() {
		super();
		this.state = {
			error: null
		};
		this.componentState = {};
	}

	componentDidMount() {
		this.executeCode();
	}

	componentDidUpdate(prevProps) {
		if (this.props.code !== prevProps.code) {
			this.executeCode();
		}
	}

	setComponentState(newState) {
		this.componentState = {...this.componentState, ...newState};
		this.executeCode();
	}

	compileCode(code) {
		return babel.transform(code, {stage: 0}).code;
	}

	executeCode() {
		let mountNode = this.refs.mount;

		ReactDOM.unmountComponentAtNode(mountNode);

		this.setState({
			error: null
		});

		let { code } = this.props;
		if (!code) {
			return;
		}

		try {
			code = `
				const state = Object.freeze(${JSON.stringify(this.componentState)});
				${code}
			`;
			let compiledCode = this.compileCode(code);
			let component = this.props.evalInContext(compiledCode, this.setComponentState.bind(this));
			let wrappedComponent = (
				<Wrapper>
					{component}
				</Wrapper>
			);
			ReactDOM.render(wrappedComponent, mountNode);
		}
		catch (err) {
			ReactDOM.unmountComponentAtNode(mountNode);
			this.setState({
				error: err.toString()
			});
		}
	}

	renderError() {
		let { error } = this.state;
		if (error) {
			return (

{error}

			);
		}
		else {
			return null;
		}
	}

	render() {
		return (

				{this.renderError()}

		);
	}
}
<commit_msg>Fix weird issue with non-working default state.<commit_after>// Based on https://github.com/joelburget/react-live-editor/blob/master/live-compile.jsx

import React, { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom';
import babel from 'babel-core/browser';
import Wrapper from 'rsg-components/Wrapper';

import s from './Preview.css';

export default class Preview extends Component {
	static propTypes = {
		code: PropTypes.string.isRequired,
		evalInContext: PropTypes.func.isRequired,
	}

	constructor() {
		super();
		this.state = {
			error: null
		};
		this.componentState = {};
	}

	componentDidMount() {
		this.executeCode();
	}

	componentDidUpdate(prevProps) {
		if (this.props.code !== prevProps.code) {
			this.executeCode();
		}
	}

	setComponentState(newState) {
		this.componentState = {...this.componentState, ...newState};
		setTimeout(this.executeCode.bind(this), 0);
	}

	compileCode(code) {
		return babel.transform(code, {stage: 0}).code;
	}

	executeCode() {
		let mountNode = this.refs.mount;

		ReactDOM.unmountComponentAtNode(mountNode);

		this.setState({
			error: null
		});

		let { code } = this.props;
		if (!code) {
			return;
		}

		try {
			code = `
				const state = Object.freeze(${JSON.stringify(this.componentState)});
				${code}
			`;
			let compiledCode = this.compileCode(code);
			let component = this.props.evalInContext(compiledCode, this.setComponentState.bind(this));
			let wrappedComponent = (
				<Wrapper>
					{component}
				</Wrapper>
			);
			ReactDOM.render(wrappedComponent, mountNode);
		}
		catch (err) {
			ReactDOM.unmountComponentAtNode(mountNode);
			this.setState({
				error: err.toString()
			});
		}
	}

	renderError() {
		let { error } = this.state;
		if (error) {
			return (

{error}

			);
		}
		else {
			return null;
		}
	}

	render() {
		return (

				{this.renderError()}

		);
	}
}
<|endoftext|>


<commit_before>/* jslint node: true */
'use strict';

/*
* @name /lib/tapestry-logger-loggly.js
* @description A Tapestry logger module to send logs to Loggly
* @since Wed Feb 12 2014
* @author Kevin Hodges <kevin.hodges@holidayextras.com>
*/

( function() {

	var http = require( 'http' );

	/**
	* Constructor for a Loggly object
	* @param {Object} connectionOptions, proxies whatever is passed in to Tapestry as the logger.connection
	*/
	var loggly = function( connectionOptions ) {
		this.connection = connectionOptions;
	};

	exports = module.exports = loggly;

	/**
	* Push to Loggly the passed value
	* @param {Object} options:
	* - service, tell Loggly who this log is from, probably the name of your app/module
	* - type, payload? error? system log?
	* - namespace, which of the services "buckets" should we throw this in?
	* @param {Object} log, the object to push to Loggly
	*/
	loggly.prototype.log = function( options, log ) {

		var self = this;
		// if we have stuff...
		if( options.service && options.type && options.namespace && log ) {
			// the options make up our tags to Loggly
			var httpOptions = {
				hostname: self.connection.host,
				port: 80,
				path: '/' + self.connection.path + '/' + self.connection.key + '/tag/' + options.service + ',' + options.type + ',' + options.namespace,
				method: 'POST'
			};
			var request = http.request( httpOptions );
			// add the namespace to the log
			log.namespace = options.namespace;
			// ensure the log is a string
			if( typeof log !== 'string' ) {
				log = JSON.stringify( log );
			}
			// write data to request body
			request.write( log );
			request.end();
		}

	};

} )();<commit_msg>loggly-interface.js tweaked comments and removed function wrapper<commit_after>/* jslint node: true */
'use strict';

/*
* @name /lib/loggly-interface.js
* @description A logger module to send logs to Loggly
* @since Wed Feb 12 2014
* @author Kevin Hodges <kevin.hodges@holidayextras.com>
*/

var http = require( 'http' );

/**
	* Constructor for a Loggly object
	* @param {Object} connectionOptions, proxies whatever is passed in as the logger.connection
	*/
var loggly = function( connectionOptions ) {
	this.connection = connectionOptions;
};

exports = module.exports = loggly;

/**
	* Push to Loggly the passed value
	* @param {Object} options:
	* - service, tell Loggly who this log is from, probably the name of your app/module
	* - type, payload? error? system log?
	* - namespace, which of the services "buckets" should we throw this in?
	* @param {Object} log, the object to push to Loggly
	*/
loggly.prototype.log = function( options, log ) {

	var self = this;
	// if we have stuff...
	if( options.service && options.type && options.namespace && log ) {
		// the options make up our tags to Loggly
		var httpOptions = {
			hostname: self.connection.host,
			port: 80,
			path: '/' + self.connection.path + '/' + self.connection.key + '/tag/' + options.service + ',' + options.type + ',' + options.namespace,
			method: 'POST'
		};
		var request = http.request( httpOptions );
		// add the namespace to the log
		log.namespace = options.namespace;
		// ensure the log is a string
		if( typeof log !== 'string' ) {
			log = JSON.stringify( log );
		}
		// write data to request body
		request.write( log );
		request.end();
	}

};<|endoftext|>


<commit_before>var _ = require('underscore'),
    async = require('async'),
    styleDoc = require('./style-doc');

var resourceDir = require('path').resolve(__dirname + '/../resources/');

function fileList(context, callback) {
  var sheets = [],
      loadPrefix = context.config.loadPrefix();

  if (loadPrefix) {
    loadPrefix += context.platformPath;
  }

  context.plugins.get('module-map').buildMap(context, function(err, map) {
    if (err) {
      return callback(err);
    }

    var css = _.pluck(map.modules, 'css');
    if (map.base && map.base.css) {
      css.unshift(map.base.css);
    }

    css = _.flatten(css, true);
    _.each(css, function(css) {
      if (!css) {
        return;
      }

      var media = [[], [], []];
      if (css.minRatio) {
        _.each(['min--moz-device-pixel-ratio', '-webkit-min-device-pixel-ratio', 'min-device-pixel-ratio'], function(name, index) {
          media[index].push(name + ': ' + css.minRatio);
        })
      }
      if (css.maxRatio) {
        _.each(['max--moz-device-pixel-ratio', '-webkit-max-device-pixel-ratio', 'max-device-pixel-ratio'], function(name, index) {
          media[index].push(name + ': ' + css.maxRatio);
        })
      }
      if (media[0].length) {
        media = 'only screen and (' + _.map(media, function(engine) { return engine.join(' and '); }).join('), only screen and (') + ')';
      } else {
        media = undefined;
      }

      sheets.push({href: loadPrefix + css.href, media: media});
    });

    callback(err, {
      sheets: sheets,
      scripts: [map.modules[context.module.name].js]
    });
  });
}

module.exports = {
  priority: 50,

  moduleResources: function(context, next, complete) {
    next(function(err, moduleResources) {
      if (context.module['style-doc']) {
        var styleDoc = context.module['style-doc'];
        moduleResources = moduleResources || [];

        if (context.mode === 'static') {
          var staticList = context.static = context.static || [];

          styleDoc['style-doc'] = true;
          moduleResources.push(styleDoc);
        } else if (context.mode === 'scripts') {
          moduleResources.unshift({src: resourceDir + '/style-doc.js', global: true});
          moduleResources.unshift({src: resourceDir + '/handlebars.js', global: true});
          moduleResources.unshift({src: resourceDir + '/zepto.js', global: true});
        } else if (context.mode === 'styles') {
          moduleResources.push(resourceDir + '/highlight.css');
          moduleResources.push(resourceDir + '/style-doc.styl');
        }
      }
      complete(err, moduleResources);
    });
  },

  resource: function(context, next, complete) {
    if (context.resource['style-doc'] === true) {
      next(function(err, resource) {
        function generator(context, callback) {
          context.loadResource(resource, function(err, fileInfo) {
            if (err) {
              return callback(err);
            }

            fileList(context, function(err, options) {
              var templatePathPrefix = context.module.templatePathPrefix,
                  markdown = fileInfo.content.toString(),
                  templateFiles = [],
                  templates = {};

              async.forEach(styleDoc.findTemplates(markdown), function(template, callback) {
                  var filename =
                      (templatePathPrefix || '')
                      + template
                      + (/\.handlebars$/.test(template) ? '' : '.handlebars');
                  templateFiles.push(filename);
                  context.fileUtil.readFile(filename, function(err, data) {
                    templates[template] = data && data.toString();
                    callback(err);
                  });
                },
                function(err) {
                  if (err) {
                    return callback(err);
                  }

                  // Ensure that we rebuild if the markdown file changes
                  templateFiles.push(generator.sourceFile);

                  options.templates = templates;
                  callback(err, {
                    data: styleDoc(markdown, options),
                    inputs: templateFiles
                  });
                });
            });
          });
        };

        // Include any attributes that may have been defined on the base entry
        if (!_.isString(resource)) {
          _.extend(generator, resource);
        }
        generator.sourceFile = resource.src || resource;
        complete(undefined, generator);
      });
    } else {
      next(complete);
    }
  }
};
<commit_msg>Limit resource processing to static mode<commit_after>var _ = require('underscore'),
    async = require('async'),
    styleDoc = require('./style-doc');

var resourceDir = require('path').resolve(__dirname + '/../resources/');

function fileList(context, callback) {
  var sheets = [],
      loadPrefix = context.config.loadPrefix();

  if (loadPrefix) {
    loadPrefix += context.platformPath;
  }

  context.plugins.get('module-map').buildMap(context, function(err, map) {
    if (err) {
      return callback(err);
    }

    var css = _.pluck(map.modules, 'css');
    if (map.base && map.base.css) {
      css.unshift(map.base.css);
    }

    css = _.flatten(css, true);
    _.each(css, function(css) {
      if (!css) {
        return;
      }

      var media = [[], [], []];
      if (css.minRatio) {
        _.each(['min--moz-device-pixel-ratio', '-webkit-min-device-pixel-ratio', 'min-device-pixel-ratio'], function(name, index) {
          media[index].push(name + ': ' + css.minRatio);
        })
      }
      if (css.maxRatio) {
        _.each(['max--moz-device-pixel-ratio', '-webkit-max-device-pixel-ratio', 'max-device-pixel-ratio'], function(name, index) {
          media[index].push(name + ': ' + css.maxRatio);
        })
      }
      if (media[0].length) {
        media = 'only screen and (' + _.map(media, function(engine) { return engine.join(' and '); }).join('), only screen and (') + ')';
      } else {
        media = undefined;
      }

      sheets.push({href: loadPrefix + css.href, media: media});
    });

    callback(err, {
      sheets: sheets,
      scripts: [map.modules[context.module.name].js]
    });
  });
}

module.exports = {
  priority: 50,

  moduleResources: function(context, next, complete) {
    next(function(err, moduleResources) {
      if (context.module['style-doc']) {
        var styleDoc = context.module['style-doc'];
        moduleResources = moduleResources || [];

        if (context.mode === 'static') {
          var staticList = context.static = context.static || [];

          styleDoc['style-doc'] = true;
          moduleResources.push(styleDoc);
        } else if (context.mode === 'scripts') {
          moduleResources.unshift({src: resourceDir + '/style-doc.js', global: true});
          moduleResources.unshift({src: resourceDir + '/handlebars.js', global: true});
          moduleResources.unshift({src: resourceDir + '/zepto.js', global: true});
        } else if (context.mode === 'styles') {
          moduleResources.push(resourceDir + '/highlight.css');
          moduleResources.push(resourceDir + '/style-doc.styl');
        }
      }
      complete(err, moduleResources);
    });
  },

  resource: function(context, next, complete) {
    if (context.mode === 'static' && context.resource['style-doc'] === true) {
      next(function(err, resource) {
        function generator(context, callback) {
          context.loadResource(resource, function(err, fileInfo) {
            if (err) {
              return callback(err);
            }

            fileList(context, function(err, options) {
              var templatePathPrefix = context.module.templatePathPrefix,
                  markdown = fileInfo.content.toString(),
                  templateFiles = [],
                  templates = {};

              async.forEach(styleDoc.findTemplates(markdown), function(template, callback) {
                  var filename =
                      (templatePathPrefix || '')
                      + template
                      + (/\.handlebars$/.test(template) ? '' : '.handlebars');
                  templateFiles.push(filename);
                  context.fileUtil.readFile(filename, function(err, data) {
                    templates[template] = data && data.toString();
                    callback(err);
                  });
                },
                function(err) {
                  if (err) {
                    return callback(err);
                  }

                  // Ensure that we rebuild if the markdown file changes
                  templateFiles.push(generator.sourceFile);

                  options.templates = templates;
                  callback(err, {
                    data: styleDoc(markdown, options),
                    inputs: templateFiles
                  });
                });
            });
          });
        };

        // Include any attributes that may have been defined on the base entry
        if (!_.isString(resource)) {
          _.extend(generator, resource);
        }
        generator.sourceFile = resource.src || resource;
        complete(undefined, generator);
      });
    } else {
      next(complete);
    }
  }
};
<|endoftext|>


<commit_before>'use strict';

//trim some strings
if (!String.prototype.trim) {
	String.prototype.trim = function () {
		return this.replace(/^\s+|\s+$/g, '');
	};
}

var Learning = function (m) {
	this.module = m;
};

Learning.prototype.reply = function (source, text) {
	if (text.substr(0, 1) === '?') {
		if (typeof this.module.config.terms[text.substr(1).trim()] === 'string') {
			source.reply(this.module.config.terms[text.substr(1).trim()]);
		} else {
			source.mention('i\'m pretty sure i don\'t have this in my books');
		}
	}
};

Learning.prototype.replyAction = function (source, args, text) {
	return this.reply(source, text);
};

Learning.prototype.learnCommand = function (source, args) {
	var word = args.shift();
	var text = args.join(' ');
	if (word !== '') {
		if (text.trim() !== '') {
			var old = (typeof this.module.config.terms[word] === 'string');
			this.module.config.terms[word] = text;
			source.mention('you successfully managed to ' + (old ? 're-' : '') + 'learn me "' + word + '"');
		} else if (typeof this.module.config.terms[word] === 'string') {
			delete this.module.config.terms[word];
			source.mention('you successfully managed to unlearn me "' + word + '"');
		} else {
			source.mention('you need to learn me in with: <word> <some text>');
		}
	} else {
		source.mention('you need to learn me in with: <word> <some text>');
	}
};

Learning.prototype.learnAction = function (source, args) {
	args.shift(); //throw the main one out
	return this.learnCommand(source, args);
};

Learning.prototype.list = function (source) {
	source.reply('i learned all this: ' + Object.keys(this.module.config.terms).join(', '));
};

exports.init = function () {
	if (typeof this.config.terms === 'undefined') {
		this.config.terms = {};
	}
	this.learning = new Learning(this);
	this.addCommand('list', this.learning.list.bind(this.learning))
		.addAction('list', this.learning.list.bind(this.learning), /^list$/)
		.addCommand('learn', this.learning.learnCommand.bind(this.learning), ['owner', 'operators'])
		.addAction('learn', this.learning.learnAction.bind(this.learning), /^learn (\w+){1} (.*)$/, ['owner', 'operators'])
		.addAction('learnreply', this.learning.replyAction.bind(this.learning), /^\? (\w+){1}$/);
	this.dispatcher.on('irc/PRIVMSG', this.learning.reply.bind(this.learning));
};
<commit_msg>learn - dont trigger on empty '?'<commit_after>'use strict';

//trim some strings
if (!String.prototype.trim) {
	String.prototype.trim = function () {
		return this.replace(/^\s+|\s+$/g, '');
	};
}

var Learning = function (m) {
	this.module = m;
};

Learning.prototype.reply = function (source, text) {
	if (text.substr(0, 1) === '?' && text.substr(1).trim() !== '') {
		if (typeof this.module.config.terms[text.substr(1).trim()] === 'string') {
			source.reply(this.module.config.terms[text.substr(1).trim()]);
		} else {
			source.mention('i\'m pretty sure i don\'t have this in my books');
		}
	}
};

Learning.prototype.replyAction = function (source, args, text) {
	return this.reply(source, text);
};

Learning.prototype.learnCommand = function (source, args) {
	var word = args.shift();
	var text = args.join(' ');
	if (word !== '') {
		if (text.trim() !== '') {
			var old = (typeof this.module.config.terms[word] === 'string');
			this.module.config.terms[word] = text;
			source.mention('you successfully managed to ' + (old ? 're-' : '') + 'learn me "' + word + '"');
		} else if (typeof this.module.config.terms[word] === 'string') {
			delete this.module.config.terms[word];
			source.mention('you successfully managed to unlearn me "' + word + '"');
		} else {
			source.mention('you need to learn me in with: <word> <some text>');
		}
	} else {
		source.mention('you need to learn me in with: <word> <some text>');
	}
};

Learning.prototype.learnAction = function (source, args) {
	args.shift(); //throw the main one out
	return this.learnCommand(source, args);
};

Learning.prototype.list = function (source) {
	source.reply('i learned all this: ' + Object.keys(this.module.config.terms).join(', '));
};

exports.init = function () {
	if (typeof this.config.terms === 'undefined') {
		this.config.terms = {};
	}
	this.learning = new Learning(this);
	this.addCommand('list', this.learning.list.bind(this.learning))
		.addAction('list', this.learning.list.bind(this.learning), /^list$/)
		.addCommand('learn', this.learning.learnCommand.bind(this.learning), ['owner', 'operators'])
		.addAction('learn', this.learning.learnAction.bind(this.learning), /^learn (\w+){1} (.*)$/, ['owner', 'operators'])
		.addAction('learnreply', this.learning.replyAction.bind(this.learning), /^\? (\w+){1}$/);
	this.dispatcher.on('irc/PRIVMSG', this.learning.reply.bind(this.learning));
};
<|endoftext|>


<commit_before>var fs = require('fs');
var exec = require('child_process').exec;

exports.loadGeoJSON = function (filename) {
	var me = this;

	console.log('Lade GeoJSON');
	var regions = fs.readFileSync(filename, 'utf8');

	console.log('Lese GeoJSON');
	regions = JSON.parse(regions);

	me.match = function (options) {
		console.log('Matching');
		var data = options.data;
		var lut = {};
		data.forEach(function (entry) {
			lut['_'+entry[options.foreignField]] = entry;
		});

		regions.features.forEach(function (region) {
			var id = region.properties[options.myField];
			if (lut['_'+id] === undefined) {
				if (!options.hideWarning || !options.hideWarning(region.properties)) {
					console.warn('id nicht gefunden');
					console.warn(region.properties);
				}
			} else {
				options.addFields.forEach(function (field) {
					region.properties[field.name] = field.convert(lut['_'+id][field.name]);
				})
			}
		})
	}

	me.saveGeo = function (filename, convertShape) {
		console.log('Erstelle GeoJSON');
		var json = JSON.stringify(regions/*, null, '\t'*/);
		console.log('Speichere GeoJSON');
		ensureFolder(filename);
		fs.writeFileSync(filename+'.geojson', json, 'utf8');

		if (convertShape) {
			console.log('Konvertiere zu Shapefile');
			exec('ogr2ogr -f "ESRI Shapefile" '+filename+'.shp '+filename+'.geojson');
		}
	}

	me.generateLokaler = function (options) {
		console.log('Erstelle Zensus-Auswertungen');

		// Welche Zahlen sind für die Skalierung erlaubt?
		var allowedSteps = [];
		for (var i = -4; i <= 8; i++) {
			var f = Math.pow(10, i);
			allowedSteps.push(f*1);
			allowedSteps.push(f*2);
			allowedSteps.push(f*3);
			allowedSteps.push(f*5);
		}

		options.fields.forEach(function (field) {
			var values = [];
			var isFunction = Object.prototype.toString.call(field.value) == '[object Function]';

			// Berechne Werte
			regions.features.forEach(function (region) {
				var value = isFunction ? field.value(region.properties) : region.properties[field.value];
				if (isFinite(value)) {
					values.push(value);
				} else {
					value = undefined;
				}
				region.properties['ZENSUS'+field.id] = value;
			});

			// Berechne Skale
			values = values.sort(function (a,b) { return a-b });

			var min = values[Math.round(values.length*0.01)];
			var max = values[Math.round(values.length*0.99)];

			if (field.min) min = field.min;
			if (field.max) max = field.max;

			var step = (max-min)/5;
			var bestStep = 1e30;
			allowedSteps.forEach(function (newStep) {
				if (Math.abs(Math.log(step/newStep)) < Math.abs(Math.log(step/bestStep))) bestStep = newStep;
			});
			var roundMin = Math.floor(min/bestStep)*bestStep;
			var roundMax = Math.ceil( max/bestStep)*bestStep;

			// Berechne Farben
			regions.features.forEach(function (region) {
				var value = region.properties['ZENSUS'+field.id];
				var color = Math.round(options.nuances*(value-roundMin)/(roundMax-roundMin));
				if (color < 0) color = 0;
				if (color > options.nuances) color = options.nuances;
				region.properties['COLOR'+field.id] = (value === undefined) ? 0 : color+1;
			});

			// Generiere Mapnik-XML
			if (options.mapnikFile) {
				var xml = fs.readFileSync('./mapnik.template.xml', 'utf8');

				var rules = [];

				for (var i = 0; i <= options.nuances; i++) {
					var color = interpolateColor(field.gradient, i/options.nuances);
					var line = '<Rule><Filter>([COLOR'+field.id+']='+(i+1)+')</Filter><PolygonSymbolizer fill="#'+color+'" fill-opacity="1"/></Rule>';
					rules.push(line);
				}

				rules.push('<Rule><PolygonSymbolizer fill="#'+field.gradient[0]+'" fill-opacity="1"/></Rule>');

				xml = xml.replace(/\%id\%/g, field.id);
				xml = xml.replace(/\%rules\%/g, rules.join('\n\t\t'));
				xml = xml.replace(/\%shape\%/g, options.shapeFile);

				var mapnikFile = options.mapnikFile.replace(/\%/g, field.id);
				ensureFolder(mapnikFile);
				fs.writeFileSync(mapnikFile, xml, 'utf8');
			}

			// Generiere Gradient
			if (options.gradientFile) {
				var stops = [];
				for (var i = 1; i < field.gradient.length; i++) {
					stops.push('<stop offset="'+(i-1)/(field.gradient.length-2)+'" style="stop-color:#'+field.gradient[i]+'"/>');
				}

				var labels = [];
				var mini = Math.round(roundMin/bestStep);
				var maxi = Math.round(roundMax/bestStep);
				var digits = -Math.log(bestStep)/Math.LN10;
				digits = Math.ceil(Math.max(digits, 0));

				for (var i = mini+1; i < maxi; i++) {
					labels.push('<text x="'+(580*(i-mini)/(maxi-mini))+'" y="90" style="font-family:\'MyriadPro-Regular\'; font-size:30;" text-anchor="middle">'+(i*bestStep).toFixed(digits)+'</text>');
				}

				var svg = [
					'<?xml version="1.0" encoding="utf-8"?>',
					'<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">',
					'<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="580px" height="96px" viewBox="0 0 580 96" style="enable-background:new 0 0 580 96;" xml:space="preserve">',
					'<g>',
					'<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="0.5" y1="30" x2="579.5" y2="30">',
					stops.join('\n'),
					'</linearGradient>',
					'<rect x="0.5" y="0.5" style="fill:url(#SVGID_1_);" width="579" height="59"/>',
					'<path style="fill:#231F20;" d="M579,1v58H1V1H579 M580,0h-1H1H0v1v58v1h1h578h1v-1V1V0L580,0z"/>',
					'</g>',
					labels.join('\n'),
					'</svg>'
				];

				var gradientFile = options.gradientFile.replace(/\%/g, field.id);
				ensureFolder(gradientFile);
				fs.writeFileSync(gradientFile+'.svg', svg.join('\n'), 'utf8');

				exec('convert -background white -quality 95 '+gradientFile+'.svg '+gradientFile+' && rm '+gradientFile+'.svg');
			}
		})
	}

	return me;
}

exports.loadCSV = function (filename) {
	console.log('Lade CSV');
	var data = fs.readFileSync(filename, 'utf8');

	console.log('Lese CSV');
	data = data.split('\r\n');

	while (data[data.length-1].replace(/^\s+|\s+$/,'') == '') data.pop();

	var header = data.shift().replace(/\"/g, '').split(';');

	data = data.map(function (line) {
		var fields = line.replace(/\"/g, '').split(';');
		var result = {};
		header.forEach(function (colName, i) {
			result[colName] = fields[i];
		});
		return result;
	});

	return data;
}

var interpolateColor = function (gradient, value) {
	if (value < 0) value = 0;
	if (value > 1) value = 1;

	var value = value*(gradient.length-2);

	var index = Math.floor(value);
	if (index < 0) index = 0;
	if (index > gradient.length-3) index = gradient.length-3;

	var offset = value - index;
	if (offset < 0) offset = 0;
	if (offset > 1) offset = 1;

	index += 1;

	var color = '';
	for (var i = 0; i < 3; i++) {
		var v0 = parseInt(gradient[index  ].substr(i*2, 2), 16);
		var v1 = parseInt(gradient[index+1].substr(i*2, 2), 16);
		var v = Math.round((v1-v0)*offset + v0);
		v = '00'+v.toString(16);
		color += v.substr(v.length-2, 2);
	}

	return color;
}

var path = require('path');
var ensureFolder = function (folder) {
	folder = path.resolve(path.dirname(require.main.filename), folder);
	var rec = function (fol) {
		if (fol != '/') {
			rec(path.dirname(fol));
			if (!fs.existsSync(fol)) fs.mkdirSync(fol);
		}
	}
	rec(path.dirname(folder));
}
<commit_msg>adding overwrite and callback to shape converter<commit_after>var fs = require('fs');
var exec = require('child_process').exec;

exports.loadGeoJSON = function (filename) {
	var me = this;

	console.log('Lade GeoJSON');
	var regions = fs.readFileSync(filename, 'utf8');

	console.log('Lese GeoJSON');
	regions = JSON.parse(regions);

	me.match = function (options) {
		console.log('Matching');
		var data = options.data;
		var lut = {};
		data.forEach(function (entry) {
			lut['_'+entry[options.foreignField]] = entry;
		});

		regions.features.forEach(function (region) {
			var id = region.properties[options.myField];
			if (lut['_'+id] === undefined) {
				if (!options.hideWarning || !options.hideWarning(region.properties)) {
					console.warn('id nicht gefunden');
					console.warn(region.properties);
				}
			} else {
				options.addFields.forEach(function (field) {
					region.properties[field.name] = field.convert(lut['_'+id][field.name]);
				})
			}
		})
	}

	me.saveGeo = function (filename, convertShape) {
		console.log('Erstelle GeoJSON');
		var json = JSON.stringify(regions/*, null, '\t'*/);
		console.log('Speichere GeoJSON');
		ensureFolder(filename);
		fs.writeFileSync(filename+'.geojson', json, 'utf8');

		if (convertShape) {
			console.log('Konvertiere zu Shapefile');
			exec('ogr2ogr -overwrite -f "ESRI Shapefile" '+filename+'.shp '+filename+'.geojson', function (error, stdout, stderr) {
				console.log('stdout: ' + stdout);
				console.log('stderr: ' + stderr);
				if (error !== null) {
					console.log('exec error: ' + error);
				}
			});
		}
	}

	me.generateLokaler = function (options) {
		console.log('Erstelle Zensus-Auswertungen');

		// Welche Zahlen sind für die Skalierung erlaubt?
		var allowedSteps = [];
		for (var i = -4; i <= 8; i++) {
			var f = Math.pow(10, i);
			allowedSteps.push(f*1);
			allowedSteps.push(f*2);
			allowedSteps.push(f*3);
			allowedSteps.push(f*5);
		}

		options.fields.forEach(function (field) {
			var values = [];
			var isFunction = Object.prototype.toString.call(field.value) == '[object Function]';

			// Berechne Werte
			regions.features.forEach(function (region) {
				var value = isFunction ? field.value(region.properties) : region.properties[field.value];
				if (isFinite(value)) {
					values.push(value);
				} else {
					value = undefined;
				}
				region.properties['ZENSUS'+field.id] = value;
			});

			// Berechne Skale
			values = values.sort(function (a,b) { return a-b });

			var min = values[Math.round(values.length*0.01)];
			var max = values[Math.round(values.length*0.99)];

			if (field.min) min = field.min;
			if (field.max) max = field.max;

			var step = (max-min)/5;
			var bestStep = 1e30;
			allowedSteps.forEach(function (newStep) {
				if (Math.abs(Math.log(step/newStep)) < Math.abs(Math.log(step/bestStep))) bestStep = newStep;
			});
			var roundMin = Math.floor(min/bestStep)*bestStep;
			var roundMax = Math.ceil( max/bestStep)*bestStep;

			// Berechne Farben
			regions.features.forEach(function (region) {
				var value = region.properties['ZENSUS'+field.id];
				var color = Math.round(options.nuances*(value-roundMin)/(roundMax-roundMin));
				if (color < 0) color = 0;
				if (color > options.nuances) color = options.nuances;
				region.properties['COLOR'+field.id] = (value === undefined) ? 0 : color+1;
			});

			// Generiere Mapnik-XML
			if (options.mapnikFile) {
				var xml = fs.readFileSync('./mapnik.template.xml', 'utf8');

				var rules = [];

				for (var i = 0; i <= options.nuances; i++) {
					var color = interpolateColor(field.gradient, i/options.nuances);
					var line = '<Rule><Filter>([COLOR'+field.id+']='+(i+1)+')</Filter><PolygonSymbolizer fill="#'+color+'" fill-opacity="1"/></Rule>';
					rules.push(line);
				}

				rules.push('<Rule><PolygonSymbolizer fill="#'+field.gradient[0]+'" fill-opacity="1"/></Rule>');

				xml = xml.replace(/\%id\%/g, field.id);
				xml = xml.replace(/\%rules\%/g, rules.join('\n\t\t'));
				xml = xml.replace(/\%shape\%/g, options.shapeFile);

				var mapnikFile = options.mapnikFile.replace(/\%/g, field.id);
				ensureFolder(mapnikFile);
				fs.writeFileSync(mapnikFile, xml, 'utf8');
			}

			// Generiere Gradient
			if (options.gradientFile) {
				var stops = [];
				for (var i = 1; i < field.gradient.length; i++) {
					stops.push('<stop offset="'+(i-1)/(field.gradient.length-2)+'" style="stop-color:#'+field.gradient[i]+'"/>');
				}

				var labels = [];
				var mini = Math.round(roundMin/bestStep);
				var maxi = Math.round(roundMax/bestStep);
				var digits = -Math.log(bestStep)/Math.LN10;
				digits = Math.ceil(Math.max(digits, 0));

				for (var i = mini+1; i < maxi; i++) {
					labels.push('<text x="'+(580*(i-mini)/(maxi-mini))+'" y="90" style="font-family:\'MyriadPro-Regular\'; font-size:30;" text-anchor="middle">'+(i*bestStep).toFixed(digits)+'</text>');
				}

				var svg = [
					'<?xml version="1.0" encoding="utf-8"?>',
					'<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">',
					'<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="580px" height="96px" viewBox="0 0 580 96" style="enable-background:new 0 0 580 96;" xml:space="preserve">',
					'<g>',
					'<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="0.5" y1="30" x2="579.5" y2="30">',
					stops.join('\n'),
					'</linearGradient>',
					'<rect x="0.5" y="0.5" style="fill:url(#SVGID_1_);" width="579" height="59"/>',
					'<path style="fill:#231F20;" d="M579,1v58H1V1H579 M580,0h-1H1H0v1v58v1h1h578h1v-1V1V0L580,0z"/>',
					'</g>',
					labels.join('\n'),
					'</svg>'
				];

				var gradientFile = options.gradientFile.replace(/\%/g, field.id);
				ensureFolder(gradientFile);
				fs.writeFileSync(gradientFile+'.svg', svg.join('\n'), 'utf8');

				exec('convert -background white -quality 95 '+gradientFile+'.svg '+gradientFile+' && rm '+gradientFile+'.svg');
			}
		})
	}

	return me;
}

exports.loadCSV = function (filename) {
	console.log('Lade CSV');
	var data = fs.readFileSync(filename, 'utf8');

	console.log('Lese CSV');
	data = data.split('\r\n');

	while (data[data.length-1].replace(/^\s+|\s+$/,'') == '') data.pop();

	var header = data.shift().replace(/\"/g, '').split(';');

	data = data.map(function (line) {
		var fields = line.replace(/\"/g, '').split(';');
		var result = {};
		header.forEach(function (colName, i) {
			result[colName] = fields[i];
		});
		return result;
	});

	return data;
}

var interpolateColor = function (gradient, value) {
	if (value < 0) value = 0;
	if (value > 1) value = 1;

	var value = value*(gradient.length-2);

	var index = Math.floor(value);
	if (index < 0) index = 0;
	if (index > gradient.length-3) index = gradient.length-3;

	var offset = value - index;
	if (offset < 0) offset = 0;
	if (offset > 1) offset = 1;

	index += 1;

	var color = '';
	for (var i = 0; i < 3; i++) {
		var v0 = parseInt(gradient[index  ].substr(i*2, 2), 16);
		var v1 = parseInt(gradient[index+1].substr(i*2, 2), 16);
		var v = Math.round((v1-v0)*offset + v0);
		v = '00'+v.toString(16);
		color += v.substr(v.length-2, 2);
	}

	return color;
}

var path = require('path');
var ensureFolder = function (folder) {
	folder = path.resolve(path.dirname(require.main.filename), folder);
	var rec = function (fol) {
		if (fol != '/') {
			rec(path.dirname(fol));
			if (!fs.existsSync(fol)) fs.mkdirSync(fol);
		}
	}
	rec(path.dirname(folder));
}
<|endoftext|>


<commit_before>var nconf = require('nconf');
var ldap  = require('ldapjs');
var exit  = require('./exit');
var client, binder;
var crypto = require('./crypto');
var cb = require('cb');

ldap.Attribute.settings.guid_format = ldap.GUID_FORMAT_D;

function createConnection () {
  var tlsOptions = null;

  if (process.platform === 'win32' &&
      nconf.get('LDAP_URL').toLowerCase().substr(0, 5) === 'ldaps') {

    var cas = certs.get({
      storeLocation: 'LocalMachine',
      storeName: ['TrustedPeople', 'CertificateAuthority', 'Root']
    }).map(function (cert) {
      return cert.pem;
    });

    tlsOptions = { ca: cas };
  }

  var connection = ldap.createClient({
    url: nconf.get("LDAP_URL"),
    tlsOptions: tlsOptions
  });

  connection.on('close', function () {
    console.error('Connection to ldap was closed.');
    exit(1);
  });

  var LDAP_BIND_CREDENTIALS = nconf.get('LDAP_BIND_PASSWORD') || crypto.decrypt(nconf.get('LDAP_BIND_CREDENTIALS'));

  connection.heartbeat = function (callback) {
    connection.search('', '(objectclass=*)', function (err, res) {
      if (err) {
        return callback(err);
      }

      var abort = setTimeout(function () {
        client.removeAllListeners('end');
        client.removeAllListeners('error');
        callback(new Error('No heartbeat response'));
      }, 5000);

      res.once('error', function(err) {
        client.removeAllListeners('end');
        clearTimeout(abort);
        callback(err);
      }).once('end', function () {
        client.removeAllListeners('error');
        clearTimeout(abort);
        callback();
      });
    });
  };

  function protect_with_timeout (func) {
    var original = connection[func];
    connection[func] = function () {
      var args = [].slice.call(arguments);
      var original_callback = args.pop();
      var timeoutable_callback = cb(original_callback).timeout(450000);
      var new_args = args.concat([timeoutable_callback]);
      return original.apply(this, new_args);
    };
  }

  protect_with_timeout('bind');
  protect_with_timeout('search');

  connection.bind(nconf.get("LDAP_BIND_USER"), LDAP_BIND_CREDENTIALS, function(err) {
    if(err){
      console.error("Error binding to LDAP", 'dn: ' + err.dn + '\n code: ' + err.code + '\n message: ' + err.message);
      return exit(1);
    }

    function ping_recurse () {
      connection.heartbeat(function (err) {
        if (err) {
          console.error('Error on heartbeat response from LDAP: ', err.message);
          return exit(1);
        }
        setTimeout(ping_recurse, nconf.get('LDAP_HEARTBEAT_SECONDS') * 1000);
      });
    }

    ping_recurse();
  });

  return connection;
}

Object.defineProperty(module.exports, 'client', {
  enumerable: true,
  configurable: false,
  get: function () {
    client = client || createConnection();
    return client;
  }
});

Object.defineProperty(module.exports, 'binder', {
  enumerable: true,
  configurable: false,
  get: function () {
    binder = binder || createConnection();
    return binder;
  }
});<commit_msg>fix missing windows-certs req<commit_after>var nconf = require('nconf');
var ldap  = require('ldapjs');
var exit  = require('./exit');
var client, binder;
var crypto = require('./crypto');
var cb = require('cb');

ldap.Attribute.settings.guid_format = ldap.GUID_FORMAT_D;

function createConnection () {
  var tlsOptions = null;

  if (process.platform === 'win32' &&
      nconf.get('LDAP_URL').toLowerCase().substr(0, 5) === 'ldaps') {

    var certs = require('windows-certs');

    var cas = certs.get({
      storeLocation: 'LocalMachine',
      storeName: ['TrustedPeople', 'CertificateAuthority', 'Root']
    }).map(function (cert) {
      return cert.pem;
    });

    tlsOptions = { ca: cas };
  }

  var connection = ldap.createClient({
    url: nconf.get("LDAP_URL"),
    tlsOptions: tlsOptions
  });

  connection.on('close', function () {
    console.error('Connection to ldap was closed.');
    exit(1);
  });

  var LDAP_BIND_CREDENTIALS = nconf.get('LDAP_BIND_PASSWORD') || crypto.decrypt(nconf.get('LDAP_BIND_CREDENTIALS'));

  connection.heartbeat = function (callback) {
    connection.search('', '(objectclass=*)', function (err, res) {
      if (err) {
        return callback(err);
      }

      var abort = setTimeout(function () {
        client.removeAllListeners('end');
        client.removeAllListeners('error');
        callback(new Error('No heartbeat response'));
      }, 5000);

      res.once('error', function(err) {
        client.removeAllListeners('end');
        clearTimeout(abort);
        callback(err);
      }).once('end', function () {
        client.removeAllListeners('error');
        clearTimeout(abort);
        callback();
      });
    });
  };

  function protect_with_timeout (func) {
    var original = connection[func];
    connection[func] = function () {
      var args = [].slice.call(arguments);
      var original_callback = args.pop();
      var timeoutable_callback = cb(original_callback).timeout(450000);
      var new_args = args.concat([timeoutable_callback]);
      return original.apply(this, new_args);
    };
  }

  protect_with_timeout('bind');
  protect_with_timeout('search');

  connection.bind(nconf.get("LDAP_BIND_USER"), LDAP_BIND_CREDENTIALS, function(err) {
    if(err){
      console.error("Error binding to LDAP", 'dn: ' + err.dn + '\n code: ' + err.code + '\n message: ' + err.message);
      return exit(1);
    }

    function ping_recurse () {
      connection.heartbeat(function (err) {
        if (err) {
          console.error('Error on heartbeat response from LDAP: ', err.message);
          return exit(1);
        }
        setTimeout(ping_recurse, nconf.get('LDAP_HEARTBEAT_SECONDS') * 1000);
      });
    }

    ping_recurse();
  });

  return connection;
}

Object.defineProperty(module.exports, 'client', {
  enumerable: true,
  configurable: false,
  get: function () {
    client = client || createConnection();
    return client;
  }
});

Object.defineProperty(module.exports, 'binder', {
  enumerable: true,
  configurable: false,
  get: function () {
    binder = binder || createConnection();
    return binder;
  }
});<|endoftext|>