<commit_before>/**
 * @fileOverview Plugins for tQuery.Object3D to play with .position/.rotation/.scale
*/

(function(){	// TODO why is there a closure here ?

//////////////////////////////////////////////////////////////////////////////////
//		set function							//
//////////////////////////////////////////////////////////////////////////////////

tQuery.Object3D.register('scale', function(scale){
	// handle parameters
	if( typeof scale === "number" && arguments.length === 1 ){
		scale	= new THREE.Vector3(scale, scale, scale);
	}else if( typeof scale === "number" && arguments.length === 3 ){
		scale	= new THREE.Vector3(arguments[0], arguments[1], arguments[2]);
	}
	console.assert(scale instanceof THREE.Vector3, "Geometry.scale parameter error");

	// do the operation on each node
	this.each(function(object3d){
		object3d.scale.copy(scale);
	});

	// return this, to get chained API
	return this;
});

tQuery.Object3D.register('position', function(vector3){
	// handle parameters
	if( typeof vector3 === "number" && arguments.length === 3 ){
		vector3	= new THREE.Vector3(arguments[0], arguments[1], arguments[2]);
	}
	console.assert(vector3 instanceof THREE.Vector3, "Object3D.position parameter error");

	// do the operation on each node
	this.each(function(object3d){
		object3d.position.copy(vector3);
	})

	// return this, to get chained API
	return this;
});

tQuery.Object3D.register('rotation', function(vector3){
	// handle parameters
	if( typeof vector3 === "number" && arguments.length === 3 ){
		vector3	= new THREE.Vector3(arguments[0], arguments[1], arguments[2]);
	}
	console.assert(vector3 instanceof THREE.Vector3, "Object3D.rotation parameter error");

	// do the operation on each node
	this.each(function(object3d){
		object3d.rotation.copy(vector3);
	})

	// return this, to get chained API
	return this;
});

//////////////////////////////////////////////////////////////////////////////////
//		add function							//
//////////////////////////////////////////////////////////////////////////////////

tQuery.Object3D.register('translate', function(delta){
	// handle parameters
	if( typeof delta === "number" && arguments.length === 3 ){
		delta	= new THREE.Vector3(arguments[0], arguments[1], arguments[2]);
	}
	console.assert(delta instanceof THREE.Vector3, "Object3D.translate parameter error");

	// do the operation on each node
	this.each(function(object3d){
		object3d.position.addSelf(delta);
	})

	// return this, to get chained API
	return this;
});

tQuery.Object3D.register('rotate', function(angles){
	// handle parameters
	if( typeof angles === "number" && arguments.length === 3 ){
		angles	= new THREE.Vector3(arguments[0], arguments[1], arguments[2]);
	}
	console.assert(angles instanceof THREE.Vector3, "Object3D.rotate parameter error");

	// do the operation on each node
	this.each(function(object3d){
		object3d.rotation.addSelf(angles);
	})

	// return this, to get chained API
	return this;
});

tQuery.Object3D.register('scaleBy', function(ratio){
	// handle parameters
	if( typeof ratio === "number" && arguments.length === 1 ){
		ratio	= new THREE.Vector3(ratio, ratio, ratio);
	}else if( typeof ratio === "number" && arguments.length === 3 ){
		ratio	= new THREE.Vector3(arguments[0], arguments[1], arguments[2]);
	}
	console.assert(ratio instanceof THREE.Vector3, "Object3D.rotate parameter error");

	// do the operation on each node
	this.each(function(object3d){
		object3d.scale.multiplySelf(ratio);
	})

	// return this, to get chained API
	return this;
});

// some shortcuts
tQuery.Object3D.register('translateX'	, function(delta){ return this.translate(delta, 0, 0);	});
tQuery.Object3D.register('translateY'	, function(delta){ return this.translate(0, delta, 0);	});
tQuery.Object3D.register('translateZ'	, function(delta){ return this.translate(0, 0, delta);	});
tQuery.Object3D.register('rotateX'	, function(angle){ return this.rotate(angle, 0, 0);	});
tQuery.Object3D.register('rotateY'	, function(angle){ return this.rotate(0, angle, 0);	});
tQuery.Object3D.register('rotateZ'	, function(angle){ return this.rotate(0, 0, angle);	});
tQuery.Object3D.register('scaleXBy'	, function(ratio){ return this.scaleBy(ratio, 1, 1);	});
tQuery.Object3D.register('scaleYBy'	, function(ratio){ return this.scaleBy(1, ratio, 1);	});
tQuery.Object3D.register('scaleZBy'	, function(ratio){ return this.scaleBy(1, 1, ratio);	});

// backward compatibility
tQuery.Object3D.register('zoom'		, function(value){ return this.scaleBy(value);		});
tQuery.Object3D.register('zoomX'	, function(ratio){ return this.zoom(ratio, 1, 1);	});
tQuery.Object3D.register('zoomY'	, function(ratio){ return this.zoom(1, ratio, 1);	});
tQuery.Object3D.register('zoomZ'	, function(ratio){ return this.zoom(1, 1, ratio);	});

})();	// closure function end
<commit_msg>js/plugins/tquery.object3d.geometry.js more shortcut<commit_after>/**
 * @fileOverview Plugins for tQuery.Object3D to play with .position/.rotation/.scale
*/

(function(){	// TODO why is there a closure here ?

//////////////////////////////////////////////////////////////////////////////////
//		set function							//
//////////////////////////////////////////////////////////////////////////////////

tQuery.Object3D.register('scale', function(scale){
	// handle parameters
	if( typeof scale === "number" && arguments.length === 1 ){
		scale	= new THREE.Vector3(scale, scale, scale);
	}else if( typeof scale === "number" && arguments.length === 3 ){
		scale	= new THREE.Vector3(arguments[0], arguments[1], arguments[2]);
	}
	console.assert(scale instanceof THREE.Vector3, "Geometry.scale parameter error");

	// do the operation on each node
	this.each(function(object3d){
		object3d.scale.copy(scale);
	});

	// return this, to get chained API
	return this;
});

tQuery.Object3D.register('position', function(vector3){
	// handle parameters
	if( typeof vector3 === "number" && arguments.length === 3 ){
		vector3	= new THREE.Vector3(arguments[0], arguments[1], arguments[2]);
	}
	console.assert(vector3 instanceof THREE.Vector3, "Object3D.position parameter error");

	// do the operation on each node
	this.each(function(object3d){
		object3d.position.copy(vector3);
	})

	// return this, to get chained API
	return this;
});

tQuery.Object3D.register('rotation', function(vector3){
	// handle parameters
	if( typeof vector3 === "number" && arguments.length === 3 ){
		vector3	= new THREE.Vector3(arguments[0], arguments[1], arguments[2]);
	}
	console.assert(vector3 instanceof THREE.Vector3, "Object3D.rotation parameter error");

	// do the operation on each node
	this.each(function(object3d){
		object3d.rotation.copy(vector3);
	})

	// return this, to get chained API
	return this;
});

//////////////////////////////////////////////////////////////////////////////////
//		add function							//
//////////////////////////////////////////////////////////////////////////////////

tQuery.Object3D.register('translate', function(delta){
	// handle parameters
	if( typeof delta === "number" && arguments.length === 3 ){
		delta	= new THREE.Vector3(arguments[0], arguments[1], arguments[2]);
	}
	console.assert(delta instanceof THREE.Vector3, "Object3D.translate parameter error");

	// do the operation on each node
	this.each(function(object3d){
		object3d.position.addSelf(delta);
	})

	// return this, to get chained API
	return this;
});

tQuery.Object3D.register('rotate', function(angles){
	// handle parameters
	if( typeof angles === "number" && arguments.length === 3 ){
		angles	= new THREE.Vector3(arguments[0], arguments[1], arguments[2]);
	}
	console.assert(angles instanceof THREE.Vector3, "Object3D.rotate parameter error");

	// do the operation on each node
	this.each(function(object3d){
		object3d.rotation.addSelf(angles);
	})

	// return this, to get chained API
	return this;
});

tQuery.Object3D.register('scaleBy', function(ratio){
	// handle parameters
	if( typeof ratio === "number" && arguments.length === 1 ){
		ratio	= new THREE.Vector3(ratio, ratio, ratio);
	}else if( typeof ratio === "number" && arguments.length === 3 ){
		ratio	= new THREE.Vector3(arguments[0], arguments[1], arguments[2]);
	}
	console.assert(ratio instanceof THREE.Vector3, "Object3D.rotate parameter error");

	// do the operation on each node
	this.each(function(object3d){
		object3d.scale.multiplySelf(ratio);
	})

	// return this, to get chained API
	return this;
});

// some shortcuts
tQuery.Object3D.register('positionX'	, function(delta){ return this.position(delta, 0, 0);	});
tQuery.Object3D.register('positionY'	, function(delta){ return this.position(0, delta, 0);	});
tQuery.Object3D.register('positionZ'	, function(delta){ return this.position(0, 0, delta);	});
tQuery.Object3D.register('scaleX'	, function(delta){ return this.scale(delta, 0, 0);	});
tQuery.Object3D.register('scaleY'	, function(delta){ return this.scale(0, delta, 0);	});
tQuery.Object3D.register('scaleZ'	, function(delta){ return this.scale(0, 0, delta);	});
tQuery.Object3D.register('rotationX'	, function(delta){ return this.rotation(delta, 0, 0);	});
tQuery.Object3D.register('rotationY'	, function(delta){ return this.rotation(0, delta, 0);	});
tQuery.Object3D.register('rotationZ'	, function(delta){ return this.rotation(0, 0, delta);	});

// some shortcuts
tQuery.Object3D.register('translateX'	, function(delta){ return this.translate(delta, 0, 0);	});
tQuery.Object3D.register('translateY'	, function(delta){ return this.translate(0, delta, 0);	});
tQuery.Object3D.register('translateZ'	, function(delta){ return this.translate(0, 0, delta);	});
tQuery.Object3D.register('rotateX'	, function(angle){ return this.rotate(angle, 0, 0);	});
tQuery.Object3D.register('rotateY'	, function(angle){ return this.rotate(0, angle, 0);	});
tQuery.Object3D.register('rotateZ'	, function(angle){ return this.rotate(0, 0, angle);	});
tQuery.Object3D.register('scaleXBy'	, function(ratio){ return this.scaleBy(ratio, 1, 1);	});
tQuery.Object3D.register('scaleYBy'	, function(ratio){ return this.scaleBy(1, ratio, 1);	});
tQuery.Object3D.register('scaleZBy'	, function(ratio){ return this.scaleBy(1, 1, ratio);	});

// backward compatibility
tQuery.Object3D.register('zoom'		, function(value){ return this.scaleBy(value);		});
tQuery.Object3D.register('zoomX'	, function(ratio){ return this.zoom(ratio, 1, 1);	});
tQuery.Object3D.register('zoomY'	, function(ratio){ return this.zoom(1, ratio, 1);	});
tQuery.Object3D.register('zoomZ'	, function(ratio){ return this.zoom(1, 1, ratio);	});

})();	// closure function end
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015, Wannabe Mutants LLC.
 * All rights reserved.
 *
 * FlistStore Tests
 */

jest.dontMock('../../constants/FlistConstants');
jest.dontMock('../FlistStore');
jest.dontMock('object-assign');

describe('FlistStore', function() {

  var FlistConstants = require('../../constants/FlistConstants');
  var AppDispatcher;
  var FlistStore;
  var callback;

  //Actions
  var actionCategoryUnselect = {
    actionType: FlistConstants.CATEGORY_UNSELECT
  };
  var actionCategorySelect = {
    actionType: FlistConstants.CATEGORY_SELECT,
    data: {name: 'Sample'}
  };

  beforeEach(function() {
    AppDispatcher = require('../../dispatcher/AppDispatcher');
    FlistStore = require('../FlistStore');
    callback = AppDispatcher.register.mock.calls[0][0];
  });

  it('registers a callback with the dispatcher', function() {
    expect(AppDispatcher.register.mock.calls.length).toBe(1);
  });

  it('initializes with an empty state', function() {
    var state = FlistStore.getState();
    expect(state).toEqual({category: null});
  });

  it('selects a category', function() {
    callback(actionCategorySelect);
    var state = FlistStore.getState();
    expect(state.category).toEqual({name: 'Sample'});
  });

  it('unselects a category', function() {
    callback(actionCategorySelect);
    var state = FlistStore.getState();
    expect(state.category).toEqual({name: 'Sample'});

    callback(actionCategoryUnselect);
    state = FlistStore.getState();
    expect(state.category).toEqual(null);
  });
});
<commit_msg>Fix Broken Test<commit_after>/*
 * Copyright (c) 2015, Wannabe Mutants LLC.
 * All rights reserved.
 *
 * FlistStore Tests
 */

jest.dontMock('../../constants/FlistConstants');
jest.dontMock('../FlistStore');
jest.dontMock('object-assign');

describe('FlistStore', function() {

  var FlistConstants = require('../../constants/FlistConstants');
  var AppDispatcher;
  var FlistStore;
  var callback;

  //Actions
  var actionCategoryUnselect = {
    actionType: FlistConstants.CATEGORY_UNSELECT
  };
  var actionCategorySelect = {
    actionType: FlistConstants.CATEGORY_SELECT,
    data: {name: 'Sample'}
  };

  beforeEach(function() {
    AppDispatcher = require('../../dispatcher/AppDispatcher');
    FlistStore = require('../FlistStore');
    callback = AppDispatcher.register.mock.calls[0][0];
  });

  it('registers a callback with the dispatcher', function() {
    expect(AppDispatcher.register.mock.calls.length).toBe(1);
  });

  it('initializes with an empty state', function() {
    var state = FlistStore.getState();
    expect(state).toEqual({category: null, logged_in:false});
  });

  it('selects a category', function() {
    callback(actionCategorySelect);
    var state = FlistStore.getState();
    expect(state.category).toEqual({name: 'Sample'});
  });

  it('unselects a category', function() {
    callback(actionCategorySelect);
    var state = FlistStore.getState();
    expect(state.category).toEqual({name: 'Sample'});

    callback(actionCategoryUnselect);
    state = FlistStore.getState();
    expect(state.category).toEqual(null);
  });
});
<|endoftext|>


<commit_before>const { Knorm } = require('@knorm/knorm');

class KnormPaginate {
  constructor({ name = 'paginate', page = 1, perPage = 10 } = {}) {
    this.name = name;
    this.page = parseInt(page);
    this.perPage = parseInt(perPage);
  }

  updateModel(knorm) {
    const { Model } = knorm;

    class PaginateModel extends Model {
      static async count(options) {
        return this.query.count(options);
      }
    }

    knorm.Model = PaginateModel;
  }

  updateQuery(knorm) {
    const { Query } = knorm;
    const defaultPage = this.page;
    const defaultPerPage = this.perPage;

    class PaginateQuery extends Query {
      constructor(model) {
        super(model);

        this.setOption('withPaginationData', true);
      }

      withPaginationData(withPaginationData = true) {
        return this.setOption('withPaginationData', !!withPaginationData);
      }

      page(page) {
        return this.setOption('page', page);
      }

      perPage(perPage) {
        return this.setOption('perPage', parseInt(perPage));
      }

      async fetch(options) {
        this.setOptions(options);

        let { page, perPage } = this.options;
        const { withPaginationData } = this.options;

        if (page === undefined && perPage === undefined) {
          return super.fetch();
        }

        if (page === undefined) {
          page = defaultPage;
        }

        if (perPage === undefined) {
          perPage = defaultPerPage;
        }

        let total;

        if (withPaginationData || page === 'last') {
          const clone = this.clone().unsetOptions([
            'groupBy',
            'orderBy',
            'limit',
            'offset'
          ]);

          if (!clone.hasOption('distinct')) {
            clone.unsetOption('fields');
          }

          total = await clone.count();

          if (page === 'last') {
            page = Math.ceil(total / perPage);
          }
        }

        page = page === 'first' ? 1 : parseInt(page);

        const rows = await super.fetch({
          limit: perPage,
          offset: perPage * (page - 1)
        });

        return withPaginationData ? { total, page, perPage, rows } : rows;
      }

      async prepareSql(sql, options) {
        if (this.config.forCount) {
          const joins = this.getOption('joins');

          if (joins) {
            joins.forEach(join => {
              // disable fields on joins if none have been set
              if (!join.hasOption('fields')) {
                join.fields(false);
              }

              // enable recursively disabling joined fields
              join.config.forCount = true;
            });
          }
        }

        return super.prepareSql(sql, options);
      }

      prepareCountFields() {
        let fields = [];

        if (this.options.fields) {
          fields = fields.concat(Object.values(this.options.fields));
          this.unsetOption('fields');
        }

        fields = fields.length
          ? fields.map(this.getColumn, this).join(', ')
          : '*';

        if (this.options.distinct) {
          fields = `DISTINCT ${fields}`;
          this.unsetOption('distinct');
        }

        return this.fields({ count: `COUNT(${fields})` });
      }

      async count(options) {
        this.setOptions(options);
        this.prepareCountFields();

        this.config.forCount = true;

        const rows = await super.fetch();
        const count = parseInt(rows[0].count);

        if (!count && this.options.require) {
          throw new this.constructor.NoRowsCountedError({ query: this });
        }

        return count;
      }
    }

    PaginateQuery.NoRowsCountedError = class NoRowsCountedError extends Query.NoRowsError {};

    knorm.Query = knorm.Model.Query = PaginateQuery;
  }

  init(knorm) {
    if (!knorm) {
      throw new this.constructor.KnormPaginateError(
        'no Knorm instance provided'
      );
    }

    if (!(knorm instanceof Knorm)) {
      throw new this.constructor.KnormPaginateError(
        'invalid Knorm instance provided'
      );
    }

    this.updateModel(knorm);
    this.updateQuery(knorm);
  }
}

KnormPaginate.KnormPaginateError = class KnormPaginateError extends Knorm.KnormError {};

module.exports = KnormPaginate;
<commit_msg>refactor: use knorm helpers to update classes<commit_after>const { Knorm } = require('@knorm/knorm');

class KnormPaginate {
  constructor({ name = 'paginate', page = 1, perPage = 10 } = {}) {
    this.name = name;
    this.page = parseInt(page);
    this.perPage = parseInt(perPage);
  }

  updateModel(knorm) {
    const { Model } = knorm;

    class PaginateModel extends Model {
      static async count(options) {
        return this.query.count(options);
      }
    }

    knorm.updateModel(PaginateModel);
  }

  updateQuery(knorm) {
    const { Query } = knorm;
    const defaultPage = this.page;
    const defaultPerPage = this.perPage;

    class PaginateQuery extends Query {
      constructor(model) {
        super(model);

        this.setOption('withPaginationData', true);
      }

      withPaginationData(withPaginationData = true) {
        return this.setOption('withPaginationData', !!withPaginationData);
      }

      page(page) {
        return this.setOption('page', page);
      }

      perPage(perPage) {
        return this.setOption('perPage', parseInt(perPage));
      }

      async fetch(options) {
        this.setOptions(options);

        let { page, perPage } = this.options;
        const { withPaginationData } = this.options;

        if (page === undefined && perPage === undefined) {
          return super.fetch();
        }

        if (page === undefined) {
          page = defaultPage;
        }

        if (perPage === undefined) {
          perPage = defaultPerPage;
        }

        let total;

        if (withPaginationData || page === 'last') {
          const clone = this.clone().unsetOptions([
            'groupBy',
            'orderBy',
            'limit',
            'offset'
          ]);

          if (!clone.hasOption('distinct')) {
            clone.unsetOption('fields');
          }

          total = await clone.count();

          if (page === 'last') {
            page = Math.ceil(total / perPage);
          }
        }

        page = page === 'first' ? 1 : parseInt(page);

        const rows = await super.fetch({
          limit: perPage,
          offset: perPage * (page - 1)
        });

        return withPaginationData ? { total, page, perPage, rows } : rows;
      }

      async prepareSql(sql, options) {
        if (this.config.forCount) {
          const joins = this.getOption('joins');

          if (joins) {
            joins.forEach(join => {
              // disable fields on joins if none have been set
              if (!join.hasOption('fields')) {
                join.fields(false);
              }

              // enable recursively disabling joined fields
              join.config.forCount = true;
            });
          }
        }

        return super.prepareSql(sql, options);
      }

      prepareCountFields() {
        let fields = [];

        if (this.options.fields) {
          fields = fields.concat(Object.values(this.options.fields));
          this.unsetOption('fields');
        }

        fields = fields.length
          ? fields.map(this.getColumn, this).join(', ')
          : '*';

        if (this.options.distinct) {
          fields = `DISTINCT ${fields}`;
          this.unsetOption('distinct');
        }

        return this.fields({ count: `COUNT(${fields})` });
      }

      async count(options) {
        this.setOptions(options);
        this.prepareCountFields();

        this.config.forCount = true;

        const rows = await super.fetch();
        const count = parseInt(rows[0].count);

        if (!count && this.options.require) {
          throw new this.constructor.NoRowsCountedError({ query: this });
        }

        return count;
      }
    }

    PaginateQuery.NoRowsCountedError = class NoRowsCountedError extends Query.NoRowsError {};

    knorm.updateQuery(PaginateQuery);
  }

  init(knorm) {
    if (!knorm) {
      throw new this.constructor.KnormPaginateError(
        'no Knorm instance provided'
      );
    }

    if (!(knorm instanceof Knorm)) {
      throw new this.constructor.KnormPaginateError(
        'invalid Knorm instance provided'
      );
    }

    this.updateModel(knorm);
    this.updateQuery(knorm);
  }
}

KnormPaginate.KnormPaginateError = class KnormPaginateError extends Knorm.KnormError {};

module.exports = KnormPaginate;
<|endoftext|>


<commit_before>import { Component } from 'react'
import classNames from 'classnames'
import { colors } from 'msi-keyboard/lib/constants'
import keyboard from '../lib/keyboard'
import KeyboardView from './Keyboard'
import ColorPicker from './ColorPicker'

module.exports = class App extends Component {
  constructor (props) {
    super(props)
    this.state = {
      error: null,
      on: true,
      tip: 'Click on a region to choose a color',
      colors: {
        left: 'red',
        middle: 'blue',
        right: 'green'
      }
    }
  }

  componentDidMount () {
    if (keyboard.stack) {
      this.setState({error: keyboard.message})
    }
  }

  handleColors (opts) {
    this.setState({
      colors: Object.assign(this.state.colors, opts),
      choose: null
    })
  }

  setKeyboard (regions, on) {
    if (on) this.setState({ on })
    for (const k in regions) {
      if (!regions[k]) return
      keyboard.color(k, {
        color: regions[k],
        intensity: 'high'
      })
    }
  }

  handleColorClick (region) {
    this.setState({choose: region})
  }
  toggleOn () {
    this.setState({on: !this.state.on}, () => {
      if (!this.state.on) {
        return this.setKeyboard({
          left: 'black',
          middle: 'black',
          right: 'black'
        })
      }
      this.setKeyboard(this.state.colors)
    })
  }

  handleColor (color, num) {
    let obj = {}
    obj[this.state.choose] = color
    obj.choose = null
    this.handleColors(obj)
  }

  close () {
    this.setState({choose: null})
  }

  // setMode () {
  //   keyboard.mode('breathe', this.state.colors)
  // }

  render () {
    let errorEl
    if (this.state.error) {
      errorEl =

 Error

            {this.state.error}

          Did you try using sudo?

    }

    let ColorEl = <ColorPicker
      className={this.state.choose ? 'active' : null}
      close={() => this.close()}
      handleColor={(k, v) => this.handleColor(k, v)}
      region={this.state.choose} />

    return

      {errorEl}
      {ColorEl}

 this.toggleOn()}
        className={classNames('button toggle', {
        active: this.state.on
      })}>

        {this.state.tip}

      <KeyboardView
        on={this.state.on}
        initialColors={this.state.colors}
        handleColorClick={(e) => this.handleColorClick(e)}
        handleColors={(e) => this.handleColors(e)}/>

      <button
        onClick={() => this.setKeyboard(this.state.colors, true)}
        className='button submit'>
        set colors
        </button>

  }
}
<commit_msg>add modes!<commit_after>import { Component } from 'react'
import classNames from 'classnames'
import { colors } from 'msi-keyboard/lib/constants'
import keyboard from '../lib/keyboard'
import KeyboardView from './Keyboard'
import ColorPicker from './ColorPicker'
import Selector from './Selector'

module.exports = class App extends Component {
  constructor (props) {
    super(props)
    this.state = {
      error: null,
      on: true,
      tip: 'Click on a region to choose a color',
      mode: null,
      colors: {
        left: 'red',
        middle: 'blue',
        right: 'green'
      }
    }
  }

  componentDidMount () {
    if (keyboard.stack) {
      this.setState({error: keyboard.message})
    }
  }

  handleColors (opts) {
    this.setState({
      colors: Object.assign(this.state.colors, opts),
      choose: null
    })
  }

  handleSelector (mode) {
    this.setState({mode})
  }

  setKeyboard (regions, on) {
    if (on) this.setState({ on })
    for (const k in regions) {
      if (!regions[k]) return
      keyboard.color(k, {
        color: regions[k],
        intensity: 'high'
      })
    }
  }

  handleColorClick (region) {
    this.setState({choose: region})
  }
  toggleOn () {
    this.setState({on: !this.state.on}, () => {
      if (!this.state.on) {
        return this.setKeyboard({
          left: 'black',
          middle: 'black',
          right: 'black'
        })
      }
      this.setKeyboard(this.state.colors)
    })
  }

  handleColor (color, num) {
    let obj = {}
    obj[this.state.choose] = color
    obj.choose = null
    this.handleColors(obj)
  }

  close () {
    this.setState({choose: null})
  }

  setMode () {
    this.setState({mode: null})
    keyboard.mode(this.state.mode, {
      left: {color: this.state.colors.left},
      middle: {color: this.state.colors.middle},
      right: {color: this.state.colors.right}
    })
    if (this.state.mode === 'normal') {
      this.setKeyboard(this.state.colors)
    }
  }

  render () {
    let errorEl
    if (this.state.error) {
      errorEl =

 Error

            {this.state.error}

          Did you try using sudo?

    }

    let ColorEl = <ColorPicker
      className={this.state.choose ? 'active' : null}
      close={() => this.close()}
      handleColor={(k, v) => this.handleColor(k, v)}
      region={this.state.choose} />

    return

      {errorEl}
      {ColorEl}

 this.toggleOn()}
        className={classNames('button toggle', {
        active: this.state.on
      })}>

        {this.state.tip}

      <KeyboardView
        on={this.state.on}
        initialColors={this.state.colors}
        handleColorClick={(e) => this.handleColorClick(e)}
        handleColors={(e) => this.handleColors(e)}/>

      <button
        onClick={() => this.setKeyboard(this.state.colors, true)}
        className='button submit'>
        set colors
        </button>

      <Selector
        items={[
          'breathe',
          'wave',
          'normal'
        ]}
        handleSelector={(e) => this.handleSelector(e)}
        />

      <button
        onClick={() => this.setMode()}
        style={{
          opacity: this.state.mode ? 1 : 0,
          visibility: this.state.mode ? 'visible' : 'hidden'
        }}
        className='button submit'>
        set mode
        </button>

  }
}
<|endoftext|>


<commit_before>import React, {Component} from 'react';

const styles = {
    map: {
        marginTop: '-20px',
        height: '600px',
        width: '100%'
    }
};

class Map extends Component {
    componentDidMount(rootNode) {
        var mapOptions = {
                center: this.mapCenterLatLng(),
                zoom: this.props.initialZoom
        };

        var map = new google.maps.Map(React.findDOMNode(this.refs.map), mapOptions);
        var marker = new google.maps.Marker({position: this.mapCenterLatLng(), title: 'Hi', map: map});
        this.setState({map: map});
    }

    mapCenterLatLng() {
        var props = this.props;
        return new google.maps.LatLng(props.mapCenterLat, props.mapCenterLng);
    }

    render() {
        return (

        );
    }
}

Map.defaultProps = {
    initialZoom: 8,
    mapCenterLat: 49.191030,
    mapCenterLng: 16.611521
};

export default Map;<commit_msg>Simple map view<commit_after>import React, {Component} from 'react';

const styles = {
    map: {
        marginTop: '-20px',
        height: '600px',
        width: '100%'
    },
    stats: {
        zIndex: 100
    }
};

class Map extends Component {
    constructor(props) {
        super(props);

        this.layer = null;
        this.stats = null;
    }
    componentDidMount(rootNode) {
        var mapOptions = {
                center: this.mapCenterLatLng(),
                zoom: this.props.initialZoom
        };

        var map = new google.maps.Map(React.findDOMNode(this.refs.map), mapOptions);
        var marker = new google.maps.Marker({position: this.mapCenterLatLng(), title: 'Hi', map: map});

        this.layer = new ThreejsLayer({map: map}, function (layer) {

        });

        this.setState({map: map});

        var stats = new Stats();
        stats.setMode(0); // 0: fps, 1: ms

        React.findDOMNode(this.refs.stats).appendChild(stats.domElement);

        this.stats = stats;

        // Start ticking
        requestAnimationFrame(this.tick.bind(this));
    }

    mapCenterLatLng() {
        var props = this.props;
        return new google.maps.LatLng(props.mapCenterLat, props.mapCenterLng);
    }

    render() {
        return (

        );
    }

    tick() {
        // Begin of stats loop
        this.stats.begin();

        // TODO: Do heavy work here

        // Begin of stats loop
        this.stats.end();

        requestAnimationFrame(this.tick.bind(this));
    }
}

Map.defaultProps = {
    initialZoom: 8,
    mapCenterLat: 49.191030,
    mapCenterLng: 16.611521
};

export default Map;<|endoftext|>


<commit_before>/*
nodeGaudi platform agnostic build tool.
Copyright 2014 Sam Saint-Pettersen.

Gaudi implemented with Node.js

Released under the MIT/X11 License.
Please see LICENSE file.
*/

// Custom includes.
var g = require('./GenericFunctions.js');

// Node.js standard includes.
var fs = require('fs');

var NodeGaudiBase = exports;

// File writing operations
NodeGaudiBase.writeToFile = function(file, message, append) {
	if(!append) fs.writeFileSync(file, message);
	else fs.appendFileSync(file, message + "\n");
}
<commit_msg>Update NodeGaudiBase.js<commit_after>/*
nodeGaudi platform agnostic build tool.
Copyright 2014 Sam Saint-Pettersen.

Gaudi implemented with Node.js

Released under the MIT/X11 License.
Please see LICENSE file.
*/

// Custom includes.
var g = require('./GenericFunctions.js');

// Node.js standard includes.
var fs = require('fs');

var NodeGaudiBase = exports;

// File writing operations
NodeGaudiBase.writeToFile = function(file, message, append) {
	if(!append) fs.writeFileSync(file, message + "\n");
	else fs.appendFileSync(file, message + "\n");
}
<|endoftext|>


<commit_before>'use strict';

var some = require('./some');

module.exports = function (obj, searchValue) {
	var r;
	return some(obj, function (value, name) {
		if (value === searchValue) {
			r = name;
			return true;
		}
		return false;
	}) ? r : null;
};
<commit_msg>Use Object.is for comparision in Object.keyOf<commit_after>'use strict';

var ois  = require('./is')
  , some = require('./some');

module.exports = function (obj, searchValue) {
	var r;
	return some(obj, function (value, name) {
		if (ois(value, searchValue)) {
			r = name;
			return true;
		}
		return false;
	}) ? r : null;
};
<|endoftext|>


<commit_before>require('enyo');

/**
* Exports Prioriy options used by {@link module:enyo/BackgroundTaskManager}
* @module enyo/PriorityQueue
*/

var
	kind = require('./kind'),
	utils = require('./utils');

var
	CoreObject = require('./CoreObject');

/**
* @enum {Number}
* @memberof module:enyo/PriorityQueue~PriorityQueue
* @public
*/
var Priorities = {

	/**
	* This is effectively the probable-need priority. Any customers who have enqueued a task
	* with this priority will automatically be bumped to the front of the queue.
	*
	* @default 1
	*/
	SOON: 1,

	/**
	* This is the default priority and is used to indicate that the execution of the task is not
	* required in the near future.
	*
	* @default 5
	*/
	SOMETIME: 5
};

/**
* The default configurable options used by {@link module:enyo/PriorityQueue~PriorityQueue}.
*
* @typedef {Object} module:enyo/PriorityQueue~PriorityQueue~Options
* @property {Function} [compareFn] - A comparison function to be utilized when comparing two
*	items to determine prioritization. The function will receive two parameters, and should
*	return a boolean indicating whether or not the priority of the first item is greater than
*	the priority of the second time.
*/

/**
* @class PriorityQueue
* @public
*/
module.exports = exports = kind(
	/** @lends module:enyo/PriorityQueue~PriorityQueue */ {

	/**
	* @private
	*/
	name: 'enyo.PriorityQueue',

	/**
	* @private
	*/
	kind: CoreObject,

	/**
	* The type of heap utilized by the {@link module:enyo/PriorityQueue~PriorityQueue}. Possible values include
	* 'minHeap' and 'maxHeap', which correspond to overridable functions that are used when
	* comparing values. This value is ignored if a comparison function is provided at
	* initialization time via [configuration options]{@link module:enyo/PriorityQueue~PriorityQueue~Options}.
	*
	* @type {String}
	* @default 'minHeap'
	* @public
	*/
	type: 'minHeap',

	/**
	* @private
	* @default module:enyo/PriorityQueue~PriorityQueue#Priority.SOMETIME
	*/
	defaultPriority: Priorities.SOMETIME,

	/**
	* Initializes the {@link module:enyo/PriorityQueue~PriorityQueue}.
	*
	* @param {module:enyo/PriorityQueue~PriorityQueue~Options} [opts] - The hash of configuration options.
	* @method
	* @public
	*/
	constructor: kind.inherit( function (sup) {
		return function (opts) {
			sup.apply(this, arguments);
			this.queue = [];
			this.length = 0;
			this.compareFn = (opts && opts.compareFn) || this[this.type];
		};
	}),

	/**
	* Inserts a given item into the queue, with an optional priority.
	*
	* @param {Object} item - The item to insert.
	* @param {Number} [priority] - The priority of the item in the queue.
	* @public
	*/
	add: function (item, priority) {
		priority = this.normalizePriority(priority) || this.defaultPriority;
		this.length = this.queue.push({
			item: item,
			priority: priority
		});
		this.bubbleUp(this.length - 1);
	},

	/**
	* Empties all of the items from the queue.
	*
	* @public
	*/
	clear: function () {
		this.queue = [];
		this.length = 0;
	},

	/**
	* Retrives the highest-priority item from the queue, without removing it from the queue.
	*
	* @return {Object} The highest-priority item in the queue.
	* @public
	*/
	peek: function () {
		return this.queue[0] && this.queue[0].item;
	},

	/**
	* Retrives and removes the highest-priority item from the queue.
	*
	* @return {Object} The highest-priority item in the queue.
	* @public
	*/
	poll: function () {
		var item;
		if (this.length) {
			item = this.queue.shift();

			if (this.queue.length > 1) { // heapify
				this.moveFromEnd(0);
			}

			this.length = this.queue.length;
		}

		return item && item.item;
	},

	/**
	* Removes the given item from the queue.
	*
	* @param {Object} item - The item to be removed.
	* @public
	*/
	remove: function (item) {
		// TODO: explore a more efficient technique
		//var idx = this.queue.indexOf(item);
		var idx = this.findIndexInQueue(item);

		if (idx > -1) {
			this.moveFromEnd(idx, true);
		}

		this.length = this.queue.length;
	},

	/**
	* Updates the priority for the given item.
	*
	* @param {Object} item - The item whose priority is to be updated.
	* @param {Number} priority - The new priority value.
	* @public
	*/
	updatePriority: function (item, priority) {
		var idx = this.findIndexInQueue(item),
			itemInQueue = this.queue[idx];

		itemInQueue.priority = priority;
		this.swap(idx, this.queue.length - 1);
		this.bubbleUp();
	},

	/**
	* Normalizes the priority to a numerical value.
	*
	* @param {String|Number} priority - The priority value to normalize.
	* @private
	*/
	normalizePriority: function (priority) {
		return utils.isString(priority) ? Priorities[utils.toUpperCase(priority)] : priority;
	},

	/**
	* This is our up-heap function.
	*
	* @param {Number} idx - The position from which we want to start bubbling up.
	* @private
	*/
	bubbleUp: function (idx) {
		var length = this.queue.length,
			current = this.queue[idx],
			parent, parentIdx;

		if (length == 1) {
			return;
		}

		parentIdx = Math.floor((idx + 1) / 2) - 1;
		parent = this.queue[parentIdx];

		if (parent && this.compareFn(current, parent)) {
			this.swap(idx, parentIdx);
			this.bubbleUp(parentIdx);
		}
	},

	/**
	* This is our down-heap function.
	*
	* @param {Number} idx - The position from which we want to start bubbling down.
	* @private
	*/
	bubbleDown: function (idx) {
		var current = this.queue[idx],
			leftIdx = (idx + 1) * 2 - 1,
			rightIdx = (idx + 1) * 2,
			left = this.queue[leftIdx],
			right = this.queue[rightIdx],
			swapIdx;

		if (left) {
			if (this.compareFn(left, current)) {
				if (right && this.compareFn(right, left)) {
					swapIdx = rightIdx;
					this.swap(swapIdx, idx);
				} else {
					swapIdx = leftIdx;
					this.swap(swapIdx, idx);
				}
				this.bubbleDown(swapIdx);
			} else {
				if (right && this.compareFn(right, current)) {
					swapIdx = rightIdx;
					this.swap(swapIdx, idx);
				}
			}
		}
	},

	/**
	* Swap the position of the given elements.
	*
	* @param {Number} idx1 - The position of the first element.
	* @param {Number} idx2 - The position of the second element.
	* @private
	*/
	swap: function (idx1, idx2) {
		var tmp = this.queue[idx1];
		this.queue[idx1] = this.queue[idx2];
		this.queue[idx2] = tmp;
	},

	/**
	* Move the last item into a specified position, usually to handle item removal.
	*
	* @param {Number} idx - The position where we wish to insert the element from the end of the
	*	queue.
	* @param {Boolean} [replace] - If `true`, the element at the specified position will be
	*	replaced by the element from the end of the queue; otherwise, an insertion will occur.
	* @private
	*/
	moveFromEnd: function (idx, replace) {
		var len = this.queue.length;

		if (replace) {
			this.queue.splice(idx, 1, this.queue[len - 1]);
			this.queue.splice(len - 1, 1);
		} else {
			this.queue.splice(idx, 0, this.queue[len - 1]);
			this.queue.splice(len, 1);
		}
		this.bubbleDown(idx);
	},

	/**
	* The comparison {@glossary function} used when the {@link module:enyo/PriorityQueue~PriorityQueue} utilizes a
	* min heap. This assumes that we wish to make a comparison utilizing the `priority` property
	* of the given items.
	*
	* @param {Object} item1 - The first item whose priority we are comparing.
	* @param {Object} item2 - The second item whose priority we are comparing.
	* @return {Boolean} If `true`, the first item has higher priority than the second item.
	* @private
	*/
	minHeap: function (item1, item2) {
		return item1.priority < item2.priority;
	},

	/**
	* The comparison {@glossary function} used when the {@link module:enyo/PriorityQueue~PriorityQueue} utilizes a
	* max heap. This assumes that we wish to make a comparison utilizing the `priority` property
	* of the given items.
	*
	* @param {Object} item1 - The first item whose priority we are comparing.
	* @param {Object} item2 - The second item whose priority we are comparing.
	* @return {Boolean} If `true`, the first item has higher priority than the second item.
	* @private
	*/
	maxHeap: function (item1, item2) {
		return item1.priority > item2.priority;
	},

	/**
	* For a given element, determines its index in our internal queue structure.
	*
	* @param {Object} item - The element whose index in our queue we wish to retrieve.
	* @private
	*/
	findIndexInQueue: function (item) {
		var idx;
		for (idx = 0; idx < this.queue.length; idx++) {
			if (item === this.queue[idx].item) {
				return idx;
			}
		}
	}

});

exports.Priorities = Priorities;
<commit_msg>Fixed typo Enyo-DCO-1.1-Signed-Off-By: Jim Tang (jim.tang@lge.com)<commit_after>require('enyo');

/**
* Exports Priority options used by {@link module:enyo/BackgroundTaskManager}.
* @module enyo/PriorityQueue
*/

var
	kind = require('./kind'),
	utils = require('./utils');

var
	CoreObject = require('./CoreObject');

/**
* @enum {Number}
* @memberof module:enyo/PriorityQueue~PriorityQueue
* @public
*/
var Priorities = {

	/**
	* This is effectively the probable-need priority. Any customers who have enqueued a task
	* with this priority will automatically be bumped to the front of the queue.
	*
	* @default 1
	*/
	SOON: 1,

	/**
	* This is the default priority and is used to indicate that the execution of the task is not
	* required in the near future.
	*
	* @default 5
	*/
	SOMETIME: 5
};

/**
* The default configurable options used by {@link module:enyo/PriorityQueue~PriorityQueue}.
*
* @typedef {Object} module:enyo/PriorityQueue~PriorityQueue~Options
* @property {Function} [compareFn] - A comparison function to be utilized when comparing two
*	items to determine prioritization. The function will receive two parameters, and should
*	return a boolean indicating whether or not the priority of the first item is greater than
*	the priority of the second time.
*/

/**
* @class PriorityQueue
* @public
*/
module.exports = exports = kind(
	/** @lends module:enyo/PriorityQueue~PriorityQueue */ {

	/**
	* @private
	*/
	name: 'enyo.PriorityQueue',

	/**
	* @private
	*/
	kind: CoreObject,

	/**
	* The type of heap utilized by the {@link module:enyo/PriorityQueue~PriorityQueue}. Possible values include
	* 'minHeap' and 'maxHeap', which correspond to overridable functions that are used when
	* comparing values. This value is ignored if a comparison function is provided at
	* initialization time via [configuration options]{@link module:enyo/PriorityQueue~PriorityQueue~Options}.
	*
	* @type {String}
	* @default 'minHeap'
	* @public
	*/
	type: 'minHeap',

	/**
	* @private
	* @default module:enyo/PriorityQueue~PriorityQueue#Priority.SOMETIME
	*/
	defaultPriority: Priorities.SOMETIME,

	/**
	* Initializes the {@link module:enyo/PriorityQueue~PriorityQueue}.
	*
	* @param {module:enyo/PriorityQueue~PriorityQueue~Options} [opts] - The hash of configuration options.
	* @method
	* @public
	*/
	constructor: kind.inherit( function (sup) {
		return function (opts) {
			sup.apply(this, arguments);
			this.queue = [];
			this.length = 0;
			this.compareFn = (opts && opts.compareFn) || this[this.type];
		};
	}),

	/**
	* Inserts a given item into the queue, with an optional priority.
	*
	* @param {Object} item - The item to insert.
	* @param {Number} [priority] - The priority of the item in the queue.
	* @public
	*/
	add: function (item, priority) {
		priority = this.normalizePriority(priority) || this.defaultPriority;
		this.length = this.queue.push({
			item: item,
			priority: priority
		});
		this.bubbleUp(this.length - 1);
	},

	/**
	* Empties all of the items from the queue.
	*
	* @public
	*/
	clear: function () {
		this.queue = [];
		this.length = 0;
	},

	/**
	* Retrives the highest-priority item from the queue, without removing it from the queue.
	*
	* @return {Object} The highest-priority item in the queue.
	* @public
	*/
	peek: function () {
		return this.queue[0] && this.queue[0].item;
	},

	/**
	* Retrives and removes the highest-priority item from the queue.
	*
	* @return {Object} The highest-priority item in the queue.
	* @public
	*/
	poll: function () {
		var item;
		if (this.length) {
			item = this.queue.shift();

			if (this.queue.length > 1) { // heapify
				this.moveFromEnd(0);
			}

			this.length = this.queue.length;
		}

		return item && item.item;
	},

	/**
	* Removes the given item from the queue.
	*
	* @param {Object} item - The item to be removed.
	* @public
	*/
	remove: function (item) {
		// TODO: explore a more efficient technique
		//var idx = this.queue.indexOf(item);
		var idx = this.findIndexInQueue(item);

		if (idx > -1) {
			this.moveFromEnd(idx, true);
		}

		this.length = this.queue.length;
	},

	/**
	* Updates the priority for the given item.
	*
	* @param {Object} item - The item whose priority is to be updated.
	* @param {Number} priority - The new priority value.
	* @public
	*/
	updatePriority: function (item, priority) {
		var idx = this.findIndexInQueue(item),
			itemInQueue = this.queue[idx];

		itemInQueue.priority = priority;
		this.swap(idx, this.queue.length - 1);
		this.bubbleUp();
	},

	/**
	* Normalizes the priority to a numerical value.
	*
	* @param {String|Number} priority - The priority value to normalize.
	* @private
	*/
	normalizePriority: function (priority) {
		return utils.isString(priority) ? Priorities[utils.toUpperCase(priority)] : priority;
	},

	/**
	* This is our up-heap function.
	*
	* @param {Number} idx - The position from which we want to start bubbling up.
	* @private
	*/
	bubbleUp: function (idx) {
		var length = this.queue.length,
			current = this.queue[idx],
			parent, parentIdx;

		if (length == 1) {
			return;
		}

		parentIdx = Math.floor((idx + 1) / 2) - 1;
		parent = this.queue[parentIdx];

		if (parent && this.compareFn(current, parent)) {
			this.swap(idx, parentIdx);
			this.bubbleUp(parentIdx);
		}
	},

	/**
	* This is our down-heap function.
	*
	* @param {Number} idx - The position from which we want to start bubbling down.
	* @private
	*/
	bubbleDown: function (idx) {
		var current = this.queue[idx],
			leftIdx = (idx + 1) * 2 - 1,
			rightIdx = (idx + 1) * 2,
			left = this.queue[leftIdx],
			right = this.queue[rightIdx],
			swapIdx;

		if (left) {
			if (this.compareFn(left, current)) {
				if (right && this.compareFn(right, left)) {
					swapIdx = rightIdx;
					this.swap(swapIdx, idx);
				} else {
					swapIdx = leftIdx;
					this.swap(swapIdx, idx);
				}
				this.bubbleDown(swapIdx);
			} else {
				if (right && this.compareFn(right, current)) {
					swapIdx = rightIdx;
					this.swap(swapIdx, idx);
				}
			}
		}
	},

	/**
	* Swap the position of the given elements.
	*
	* @param {Number} idx1 - The position of the first element.
	* @param {Number} idx2 - The position of the second element.
	* @private
	*/
	swap: function (idx1, idx2) {
		var tmp = this.queue[idx1];
		this.queue[idx1] = this.queue[idx2];
		this.queue[idx2] = tmp;
	},

	/**
	* Move the last item into a specified position, usually to handle item removal.
	*
	* @param {Number} idx - The position where we wish to insert the element from the end of the
	*	queue.
	* @param {Boolean} [replace] - If `true`, the element at the specified position will be
	*	replaced by the element from the end of the queue; otherwise, an insertion will occur.
	* @private
	*/
	moveFromEnd: function (idx, replace) {
		var len = this.queue.length;

		if (replace) {
			this.queue.splice(idx, 1, this.queue[len - 1]);
			this.queue.splice(len - 1, 1);
		} else {
			this.queue.splice(idx, 0, this.queue[len - 1]);
			this.queue.splice(len, 1);
		}
		this.bubbleDown(idx);
	},

	/**
	* The comparison {@glossary function} used when the {@link module:enyo/PriorityQueue~PriorityQueue} utilizes a
	* min heap. This assumes that we wish to make a comparison utilizing the `priority` property
	* of the given items.
	*
	* @param {Object} item1 - The first item whose priority we are comparing.
	* @param {Object} item2 - The second item whose priority we are comparing.
	* @return {Boolean} If `true`, the first item has higher priority than the second item.
	* @private
	*/
	minHeap: function (item1, item2) {
		return item1.priority < item2.priority;
	},

	/**
	* The comparison {@glossary function} used when the {@link module:enyo/PriorityQueue~PriorityQueue} utilizes a
	* max heap. This assumes that we wish to make a comparison utilizing the `priority` property
	* of the given items.
	*
	* @param {Object} item1 - The first item whose priority we are comparing.
	* @param {Object} item2 - The second item whose priority we are comparing.
	* @return {Boolean} If `true`, the first item has higher priority than the second item.
	* @private
	*/
	maxHeap: function (item1, item2) {
		return item1.priority > item2.priority;
	},

	/**
	* For a given element, determines its index in our internal queue structure.
	*
	* @param {Object} item - The element whose index in our queue we wish to retrieve.
	* @private
	*/
	findIndexInQueue: function (item) {
		var idx;
		for (idx = 0; idx < this.queue.length; idx++) {
			if (item === this.queue[idx].item) {
				return idx;
			}
		}
	}

});

exports.Priorities = Priorities;
<|endoftext|>


<commit_before>/*
 * ProduceModule
 * https://github.com/mkatanski/grunt-produce
 *
 * Copyright (c) 2015 Michał Katański
 * Licensed under the MIT license.
 */

var ProduceModule = (function () {

    require('shelljs/global');

    var path = require('path'),
        inquirer = require('inquirer'),
        _ = require('underscore'),
        yaml = require('js-yaml'),
        validator = require('validator'),
        fs = require('fs');

    /**
     * Create ProduceModule instance
     *
     * @param grunt {Class} Grunt class
     * @constructor
     */
    function ProduceModule(grunt) {
        this.grunt = grunt;
        this.template = {};
        this.locals = {};
        this.destinationFile = '';
    }

    /**
     * Validate locals
     */
    ProduceModule.prototype.validate = function () {
        _.each(this.locals, function (value, varName) {
            // check if variable is required
            if ((_.isNaN(this.locals[varName]) ||
                    this.locals[varName].trim() === '') &&
                    this.template.variables[varName].required === true) {
                throw "Variable [" + varName + "] is required";
            }

            // validate variable
            if (_.isFunction(this.template.variables[varName].validate) &&
                    !this.template.variables[varName].
                        validate(this.locals[varName], validator)) {
                throw "Variable [" + varName + "] value is incorrect";
            }
        }, this);
    };

    /**
     * Get array of questions for user
     */
    ProduceModule.prototype.getQuestions = function () {
        var _questions = [],
            _questionIndex = 0;
        // for each available variable
        _.each(this.locals, function (value, varName, list) {
            // create new question object
            _questions[_questionIndex] = {
                name   : varName,
                message: varName,
                default: list[varName]
            };
            _questionIndex++;
        }, this);
        return _questions;
    };

    /**
     * Create locals to use in template
     * @returns {boolean} Return false if no locals were passed in via CLI
     */
    ProduceModule.prototype._prepareVariables = function () {
        // number of collected locals via CLI
        var _variablesCount = 0,
            _initial;

        // Assign to locals object initial values
        _initial = { default: this.template.username };
        if (_.isUndefined(this.template.variables.username)) {
            this.template.variables.username = _initial;
        } else {
            this.template.variables.username.default = _initial.default;
        }

        _initial = { default: this.template.email };
        if (_.isUndefined(this.template.variables.email)) {
            this.template.variables.email = _initial;
        } else {
            this.template.variables.email.default = _initial.default;
        }

        if (_.isObject(this.template.variables)) {
            // for each defined variable collect variable value
            _.each(this.template.variables, function (value, varName, list) {
                // if variable is passed in via CLI
                if (this.grunt.option(varName)) {
                    // increment counter
                    _variablesCount++;
                }
                // assign variable value
                this.locals[varName] = this.grunt.option(varName) ||
                    list[varName].default;
            }, this);
        }
        return (_variablesCount !== 0);
    };

    /**
     * Check if template are correct
     */
    ProduceModule.prototype._checkOptions = function () {
        if (!_.isFunction(this.template.fileName) &&
                !_.isString(this.template.fileName)) {
            throw 'fileName is required and must be a string or function';
        }

        if (!_.isString(this.template.template)) {
            throw 'template is required and must be a string';
        }

        if (this.template.fileOverwrite !== 'block' &&
                this.template.fileOverwrite !== 'warning') {
            throw 'options.fileOverwrite must be equal to "block" or "warning"!';
        }
    };

    /**
     * Save destination file as expanded template
     */
    ProduceModule.prototype.saveFile = function () {
        // validate locals
        this.validate();

        // if fileName is a function, run it passing locals as an argument
        if (_.isFunction(this.template.fileName)) {
            this.template.fileName = this.template.fileName(this.locals);
        }

        // Replace locals in file name
        this.template.fileName = _.template(this.template.fileName)(this.locals);
        // Create destination path
        this.destinationFile = path.join(this.template.fileName);

        // Replace locals in template file
        this.template.template = _.template(this.template.template)(this.locals);

        // Check if destination file exists
        if (this.grunt.file.exists(this.destinationFile)) {
            if (this.template.fileOverwrite === 'block') {
                throw 'Destination file exists! [' + this.destinationFile + ']';
            }
            if (this.template.fileOverwrite === 'warning') {
                this.grunt.log.errorlns(
                    'Destination file will be overwriten! [' +
                        this.destinationFile + ']'
                );
            }
        }

        var templateName = this.template.templateName || this.template.templateFile,
            description =  this.template.description || '';

        console.log(
            '\n\nSaving new file [' + this.destinationFile + '] based on:\n' +
                templateName + ': ' + description + '\n'
        );

        // Save file
        this.grunt.file.write(this.destinationFile, this.template.template);
        this.grunt.log.writeln('File saved as: ' + this.destinationFile);
    };

    /**
     * Get git config
     *
     * @param configName {string} git config name
     * @returns {string} Git config value
     * @private
     */
    ProduceModule.prototype._getGitConfig = function (configName) {
        return exec('git config ' + configName,
            {silent: true}).output.replace('\n', '').trim();
    };

    /**
     * Asynchronously prompt user for locals values
     *
     * @param async {function} grunt async object
     * @param callback {function} callback function which is triggered
     * after prompting is complete
     */
    ProduceModule.prototype.promptUserAsync = function (async, callback) {
        inquirer.prompt(this.getQuestions(), function (answers) {
            _.each(answers, function (answer, varName) {
                // assign user answers to variable
                this.locals[varName] = answer;
            }, this);
            // finish async mode
            async();
            // run callback function
            callback();
        }, this);
    };

    /**
     * Setup module, collect all required data and load template file
     *
     * @param options {object} Module options
     */
    ProduceModule.prototype.setup = function (options) {
        // load template from YAML file
        this.template = yaml.load(fs.readFileSync(options.templateFile, 'utf8'));
        this.template.templateFile = options.templateFile;

        // Get GIT config values for username and user e-mail
        // (empty string as default if loading data from git config was unsuccessful)
        this.template.username = this._getGitConfig('user.name') || '';
        this.template.email = this._getGitConfig('user.email') || '';

        // Prepare defined locals and check if prompting for variable
        // values is required
        this.promptUser = !this._prepareVariables();

        this._checkOptions();

        // Check if template file exists
        if (this.grunt.file.exists(this.template.template)) {
            // Read template file
            this.template.template = this.grunt.file.read(this.template.template);
        }
    };

    return ProduceModule;
})();

module.exports = ProduceModule;
<commit_msg>refactor(app): Small refactor corrections<commit_after>/*
 * ProduceModule
 * https://github.com/mkatanski/grunt-produce
 *
 * Copyright (c) 2015 Michał Katański
 * Licensed under the MIT license.
 */

var ProduceModule = (function () {

    require('shelljs/global');

    var path = require('path'),
        inquirer = require('inquirer'),
        _ = require('underscore'),
        yaml = require('js-yaml'),
        validator = require('validator'),
        fs = require('fs');

    /**
     * Create ProduceModule instance
     *
     * @param grunt {Class} Grunt class
     * @constructor
     */
    function ProduceModule(grunt) {
        this.grunt = grunt;
        this.template = {};
        this.locals = {};
        this.destinationFile = '';
    }

    /**
     * Validate locals
     */
    ProduceModule.prototype.validate = function () {
        _.each(this.locals, function (value, varName) {
            // check if variable is required
            if ((_.isNaN(this.locals[varName]) ||
                    this.locals[varName].trim() === '') &&
                    this.template.variables[varName].required === true) {
                throw "Variable [" + varName + "] is required";
            }

            // validate variable
            if (_.isFunction(this.template.variables[varName].validate) &&
                    !this.template.variables[varName].
                        validate(this.locals[varName], validator)) {
                throw "Variable [" + varName + "] value is incorrect";
            }
        }, this);
    };

    /**
     * Get array of questions for user
     */
    ProduceModule.prototype.getQuestions = function () {
        var _questions = [],
            _questionIndex = 0;
        // for each available variable
        _.each(this.locals, function (value, varName) {
            // create new question object
            _questions[_questionIndex] = {
                name   : varName,
                message: varName,
                default: value
            };
            _questionIndex++;
        }, this);
        return _questions;
    };

    /**
     * Create locals to use in template
     * @returns {boolean} Return false if no locals were passed in via CLI
     */
    ProduceModule.prototype._prepareVariables = function () {
        // number of collected locals via CLI
        var _variablesCount = 0,
            _initial;

        // Assign to locals object initial values
        _initial = { default: this.template.username };
        if (_.isUndefined(this.template.variables.username)) {
            this.template.variables.username = _initial;
        } else {
            this.template.variables.username.default = _initial.default;
        }

        _initial = { default: this.template.email };
        if (_.isUndefined(this.template.variables.email)) {
            this.template.variables.email = _initial;
        } else {
            this.template.variables.email.default = _initial.default;
        }

        if (_.isObject(this.template.variables)) {
            // for each defined variable collect variable value
            _.each(this.template.variables, function (value, varName, list) {
                // if variable is passed in via CLI
                if (this.grunt.option(varName)) {
                    // increment counter
                    _variablesCount++;
                }
                // assign variable value
                this.locals[varName] = this.grunt.option(varName) ||
                    list[varName].default;
            }, this);
        }
        return (_variablesCount !== 0);
    };

    /**
     * Check if template are correct
     */
    ProduceModule.prototype._checkOptions = function () {
        if (!_.isFunction(this.template.fileName) &&
                !_.isString(this.template.fileName)) {
            throw 'fileName is required and must be a string or function';
        }

        if (!_.isString(this.template.template)) {
            throw 'template is required and must be a string';
        }

        if (this.template.fileOverwrite !== 'block' &&
                this.template.fileOverwrite !== 'warning') {
            throw 'options.fileOverwrite must be equal to "block" or "warning"!';
        }
    };

    /**
     * Save destination file as expanded template
     */
    ProduceModule.prototype.saveFile = function () {
        // validate locals
        this.validate();

        // if fileName is a function, run it passing locals as an argument
        if (_.isFunction(this.template.fileName)) {
            this.template.fileName = this.template.fileName(this.locals);
        }

        // Replace locals in file name
        this.template.fileName = _.template(this.template.fileName)(this.locals);
        // Create destination path
        this.destinationFile = path.join(this.template.fileName);

        // Replace locals in template file
        this.template.template = _.template(this.template.template)(this.locals);

        // Check if destination file exists
        if (this.grunt.file.exists(this.destinationFile)) {
            if (this.template.fileOverwrite === 'block') {
                throw 'Destination file exists! [' + this.destinationFile + ']';
            }
            if (this.template.fileOverwrite === 'warning') {
                this.grunt.log.errorlns(
                    'Destination file will be overwriten! [' +
                        this.destinationFile + ']'
                );
            }
        }

        var _templateName = this.template.templateName || this.template.templateFile,
            _description =  this.template.description || '';

        console.log(
            '\n\nSaving new file [' + this.destinationFile + '] based on:\n' +
                _templateName + ': ' + _description + '\n'
        );

        // Save file
        this.grunt.file.write(this.destinationFile, this.template.template);
        this.grunt.log.writeln('File saved as: ' + this.destinationFile);
    };

    /**
     * Get git config
     *
     * @param configName {string} git config name
     * @returns {string} Git config value
     * @private
     */
    ProduceModule.prototype._getGitConfig = function (configName) {
        return exec('git config ' + configName,
            {silent: true}).output.replace('\n', '').trim();
    };

    /**
     * Asynchronously prompt user for locals values
     *
     * @param async {function} grunt async object
     * @param callback {function} callback function which is triggered
     * after prompting is complete
     */
    ProduceModule.prototype.promptUserAsync = function (async, callback) {
        inquirer.prompt(this.getQuestions(), function (answers) {
            _.each(answers, function (answer, varName) {
                // assign user answers to variable
                this.locals[varName] = answer;
            }, this);
            // finish async mode
            async();
            // run callback function
            callback();
        }, this);
    };

    /**
     * Setup module, collect all required data and load template file
     *
     * @param options {object} Module options
     */
    ProduceModule.prototype.setup = function (options) {
        // load template from YAML file
        this.template = yaml.load(fs.readFileSync(options.templateFile, 'utf8'));
        this.template.templateFile = options.templateFile;

        // Get GIT config values for username and user e-mail
        // (empty string as default if loading data from git config was unsuccessful)
        this.template.username = this._getGitConfig('user.name') || '';
        this.template.email = this._getGitConfig('user.email') || '';

        // Prepare defined locals and check if prompting for variable
        // values is required
        this.promptUser = !this._prepareVariables();

        this._checkOptions();

        // Check if template file exists
        if (this.grunt.file.exists(this.template.template)) {
            // Read template file
            this.template.template = this.grunt.file.read(this.template.template);
        }
    };

    return ProduceModule;
})();

module.exports = ProduceModule;
<|endoftext|>


<commit_before>/**
 * Copyright 2013-2015, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

'use strict';

const crypto = require('crypto');
const fs = require('fs');
const path = require('path');

function buildCacheKey(files, base) {
  return files.reduce(
    (src, fileName) => src + fs.readFileSync(fileName),
    base
  );
}

module.exports = files => {
  const presetVersion = require('../package').dependencies['babel-preset-fbjs'];
  const cacheKey = buildCacheKey(files, presetVersion);
  return (src, file, configString) => crypto.createHash('md5')
    .update(cacheKey)
    .update(src + file + configString)
    .digest('hex');
};
<commit_msg>Remove unused `path` dependency from createCacheKeyFunction.js<commit_after>/**
 * Copyright 2013-2015, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

'use strict';

const crypto = require('crypto');
const fs = require('fs');

function buildCacheKey(files, base) {
  return files.reduce(
    (src, fileName) => src + fs.readFileSync(fileName),
    base
  );
}

module.exports = files => {
  const presetVersion = require('../package').dependencies['babel-preset-fbjs'];
  const cacheKey = buildCacheKey(files, presetVersion);
  return (src, file, configString) => crypto.createHash('md5')
    .update(cacheKey)
    .update(src + file + configString)
    .digest('hex');
};
<|endoftext|>


<commit_before>import Promise from 'bluebird';
import { List } from 'immutable';

const reconnectableStatus = 4000;
const timeoutStart = 300;
const timeoutMax = 2 * 60 * 1000;
export const readyStates = {
  CONNECTING: 0,
  OPEN: 1,
  CLOSING: 2,
  CLOSED: 3,
  RECONNECT_ABORTED: 4,
};

const globalVar = typeof global !== 'undefined' // eslint-disable-line
  ? global
  : (typeof window !== 'undefined' ? window : {});

function createWebSocket(url, protocols, customWsClient) {
  const urlOk = /wss?:\/\//.exec(url);
  if (!urlOk) {
    throw new Error('Invalid url provided');
  }
  const Socket = customWsClient || globalVar.WebSocket || globalVar.MozWebSocket;
  return new Socket(url, protocols || undefined);
}

export default class WsClient {

  constructor(url, protocols, options = {}) {
    this.init(url, protocols, options);
    this.reconnectAttempts = 0;
    this.manualClose = false;
    this.sendQueue = List();
    this.onOpenCallbacks = List();
    this.onCloseCallbacks = List();
    this.onErrorCallbacks = List();
    this.onMessageCallbacks = List();
    this.socket = undefined;
  }

  // ==============================================================================================
  //  PUBLIC

  connect = (url, protocols, options = {}) => {
    this.init(url, protocols, options);
    if (!this.isOpen()) {
      this.socket = createWebSocket(this.url, this.protocols, this.customWsClient);
      this.socket.onmessage = this.onMessageHandler;
      this.socket.onopen = this.onOpenHandler;
      this.socket.onerror = this.onErrorHandler;
      this.socket.onclose = this.onCloseHandler;
    }
    return this;
  }

  isOpen() {
    return this.socket && this.socket.readyState === readyStates.OPEN;
  }

  init(url, protocols, options = {}) {
    if (url) {
      this.url = url;
      this.isEncrypted = /^(wss:)/i.test(this.url);
    }
    if (protocols) this.protocols = protocols;

    if (options.timeoutStart) this.timeoutStart = options.timeoutStart;
    else if (!this.timeoutStart) this.timeoutStart = timeoutStart;

    if (options.timeoutMax) this.timeoutMax = options.timeoutMax;
    else if (!this.timeoutMax) this.timeoutMax = timeoutMax;

    if (options.reconnectIfNotNormalClose) {
      this.reconnectIfNotNormalClose = options.reconnectIfNotNormalClose;
    }

    if (options.customWsClient) this.customWsClient = options.customWsClient;
    return this;
  }

  onOpen(cb) {
    this.onOpenCallbacks = this.onOpenCallbacks.push(cb);
    return this;
  }

  onClose(cb) {
    this.onCloseCallbacks = this.onCloseCallbacks.push(cb);
    return this;
  }

  onError(cb) {
    this.onErrorCallbacks = this.onErrorCallbacks.push(cb);
    return this;
  }

  onMessage(cb) {
    this.onMessageCallbacks = this.onMessageCallbacks.push(cb);
    return this;
  }

  clearCallbacks() {
    this.onOpenCallbacks = this.onOpenCallbacks.clear();
    this.onCloseCallbacks = this.onCloseCallbacks.clear();
    this.onErrorCallbacks = this.onErrorCallbacks.clear();
    this.onMessageCallbacks = this.onMessageCallbacks.clear();
    return this;
  }

  send(message) {
    const self = this;
    return new Promise((resolve, reject) => {
      if (self.socket.readyState === readyStates.RECONNECT_ABORTED) {
        reject(new Error('Could not send: Socket closed'));
      } else {
        self.sendQueue = self.sendQueue.push({ message, resolve });
        self.fireQueue();
      }
    });
  }

  close() {
    this.terminate();
    this.manualClose = true;
    return this;
  }

  terminate() {
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer);
      this.reconnectTimer = undefined;
    }
    this.socket.close();
  }

  reconnect() {
    this.terminate();
    const backoffDelay = this.getBackoffDelay(++this.reconnectAttempts);
    const backoffDelaySeconds = backoffDelay / 1000;
    console.log(`Reconnecting in ${backoffDelaySeconds} seconds`);
    this.reconnectTimer = setTimeout(this.connect, backoffDelay);
    return this;
  }

  // ==============================================================================================

  fireQueue() {
    while (this.sendQueue.size && this.socket.readyState === readyStates.OPEN) {
      const data = this.sendQueue.first();
      this.sendQueue = this.sendQueue.shift();
      this.socket.send(data.message);
      data.resolve();
    }
    return this;
  }

  // ==============================================================================================
  //  PRIVATE

  onOpenHandler = (event) => {
    this.reconnectAttempts = 0;
    this.manualClose = false;
    this.onOpenCallbacks.forEach(cb => cb(event));
    this.fireQueue();
  }

  onCloseHandler = (event) => {
    this.onCloseCallbacks.forEach(cb => cb(event));
    const notNormalReconnect = this.reconnectIfNotNormalClose && !this.manualClose;
    if (notNormalReconnect && event.code === reconnectableStatus) {
      this.reconnect();
    }
  }

  onErrorHandler = (event) => {
    this.onErrorCallbacks.forEach(cb => cb(event));
  }

  onMessageHandler = (message) => {
    this.onMessageCallbacks.forEach(cb => cb(message));
  }

  getBackoffDelay(attempt) {
    // Exponential Backoff Formula by Prof. Douglas Thain
    // http://dthain.blogspot.co.uk/2009/02/exponential-backoff-in-distributed.html
    return Math.floor(Math.min(
      (Math.random() + 1) * this.timeoutStart * Math.pow(2, attempt),
      this.timeoutMax
    ));
  }
}
<commit_msg>connecting state check on (re?)connect<commit_after>import Promise from 'bluebird';
import { List } from 'immutable';

const reconnectableStatus = 4000;
const timeoutStart = 300;
const timeoutMax = 2 * 60 * 1000;
export const readyStates = {
  CONNECTING: 0,
  OPEN: 1,
  CLOSING: 2,
  CLOSED: 3,
  RECONNECT_ABORTED: 4,
};

const globalVar = typeof global !== 'undefined' // eslint-disable-line
  ? global
  : (typeof window !== 'undefined' ? window : {});

function createWebSocket(url, protocols, customWsClient) {
  const urlOk = /wss?:\/\//.exec(url);
  if (!urlOk) {
    throw new Error('Invalid url provided');
  }
  const Socket = customWsClient || globalVar.WebSocket || globalVar.MozWebSocket;
  return new Socket(url, protocols || undefined);
}

export default class WsClient {

  constructor(url, protocols, options = {}) {
    this.init(url, protocols, options);
    this.reconnectAttempts = 0;
    this.manualClose = false;
    this.sendQueue = List();
    this.onOpenCallbacks = List();
    this.onCloseCallbacks = List();
    this.onErrorCallbacks = List();
    this.onMessageCallbacks = List();
    this.socket = undefined;
  }

  // ==============================================================================================
  //  PUBLIC

  connect = (url, protocols, options = {}) => {
    this.init(url, protocols, options);
    if (!this.isOpen() && this.socket.readyState !== readyStates.CONNECTING) {
      this.socket = createWebSocket(this.url, this.protocols, this.customWsClient);
      this.socket.onmessage = this.onMessageHandler;
      this.socket.onopen = this.onOpenHandler;
      this.socket.onerror = this.onErrorHandler;
      this.socket.onclose = this.onCloseHandler;
    }
    return this;
  }

  isOpen() {
    return this.socket && this.socket.readyState === readyStates.OPEN;
  }

  init(url, protocols, options = {}) {
    if (url) {
      this.url = url;
      this.isEncrypted = /^(wss:)/i.test(this.url);
    }
    if (protocols) this.protocols = protocols;

    if (options.timeoutStart) this.timeoutStart = options.timeoutStart;
    else if (!this.timeoutStart) this.timeoutStart = timeoutStart;

    if (options.timeoutMax) this.timeoutMax = options.timeoutMax;
    else if (!this.timeoutMax) this.timeoutMax = timeoutMax;

    if (options.reconnectIfNotNormalClose) {
      this.reconnectIfNotNormalClose = options.reconnectIfNotNormalClose;
    }

    if (options.customWsClient) this.customWsClient = options.customWsClient;
    return this;
  }

  onOpen(cb) {
    this.onOpenCallbacks = this.onOpenCallbacks.push(cb);
    return this;
  }

  onClose(cb) {
    this.onCloseCallbacks = this.onCloseCallbacks.push(cb);
    return this;
  }

  onError(cb) {
    this.onErrorCallbacks = this.onErrorCallbacks.push(cb);
    return this;
  }

  onMessage(cb) {
    this.onMessageCallbacks = this.onMessageCallbacks.push(cb);
    return this;
  }

  clearCallbacks() {
    this.onOpenCallbacks = this.onOpenCallbacks.clear();
    this.onCloseCallbacks = this.onCloseCallbacks.clear();
    this.onErrorCallbacks = this.onErrorCallbacks.clear();
    this.onMessageCallbacks = this.onMessageCallbacks.clear();
    return this;
  }

  send(message) {
    const self = this;
    return new Promise((resolve, reject) => {
      if (self.socket.readyState === readyStates.RECONNECT_ABORTED) {
        reject(new Error('Could not send: Socket closed'));
      } else {
        self.sendQueue = self.sendQueue.push({ message, resolve });
        self.fireQueue();
      }
    });
  }

  close() {
    this.terminate();
    this.manualClose = true;
    return this;
  }

  terminate() {
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer);
      this.reconnectTimer = undefined;
    }
    this.socket.close();
  }

  reconnect() {
    this.terminate();
    const backoffDelay = this.getBackoffDelay(++this.reconnectAttempts);
    const backoffDelaySeconds = backoffDelay / 1000;
    console.log(`Reconnecting in ${backoffDelaySeconds} seconds`);
    this.reconnectTimer = setTimeout(this.connect, backoffDelay);
    return this;
  }

  // ==============================================================================================

  fireQueue() {
    while (this.sendQueue.size && this.socket.readyState === readyStates.OPEN) {
      const data = this.sendQueue.first();
      this.sendQueue = this.sendQueue.shift();
      this.socket.send(data.message);
      data.resolve();
    }
    return this;
  }

  // ==============================================================================================
  //  PRIVATE

  onOpenHandler = (event) => {
    this.reconnectAttempts = 0;
    this.manualClose = false;
    this.onOpenCallbacks.forEach(cb => cb(event));
    this.fireQueue();
  }

  onCloseHandler = (event) => {
    this.onCloseCallbacks.forEach(cb => cb(event));
    const notNormalReconnect = this.reconnectIfNotNormalClose && !this.manualClose;
    if (notNormalReconnect && event.code === reconnectableStatus) {
      this.reconnect();
    }
  }

  onErrorHandler = (event) => {
    this.onErrorCallbacks.forEach(cb => cb(event));
  }

  onMessageHandler = (message) => {
    this.onMessageCallbacks.forEach(cb => cb(message));
  }

  getBackoffDelay(attempt) {
    // Exponential Backoff Formula by Prof. Douglas Thain
    // http://dthain.blogspot.co.uk/2009/02/exponential-backoff-in-distributed.html
    return Math.floor(Math.min(
      (Math.random() + 1) * this.timeoutStart * Math.pow(2, attempt),
      this.timeoutMax
    ));
  }
}
<|endoftext|>