<commit_before>import React from 'react'
import './HomeView.scss'

import { Link } from 'react-router';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'
import { BootstrapTable, TableHeaderColumn } from 'react-bootstrap-table';
import { ControlLabel, FormControl, HelpBlock, FormGroup, Checkbox,Radio, Button, Tabs, Tab } from 'react-bootstrap';
import PropTypes from 'prop-types'
import { getInitData, addPlacement, removePlacement,addPublisher,removePublisher} from '../../../redux/modules/placements'
import { handleArticleSubmit } from 'modules/placements'
import { Provider } from 'react-redux'

const statusType = {
  0: 'matching',
  1: 'publisher-submitted',
  2: 'publisher-rejected'
}

class SelectedPlacements extends React.Component {
  constructor(props){
    super(props);
  }
    static defaultProps = {
        selected_placements: []
  }
  render() {
    var i = 1;
    if ( this.props.placements.placements) {
        let list = this.props.selected_placements.map( (placement) => {
          return
{placement.company_name}
;
          }
        )
        return
{list}
;
      }
    return

    }
}

class PlacementTable extends React.Component {
  constructor(props) {
    super(props);
    this.selectRowProp = {
      mode: 'checkbox',
      clickToSelect: true,
      bgColor: 'lightblue',
      onSelect: this.onRowSelect.bind(this),
    }
  }
  isExpandableRow (row) {
    return true
    if (row.id < 3) return true;
    else return false;
  }
  expandComponent (row) {
    return (

    )
  }
  onRowSelect(row, isSelected, e) {
    if ( isSelected ) {
      this.props.add_placement(row)
    }
    else {
      this.props.remove_placement(row)
    }
  }
  render() {
    const options = {
      expandRowBgColor: 'rgb(242, 255, 163)',
      expandBy: 'column',  // Currently, available value is row andcolumn, default is row
    }
    if (this.props.data) {
      const data = this.props.data
      data.forEach((column, i) => {
              column["id"] = i
      }, this);

      return (

            <BootstrapTable
              data = { data || [] }
              options={ options }
              selectRow={ this.selectRowProp }>
              <TableHeaderColumn dataField='id' isKey={ true }hidden>ID</TableHeaderColumn>
              <TableHeaderColumn dataField='company_name' dataSort={ true } filter={ { type: 'TextFilter', delay: 10 } } expandable={ false }>Company Name</TableHeaderColumn>
              <TableHeaderColumn dataField='target_da_range' dataSort={ true } filter={ { type: 'TextFilter', delay: 10 } } expandable={ false }>DA Range</TableHeaderColumn>
              <TableHeaderColumn dataField='status' dataSort={ true } filterFormatted expandable={ false }>Status</TableHeaderColumn>
              <TableHeaderColumn dataField='count' dataSort={ true }>Count</TableHeaderColumn>
            </BootstrapTable>

      )
    }
    else
      return (

)
  }
}

class ContributorTable extends React.Component {
  constructor(props) {
    super(props);
    this.selectRowProp = {
      mode: 'checkbox',
      clickToSelect: true,
      bgColor: 'lightblue',
      onSelect: this.onRowSelect.bind(this),
    }
  }
  isExpandableRow(row) {
    if (row.id < 3) return true;
    else return false;
  }
  expandComponent(row) {
    return (

    );
  }
  onRowSelect(row, isSelected, e) {
    if ( isSelected ) {
      this.props.add_publisher(row)
    }
    else {
      this.props.remove_publisher(row)
    }
  }
  render() {
    const options = {
      expandRowBgColor: 'rgb(242, 255, 163)',
      expandBy: 'column',  // Currently, available value is row and column, default is row
    }
    const data = this.props.data
    return (

          <BootstrapTable data={Boolean(data) ? data : []}
            options={ options }
            expandableRow={ this.isExpandableRow }
            expandComponent={ this.expandComponent }
            selectRow={ this.selectRowProp }>
            <TableHeaderColumn dataField='id' isKey={ true } hidden>ID</TableHeaderColumn>
            <TableHeaderColumn dataField='name' dataSort={ false } filter={ { type: 'TextFilter', delay: 10 } } expandable={ false }>Publisher</TableHeaderColumn>
            <TableHeaderColumn dataField='url' dataSort={ false } filter={ { type: 'TextFilter', delay: 10 } } expandable={ false }>URL</TableHeaderColumn>
            <TableHeaderColumn dataField='moz_da' dataSort={ true } filter={ { type: 'TextFilter', delay: 10 } } expandable={ false }>DA</TableHeaderColumn>
            <TableHeaderColumn dataField='status' dataSort={ true } filter={ { type: 'TextFilter', delay: 10 } } expandable={ false }>Status</TableHeaderColumn>
          </BootstrapTable>

)
  }
}

function FieldGroup({ id, label, help, ...props }) {
  return (
    <FormGroup controlId={id}>
      <ControlLabel>{label}</ControlLabel>
      <FormControl {...props} />
      {help && <HelpBlock>{help}</HelpBlock>}
    </FormGroup>
  )
}

class NavDropdown extends React.Component {
  constructor(props) {
    super(props)
  }
  handleSelect(eventKey) {
    event.preventDefault();
    alert(`selected ${eventKey}`);
  }
  render() {
    return (
      <Tabs defaultActiveKey={2} id="uncontrolled-tab-example">
            <Tab eventKey={1} title="Placements">
                <PlacementTable
                  data={this.props.data.placements}
                  add_placement={this.props.data.add_placement}
                  remove_placement={this.props.data.remove_placement}/>
            </Tab>
            <Tab eventKey={2} title="Publishers">
                <ContributorTable
                  data={this.props.data.contributors}
                  add_publisher={this.props.data.add_publisher}
                  remove_publisher={this.props.data.remove_publisher}/>
            </Tab>
      </Tabs>
    )
  }
}

class HomeView extends React.Component {
    constructor(props){
      super(props)
      props.fillStore()
    }

    static propTypes = {
        statusText: PropTypes.string,
        userName: PropTypes.string,
    }

    static defaultProps = {
        statusText: '',
        userName: ''
    }

    handleClick(event) {
        event.preventDefault()
        const articleText = this.articleTitleElement.value
        const articleDescriptionText = this.articleDescriptionElement.value
        this.props.onSubmitClick({ articleTitle:articleText, articleDescription:articleDescriptionText })
    }

    render() {
        return (

                    {this.props.statusText ?

                            {this.props.statusText}

:null }

                <form>
                    <FieldGroup
                      id="article_title"
                      type="text"
                      label="Article Title"
                      placeholder="Enter article title"
                      inputRef={(input) => {this.articleTitleElement = input}} />
                    <FormGroup controlId="formControlsTextarea">
                      <ControlLabel>Article Description</ControlLabel>
                      <FormControl inputRef={(input) => {this.articleDescriptionElement = input}}
                         componentClass="textarea"
                         placeholder="Enter article description" />
                    </FormGroup>
                    <Button type="submit" onClick={this.handleClick.bind(this)} className='btn btn-success'>Submit</Button>
                </form>
                <NavDropdown data={ this.props }/>

            );
    }
}

const mapStateToProps = (state) => {
  return {
    contributors: state.data.contributordata,
    placements: state.data.placements
  }
}

const mapDispatchPlacementStateToProps = (dispatch) => {
    return bindActionCreators({
        fillStore: getInitData,
        add_placement: addPlacement,
        remove_placement: removePlacement,
        add_publisher:addPublisher,
        remove_publisher: removePublisher,
        onSubmitClick: (article) => handleArticleSubmit(article)
    },dispatch)
}

export default connect(mapStateToProps,mapDispatchPlacementStateToProps)(HomeView)
<commit_msg>added loading data from backend on page load<commit_after>import React from 'react'
import './HomeView.scss'

import { Link } from 'react-router';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'
import { BootstrapTable, TableHeaderColumn } from 'react-bootstrap-table';
import { ControlLabel, FormControl, HelpBlock, FormGroup, Checkbox,Radio, Button, Tabs, Tab } from 'react-bootstrap';
import PropTypes from 'prop-types'
import { getInitData, addPlacement, removePlacement,addPublisher,removePublisher} from 'modules/placements'
import { handleArticleSubmit } from 'modules/placements'
import { Provider } from 'react-redux'

const statusType = {
  0: 'matching',
  1: 'publisher-submitted',
  2: 'publisher-rejected'
}

class SelectedPlacements extends React.Component {
  constructor(props){
    super(props);
  }
    static defaultProps = {
        selected_placements: []
  }
  render() {
    var i = 1;
    if ( this.props.placements.placements) {
        let list = this.props.selected_placements.map( (placement) => {
          return
{placement.company_name}
;
          }
        )
        return
{list}
;
      }
    return

    }
}

class PlacementTable extends React.Component {
  constructor(props) {
    super(props);
    this.selectRowProp = {
      mode: 'checkbox',
      clickToSelect: true,
      bgColor: 'lightblue',
      onSelect: this.onRowSelect.bind(this),
    }
  }
  isExpandableRow (row) {
    return true
    if (row.id < 3) return true;
    else return false;
  }
  expandComponent (row) {
    return (

    )
  }
  onRowSelect(row, isSelected, e) {
    if ( isSelected ) {
      this.props.add_placement(row)
    }
    else {
      this.props.remove_placement(row)
    }
  }
  render() {
    const options = {
      expandRowBgColor: 'rgb(242, 255, 163)',
      expandBy: 'column',  // Currently, available value is row andcolumn, default is row
    }
    if (this.props.data) {
      //TODO remove this id and add in data
      const data = this.props.data
      data.forEach((column, i) => {
              column["id"] = i
      }, this);
      this.selectRowProp.selected = this.props.selected ? this.props.selected.placements : []
      if (this.props.selected)
        this.selectRowProp.selected.map(i => {
          this.onRowSelect({id:i},true)
          return i
        })

      return (

            <BootstrapTable
              data = { data || [] }
              options={ options }
              selectRow={ this.selectRowProp }>
              <TableHeaderColumn dataField='id' isKey={ true }hidden>ID</TableHeaderColumn>
              <TableHeaderColumn dataField='company_name' dataSort={ true } filter={ { type: 'TextFilter', delay: 10 } } expandable={ false }>Company Name</TableHeaderColumn>
              <TableHeaderColumn dataField='target_da_range' dataSort={ true } filter={ { type: 'TextFilter', delay: 10 } } expandable={ false }>DA Range</TableHeaderColumn>
              <TableHeaderColumn dataField='status' dataSort={ true } filterFormatted expandable={ false }>Status</TableHeaderColumn>
              <TableHeaderColumn dataField='count' dataSort={ true }>Count</TableHeaderColumn>
            </BootstrapTable>

      )
    }
    else
      return (

)
  }
}

class ContributorTable extends React.Component {
  constructor(props) {
    super(props);
    this.selectRowProp = {
      mode: 'checkbox',
      clickToSelect: true,
      bgColor: 'lightblue',
      onSelect: this.onRowSelect.bind(this),
    }
  }
  isExpandableRow(row) {
    if (row.id < 3) return true;
    else return false;
  }
  expandComponent(row) {
    return (

    );
  }
  onRowSelect(row, isSelected, e) {
    if ( isSelected ) {
      this.props.add_publisher(row)
    }
    else {
      this.props.remove_publisher(row)
    }
  }
  render() {
    const options = {
      expandRowBgColor: 'rgb(242, 255, 163)',
      expandBy: 'column',  // Currently, available value is row and column, default is row
    }
    const data = this.props.data
    this.selectRowProp.selected = this.props.selected ? this.props.selected.contributors : []
    if (this.props.selected)
      this.selectRowProp.selected.map(i => {
        this.onRowSelect({id:i},true)
        return i
      })
    return (

          <BootstrapTable data={Boolean(data) ? data : []}
            options={ options }
            expandableRow={ this.isExpandableRow }
            expandComponent={ this.expandComponent }
            selectRow={ this.selectRowProp }>
            <TableHeaderColumn dataField='id' isKey={ true } hidden>ID</TableHeaderColumn>
            <TableHeaderColumn dataField='name' dataSort={ false } filter={ { type: 'TextFilter', delay: 10 } } expandable={ false }>Publisher</TableHeaderColumn>
            <TableHeaderColumn dataField='url' dataSort={ false } filter={ { type: 'TextFilter', delay: 10 } } expandable={ false }>URL</TableHeaderColumn>
            <TableHeaderColumn dataField='moz_da' dataSort={ true } filter={ { type: 'TextFilter', delay: 10 } } expandable={ false }>DA</TableHeaderColumn>
            <TableHeaderColumn dataField='status' dataSort={ true } filter={ { type: 'TextFilter', delay: 10 } } expandable={ false }>Status</TableHeaderColumn>
          </BootstrapTable>

)
  }
}

function FieldGroup({ id, label, help, ...props }) {
  return (
    <FormGroup controlId={id}>
      <ControlLabel>{label}</ControlLabel>
      <FormControl {...props} />
      {help && <HelpBlock>{help}</HelpBlock>}
    </FormGroup>
  )
}

class NavDropdown extends React.Component {
  constructor(props) {
    super(props)
  }
  handleSelect(eventKey) {
    event.preventDefault();
    alert(`selected ${eventKey}`);
  }
  render() {
    return (
      <Tabs defaultActiveKey={2} id="uncontrolled-tab-example">
            <Tab eventKey={1} title="Placements">
                <PlacementTable
                  data={this.props.data.placements}
                  selected={this.props.load}
                  add_placement={this.props.data.add_placement}
                  remove_placement={this.props.data.remove_placement}/>
            </Tab>
            <Tab eventKey={2} title="Publishers">
                <ContributorTable
                  selected={this.props.load}
                  data={this.props.data.contributors}
                  add_publisher={this.props.data.add_publisher}
                  remove_publisher={this.props.data.remove_publisher}/>
            </Tab>
      </Tabs>
    )
  }
}

class HomeView extends React.Component {
    constructor(props){
      super(props)
      props.fillStore()
    }

    static propTypes = {
        statusText: PropTypes.string,
        userName: PropTypes.string,
    }

    static defaultProps = {
        statusText: '',
        userName: ''
    }
    handleClick(event) {
        event.preventDefault()
        const articleText = this.articleTitleElement.value
        const articleDescriptionText = this.articleDescriptionElement.value
        this.props.onSubmitClick({ articleTitle:articleText, articleDescription:articleDescriptionText })
    }

    render() {
        return (

                    {this.props.statusText ?

                            {this.props.statusText}

:null }

                <form>
                    <FieldGroup
                      id="article_title"
                      type="text"
                      label="Article Title"
                      placeholder="Enter article title"
                      inputRef={(input) => {this.articleTitleElement = input; input && this.props.load ? input.value=this.props.load.data.title : null}} />
                    <FormGroup controlId="formControlsTextarea">
                      <ControlLabel>Article Description</ControlLabel>
                      <FormControl inputRef={(input) => {this.articleDescriptionElement = input; input && this.props.load ? input.value=this.props.load.data.description : null}}
                         componentClass="textarea"
                         placeholder="Enter article description" />
                    </FormGroup>
                    <Button type="submit" onClick={this.handleClick.bind(this)} className='btn btn-success'>Submit</Button>
                </form>
                <NavDropdown data={ this.props }  {...this.props} />

            );
    }
}

const mapStateToProps = (state) => {
  return {
    contributors: state.data.contributordata,
    placements: state.data.placements,
    load:state.data.load
  }
}

const mapDispatchPlacementStateToProps = (dispatch) => {
    return bindActionCreators({
        fillStore: getInitData,
        add_placement: addPlacement,
        remove_placement: removePlacement,
        add_publisher:addPublisher,
        remove_publisher: removePublisher,
        onSubmitClick: (article) => handleArticleSubmit(article)
    },dispatch)
}

export default connect(mapStateToProps,mapDispatchPlacementStateToProps)(HomeView)
<|endoftext|>


<commit_before>/*global Phaser, socket, console*/

var game, socket, userroom, pieces, pieceWidth, pieceHeight, myPieces, selected;

function createRectangle(objectString) {
	'use strict';
	var sprite, object;
	object = JSON.parse(objectString);
	sprite = game.add.sprite(object.piece.x, object.piece.y, 'pieces');
	sprite.anchor.setTo(0.5, 0.5);
	sprite.angle = object.piece.angle;
	sprite.frame = object.piece.frame;
	pieces.next = object.next;
	pieces[object.array].push(object.piece);
}

function setPiece(x, y, angle) {
	'use strict';
	selected.piece.x = x;
	selected.piece.y = y;
	selected.piece.angle = angle;
	return selected.piece;
}

function isMovePossible(piece, array) {
	'use strict';
	var last = pieces[array].length - 1;
	if (piece.side1 === pieces[array][last][pieces[array][last].freeSide] || piece.side2 === pieces[array][last][pieces[array][last].freeSide]) {
		return true;
	}
	return false;
}

function rotatePiece(piece, array) {
	'use strict';
	var last;
	last = pieces[array].length - 1;
	if (piece.side1 === pieces[array][last].side1 || piece.side2 === pieces[array][last].side2) {
		piece.angle = pieces[array][last].angle + 180;
		piece.freeSide = piece.side1 === pieces[array][last].side1 ? 'side2' : 'side 1';
	} else if (piece.side1 === pieces[array][last].side2 || piece.side2 === pieces[array][last].side1) {
		piece.angle = pieces[array][last].angle;
		piece.freeSide = piece.side1 === pieces[array][last].side2 ? 'side2' : 'side 1';
	}
	if (piece.side1 === piece.side2 && (piece.side1 === pieces[array][last].side1 || piece.side1 === pieces[array][last].side2)) {
		piece.angle = pieces[array][last].angle + 90;
	} else if (pieces[array][last].side1 === pieces[array][last].side2 && (pieces[array][last].side1 === piece.side1 || pieces[array][last].side1 === piece.side2)) {
		if (piece.side1 === pieces[array][last - 1].side1 || piece.side2 === pieces[array][last - 1].side2) {
			piece.angle = pieces[array][last].angle + 180;
		} else if (piece.side1 === pieces[array][last - 1].side2 || piece.side2 === pieces[array][last - 1].side1) {
			piece.angle = pieces[array][last].angle;
		}
	}
}

function playPiece2(object) {
	'use strict';
	if (Phaser.Point.distance(object, pieces.next.top) > Phaser.Point.distance(object, pieces.next.bottom)) {
		object.piece = setPiece(pieces.next.bottom.x, pieces.next.bottom.y, pieces.next.bottom.angle);
		object.array = 'bottom';
		if (!isMovePossible(object.piece, object.array)) {
			return false;
		}
		pieces.next.bottom.y += pieceHeight;
	} else {
		object.piece = setPiece(pieces.next.top.x, pieces.next.top.y, pieces.next.top.angle);
		object.array = 'top';
		if (!isMovePossible(object.piece, object.array)) {
			return false;
		}
		pieces.next.top.y -= pieceHeight;
	}
	rotatePiece(object.piece, object.array);
	object.next = pieces.next;
	return object;
}

function playPiece4(object) {
	'use strict';
	var dTop, dBottom, dLeft, dRight;
	dTop = Phaser.Point.distance(object, pieces.next.top);
	dBottom = Phaser.Point.distance(object, pieces.next.bottom);
	dLeft = Phaser.Point.distance(object, pieces.next.left);
	dRight = Phaser.Point.distance(object, pieces.next.right);
	if (dTop <= dBottom && dTop <= dLeft && dTop <= dRight) {
		object.piece = setPiece(pieces.next.top.x, pieces.next.top.y, pieces.next.top.angle);
		object.array = 'top';
		if (!isMovePossible(object.piece, object.array)) {
			return false;
		}
		pieces.next.top.y -= pieceHeight;
	} else if ((dBottom <= dTop && dBottom <= dLeft && dBottom <= dRight)) {
		object.piece = setPiece(pieces.next.bottom.x, pieces.next.bottom.y, pieces.next.bottom.angle);
		object.array = 'bottom';
		if (!isMovePossible(object.piece, object.array)) {
			return false;
		}
		pieces.next.bottom.y += pieceHeight;
	} else if ((dRight <= dTop && dRight <= dLeft && dRight <= dBottom)) {
		object.piece = setPiece(pieces.next.right.x, pieces.next.right.y, pieces.next.right.angle);
		object.array = 'right';
		if (!isMovePossible(object.piece, object.array)) {
			return false;
		}
		pieces.next.right.x += pieceHeight;
	} else {
		object.piece = setPiece(pieces.next.left.x, pieces.next.left.y, pieces.next.left.angle);
		object.array = 'left';
		if (!isMovePossible(object.piece, object.array)) {
			return false;
		}
		pieces.next.left.x -= pieceHeight;
	}
	rotatePiece(object.piece, object.array);
	object.next = pieces.next;
	return object;
}

function onClick() {
	'use strict';
	if (!selected.enabled) {
		return;
	}
	selected.enabled = false;
	var object = {
		x: game.input.position.x,
		y: game.input.position.y,
		room: userroom
	};
	if (pieces.top.length <= 1 || pieces.bottom.length <= 1) {
		object = playPiece2(object);
	} else {
		object = playPiece4(object);
	}
	if (!object) {
		console.log('move refused');
		return;
	}
	socket.emit('user clicked!', JSON.stringify(object));
}

function playSixSix() {
	'use strict';
	var sprite;
	sprite = game.add.sprite(game.world.centerX, game.world.centerY, 'pieces');
	sprite.frame = 0;
	sprite.anchor.setTo(0.5, 0.5);
	sprite.angle = 90;
}

function indexOfFrame(frame) {
	'use strict';
	var i;
	for (i = 0; i < myPieces.length; i = i + 1) {
		if (myPieces[i].frame === frame) {
			return i;
		}
	}
	return null;
}

function select(sprite, e) {
	'use strict';
	selected.piece = myPieces[indexOfFrame(sprite.frame)];
	selected.sprite = sprite;
	selected.enabled = true;
}

function showMyPieces() {
	'use strict';
	var i, x, y, sprite;
	x = game.world.centerX - 3 * pieceWidth;
	y = game.height - pieceHeight / 2;
	for (i = 0; i < myPieces.length; i = i + 1) {
		if (myPieces[i].side1 !== 6 || myPieces[i].side2  !== 6) {
			sprite = game.add.sprite(x, y, 'pieces');
			sprite.frame = myPieces[i].frame;
			sprite.anchor.setTo(0.5, 0.5);
			x = x + pieceWidth;
			sprite.inputEnabled = true;
			sprite.events.onInputDown.add(select);
		}
	}
}

function preload() {
	'use strict';
	game.load.image('rectangle', 'assets/images/rectangle.png');
	game.load.spritesheet('pieces', 'assets/spritesheets/domino.png', 30, 60);
}

function create() {
	'use strict';
    showMyPieces();
	playSixSix();
	game.stage.backgroundColor = "#ffffff";
	game.input.onDown.add(onClick);
	pieces = {
		top: [],
		bottom: [],
		left: [],
		right: [],
		next: {
			top: {x: game.world.centerX, y: game.world.centerY - (pieceHeight / 2 + pieceWidth / 2), angle: 0},
			bottom: {x: game.world.centerX, y: game.world.centerY + (pieceHeight / 2 + pieceWidth / 2), angle: 0},
			left: {x: game.world.centerX - pieceHeight, y: game.world.centerY, angle: 90},
			right: {x: game.world.centerX + pieceHeight, y: game.world.centerY, angle: 90}
		}
	};
	pieces.top.push({side1: 6, side2: 7, angle: 0, freeSide: 'side1'});
	pieces.bottom.push({side1: 6, side2: 7, angle: 180, freeSide: 'side1'});
	pieces.left.push({side1: 6, side2: 7, angle: 270, freeSide: 'side1'});
	pieces.right.push({side1: 6, side2: 7, angle: 90, freeSide: 'side1'});
}

function update() {
	'use strict';
	game.scale.setExactFit();
	game.scale.refresh();
}

function start(dataString) {
	'use strict';
	var data = JSON.parse(dataString);
	userroom = data.room;
	myPieces = data.pieces;
	pieceHeight = 60;
	pieceWidth = 30;
	game = new Phaser.Game(960, 600, Phaser.AUTO, 'game', {preload: preload, create: create, update: update});
}

selected = {};
socket.on('create rectangle', createRectangle);
socket.on('start game', start);<commit_msg>[Phaser][Multiplayer] Trajetória das peças melhorada<commit_after>/*global Phaser, socket, console*/

var game, socket, userroom, pieces, pieceWidth, pieceHeight, myPieces, selected;

function countCarroca(array, branch) {
	'use strict';
	var i, counter = 0, size = pieces[array].length;
	for (i = 0; i < size; i = i + 1) {
		if (pieces[array][i].side1 === pieces[array][i].side2 && pieces[array][i].branch === branch) {
			counter = counter + 1;
		}
	}
	return counter;
}

function calculateRotationMoment(array) {
	'use strict';
	if (pieces.grow[array] === 'top' && countCarroca(array, pieces.branch[array]) === 2) {
		pieces.numberRotate[array][0] = pieces.numberRotate[array][0] + 1;
	} else if (pieces.grow[array] === 'right' && countCarroca(array, pieces.branch[array]) === 1) {
		pieces.numberRotate[array][0] = pieces.numberRotate[array][0] + 1;
	} else if (pieces.grow[array] === 'left' && countCarroca(array, pieces.branch[array]) === 1) {
		pieces.numberRotate[array][0] = pieces.numberRotate[array][0] + 1;
	} else if (pieces.grow[array] === 'bottom' && countCarroca(array, pieces.branch[array]) === 2) {
		pieces.numberRotate[array][0] = pieces.numberRotate[array][0] + 1;
	}
}

function rotateNextPosition() {
	'use strict';
	var i, arrays;
	arrays = ['top', 'right', 'bottom', 'left'];
	for (i = 0; i < 4; i = i + 1) {
		if (pieces.numberRotate[arrays[i]].length > 0 && pieces[arrays[i]].length === pieces.numberRotate[arrays[i]][0]) {
			pieces.numberRotate[arrays[i]][1] += pieces.numberRotate[arrays[i]][0];
			pieces.numberRotate[arrays[i]].shift();
			pieces.angle[arrays[i]] = pieces.angle[arrays[i]] + 90;
			if (pieces.grow[arrays[i]] === 'left') {
				pieces.next[arrays[i]].x = pieces.next[arrays[i]].x + pieceHeight / 2 + pieceWidth / 2;
				pieces.next[arrays[i]].y = pieces.next[arrays[i]].y - pieceWidth / 2 - pieceHeight / 2;
				if (pieces[arrays[i]][pieces[arrays[i]].length - 1].side1 === pieces[arrays[i]][pieces[arrays[i]].length - 1].side2) {
					pieces.next[arrays[i]].y = pieces.next[arrays[i]].y - pieceHeight / 4;
				}
			} else if (pieces.grow[arrays[i]] === 'top') {
				pieces.next[arrays[i]].x = pieces.next[arrays[i]].x + pieceHeight / 2 + pieceWidth / 2;
				pieces.next[arrays[i]].y = pieces.next[arrays[i]].y + pieceWidth / 2 + pieceHeight / 2;
				if (pieces[arrays[i]][pieces[arrays[i]].length - 1].side1 === pieces[arrays[i]][pieces[arrays[i]].length - 1].side2) {
					pieces.next[arrays[i]].x = pieces.next[arrays[i]].x + pieceHeight / 4;
				}
			} else if (pieces.grow[arrays[i]] === 'right') {
				pieces.next[arrays[i]].x = pieces.next[arrays[i]].x - pieceHeight / 2 - pieceWidth / 2;
				pieces.next[arrays[i]].y = pieces.next[arrays[i]].y + pieceWidth / 2 + pieceHeight / 2;
				if (pieces[arrays[i]][pieces[arrays[i]].length - 1].side1 === pieces[arrays[i]][pieces[arrays[i]].length - 1].side2) {
					pieces.next[arrays[i]].y = pieces.next[arrays[i]].y + pieceHeight / 4;
				}
			} else {
				pieces.next[arrays[i]].x = pieces.next[arrays[i]].x - pieceHeight / 2 - pieceWidth / 2;
				pieces.next[arrays[i]].y = pieces.next[arrays[i]].y - pieceWidth / 2 - pieceHeight / 2;
				if (pieces[arrays[i]][pieces[arrays[i]].length - 1].side1 === pieces[arrays[i]][pieces[arrays[i]].length - 1].side2) {
					pieces.next[arrays[i]].x = pieces.next[arrays[i]].x - pieceHeight / 4;
				}
			}
			pieces.grow[arrays[i]] = arrays[(arrays.indexOf(pieces.grow[arrays[i]]) + 1) % arrays.length];
			pieces.branch[arrays[i]] = pieces.branch[arrays[i]] + 1;
		}
	}
}

function createRectangle(objectString) {
	'use strict';
	var sprite, object;
	object = JSON.parse(objectString);
	sprite = game.add.sprite(object.piece.x, object.piece.y, 'pieces');
	sprite.anchor.setTo(0.5, 0.5);
	sprite.angle = object.piece.angle;
	sprite.frame = object.piece.frame;
	pieces.next = object.next;
	pieces.angle = object.angle;
	pieces[object.array].push(object.piece);
	if (object.piece.side1 === object.piece.side2) {
		calculateRotationMoment(object.array);
	}
	rotateNextPosition();
}

function setPiece(x, y, angle) {
	'use strict';
	selected.piece.x = x;
	selected.piece.y = y;
	selected.piece.angle = angle;
	return selected.piece;
}

function isMovePossible(piece, array) {
	'use strict';
	var last = pieces[array].length - 1;
	if (piece.side1 === pieces[array][last][pieces[array][last].freeSide] || piece.side2 === pieces[array][last][pieces[array][last].freeSide]) {
		return true;
	}
	return false;
}

function rotatePiece(piece, array) {
	'use strict';
	var index;
	index = pieces[array].length - 1;
	if (pieces[array][index].side1 === pieces[array][index].side2) {
		index = index - 1;
	}
	if (piece.side1 === piece.side2 && (piece.side1 === pieces[array][index].side1 || piece.side1 === pieces[array][index].side2)) {
		piece.angle = pieces.angle[array] + 90;
		piece.freeSide = 'side1';
		return;
	}
	if (piece.side1 === pieces[array][index].side1 || piece.side2 === pieces[array][index].side2) {
		piece.angle = pieces.angle[array] + 180;
		pieces.angle[array] = piece.angle;
		piece.freeSide = piece.side1 === pieces[array][index].side1 ? 'side2' : 'side1';
	} else if (piece.side1 === pieces[array][index].side2 || piece.side2 === pieces[array][index].side1) {
		piece.angle = pieces.angle[array];
		pieces.angle[array] = piece.angle;
		piece.freeSide = piece.side1 === pieces[array][index].side2 ? 'side2' : 'side1';
	}
}

function calculateNextPosition(array, piece) {
	'use strict';
	if (pieces.grow[array] === 'left') {
		if (piece.side1 === piece.side2) {
			pieces.next[array].x = pieces.next[array].x - pieceWidth;
			piece.x = piece.x + pieceHeight / 2 - pieceWidth / 2;
		} else {
			pieces.next[array].x -= pieceHeight;
		}
	} else if (pieces.grow[array] === 'top') {
		if (piece.side1 === piece.side2) {
			pieces.next[array].y = pieces.next[array].y - pieceWidth;
			piece.y = piece.y + pieceHeight / 2 - pieceWidth / 2;
		} else {
			pieces.next[array].y -= pieceHeight;
		}
	} else if (pieces.grow[array] === 'right') {
		if (piece.side1 === piece.side2) {
			pieces.next[array].x = pieces.next[array].x + pieceWidth;
			piece.x = piece.x - pieceHeight / 2 + pieceWidth / 2;
		} else {
			pieces.next[array].x += pieceHeight;
		}
	} else {
		if (piece.side1 === piece.side2) {
			pieces.next[array].y = pieces.next[array].y + pieceWidth;
			piece.y = piece.y - pieceHeight / 2 + pieceWidth / 2;
		} else {
			pieces.next[array].y += pieceHeight;
		}
	}
}

function playPiece2(object) {
	'use strict';
	if (Phaser.Point.distance(object, pieces.next.top) > Phaser.Point.distance(object, pieces.next.bottom)) {
		object.piece = setPiece(pieces.next.bottom.x, pieces.next.bottom.y, pieces.next.bottom.angle);
		object.array = 'bottom';
		if (!isMovePossible(object.piece, object.array)) {
			return false;
		}
	} else {
		object.piece = setPiece(pieces.next.top.x, pieces.next.top.y, pieces.next.top.angle);
		object.array = 'top';
		if (!isMovePossible(object.piece, object.array)) {
			return false;
		}
	}
	calculateNextPosition(object.array, object.piece);
	rotatePiece(object.piece, object.array);
	object.next = pieces.next;
	return object;
}

function playPiece4(object) {
	'use strict';
	var dTop, dBottom, dLeft, dRight;
	dTop = Phaser.Point.distance(object, pieces.next.top);
	dBottom = Phaser.Point.distance(object, pieces.next.bottom);
	dLeft = Phaser.Point.distance(object, pieces.next.left);
	dRight = Phaser.Point.distance(object, pieces.next.right);
	if (dTop <= dBottom && dTop <= dLeft && dTop <= dRight) {
		object.piece = setPiece(pieces.next.top.x, pieces.next.top.y, pieces.next.top.angle);
		object.array = 'top';
		if (!isMovePossible(object.piece, object.array)) {
			return false;
		}
	} else if ((dBottom <= dTop && dBottom <= dLeft && dBottom <= dRight)) {
		object.piece = setPiece(pieces.next.bottom.x, pieces.next.bottom.y, pieces.next.bottom.angle);
		object.array = 'bottom';
		if (!isMovePossible(object.piece, object.array)) {
			return false;
		}
	} else if ((dRight <= dTop && dRight <= dLeft && dRight <= dBottom)) {
		object.piece = setPiece(pieces.next.right.x, pieces.next.right.y, pieces.next.right.angle);
		object.array = 'right';
		if (!isMovePossible(object.piece, object.array)) {
			return false;
		}
	} else {
		object.piece = setPiece(pieces.next.left.x, pieces.next.left.y, pieces.next.left.angle);
		object.array = 'left';
		if (!isMovePossible(object.piece, object.array)) {
			return false;
		}
	}
	calculateNextPosition(object.array, object.piece);
	rotatePiece(object.piece, object.array);
	object.next = pieces.next;
	return object;
}

function onClick() {
	'use strict';
	if (!selected.enabled) {
		return;
	}
	selected.enabled = false;
	var object = {
		x: game.input.position.x,
		y: game.input.position.y,
		room: userroom
	};
	if (pieces.top.length <= 1 || pieces.bottom.length <= 1) {
		object = playPiece2(object);
	} else {
		object = playPiece4(object);
	}
	if (!object) {
		console.log('move refused');
		return;
	}
	object.piece.branch = pieces.branch[object.array];
	object.angle = pieces.angle;
	socket.emit('user clicked!', JSON.stringify(object));
}

function playSixSix() {
	'use strict';
	var sprite;
	sprite = game.add.sprite(game.world.centerX, game.world.centerY, 'pieces');
	sprite.frame = 0;
	sprite.anchor.setTo(0.5, 0.5);
	sprite.angle = 90;
}

function indexOfFrame(frame) {
	'use strict';
	var i;
	for (i = 0; i < myPieces.length; i = i + 1) {
		if (myPieces[i].frame === frame) {
			return i;
		}
	}
	return null;
}

function select(sprite, e) {
	'use strict';
	selected.piece = myPieces[indexOfFrame(sprite.frame)];
	selected.sprite = sprite;
	selected.enabled = true;
}

function showMyPieces() {
	'use strict';
	var i, x, y, sprite;
	x = game.world.centerX - 3 * pieceWidth;
	y = game.height - pieceHeight / 2;
	for (i = 0; i < myPieces.length; i = i + 1) {
		if (myPieces[i].side1 !== 6 || myPieces[i].side2  !== 6) {
			sprite = game.add.sprite(x, y, 'pieces');
			sprite.frame = myPieces[i].frame;
			sprite.anchor.setTo(0.5, 0.5);
			x = x + pieceWidth;
			sprite.inputEnabled = true;
			sprite.events.onInputDown.add(select);
		}
	}
}

function preload() {
	'use strict';
	game.load.image('rectangle', 'assets/images/rectangle.png');
	game.load.spritesheet('pieces', 'assets/spritesheets/domino.png', 30, 60);
}

function create() {
	'use strict';
    showMyPieces();
	playSixSix();
	game.stage.backgroundColor = "#ffffff";
	game.input.onDown.add(onClick);
	pieces = {
		top: [],
		bottom: [],
		left: [],
		right: [],
		next: {
			top: {x: game.world.centerX, y: game.world.centerY - (pieceHeight / 2 + pieceWidth / 2), angle: 0},
			bottom: {x: game.world.centerX, y: game.world.centerY + (pieceHeight / 2 + pieceWidth / 2), angle: 0},
			left: {x: game.world.centerX - pieceHeight, y: game.world.centerY, angle: 90},
			right: {x: game.world.centerX + pieceHeight, y: game.world.centerY, angle: 90}
		},
		grow: {
			top: 'top',
			bottom: 'bottom',
			left: 'left',
			right: 'right'
		},
		angle: {
			top: 0,
			bottom: 180,
			left: 270,
			right: 90
		},
		numberRotate: {
			top: [5, 6, 3, 5, 2, 3, 1],
			bottom: [5, 6, 3, 5, 2, 3, 1],
			left:  [7, 4, 4, 4, 3, 2, 2],
			right:  [7, 4, 4, 4, 3, 2, 2]
		},
		branch: {
			top: 0,
			bottom: 0,
			left: 0,
			right: 0
		}
	};
	pieces.top.push({side1: 6, side2: 7, angle: 0, freeSide: 'side1'});
	pieces.bottom.push({side1: 6, side2: 7, angle: 180, freeSide: 'side1'});
	pieces.left.push({side1: 6, side2: 7, angle: 270, freeSide: 'side1'});
	pieces.right.push({side1: 6, side2: 7, angle: 90, freeSide: 'side1'});
}

function update() {
	'use strict';
	game.scale.setExactFit();
	game.scale.refresh();
}

function start(dataString) {
	'use strict';
	var data = JSON.parse(dataString);
	userroom = data.room;
	myPieces = data.pieces;
	pieceHeight = 60;
	pieceWidth = 30;
	game = new Phaser.Game(960, 600, Phaser.AUTO, 'game', {preload: preload, create: create, update: update});
}

selected = {};
socket.on('create rectangle', createRectangle);
socket.on('start game', start);<|endoftext|>


<commit_before>var debug = require('debug')('BrewUI:WebSocket');

// Actions
var receiveTemperature = require('./../../app/actions/brewer/receiveTemperature');
var receivePWM = require('./../../app/actions/brewer/receivePWM');

var receiveBrew = require('./../../app/actions/brew/receiveBrew');

/*
 * init
 *
 * @method init
 */
function init(options) {
  options = options || {};

  var server = options.server;
  var context = options.context;

  var socket = require('socket.io-client')(server);

  /*
   * On temperature changed
   *
   * @method onTemperatureChanged
   * @param {Number} temp
   */
  function onTemperatureChanged(temp) {
    if (isNaN(temp)) {
      return;
    }

    var roundedTemp = Math.round(temp * 100) / 100;

    context.executeAction(receiveTemperature, {
      temperature: roundedTemp
    });
  }

  /*
   * On temperature changed
   *
   * @method onTemperatureChanged
   * @param {Number} pwm
   */
  function onPWMChanged(pwm) {
    if (isNaN(pwm)) {
      return;
    }

    var roundedPWM = Math.round(pwm * 100) / 100;

    context.executeAction(receivePWM, {
      pwm: roundedPWM
    });
  }

  /*
   * On brew changed
   *
   * @method onBrewChanged
   * @param {Number} brew
   */
  function onBrewChanged(brew) {
    context.executeAction(receiveBrew, brew);
  }

  // Events
  socket.on('connect', function() {
    debug('Connect: add listeners');

    socket.on('temperature_changed', onTemperatureChanged);
    socket.on('pwm_changed', onPWMChanged);
    socket.on('brew_changed', onBrewChanged);

    socket.on('disconnect', function () {
      socket.off('temperature_changed', onTemperatureChanged);
      socket.off('pwm_changed', onPWMChanged);
      socket.off('brew_changed', onBrewChanged);

      debug('Disconnect: remove listeners');
    });
  });

  socket.on('error', function (err) {
    debug('Error', err);
  });
}

module.exports = init;
<commit_msg>Fix comments<commit_after>var debug = require('debug')('BrewUI:WebSocket');

// Actions
var receiveTemperature = require('./../../app/actions/brewer/receiveTemperature');
var receivePWM = require('./../../app/actions/brewer/receivePWM');

var receiveBrew = require('./../../app/actions/brew/receiveBrew');

/*
 * init
 *
 * @method init
 */
function init(options) {
  options = options || {};

  var server = options.server;
  var context = options.context;

  var socket = require('socket.io-client')(server);

  /*
   * On temperature changed
   *
   * @method onTemperatureChanged
   * @param {Number} temp
   */
  function onTemperatureChanged(temp) {
    if (isNaN(temp)) {
      return;
    }

    var roundedTemp = Math.round(temp * 100) / 100;

    context.executeAction(receiveTemperature, {
      temperature: roundedTemp
    });
  }

  /*
   * On pwm changed
   *
   * @method onPWMChanged
   * @param {Number} pwm
   */
  function onPWMChanged(pwm) {
    if (isNaN(pwm)) {
      return;
    }

    var roundedPWM = Math.round(pwm * 100) / 100;

    context.executeAction(receivePWM, {
      pwm: roundedPWM
    });
  }

  /*
   * On brew changed
   *
   * @method onBrewChanged
   * @param {Number} brew
   */
  function onBrewChanged(brew) {
    context.executeAction(receiveBrew, brew);
  }

  // Events
  socket.on('connect', function() {
    debug('Connect: add listeners');

    socket.on('temperature_changed', onTemperatureChanged);
    socket.on('pwm_changed', onPWMChanged);
    socket.on('brew_changed', onBrewChanged);

    socket.on('disconnect', function () {
      socket.off('temperature_changed', onTemperatureChanged);
      socket.off('pwm_changed', onPWMChanged);
      socket.off('brew_changed', onBrewChanged);

      debug('Disconnect: remove listeners');
    });
  });

  socket.on('error', function (err) {
    debug('Error', err);
  });
}

module.exports = init;
<|endoftext|>


<commit_before>import Service from '../core/Service';
import { getOpt } from '../../utils/helpers';
import serviceManager from '../core/serviceManager';

const SERVICE_ID = 'service:metric-scheduler';

/**
 * Interface for the server `'metric-scheduler'` service.
 *
 * @memberof module:soundworks/server
 * @example
 * // inside the experience constructor
 * this.metricScheduler = this.require('metric-scheduler');
 */
class MetricScheduler extends Service {
  /** ___WARNING__ This class should never be instanciated manually_ */
  constructor() {
    super(SERVICE_ID);

    this._syncTime = 0;
    this._metricPosition = 0;
    this._tempo = 60; // tempo in beats per minute (BPM)
    this._tempoUnit = 0.25; // tempo unit expressed in fractions of a whole note

    this._nextSyncEvent = null;
    this._nextSyncTime = Infinity;

    this._syncScheduler = this.require('sync-scheduler');

    this._onRequest = this._onRequest.bind(this);
  }

  /** @private */
  configure(options) {
    if (options.tempo !== undefined)
      this._tempo = options.tempo;

    if (options.tempoUnit !== undefined)
      this._tempoUnit = options.tempoUnit;

    super.configure(options);
  }

  /** @private */
  start() {
    super.start();

    this.ready();
  }

  /** @private */
  _resetSync() {
    this._nextSyncEvent = null;
    this._nextSyncTime = Infinity;
  }

  /** @private */
  _setSync(syncTime, metricPosition, tempo, tempoUnit, event) {
    this._resetSync();

    if (syncTime <= this.syncTime) {
      this._syncTime = syncTime;
      this._metricPosition = metricPosition;
      this._tempo = tempo;
      this._tempoUnit = tempoUnit;
      this._metricSpeed = tempo * tempoUnit / 60;
    } else {
      this._nextSyncEvent = { syncTime, metricPosition, tempo, tempoUnit, event };
      this._nextSyncTime = syncTime;
    }

    this.broadcast(null, null, 'sync', syncTime, metricPosition, tempo, tempoUnit, event);
  }

  /** @private */
  _updateSync() {
    if (this.syncTime >= this._nextSyncTime) {
      const { syncTime, metricPosition, tempo, tempoUnit } = this._nextSyncEvent;
      this._syncTime = syncTime;
      this._metricPosition = metricPosition;
      this._tempo = tempo;
      this._tempoUnit = tempoUnit;
      this._metricSpeed = tempo * tempoUnit / 60;
      this._nextSyncTime = Infinity;
    }
  }

  /** @private */
  _onRequest(client) {
    return () => {
      this._updateSync();
      this.send(client, 'init', this._syncTime, this._metricPosition, this._tempo, this._tempoUnit);

      if (this._nextSyncTime < Infinity) {
        const { syncTime, metricPosition, tempo, tempoUnit, event } = this._nextSyncEvent;
        this.send(client, 'sync', syncTime, metricPosition, tempo, tempoUnit, event);
      }
    };
  }

  sync(syncTime, metricPosition, tempo, tempoUnit, event = undefined) {
    this._setSync(syncTime, metricPosition, tempo, tempoUnit, event);
  }

  clear() {
    this.broadcast(null, null, 'clear');
  }

  get currentTime() {
    return this._syncScheduler.currentTime;
  }

  get syncTime() {
    return this._syncScheduler.currentTime;
  }

  get metricPosition() {
    this._updateSync();

    if (this._tempo > 0)
      return this._metricPosition + (this.syncTime - this._syncTime) * this._metricSpeed;

    return this._metricPosition;
  }

  get currentPosition() {
    return this.metricPosition;
  }

  /**
   * Current tempo.
   * @return {Number} - Tempo in BPM.
   */
  get tempo() {
    this._updateSync();
    return this._tempo;
  }

  /**
   * Current tempo unit.
   * @return {Number} - Tempo unit in respect to whole note.
   */
  get tempoUnit() {
    this._updateSync();
    return this._tempoUnit;
  }

  /**
   * Get metric position corrsponding to a given sync time (regarding the current tempo).
   * @param  {Number} time - time
   * @return {Number} - metric position
   */
  getMetricPositionAtSyncTime(syncTime) {
    this._updateSync();

    if (this._tempo > 0)
      return this._metricPosition + (syncTime - this._syncTime) * this._metricSpeed;

    return this._metricPosition;
  }

  /**
   * Get sync time corrsponding to a given metric position (regarding the current tempo).
   * @param  {Number} position - metric position
   * @return {Number} - time
   */
  getSyncTimeAtMetricPosition(metricPosition) {
    this._updateSync();

    const metricSpeed = this._metricSpeed;

    if (metricPosition < Infinity && metricSpeed > 0)
      return this._syncTime + (metricPosition - this._metricPosition) / metricSpeed;

    return Infinity;
  }

  /** @private */
  connect(client) {
    super.connect(client);
    this.receive(client, 'request', this._onRequest(client));
  }

  /** @private */
  disconnect(client) {
    super.disconnect(client);
  }
}

serviceManager.register(SERVICE_ID, MetricScheduler);

export default MetricScheduler;
<commit_msg>fixed missing initial metric speed in metric scheduler<commit_after>import Service from '../core/Service';
import { getOpt } from '../../utils/helpers';
import serviceManager from '../core/serviceManager';

const SERVICE_ID = 'service:metric-scheduler';

/**
 * Interface for the server `'metric-scheduler'` service.
 *
 * @memberof module:soundworks/server
 * @example
 * // inside the experience constructor
 * this.metricScheduler = this.require('metric-scheduler');
 */
class MetricScheduler extends Service {
  /** ___WARNING__ This class should never be instanciated manually_ */
  constructor() {
    super(SERVICE_ID);

    this._syncTime = 0;
    this._metricPosition = 0;
    this._tempo = 60; // tempo in beats per minute (BPM)
    this._tempoUnit = 0.25; // tempo unit expressed in fractions of a whole note
    this._metricSpeed = 0.25;

    this._nextSyncEvent = null;
    this._nextSyncTime = Infinity;

    this._syncScheduler = this.require('sync-scheduler');

    this._onRequest = this._onRequest.bind(this);
  }

  /** @private */
  configure(options) {
    if (options.tempo !== undefined)
      this._tempo = options.tempo;

    if (options.tempoUnit !== undefined)
      this._tempoUnit = options.tempoUnit;

    this._metricSpeed = this._tempo * this._tempoUnit / 60;

    super.configure(options);
  }

  /** @private */
  start() {
    super.start();

    this.ready();
  }

  /** @private */
  _resetSync() {
    this._nextSyncEvent = null;
    this._nextSyncTime = Infinity;
  }

  /** @private */
  _setSync(syncTime, metricPosition, tempo, tempoUnit, event) {
    this._resetSync();

    if (syncTime <= this.syncTime) {
      this._syncTime = syncTime;
      this._metricPosition = metricPosition;
      this._tempo = tempo;
      this._tempoUnit = tempoUnit;
      this._metricSpeed = tempo * tempoUnit / 60;
    } else {
      this._nextSyncEvent = { syncTime, metricPosition, tempo, tempoUnit, event };
      this._nextSyncTime = syncTime;
    }

    this.broadcast(null, null, 'sync', syncTime, metricPosition, tempo, tempoUnit, event);
  }

  /** @private */
  _updateSync() {
    if (this.syncTime >= this._nextSyncTime) {
      const { syncTime, metricPosition, tempo, tempoUnit } = this._nextSyncEvent;
      this._syncTime = syncTime;
      this._metricPosition = metricPosition;
      this._tempo = tempo;
      this._tempoUnit = tempoUnit;
      this._metricSpeed = tempo * tempoUnit / 60;
      this._nextSyncTime = Infinity;
    }
  }

  /** @private */
  _onRequest(client) {
    return () => {
      this._updateSync();
      this.send(client, 'init', this._syncTime, this._metricPosition, this._tempo, this._tempoUnit);

      if (this._nextSyncTime < Infinity) {
        const { syncTime, metricPosition, tempo, tempoUnit, event } = this._nextSyncEvent;
        this.send(client, 'sync', syncTime, metricPosition, tempo, tempoUnit, event);
      }
    };
  }

  sync(syncTime, metricPosition, tempo, tempoUnit, event = undefined) {
    this._setSync(syncTime, metricPosition, tempo, tempoUnit, event);
  }

  clear() {
    this.broadcast(null, null, 'clear');
  }

  get currentTime() {
    return this._syncScheduler.currentTime;
  }

  get syncTime() {
    return this._syncScheduler.currentTime;
  }

  get metricPosition() {
    this._updateSync();

    if (this._tempo > 0)
      return this._metricPosition + (this.syncTime - this._syncTime) * this._metricSpeed;

    return this._metricPosition;
  }

  get currentPosition() {
    return this.metricPosition;
  }

  /**
   * Current tempo.
   * @return {Number} - Tempo in BPM.
   */
  get tempo() {
    this._updateSync();
    return this._tempo;
  }

  /**
   * Current tempo unit.
   * @return {Number} - Tempo unit in respect to whole note.
   */
  get tempoUnit() {
    this._updateSync();
    return this._tempoUnit;
  }

  /**
   * Get metric position corrsponding to a given sync time (regarding the current tempo).
   * @param  {Number} time - time
   * @return {Number} - metric position
   */
  getMetricPositionAtSyncTime(syncTime) {
    this._updateSync();

    if (this._tempo > 0)
      return this._metricPosition + (syncTime - this._syncTime) * this._metricSpeed;

    return this._metricPosition;
  }

  /**
   * Get sync time corrsponding to a given metric position (regarding the current tempo).
   * @param  {Number} position - metric position
   * @return {Number} - time
   */
  getSyncTimeAtMetricPosition(metricPosition) {
    this._updateSync();

    const metricSpeed = this._metricSpeed;

    if (metricPosition < Infinity && metricSpeed > 0)
      return this._syncTime + (metricPosition - this._metricPosition) / metricSpeed;

    return Infinity;
  }

  /** @private */
  connect(client) {
    super.connect(client);
    this.receive(client, 'request', this._onRequest(client));
  }

  /** @private */
  disconnect(client) {
    super.disconnect(client);
  }
}

serviceManager.register(SERVICE_ID, MetricScheduler);

export default MetricScheduler;
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const { chai, mocha, expect, app, testDB, testUser } = require('../common');
const Meter = require('../../models/Meter');
const Reading = require('../../models/Reading');
const zlib = require('zlib');

const fs = require('fs');
const csv = require('csv');
const promisify = require('es6-promisify');

const parseCsv = promisify(csv.parse);

const UPLOAD_METERS_ROUTE = '/api/csv/meters';
const UPLOAD_READINGS_ROUTE = '/api/csv/readings';

// File buffers for testing
const readingsPath = `${__dirname}/csvPipeline/sampleReadings.csv`;
const readingsBuffer = fs.readFileSync(readingsPath);
const zippedReadingsBuffer = zlib.gzipSync(readingsBuffer);
const metersPath = `${__dirname}/csvPipeline/sampleMeters.csv`;
const metersBuffer = fs.readFileSync(metersPath);
const zippedMetersBuffer = zlib.gzipSync(metersBuffer);
const metersPathWithHeader = `${__dirname}/csvPipeline/sampleMetersWithHeader.csv`;
const metersWithHeaderBuffer = fs.readFileSync(metersPathWithHeader);
const zippedMetersWithHeaderBuffer = zlib.gzipSync(metersWithHeaderBuffer);

mocha.describe('csv API', () => {
	mocha.it('should be able to accept a post request to upload meter data.', async () => {
		const res = await chai.request(app).post(UPLOAD_METERS_ROUTE)
			.field('email', testUser.email)
			.field('password', testUser.password)
			.attach('csvfile', zippedMetersBuffer, `${readingsPath}.gz`)

		expect(res).to.have.status(200);
		const csvMeters = (await parseCsv(metersBuffer)).map(row =>
			(new Meter(undefined, row[0], row[1], row[2] === 'TRUE', row[3] === 'TRUE', row[4], row[5]))
		);

		const conn = testDB.getConnection();
		const dbMeters = await Promise.all(csvMeters.map(async (meter, idx) => {
			const dbMeter = await Meter.getByName(meter.name, conn);
			csvMeters[idx].id = dbMeter.id;
			return meter;
		}));
		expect(dbMeters).to.deep.equal(csvMeters);
		expect((await Meter.getAll(conn)).length).to.equal(3);
	});
	mocha.it('should be able to accept a post request to upload meter data with header row.', async () => {
		const res = await chai.request(app).post(UPLOAD_METERS_ROUTE)
			.field('email', testUser.email)
			.field('password', testUser.password)
			.field('headerRow', 'true')
			.attach('csvfile', zippedMetersWithHeaderBuffer, `${metersPathWithHeader}.gz`)
		expect(res).to.have.status(200);
		const csvMeters = (await parseCsv(metersWithHeaderBuffer)).map(row =>
			(new Meter(undefined, row[0], row[1], row[2] === 'TRUE', row[3] === 'TRUE', row[4], row[5]))
		).slice(1);

		const conn = testDB.getConnection();
		const dbMeters = await Promise.all(csvMeters.map(async (meter, idx) => {
			const dbMeter = await Meter.getByName(meter.name, conn);
			csvMeters[idx].id = dbMeter.id;
			return meter;
		}));
		expect(dbMeters).to.deep.equal(csvMeters);
		expect((await Meter.getAll(conn)).length).to.equal(3);
	});
	mocha.it('should be able to load readings data for an existing meter.', async () => {
		const conn = testDB.getConnection();
		const meter = new Meter(undefined, 'XXX', undefined, false, false, Meter.type.MAMAC, 'XXX')
		await meter.insert(conn); // insert meter
		const res = await chai.request(app).post(UPLOAD_READINGS_ROUTE) // make request to api to upload readings data for this meter
			.field('email', testUser.email)
			.field('password', testUser.password)
			.field('meterName', 'XXX')
			.field('timeSort', 'increasing')
			.attach('csvfile', zippedReadingsBuffer, `${readingsPath}.gz`)

		expect(res).to.have.status(200);
		const readings = await Reading.getAllByMeterID(meter.id, conn);
		const extractedReadings = readings.map(reading => {
			return [`${reading.reading}`, reading.startTimestamp._i, reading.endTimestamp._i];
		});
		const fileReadings = await parseCsv(readingsBuffer);
		expect(extractedReadings).to.deep.equals(fileReadings);
	});
	mocha.it('should be able to load readings data for a non existing meter.', async () => {
		const conn = testDB.getConnection();
		const res = await chai.request(app).post(UPLOAD_READINGS_ROUTE) // make request to api to upload readings data for this meter
			.field('email', testUser.email)
			.field('password', testUser.password)
			.field('createMeter', 'true')
			.field('meterName', 'ABG')
			.field('timeSort', 'increasing')
			.attach('csvfile', zippedReadingsBuffer, `${readingsPath}.gz`)
		const meter = await Meter.getByName('ABG', conn);
		const readings = await Reading.getAllByMeterID(meter.id, conn);
		const extractedReadings = readings.map(reading => {
			return [`${reading.reading}`, reading.startTimestamp._i, reading.endTimestamp._i];
		});
		const fileReadings = await parseCsv(readingsBuffer);
		expect(extractedReadings).to.deep.equals(fileReadings);
	});
});<commit_msg>Resolve comments for tests<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const { chai, mocha, expect, app, testDB, testUser } = require('../common');
const Meter = require('../../models/Meter');
const Reading = require('../../models/Reading');
const zlib = require('zlib');

const fs = require('fs');
const csv = require('csv');
const promisify = require('es6-promisify');

const parseCsv = promisify(csv.parse);

const UPLOAD_METERS_ROUTE = '/api/csv/meters';
const UPLOAD_READINGS_ROUTE = '/api/csv/readings';

// File buffers for testing
const readingsPath = `${__dirname}/csvPipeline/sampleReadings.csv`;
const readingsBuffer = fs.readFileSync(readingsPath);
const zippedReadingsBuffer = zlib.gzipSync(readingsBuffer);
const metersPath = `${__dirname}/csvPipeline/sampleMeters.csv`;
const metersBuffer = fs.readFileSync(metersPath);
const zippedMetersBuffer = zlib.gzipSync(metersBuffer);
const metersPathWithHeader = `${__dirname}/csvPipeline/sampleMetersWithHeader.csv`;
const metersWithHeaderBuffer = fs.readFileSync(metersPathWithHeader);
const zippedMetersWithHeaderBuffer = zlib.gzipSync(metersWithHeaderBuffer);

mocha.describe('csv API', () => {
	mocha.describe('not-zipped data', () => {
		mocha.it('should be able to accept a post request to upload unzipped meter data.', async () => {
			const res = await chai.request(app).post(UPLOAD_METERS_ROUTE)
				.field('email', testUser.email)
				.field('password', testUser.password)
				.field('gzip', 'false')
				.attach('csvfile', metersBuffer, `${readingsPath}.gz`)

			expect(res).to.have.status(200);
			const csvMeters = (await parseCsv(metersBuffer)).map(row =>
				(new Meter(undefined, row[0], row[1], row[2] === 'TRUE', row[3] === 'TRUE', row[4], row[5]))
			);

			const conn = testDB.getConnection();
			const dbMeters = await Promise.all(csvMeters.map(async (meter, idx) => {
				const dbMeter = await Meter.getByName(meter.name, conn);
				csvMeters[idx].id = dbMeter.id;
				return meter;
			}));
			expect(dbMeters.length).to.equal(csvMeters.length);
			expect(dbMeters).to.deep.equal(csvMeters);
			expect((await Meter.getAll(conn)).length).to.equal(3);
		});
		mocha.it('should be able to accept a post request to upload unzipped  meter data with header row.', async () => {
			const res = await chai.request(app).post(UPLOAD_METERS_ROUTE)
				.field('email', testUser.email)
				.field('password', testUser.password)
				.field('headerRow', 'true')
				.field('gzip', 'false')
				.attach('csvfile', metersWithHeaderBuffer, `${metersPathWithHeader}.gz`)

			expect(res).to.have.status(200);
			const csvMeters = (await parseCsv(metersWithHeaderBuffer)).map(row =>
				(new Meter(undefined, row[0], row[1], row[2] === 'TRUE', row[3] === 'TRUE', row[4], row[5]))
			).slice(1);

			const conn = testDB.getConnection();
			const dbMeters = await Promise.all(csvMeters.map(async (meter, idx) => {
				const dbMeter = await Meter.getByName(meter.name, conn);
				csvMeters[idx].id = dbMeter.id;
				return meter;
			}));
			expect(dbMeters).to.deep.equal(csvMeters);
			expect((await Meter.getAll(conn)).length).to.equal(3);
		});
		mocha.it('should be able to load unzipped readings data for an existing meter.', async () => {
			const conn = testDB.getConnection();
			const meter = new Meter(undefined, 'XXX', undefined, false, false, Meter.type.MAMAC, 'XXX')
			await meter.insert(conn); // insert meter
			const res = await chai.request(app).post(UPLOAD_READINGS_ROUTE) // make request to api to upload readings data for this meter
				.field('email', testUser.email)
				.field('password', testUser.password)
				.field('meterName', 'XXX')
				.field('timeSort', 'increasing')
				.field('gzip', 'false')
				.attach('csvfile', readingsBuffer, `${readingsPath}.gz`)

			expect(res).to.have.status(200);
			const readings = await Reading.getAllByMeterID(meter.id, conn);
			const extractedReadings = readings.map(reading => {
				return [`${reading.reading}`, reading.startTimestamp._i, reading.endTimestamp._i];
			});
			const fileReadings = await parseCsv(readingsBuffer);
			expect(extractedReadings).to.deep.equals(fileReadings);
		});
		mocha.it('should be able to load unzipped readings data for a non existing meter.', async () => {
			const conn = testDB.getConnection();
			const res = await chai.request(app).post(UPLOAD_READINGS_ROUTE) // make request to api to upload readings data for this meter
				.field('email', testUser.email)
				.field('password', testUser.password)
				.field('createMeter', 'true')
				.field('meterName', 'ABG')
				.field('timeSort', 'increasing')
				.field('gzip', 'false')
				.attach('csvfile', readingsBuffer, `${readingsPath}.gz`)

			const meter = await Meter.getByName('ABG', conn);
			const readings = await Reading.getAllByMeterID(meter.id, conn);
			const extractedReadings = readings.map(reading => {
				return [`${reading.reading}`, reading.startTimestamp._i, reading.endTimestamp._i];
			});
			const fileReadings = await parseCsv(readingsBuffer);
			expect(extractedReadings).to.deep.equals(fileReadings);
		});
	});
	mocha.describe('zipped data', () => {
		mocha.it('should be able to accept a post request to upload zipped meter data.', async () => {
			const res = await chai.request(app).post(UPLOAD_METERS_ROUTE)
				.field('email', testUser.email)
				.field('password', testUser.password)
				.attach('csvfile', zippedMetersBuffer, `${readingsPath}.gz`)

			expect(res).to.have.status(200);
			const csvMeters = (await parseCsv(metersBuffer)).map(row =>
				(new Meter(undefined, row[0], row[1], row[2] === 'TRUE', row[3] === 'TRUE', row[4], row[5]))
			);

			const conn = testDB.getConnection();
			const dbMeters = await Promise.all(csvMeters.map(async (meter, idx) => {
				const dbMeter = await Meter.getByName(meter.name, conn);
				csvMeters[idx].id = dbMeter.id;
				return meter;
			}));
			expect(dbMeters.length).to.equal(csvMeters.length);
			expect(dbMeters).to.deep.equal(csvMeters);
			expect((await Meter.getAll(conn)).length).to.equal(3);
		});
		mocha.it('should be able to accept a post request to upload zipped  meter data with header row.', async () => {
			const res = await chai.request(app).post(UPLOAD_METERS_ROUTE)
				.field('email', testUser.email)
				.field('password', testUser.password)
				.field('headerRow', 'true')
				.attach('csvfile', zippedMetersWithHeaderBuffer, `${metersPathWithHeader}.gz`)
			expect(res).to.have.status(200);
			const csvMeters = (await parseCsv(metersWithHeaderBuffer)).map(row =>
				(new Meter(undefined, row[0], row[1], row[2] === 'TRUE', row[3] === 'TRUE', row[4], row[5]))
			).slice(1);

			const conn = testDB.getConnection();
			const dbMeters = await Promise.all(csvMeters.map(async (meter, idx) => {
				const dbMeter = await Meter.getByName(meter.name, conn);
				csvMeters[idx].id = dbMeter.id;
				return meter;
			}));
			expect(dbMeters).to.deep.equal(csvMeters);
			expect((await Meter.getAll(conn)).length).to.equal(3);
		});
		mocha.it('should be able to load zipped readings data for an existing meter.', async () => {
			const conn = testDB.getConnection();
			const meter = new Meter(undefined, 'XXX', undefined, false, false, Meter.type.MAMAC, 'XXX')
			await meter.insert(conn); // insert meter
			const res = await chai.request(app).post(UPLOAD_READINGS_ROUTE) // make request to api to upload readings data for this meter
				.field('email', testUser.email)
				.field('password', testUser.password)
				.field('meterName', 'XXX')
				.field('timeSort', 'increasing')
				.attach('csvfile', zippedReadingsBuffer, `${readingsPath}.gz`)

			expect(res).to.have.status(200);
			const readings = await Reading.getAllByMeterID(meter.id, conn);
			const extractedReadings = readings.map(reading => {
				return [`${reading.reading}`, reading.startTimestamp._i, reading.endTimestamp._i];
			});
			const fileReadings = await parseCsv(readingsBuffer);
			expect(extractedReadings).to.deep.equals(fileReadings);
		});
		mocha.it('should be able to load zipped readings data for a non existing meter.', async () => {
			const conn = testDB.getConnection();
			const res = await chai.request(app).post(UPLOAD_READINGS_ROUTE) // make request to api to upload readings data for this meter
				.field('email', testUser.email)
				.field('password', testUser.password)
				.field('createMeter', 'true')
				.field('meterName', 'ABG')
				.field('timeSort', 'increasing')
				.attach('csvfile', zippedReadingsBuffer, `${readingsPath}.gz`)
			const meter = await Meter.getByName('ABG', conn);
			const readings = await Reading.getAllByMeterID(meter.id, conn);
			const extractedReadings = readings.map(reading => {
				return [`${reading.reading}`, reading.startTimestamp._i, reading.endTimestamp._i];
			});
			const fileReadings = await parseCsv(readingsBuffer);
			expect(extractedReadings).to.deep.equals(fileReadings);
		});
	});
});<|endoftext|>


<commit_before>/*!
Cloud4all Preferences Management Tools

Copyright 2013 Astea

Licensed under the New BSD license. You may not use this file except in
compliance with this License.

You may obtain a copy of the License at
https://github.com/GPII/prefsEditors/LICENSE.txt
*/

(function ($, fluid) {
    fluid.defaults("gpii.prefsEditor", {
        gradeNames: ["fluid.prefs.GPIIEditor", "autoInit"],
        prefsEditor: {
            gradeNames: ["fluid.prefs.msgLookup"],
            members: {
                messageResolver: "{prefsEditorLoader}.msgResolver"
            },
            events: {
                onLogin: null,
                onLogout: null,
                onRequestPageTransition: null,
                onSettingChanged: null
            },
            model: {
                userLoggedIn: false
            },
            listeners: {
                "onReady.setATTRsaveButton": {
                    "this": "{that}.dom.saveButton",
                    "method": "attr",
                    "args": ["value", "{that}.msgLookup.saveAndApplyText"]
                },
                "onSave.hideSaveButton": {
                    "this": "{that}.dom.saveButtonContainer",
                    "method": "hide",
                    "args": []
                },
                "onReady.fullEditorLink": {
                    "this": "{that}.dom.fullEditorLink",
                    "method": "click",
                    "args": ["{that}.events.onRequestPageTransition.fire"]
                },
                "onRequestPageTransition.save": "{that}.saveSettings",
                "onRequestPageTransition.goToPMT": {
                    "funcName": "fluid.set",
                    "args": [window, "location.href", "{prefsEditorLoader}.options.pmtUrl"]
                },
                "onLogin.setUserLoggedIn": {
                    listener: "{that}.applier.requestChange",
                    args: ["userLoggedIn", true]
                },
                "onLogin.showSaveMessage": {
                    "this": "{that}.dom.messageLineLabel",
                    "method": "text",
                    "args": ["{that}.msgLookup.preferencesModified"]
                },
                "onLogin.showUserStatusBar": {
                    "listener": "{that}.showUserStatusBar"
                },
                "onReset.triggerLogoutEvent": {
                    "listener": "{that}.events.onLogout.fire"
                },
                "onLogout.setUserLoggedIn": {
                    listener: "{that}.applier.requestChange",
                    args: ["userLoggedIn", false]
                },
                "onLogout.clearMessage": {
                    "this": "{that}.dom.messageLineLabel",
                    "method": "text",
                    "args": [""]
                },
                "onLogout.gpiiLogout": {
                    listener: "{gpiiSession}.logout"
                },
                "onLogout.disableSaveButton": {
                    "this": "{that}.dom.saveAndApply",
                    "method": "prop",
                    "args": ["disabled", "true"]
                },
                "onLogout.disableCloudIcon": {
                    "this": "{that}.dom.cloudIcon",
                    "method": "addClass",
                    "args": ["gpii-disabled"]
                },
                "onReady.setSaveAndApplyButtonText": {
                    "this": "{that}.dom.saveAndApply",
                    "method": "attr",
                    "args": ["value", "{that}.msgLookup.saveAndApplyText"]
                },
                "onReady.setFullEditorLinkText": {
                    "this": "{that}.dom.fullEditorLink",
                    "method": "text",
                    "args": ["{that}.msgLookup.fullEditorText"]
                },
                "onReady.fullEditorLinkPreventDefault": {
                    "this": "{that}.dom.fullEditorLink",
                    "method": "click",
                    "args": ["{that}.preventDefaultLinkEvent"]
                },
                "onReady.setLogoutLinkText": {
                    "this": "{that}.dom.logoutLink",
                    "method": "text",
                    "args": ["{that}.msgLookup.logoutText"]
                },
                "onReady.bindLogout": {
                    "this": "{that}.dom.logoutLink",
                    "method": "click",
                    "args": ["{that}.events.onLogout.fire"]
                },
                "onReady.logoutLinkPreventDefault": {
                    "this": "{that}.dom.logoutLink",
                    "method": "click",
                    "args": ["{that}.preventDefaultLinkEvent"]
                },
                "onReady.bindModelChangedListener": {
                    // used instead of the declarative syntax so that
                    // model won't "count" as updated when fetching from
                    // the server. Thus, onSettingChanged is not fired on load.
                    "listener": "{that}.applier.modelChanged.addListener",
                    "args": ["", "{that}.events.onSettingChanged.fire"]
                },
                "onSettingChanged.showSaveButton": {
                    "this": "{that}.dom.saveButtonContainer",
                    "method": "show",
                    "args": []
                }
            },
            invokers: {
                applySettings: {
                    "funcName": "gpii.applySettings",
                    "args": "{that}"
                },
                showUserStatusBar: {
                    "this": "{that}.dom.userStatusBar",
                    "method": "slideDown"
                },
                saveSettings: {
                    "func": "{gpiiStore}.set",
                    "args": "{that}.model",
                    "dynamic": true
                },
                preventDefaultLinkEvent: {
                    "funcName": "gpii.eventUtility.preventDefaultEvent"
                }
            },
            selectors: {
                saveAndApply: ".flc-prefsEditor-save",
                saveButtonContainer: ".gpii-pcp-saveButtonContainer",
                cloudIcon: ".gpii-pcp-cloudIcon",
                messageLineLabel: ".gpiic-prefsEditor-messageLine",
                fullEditorLink: ".gpiic-prefsEditor-fullEditorLink",
                logoutLink: ".gpiic-prefsEditor-userLogoutLink"
            },
            selectorsToIgnore: ["cloudIcon"]
        }
    });

    gpii.applySettings = function (that) {
        var savedSettings = that.modelTransform(that.model);
        if (that.socket) {
            that.socket.emit("message", savedSettings, fluid.log);
        } else {
            that.socket = that.socket || io.connect("http://localhost:8081/update");
            that.socket.on("connect", function () {
                that.socket.emit("message", savedSettings, fluid.log);
            });
            fluid.each(["error", "disconnect"], function (event) {
                that.socket.on(event, function (data) {
                    fluid.log(data);
                    that.socket.disconnect();
                    delete that.socket;
                });
            });
        }
    };

    gpii.prefsEditor.triggerEvent = function (that, targetSelector, event) {
        that.locate(targetSelector).trigger(event);
    };
})(jQuery, fluid);
<commit_msg>GPII-839: Stop 'Full editor' link from performing save.<commit_after>/*!
Cloud4all Preferences Management Tools

Copyright 2013 Astea

Licensed under the New BSD license. You may not use this file except in
compliance with this License.

You may obtain a copy of the License at
https://github.com/GPII/prefsEditors/LICENSE.txt
*/

(function ($, fluid) {
    fluid.defaults("gpii.prefsEditor", {
        gradeNames: ["fluid.prefs.GPIIEditor", "autoInit"],
        prefsEditor: {
            gradeNames: ["fluid.prefs.msgLookup"],
            members: {
                messageResolver: "{prefsEditorLoader}.msgResolver"
            },
            events: {
                onLogin: null,
                onLogout: null,
                onRequestPageTransition: null,
                onSettingChanged: null
            },
            model: {
                userLoggedIn: false
            },
            listeners: {
                "onReady.setATTRsaveButton": {
                    "this": "{that}.dom.saveButton",
                    "method": "attr",
                    "args": ["value", "{that}.msgLookup.saveAndApplyText"]
                },
                "onSave.hideSaveButton": {
                    "this": "{that}.dom.saveButtonContainer",
                    "method": "hide",
                    "args": []
                },
                "onReady.fullEditorLink": {
                    "this": "{that}.dom.fullEditorLink",
                    "method": "click",
                    "args": ["{that}.events.onRequestPageTransition.fire"]
                },
                "onRequestPageTransition.goToPMT": {
                    "funcName": "fluid.set",
                    "args": [window, "location.href", "{prefsEditorLoader}.options.pmtUrl"]
                },
                "onLogin.setUserLoggedIn": {
                    listener: "{that}.applier.requestChange",
                    args: ["userLoggedIn", true]
                },
                "onLogin.showSaveMessage": {
                    "this": "{that}.dom.messageLineLabel",
                    "method": "text",
                    "args": ["{that}.msgLookup.preferencesModified"]
                },
                "onLogin.showUserStatusBar": {
                    "listener": "{that}.showUserStatusBar"
                },
                "onReset.triggerLogoutEvent": {
                    "listener": "{that}.events.onLogout.fire"
                },
                "onLogout.setUserLoggedIn": {
                    listener: "{that}.applier.requestChange",
                    args: ["userLoggedIn", false]
                },
                "onLogout.clearMessage": {
                    "this": "{that}.dom.messageLineLabel",
                    "method": "text",
                    "args": [""]
                },
                "onLogout.gpiiLogout": {
                    listener: "{gpiiSession}.logout"
                },
                "onLogout.disableSaveButton": {
                    "this": "{that}.dom.saveAndApply",
                    "method": "prop",
                    "args": ["disabled", "true"]
                },
                "onLogout.disableCloudIcon": {
                    "this": "{that}.dom.cloudIcon",
                    "method": "addClass",
                    "args": ["gpii-disabled"]
                },
                "onReady.setSaveAndApplyButtonText": {
                    "this": "{that}.dom.saveAndApply",
                    "method": "attr",
                    "args": ["value", "{that}.msgLookup.saveAndApplyText"]
                },
                "onReady.setFullEditorLinkText": {
                    "this": "{that}.dom.fullEditorLink",
                    "method": "text",
                    "args": ["{that}.msgLookup.fullEditorText"]
                },
                "onReady.fullEditorLinkPreventDefault": {
                    "this": "{that}.dom.fullEditorLink",
                    "method": "click",
                    "args": ["{that}.preventDefaultLinkEvent"]
                },
                "onReady.setLogoutLinkText": {
                    "this": "{that}.dom.logoutLink",
                    "method": "text",
                    "args": ["{that}.msgLookup.logoutText"]
                },
                "onReady.bindLogout": {
                    "this": "{that}.dom.logoutLink",
                    "method": "click",
                    "args": ["{that}.events.onLogout.fire"]
                },
                "onReady.logoutLinkPreventDefault": {
                    "this": "{that}.dom.logoutLink",
                    "method": "click",
                    "args": ["{that}.preventDefaultLinkEvent"]
                },
                "onReady.bindModelChangedListener": {
                    // used instead of the declarative syntax so that
                    // model won't "count" as updated when fetching from
                    // the server. Thus, onSettingChanged is not fired on load.
                    "listener": "{that}.applier.modelChanged.addListener",
                    "args": ["", "{that}.events.onSettingChanged.fire"]
                },
                "onSettingChanged.showSaveButton": {
                    "this": "{that}.dom.saveButtonContainer",
                    "method": "show",
                    "args": []
                }
            },
            invokers: {
                applySettings: {
                    "funcName": "gpii.applySettings",
                    "args": "{that}"
                },
                showUserStatusBar: {
                    "this": "{that}.dom.userStatusBar",
                    "method": "slideDown"
                },
                saveSettings: {
                    "func": "{gpiiStore}.set",
                    "args": "{that}.model",
                    "dynamic": true
                },
                preventDefaultLinkEvent: {
                    "funcName": "gpii.eventUtility.preventDefaultEvent"
                }
            },
            selectors: {
                saveAndApply: ".flc-prefsEditor-save",
                saveButtonContainer: ".gpii-pcp-saveButtonContainer",
                cloudIcon: ".gpii-pcp-cloudIcon",
                messageLineLabel: ".gpiic-prefsEditor-messageLine",
                fullEditorLink: ".gpiic-prefsEditor-fullEditorLink",
                logoutLink: ".gpiic-prefsEditor-userLogoutLink"
            },
            selectorsToIgnore: ["cloudIcon"]
        }
    });

    gpii.applySettings = function (that) {
        var savedSettings = that.modelTransform(that.model);
        if (that.socket) {
            that.socket.emit("message", savedSettings, fluid.log);
        } else {
            that.socket = that.socket || io.connect("http://localhost:8081/update");
            that.socket.on("connect", function () {
                that.socket.emit("message", savedSettings, fluid.log);
            });
            fluid.each(["error", "disconnect"], function (event) {
                that.socket.on(event, function (data) {
                    fluid.log(data);
                    that.socket.disconnect();
                    delete that.socket;
                });
            });
        }
    };

    gpii.prefsEditor.triggerEvent = function (that, targetSelector, event) {
        that.locate(targetSelector).trigger(event);
    };
})(jQuery, fluid);
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react'
import Nearby from './NearbyComponent'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import * as SearchActions from '../actions/SearchActions'
import { updateTitle } from '../actions/LocaleActions'
import DocumentTitle from './addon/document-title'
import { BaseComponent } from 'shared/components'
import { runGeoLoc } from 'shared/utils/geoloc-utils'
import { Loading } from 'shared/components/addon/loading'
import { isEmpty } from 'lodash'

if (process.env.BROWSER) {
  require('css/addon/pin')
  require('css/addon/nearby')
}

class NearbyHandler extends BaseComponent {

  static propTypes = {
    dispatch: PropTypes.func.isRequired,
    search: PropTypes.object.isRequired
  }

  static contextTypes = {
    store: PropTypes.object.isRequired
  }

  constructor (props, context) {
    super(props)
    const { dispatch } = context.store
    dispatch(updateTitle('title.nearby'))

    const center = [25.018536, 121.529146]
    dispatch(SearchActions.updateNearbyCenter({ center }))

    runGeoLoc().then((position) => {
      dispatch(SearchActions.nearby({
        dist: 1000,
        lat: position.coords.latitude,
        lng: position.coords.longitude
      }, 50)).then((info) => {
        const { pattern } = info
        setTimeout(() => {
          dispatch(SearchActions.updateNearbyCenter({ center: [
            pattern.lat, pattern.lng
          ] }))
        }, 500)
      })
    }).catch((err) => {
      // fallback
      dispatch(SearchActions.nearby({
        dist: 1000,
        lat: center[0],
        lng: center[1]
      }, 30)).then(() => {
        setTimeout(() => {
          dispatch(SearchActions.updateNearbyCenter({ center }))
        }, 500)
      })
    })
  }

  componentDidMount () {
    Loading.show('正在努力找尋您附近的活動...')
  }

  componentWillReceiveProps (nextProps) {
    if (!nextProps.search.isFetching) {
      setTimeout(() => {
        Loading.hide()
      }, 4000)
    }
  }

  render () {
    const { dispatch, search } = this.props

    const title = this._T('title.nearby')
    const defaultTitle = this._T('title.site')

    return (
      <DocumentTitle title={title} defaultTitle={defaultTitle}>
        <Nearby
          {...this.props}
          {...bindActionCreators(SearchActions, dispatch)}
          defaultLocale={this.getLocale()}
        />
      </DocumentTitle>
    )
  }
}

export default connect(state => ({
  search: state.search
}))(NearbyHandler)
<commit_msg>more delay...<commit_after>import React, { PropTypes } from 'react'
import Nearby from './NearbyComponent'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import * as SearchActions from '../actions/SearchActions'
import { updateTitle } from '../actions/LocaleActions'
import DocumentTitle from './addon/document-title'
import { BaseComponent } from 'shared/components'
import { runGeoLoc } from 'shared/utils/geoloc-utils'
import { Loading } from 'shared/components/addon/loading'
import { isEmpty } from 'lodash'

if (process.env.BROWSER) {
  require('css/addon/pin')
  require('css/addon/nearby')
}

class NearbyHandler extends BaseComponent {

  static propTypes = {
    dispatch: PropTypes.func.isRequired,
    search: PropTypes.object.isRequired
  }

  static contextTypes = {
    store: PropTypes.object.isRequired
  }

  constructor (props, context) {
    super(props)
    const { dispatch } = context.store
    dispatch(updateTitle('title.nearby'))

    const center = [25.018536, 121.529146]
    dispatch(SearchActions.updateNearbyCenter({ center }))

    runGeoLoc().then((position) => {
      dispatch(SearchActions.nearby({
        dist: 1000,
        lat: position.coords.latitude,
        lng: position.coords.longitude
      }, 50)).then((info) => {
        const { pattern } = info
        setTimeout(() => {
          dispatch(SearchActions.updateNearbyCenter({ center: [
            pattern.lat, pattern.lng
          ] }))
        }, 500)
      })
    }).catch((err) => {
      // fallback
      dispatch(SearchActions.nearby({
        dist: 1000,
        lat: center[0],
        lng: center[1]
      }, 30)).then(() => {
        setTimeout(() => {
          dispatch(SearchActions.updateNearbyCenter({ center }))
        }, 500)
      })
    })
  }

  componentDidMount () {
    Loading.show('正在努力找尋您附近的活動...')
  }

  componentWillReceiveProps (nextProps) {
    if (!nextProps.search.isFetching) {
      setTimeout(() => {
        Loading.hide()
      }, 5000)
    }
  }

  render () {
    const { dispatch, search } = this.props

    const title = this._T('title.nearby')
    const defaultTitle = this._T('title.site')

    return (
      <DocumentTitle title={title} defaultTitle={defaultTitle}>
        <Nearby
          {...this.props}
          {...bindActionCreators(SearchActions, dispatch)}
          defaultLocale={this.getLocale()}
        />
      </DocumentTitle>
    )
  }
}

export default connect(state => ({
  search: state.search
}))(NearbyHandler)
<|endoftext|>


<commit_before>/**
 * Created by nickbespalov on 08.05.15.
 */
'use strict';

var LocalStorageDataProvider = {

    /**
     * Write data into local storage.
     * If browser does not have it nothing happens.
     * @param {string} key The name of the local storage property
     * @param {*} value
     */
    write: function (key, value) {
        if (typeof localStorage === 'object') {
            localStorage.setItem(key, JSON.stringify(value));
        }
    },

    /**
     * Read data from the local storage.
     * If there is no local storage returns undefined.
     * @param {string} key The name of the local storage property
     * @returns {undefined/*} The value of the given property
     */
    read: function (key) {
        if (typeof localStorage === 'object') {
            return JSON.parse(localStorage.getItem(key));
        }
    },

    /**
     * Create a category item.
     * @param  {string} collectionKey The name of the new collection
     */
    createCollection: function (collectionKey) {
        this.write(collectionKey, {});

    }

};

module.exports = LocalStorageDataProvider;
<commit_msg>fix typo<commit_after>/**
 * Created by nickbespalov on 08.05.15.
 */
'use strict';

var LocalStorageDataProvider = {

    /**
     * Write data into local storage.
     * If browser does not have it nothing happens.
     * @param {string} key The name of the local storage property
     * @param {*} value
     */
    write: function (key, value) {
        if (typeof localStorage === 'object') {
            localStorage.setItem(key, JSON.stringify(value));
        }
    },

    /**
     * Read data from the local storage.
     * If there is no local storage returns undefined.
     * @param {string} key The name of the local storage property
     * @returns {undefined/*} The value of the given property
     */
    read: function (key) {
        if (typeof localStorage === 'object') {
            return JSON.parse(localStorage.getItem(key));
        }
    },

    /**
     * Create new collection.
     * @param  {string} collectionKey The name of the new collection
     */
    createCollection: function (collectionKey) {
        this.write(collectionKey, {});

    }

};

module.exports = LocalStorageDataProvider;
<|endoftext|>


<commit_before>describe('the palindrome canary test', () => {
  it('shows the infrastructure works', () => {
    true.should.equal(true);
  });

  describe('palindrome should be', () => {
    it('yes for mom', () => {
      isPalindrome('mom').should.equal(true);
    });

    it('yes for dad');
    it('no for dude');
    it('yes for mom mom');
    it('no for mom dad');
    it('no for empty phrase');
    it('no for whitespace only phrase');
  });
});
<commit_msg>pass mom is palindrome test<commit_after>describe('the palindrome canary test', () => {
  it('shows the infrastructure works', () => {
    true.should.equal(true);
  });

  const isPalindrome = phrase => true;

  describe('palindrome should be', () => {
    it('yes for mom', () => {
      isPalindrome('mom').should.equal(true);
    });

    it('yes for dad');
    it('no for dude');
    it('yes for mom mom');
    it('no for mom dad');
    it('no for empty phrase');
    it('no for whitespace only phrase');
  });
});
<|endoftext|>


<commit_before>const authService = require('../services/auth-service');
const barmanService = require('../services/barman-service');
const userService = require('../services/user-service');
const specialAccountService = require('../services/special-account-service');
const { createUserError, parseStartAndEnd } = require('../../utils');
const { Barman, SpecialAccount, ConnectionInformation } = require('../models');
const { BarmanSchema, SpecialAccountSchema } = require('../models/schemas');
const Joi = require('joi');
const logger = require('../../logger');

/**
 * Send information about the connected user.
 *
 * @param req Request
 * @param res Response
 * @return {Promise.<{ barman: Barman, specialAccount: SpecialAccount}>} The connected user's information
 */
async function me(req, res) {
    const user = await authService.me(req.user.jit);

    res.send(user);
}

/**
 *
 * @param req
 * @param res
 * @returns {Promise<void>}
 */
async function updateMe(req, res) {
    const user = await authService.me(req.user.jit);

    if (user.specialAccount) {
        const schema = SpecialAccountSchema.min(1);
        const newSA = req.body.specialAccount;

        const { error } = schema.validate(newSA);
        if (error) throw createUserError('BadRequest', error.message);

        const code = req.body.code;

        if (!code) {
            throw createUserError('BadRequest', 'body.code is missing');
        }

        if (!await userService.checkCode(req.user.userId, code)) {
            throw createUserError('CodeError', 'The code provided is wrong');
        }

        logger.info(`Secure action at ${req.method} ${req.originalUrl} done by user id ${req.user.userId}`);

        let newSpecialAccount = new SpecialAccount(
            {
                ...newSA,
                _embedded: undefined, // Remove the only external object
            },
            {
                include: [
                    {
                        model: ConnectionInformation,
                        as: 'connection',
                    }
                ]
            }
        );

        newSpecialAccount = await specialAccountService
            .updateSpecialAccountById(user.specialAccount.id, newSpecialAccount);

        res.json({ specialAccount: newSpecialAccount, barman: undefined });
    }
    if (user.barman) {
        const schema = BarmanSchema.min(1);

        const newUser = req.body.barman;

        const { error } = schema.validate(newUser);
        if (error) throw createUserError('BadRequest', error.message);

        if (newUser.active) throw createUserError('BadRequest', 'Active field is not allowed throw PUT /me');

        let newBarman = new Barman(
            {
                ...newUser,
                _embedded: undefined, // Remove the only external object
            },
            {
                include: [
                    {
                        model: ConnectionInformation,
                        as: 'connection',
                    }
                ]
            }
        );

        newBarman = await barmanService.updateBarmanById(user.barman.id, newBarman);

        res.json({ specialAccount: undefined, barman: newBarman });
    }
}

/**
 *
 * @param req
 * @param res
 * @returns {Promise<void>}
 */
async function getBarmanService(req, res) {
    const { start, end } = parseStartAndEnd(req.query);
    const services = await barmanService.getBarmanServices(req.barman.id, start, end);

    res.json(services);
}

/**
 *
 * @param req
 * @param res
 * @returns {Promise<void>}
 */
async function addBarmanService(req, res) {
    const schema = Joi.array().items(Joi.number().integer().required()).required();

    const { error } = schema.validate(req.body);
    if (error) throw createUserError('BadRequest', error.message);

    const servicesId = req.body;

    await barmanService.createServiceBarman(req.barman.id, servicesId);

    res.send();
}

/**
 *
 * @param req
 * @param res
 * @returns {Promise<void>}
 */
async function removeBarmanService(req, res) {
    const schema = Joi.array().items(Joi.number().integer().required()).required();

    const { error } = schema.validate(req.body);
    if (error) throw createUserError('BadRequest', error.message);

    const servicesId = req.body;

    await barmanService.deleteServiceBarman(req.barman.id, servicesId);

    res.send();
}

module.exports = {
    me,
    updateMe,
    getBarmanService,
    addBarmanService,
    removeBarmanService,
};
<commit_msg>Use Joi to check active field<commit_after>const authService = require('../services/auth-service');
const barmanService = require('../services/barman-service');
const userService = require('../services/user-service');
const specialAccountService = require('../services/special-account-service');
const { createUserError, parseStartAndEnd } = require('../../utils');
const { Barman, SpecialAccount, ConnectionInformation } = require('../models');
const { BarmanSchema, SpecialAccountSchema } = require('../models/schemas');
const Joi = require('joi');
const logger = require('../../logger');

/**
 * Send information about the connected user.
 *
 * @param req Request
 * @param res Response
 * @return {Promise.<{ barman: Barman, specialAccount: SpecialAccount}>} The connected user's information
 */
async function me(req, res) {
    const user = await authService.me(req.user.jit);

    res.send(user);
}

/**
 *
 * @param req
 * @param res
 * @returns {Promise<void>}
 */
async function updateMe(req, res) {
    const user = await authService.me(req.user.jit);

    if (user.specialAccount) {
        const schema = SpecialAccountSchema.min(1);
        const newSA = req.body.specialAccount;

        const { error } = schema.validate(newSA);
        if (error) throw createUserError('BadRequest', error.message);

        const code = req.body.code;

        if (!code) {
            throw createUserError('BadRequest', 'body.code is missing');
        }

        if (!await userService.checkCode(req.user.userId, code)) {
            throw createUserError('CodeError', 'The code provided is wrong');
        }

        logger.info(`Secure action at ${req.method} ${req.originalUrl} done by user id ${req.user.userId}`);

        let newSpecialAccount = new SpecialAccount(
            {
                ...newSA,
                _embedded: undefined, // Remove the only external object
            },
            {
                include: [
                    {
                        model: ConnectionInformation,
                        as: 'connection',
                    },
                ],
            },
        );

        newSpecialAccount = await specialAccountService
            .updateSpecialAccountById(user.specialAccount.id, newSpecialAccount);

        res.json({ specialAccount: newSpecialAccount, barman: undefined });
    }
    if (user.barman) {
        const schema = BarmanSchema
            .forbiddenKeys('active')
            .min(1);

        const newUser = req.body.barman;

        const { error } = schema.validate(newUser);
        if (error) throw createUserError('BadRequest', error.message);

        let newBarman = new Barman(
            {
                ...newUser,
                _embedded: undefined, // Remove the only external object
            },
            {
                include: [
                    {
                        model: ConnectionInformation,
                        as: 'connection',
                    },
                ],
            },
        );

        newBarman = await barmanService.updateBarmanById(user.barman.id, newBarman, null);

        res.json({ specialAccount: undefined, barman: newBarman });
    }
}

/**
 *
 * @param req
 * @param res
 * @returns {Promise<void>}
 */
async function getBarmanService(req, res) {
    const { start, end } = parseStartAndEnd(req.query);
    const services = await barmanService.getBarmanServices(req.barman.id, start, end);

    res.json(services);
}

/**
 *
 * @param req
 * @param res
 * @returns {Promise<void>}
 */
async function addBarmanService(req, res) {
    const schema = Joi.array().items(Joi.number().integer().required()).required();

    const { error } = schema.validate(req.body);
    if (error) throw createUserError('BadRequest', error.message);

    const servicesId = req.body;

    await barmanService.createServiceBarman(req.barman.id, servicesId);

    res.send();
}

/**
 *
 * @param req
 * @param res
 * @returns {Promise<void>}
 */
async function removeBarmanService(req, res) {
    const schema = Joi.array().items(Joi.number().integer().required()).required();

    const { error } = schema.validate(req.body);
    if (error) throw createUserError('BadRequest', error.message);

    const servicesId = req.body;

    await barmanService.deleteServiceBarman(req.barman.id, servicesId);

    res.send();
}

module.exports = {
    me,
    updateMe,
    getBarmanService,
    addBarmanService,
    removeBarmanService,
};
<|endoftext|>