<commit_before>'use strict';

import React from 'react/addons';

import classNames from 'classnames';

import Icon from './Icon.js';
import TimeFormatter from './TimeFormatter.js';
import GroupAttributes from './GroupAttributes.js';
import ArtworkImage from './ArtworkImage.js';

import CollectionStore from '../stores/CollectionStore.js';
import CollectionActions from '../actions/CollectionActions.js';

import NowPlayingStore from '../stores/NowPlayingStore.js';

export class RootCollection extends React.Component {
  render() {
    var path = ["Root"];
    if (this.props.path) {
      path = this.props.path;
    }
    return <GroupContent path={path} depth={0} />;
  }
}

export class Group extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      expanded: (this.props.depth !== 1) || CollectionStore.isExpanded(this.props.path),
      common: {}
    };

    this.setCommon = this.setCommon.bind(this);

    this._onClick = this._onClick.bind(this);
    this._onClickName = this._onClickName.bind(this);
    this._onPlayNow = this._onPlayNow.bind(this);
    this._onQueue = this._onQueue.bind(this);
  }

  setCommon(c) {
    this.setState({common: c});
  }

  render() {
    var content = null;
    var play = null;
    var headerDiv = null;
    var image = null;

    if (this.state.expanded) {
      content = [
        <GroupContent path={this.props.path} depth={this.props.depth} setCommon={this.setCommon} key="GroupContent0" />
      ];

      if (this.props.depth === 1) {
        content.push(

        );
      }

      var common = this.state.common;
      var duration = null;
      if (this.state.common.TotalTime) {
        duration = <TimeFormatter className="duration" time={parseInt(common.TotalTime/1000)} />;
      }

      // NB: To avoid duplications, ignore AlbumArtist if we have a common Artist
      if (common.AlbumArtist && common.Artist) {
        delete common.AlbumArtist;
      }

      var attributeArr = [];
      var fields = ['AlbumArtist', 'Artist', 'Composer', 'Year'];
      fields.forEach(function(f) {
        if (common[f]) {
          attributeArr.push(common[f]);
        }
      });

      var attributes = null;
      if (attributeArr.length > 0) {
        attributes = <GroupAttributes list={attributeArr} />;
      }

      play = (

          <Icon icon="play" title="Play Now" onClick={this._onPlayNow} />
          <Icon icon="list" title="Queue" onClick={this._onQueue} />
          {duration}
          {attributes}

      );

      if (this.state.common.TrackID && this.props.depth == 1) {
        image = <ArtworkImage path={"/artwork/" + common.TrackID} />;
      }
    }

    // FIXME: this is to get around the "everything else" group which has no name
    // (and can't be closed)
    var itemName = this.props.item.Name;
    if (this.props.depth === 1 && itemName === "") {
      itemName = "Misc";
    }

    var albumArtist = null;
    if (this.props.depth === 1 && this.props.item.AlbumArtist !== "") {
      albumArtist = {this.props.item.AlbumArtist};
    }

    if (itemName !== "") {
      headerDiv = (

          {image}
          {itemName}{albumArtist}
          {play}

      );
    }

    var groupClasses = {
      'group': true,
      'untitled': this.props.item.Name === "",
      'expanded': this.state.expanded
    };

    return (

        {headerDiv}
        {content}

    );
  }

  _onClick(e) {
    if (!this.state.expanded) {
      this._onClickName(e);
    }
  }

  _onClickName(e) {
    e.stopPropagation();
    this.setState({expanded: !this.state.expanded});
    CollectionActions.expandPath(this.props.path, !this.state.expanded);
  }

  _onPlayNow(e) {
    CollectionActions.playNow(this.props.path);
    e.stopPropagation();
  }

  _onQueue(e) {
    CollectionActions.appendToPlaylist(this.props.path);
    e.stopPropagation();
  }

}

Group.propTypes = {
  path: React.PropTypes.array.isRequired,
  item: React.PropTypes.object.isRequired,
  depth: React.PropTypes.number.isRequired
};

class GroupContent extends React.Component {
  constructor(props) {
    super(props);

    this.state = {item: null};
    this._onChange = this._onChange.bind(this);
  }

  componentDidMount() {
    CollectionStore.addChangeListener(this._onChange);
    CollectionActions.fetch(this.props.path);
  }

  componentWillUnmount() {
    CollectionStore.removeChangeListener(this._onChange);
  }

  render() {
    var item = this.state.item;
    if (item === null) {
      return null;
    }

    if (item.Groups) {
      return <GroupList path={this.props.path} depth={this.props.depth} list={item.Groups} />;
    }
    return <TrackList path={this.props.path} list={item.Tracks} listStyle={item.ListStyle} />;
  }

  _onChange(keyPath) {
    if (CollectionStore.pathToKey(this.props.path) === keyPath) {
      var item = CollectionStore.getCollection(this.props.path);

      var common = {};
      var fields = ['TotalTime', 'AlbumArtist', 'Artist', 'TrackID', 'Composer', 'Year'];
      fields.forEach(function(f) {
        if (item[f]) {
          common[f] = item[f];
        }
      });

      if (Object.keys(common).length > 0 && this.props.setCommon) {
        this.props.setCommon(common);
      }
      this.setState({item: item});
    }
  }
}

GroupContent.propTypes = {
  path: React.PropTypes.array.isRequired,
  depth: React.PropTypes.number.isRequired
};

class GroupList extends React.Component {
  render() {
    var list = this.props.list.map(function(item) {
      return <Group path={this.props.path.concat([item.Key])} depth={this.props.depth + 1} item={item} key={item.Key} />;
    }.bind(this));

    return (

        {list}

    );
  }
}

GroupList.propTypes = {
  path: React.PropTypes.array.isRequired,
  depth: React.PropTypes.number.isRequired,
  list: React.PropTypes.array.isRequired
};

class TrackList extends React.Component {
  render() {
    var discs = {};
    var discIndices = [];
    var trackNumber = 0;
    this.props.list.forEach(function(track) {
      var discNumber = track.DiscNumber;
      if (!discs[discNumber]) {
        discs[discNumber] = [];
        discIndices.push(discNumber);
      }
      track.Key = ""+(trackNumber++);
      discs[discNumber].push(track);
    });

    var ols = [];
    var buildTrack = function(track) {
      return <Track key={track.TrackID} data={track} path={this.props.path.concat([track.Key])} />;
    }.bind(this);

    for (var i = 0; i < discIndices.length; i++) {
      var disc = discs[discIndices[i]];
      ols.push(

          {disc.map(buildTrack)}

      );
    }

    return (

        {ols}

    );
  }
}

TrackList.propTypes = {
  path: React.PropTypes.array.isRequired,
  list: React.PropTypes.array.isRequired,
  listStyle: React.PropTypes.string.isRequired,
};

function isCurrent(trackId) {
  var t = NowPlayingStore.getTrack();
  if (t) {
    return t.TrackID === trackId;
  }
  return false;
}

function getTrackState(trackID) {
  return {
    current: isCurrent(trackID),
    playing: NowPlayingStore.getPlaying()
  };
}

class Track extends React.Component {
  constructor(props) {
    super(props);

    this.state = getTrackState(this.props.data.TrackID);
    this._onChange = this._onChange.bind(this);
    this._onClick = this._onClick.bind(this);
    this._onPlayNow = this._onPlayNow.bind(this);
    this._onQueue = this._onQueue.bind(this);
  }

  componentDidMount() {
    NowPlayingStore.addChangeListener(this._onChange);
  }

  componentWillUnmount() {
    NowPlayingStore.removeChangeListener(this._onChange);
  }

  render() {
    var durationSecs = parseInt(this.props.data.TotalTime/1000);
    var liClasses = {
      'current': this.state.current,
      'playing': this.state.current && this.state.playing
    };
    return (

        {this.props.data.Name}
        <TimeFormatter className="duration" time={durationSecs} />

          <Icon icon="play" title="Play Now" onClick={this._onPlayNow} />
          <Icon icon="list" title="Queue" onClick={this._onQueue} />

    );
  }

  _onChange() {
    this.setState(getTrackState(this.props.data.TrackID));
  }

  _onClick(e) {
    e.stopPropagation();
    CollectionActions.setCurrentTrack(this.props.data);
  }

  _onPlayNow(e) {
    e.stopPropagation();
    CollectionActions.playNow(this.props.path.concat([this.props.Key]));
  }

  _onQueue(e) {
    e.stopPropagation();
    CollectionActions.appendToPlaylist(this.props.path.concat([this.props.Key]));
  }
}

Track.propTypes = {path: React.PropTypes.array.isRequired};
<commit_msg>Allow the user to collapse a Group by clicking anywhere in it's header.<commit_after>'use strict';

import React from 'react/addons';

import classNames from 'classnames';

import Icon from './Icon.js';
import TimeFormatter from './TimeFormatter.js';
import GroupAttributes from './GroupAttributes.js';
import ArtworkImage from './ArtworkImage.js';

import CollectionStore from '../stores/CollectionStore.js';
import CollectionActions from '../actions/CollectionActions.js';

import NowPlayingStore from '../stores/NowPlayingStore.js';

export class RootCollection extends React.Component {
  render() {
    var path = ["Root"];
    if (this.props.path) {
      path = this.props.path;
    }
    return <GroupContent path={path} depth={0} />;
  }
}

export class Group extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      expanded: (this.props.depth !== 1) || CollectionStore.isExpanded(this.props.path),
      common: {}
    };

    this.setCommon = this.setCommon.bind(this);

    this._onClick = this._onClick.bind(this);
    this._onClickHeader = this._onClickHeader.bind(this);
    this._onClickImage = this._onClickImage.bind(this);
    this._onPlayNow = this._onPlayNow.bind(this);
    this._onQueue = this._onQueue.bind(this);
  }

  setCommon(c) {
    this.setState({common: c});
  }

  render() {
    var content = null;
    var play = null;
    var headerDiv = null;
    var image = null;

    if (this.state.expanded) {
      content = [
        <GroupContent path={this.props.path} depth={this.props.depth} setCommon={this.setCommon} key="GroupContent0" />
      ];

      if (this.props.depth === 1) {
        content.push(

        );
      }

      var common = this.state.common;
      var duration = null;
      if (this.state.common.TotalTime) {
        duration = <TimeFormatter className="duration" time={parseInt(common.TotalTime/1000)} />;
      }

      // NB: To avoid duplications, ignore AlbumArtist if we have a common Artist
      if (common.AlbumArtist && common.Artist) {
        delete common.AlbumArtist;
      }

      var attributeArr = [];
      var fields = ['AlbumArtist', 'Artist', 'Composer', 'Year'];
      fields.forEach(function(f) {
        if (common[f]) {
          attributeArr.push(common[f]);
        }
      });

      var attributes = null;
      if (attributeArr.length > 0) {
        attributes = <GroupAttributes list={attributeArr} />;
      }

      play = (

          <Icon icon="play" title="Play Now" onClick={this._onPlayNow} />
          <Icon icon="list" title="Queue" onClick={this._onQueue} />
          {duration}
          {attributes}

      );

      if (this.state.common.TrackID && this.props.depth == 1) {
        image = <ArtworkImage path={"/artwork/" + common.TrackID} onClick={this._onClickImage}/>;
      }
    }

    // FIXME: this is to get around the "everything else" group which has no name
    // (and can't be closed)
    var itemName = this.props.item.Name;
    if (this.props.depth === 1 && itemName === "") {
      itemName = "Misc";
    }

    var albumArtist = null;
    if (this.props.depth === 1 && this.props.item.AlbumArtist !== "") {
      albumArtist = {this.props.item.AlbumArtist};
    }

    if (itemName !== "") {
      headerDiv = (

          {image}
          {itemName}{albumArtist}
          {play}

      );
    }

    var groupClasses = {
      'group': true,
      'untitled': this.props.item.Name === "",
      'expanded': this.state.expanded
    };

    return (

        {headerDiv}
        {content}

    );
  }

  _onClick(e) {
    if (!this.state.expanded) {
      this._onClickHeader(e);
    }
  }

  _onClickHeader(e) {
    e.stopPropagation();
    this.setState({expanded: !this.state.expanded});
    CollectionActions.expandPath(this.props.path, !this.state.expanded);
  }

  _onClickImage(e) {
    e.stopPropagation();
  }

  _onPlayNow(e) {
    CollectionActions.playNow(this.props.path);
    e.stopPropagation();
  }

  _onQueue(e) {
    CollectionActions.appendToPlaylist(this.props.path);
    e.stopPropagation();
  }

}

Group.propTypes = {
  path: React.PropTypes.array.isRequired,
  item: React.PropTypes.object.isRequired,
  depth: React.PropTypes.number.isRequired
};

class GroupContent extends React.Component {
  constructor(props) {
    super(props);

    this.state = {item: null};
    this._onChange = this._onChange.bind(this);
  }

  componentDidMount() {
    CollectionStore.addChangeListener(this._onChange);
    CollectionActions.fetch(this.props.path);
  }

  componentWillUnmount() {
    CollectionStore.removeChangeListener(this._onChange);
  }

  render() {
    var item = this.state.item;
    if (item === null) {
      return null;
    }

    if (item.Groups) {
      return <GroupList path={this.props.path} depth={this.props.depth} list={item.Groups} />;
    }
    return <TrackList path={this.props.path} list={item.Tracks} listStyle={item.ListStyle} />;
  }

  _onChange(keyPath) {
    if (CollectionStore.pathToKey(this.props.path) === keyPath) {
      var item = CollectionStore.getCollection(this.props.path);

      var common = {};
      var fields = ['TotalTime', 'AlbumArtist', 'Artist', 'TrackID', 'Composer', 'Year'];
      fields.forEach(function(f) {
        if (item[f]) {
          common[f] = item[f];
        }
      });

      if (Object.keys(common).length > 0 && this.props.setCommon) {
        this.props.setCommon(common);
      }
      this.setState({item: item});
    }
  }
}

GroupContent.propTypes = {
  path: React.PropTypes.array.isRequired,
  depth: React.PropTypes.number.isRequired
};

class GroupList extends React.Component {
  render() {
    var list = this.props.list.map(function(item) {
      return <Group path={this.props.path.concat([item.Key])} depth={this.props.depth + 1} item={item} key={item.Key} />;
    }.bind(this));

    return (

        {list}

    );
  }
}

GroupList.propTypes = {
  path: React.PropTypes.array.isRequired,
  depth: React.PropTypes.number.isRequired,
  list: React.PropTypes.array.isRequired
};

class TrackList extends React.Component {
  render() {
    var discs = {};
    var discIndices = [];
    var trackNumber = 0;
    this.props.list.forEach(function(track) {
      var discNumber = track.DiscNumber;
      if (!discs[discNumber]) {
        discs[discNumber] = [];
        discIndices.push(discNumber);
      }
      track.Key = ""+(trackNumber++);
      discs[discNumber].push(track);
    });

    var ols = [];
    var buildTrack = function(track) {
      return <Track key={track.TrackID} data={track} path={this.props.path.concat([track.Key])} />;
    }.bind(this);

    for (var i = 0; i < discIndices.length; i++) {
      var disc = discs[discIndices[i]];
      ols.push(

          {disc.map(buildTrack)}

      );
    }

    return (

        {ols}

    );
  }
}

TrackList.propTypes = {
  path: React.PropTypes.array.isRequired,
  list: React.PropTypes.array.isRequired,
  listStyle: React.PropTypes.string.isRequired,
};

function isCurrent(trackId) {
  var t = NowPlayingStore.getTrack();
  if (t) {
    return t.TrackID === trackId;
  }
  return false;
}

function getTrackState(trackID) {
  return {
    current: isCurrent(trackID),
    playing: NowPlayingStore.getPlaying()
  };
}

class Track extends React.Component {
  constructor(props) {
    super(props);

    this.state = getTrackState(this.props.data.TrackID);
    this._onChange = this._onChange.bind(this);
    this._onClick = this._onClick.bind(this);
    this._onPlayNow = this._onPlayNow.bind(this);
    this._onQueue = this._onQueue.bind(this);
  }

  componentDidMount() {
    NowPlayingStore.addChangeListener(this._onChange);
  }

  componentWillUnmount() {
    NowPlayingStore.removeChangeListener(this._onChange);
  }

  render() {
    var durationSecs = parseInt(this.props.data.TotalTime/1000);
    var liClasses = {
      'current': this.state.current,
      'playing': this.state.current && this.state.playing
    };
    return (

        {this.props.data.Name}
        <TimeFormatter className="duration" time={durationSecs} />

          <Icon icon="play" title="Play Now" onClick={this._onPlayNow} />
          <Icon icon="list" title="Queue" onClick={this._onQueue} />

    );
  }

  _onChange() {
    this.setState(getTrackState(this.props.data.TrackID));
  }

  _onClick(e) {
    e.stopPropagation();
    CollectionActions.setCurrentTrack(this.props.data);
  }

  _onPlayNow(e) {
    e.stopPropagation();
    CollectionActions.playNow(this.props.path.concat([this.props.Key]));
  }

  _onQueue(e) {
    e.stopPropagation();
    CollectionActions.appendToPlaylist(this.props.path.concat([this.props.Key]));
  }
}

Track.propTypes = {path: React.PropTypes.array.isRequired};
<|endoftext|>


<commit_before>export default function () {
  return true;
};
<commit_msg>fix(lib): Bump<commit_after>export default function () {
  return false;
};
<|endoftext|>


<commit_before>/** @jsx React.DOM */
'use strict';

var React = require('react/addons');

var classNames = require('classnames');

var Icon = require('./Icon.js');
var TimeFormatter = require('./TimeFormatter.js');
var GroupAttributes = require('./GroupAttributes.js');

var NowPlayingStore = require('../stores/NowPlayingStore.js');
var NowPlayingActions = require('../actions/NowPlayingActions.js');
var NowPlayingConstants = require('../constants/NowPlayingConstants.js');

var NowPlaying = React.createClass({
  getInitialState: function() {
    return {
      track: NowPlayingStore.getTrack(),
      playing: NowPlayingStore.getPlaying(),
      currentTime: NowPlayingStore.getTime(),
      buffered: 0,
      duration: 0,
    };
  },

  onPlayerEvent: function(evt) {
    switch (evt.type) {

    case "error":
      console.log("Error received from <audio> tag:");
      console.error(evt);
      break;

    case "progress":
      var range = this.buffered();
      if (range.length > 0) {
        NowPlayingActions.setBuffered(range.end(range.length-1));
      }
      break;

    case "play":
      NowPlayingActions.playing(true);
      break;

    case "pause":
      NowPlayingActions.playing(false);
      break;

    case "ended":
      NowPlayingActions.ended(NowPlayingStore.getSource());
      break;

    case "timeupdate":
      NowPlayingActions.currentTime(this.currentTime());
      break;

    case "loadedmetadata":
      NowPlayingActions.setDuration(this.duration());

      this.setCurrentTime(NowPlayingStore.getTime());
      if (this.state.playing) {
        this.play();
      }
      break;

    case "loadstart":
      NowPlayingActions.reset();
      break;

    default:
      console.warn("unhandled player event:");
      console.warn(evt);
      break;
    }
  },

  audioDOMNode: function() {
    return React.findDOMNode(this.refs.ref_audio);
  },

  buffered: function() {
    return this.audioDOMNode().buffered;
  },

  play: function() {
    this.audioDOMNode().play();
  },

  pause: function() {
    this.audioDOMNode().pause();
  },

  load: function() {
    this.audioDOMNode().load();
  },

  setCurrentTime: function(t) {
    this.audioDOMNode().currentTime = t;
  },

  currentTime: function() {
    return this.audioDOMNode().currentTime;
  },

  setVolume: function(t) {
    this.audioDOMNode().volume = t;
  },

  volume: function() {
    return this.audioDOMNode().volume;
  },

  duration: function() {
    return this.audioDOMNode().duration;
  },

  componentDidMount: function() {
    var audioNode = this.audioDOMNode();
    audioNode.addEventListener('error', this.onPlayerEvent);
    audioNode.addEventListener('progress', this.onPlayerEvent);
    audioNode.addEventListener('play', this.onPlayerEvent);
    audioNode.addEventListener('pause', this.onPlayerEvent);
    audioNode.addEventListener('ended', this.onPlayerEvent);
    audioNode.addEventListener('timeupdate', this.onPlayerEvent);
    audioNode.addEventListener('loadedmetadata', this.onPlayerEvent);
    audioNode.addEventListener('loadstart', this.onPlayerEvent);

    NowPlayingStore.addChangeListener(this._onChange);
    NowPlayingStore.addControlListener(this._onControl);

    var volume = NowPlayingStore.getVolume();
    if (NowPlayingStore.getVolumeMute()) {
      volume = 0.0;
    }
    this.setVolume(volume);
  },

  componentWillUnmount: function() {
    var audioNode = this.audioDOMNode();
    audioNode.removeEventListener('error', this.onPlayerEvent);
    audioNode.removeEventListener('progress', this.onPlayerEvent);
    audioNode.removeEventListener('play', this.onPlayerEvent);
    audioNode.removeEventListener('pause', this.onPlayerEvent);
    audioNode.removeEventListener('ended', this.onPlayerEvent);
    audioNode.removeEventListener('timeupdate', this.onPlayerEvent);
    audioNode.removeEventListener('loadedmetadata', this.onPlayerEvent);
    audioNode.removeEventListener('loadstart', this.onPlayerEvent);

    NowPlayingStore.removeChangeListener(this._onChange);
    NowPlayingStore.removeControlListener(this._onControl);
  },

  componentDidUpdate: function(prevProps, prevState) {
    if (this.state.track) {
      if (prevState.track === null || prevState.track.TrackID !== this.state.track.TrackID) {
        this.load();
        this.play();
      }
    }

    if (prevState.playing != this.state.playing) {
      if (this.state.playing) {
        this.play();
      } else {
        this.pause();
      }
    }

    var volume = NowPlayingStore.getVolume();
    if (this.volume() != volume) {
      this.setVolume(volume);
    }
  },

  render: function() {
    var trackID = "0";
    var source = null;
    var trackInfo = null;

    if (this.state.track) {
      trackID = this.state.track.TrackID;
      source = <source src={"/track/"+trackID} />;
      trackInfo = <TrackInfo />;
    }

    return (

        {trackInfo}
        <audio id={"player_"+trackID} ref="ref_audio">
         {source}
        </audio>

    );
  },

  _onChange: function() {
    this.setState({
      track: NowPlayingStore.getTrack(),
      playing: NowPlayingStore.getPlaying(),
    });

    setTimeout(0, function() {
      this.refs.now_playing.load();
    }.bind(this));
  },

  _onControl: function(type, value) {
    switch (type) {
      case NowPlayingConstants.SET_CURRENT_TIME:
        this.setCurrentTime(value);
        break;
    }
  }
});

function getTrackInfoState() {
  return {
    track: NowPlayingStore.getTrack(),
    buffered: NowPlayingStore.getBuffered(),
    duration: NowPlayingStore.getDuration(),
    currentTime: NowPlayingStore.getTime(),
  };
}

var TrackInfo = React.createClass({
  getInitialState: function() {
    return getTrackInfoState();
  },

  componentDidMount: function() {
    NowPlayingStore.addChangeListener(this._onChange);
  },

  componentWillUnmount: function() {
    NowPlayingStore.removeChangeListener(this._onChange);
  },

  render: function() {
    var track = this.state.track;
    var fields = ['Album', 'Artist', 'Year'];
    var attributeArr = [];
    fields.forEach(function(f) {
      if (track[f]) {
        attributeArr.push(track[f]);
      }
    });

    var attributes = <GroupAttributes list={attributeArr} />;
    var remainingTime = parseInt(this.state.duration) - parseInt(this.state.currentTime);

    return (

        <ArtworkImage path={"/artwork/" + track.TrackID} />
        {track.Name}<Icon icon="share-alt" />
        {attributes}

        <PlayProgress markerWidth={2} current={this.state.currentTime} duration={this.state.duration} buffered={this.state.buffered} setCurrentTime={NowPlayingActions.setCurrentTime} />

          <TimeFormatter className="currentTime" time={this.state.currentTime} />
          <TimeFormatter className="remaining" time={remainingTime} />

    );
  },

  _onChange: function() {
    this.setState(getTrackInfoState());
  }
});

var ArtworkImage = React.createClass({
  getInitialState: function() {
    return {
      visible: false,
    };
  },

  render: function() {
    var classes = {
      'visible': this.state.visible,
    };
    return (

    );
  },

  _onLoad: function() {
    this.setState({visible: true});
  },

  _onError: function() {
    this.setState({visible: false});
  },
});

function _getOffsetLeft(elem) {
    var offsetLeft = 0;
    do {
      if (!isNaN(elem.offsetLeft)) {
          offsetLeft += elem.offsetLeft;
      }
    } while ((elem = elem.offsetParent));
    return offsetLeft;
}

var PlayProgress = React.createClass({
  propTypes: {
    markerWidth: React.PropTypes.number.isRequired,
    current: React.PropTypes.number.isRequired,
    buffered: React.PropTypes.number.isRequired,
    duration: React.PropTypes.number.isRequired,
  },

  render: function() {
    var wpc = (this.props.current / this.props.duration) * 100;
    var w = "calc("+wpc+"% - " + this.props.markerWidth + "px)";
    var bpc = (this.props.buffered / this.props.duration) * 100 - wpc;
    var b = "calc("+bpc+"% - " + this.props.markerWidth + "px)";

    return (

    );
  },

  _onMouseDown: function(evt) {
    var pos = evt.pageX - _getOffsetLeft(evt.currentTarget);
    var width = evt.currentTarget.offsetWidth;
    this.props.setCurrentTime((pos / width) * this.props.duration);
  },

  _onWheel: function(evt) {
    evt.stopPropagation();
    var t = this.props.current + (0.01 * this.props.duration * evt.deltaY);
    if (t > this.props.duration) {
      t = this.props.duration;
    } else if (t < 0.00) {
      t = 0.0;
    }
    this.props.setCurrentTime(t);
  },
});

module.exports = NowPlaying;
<commit_msg>Remove unused variables from NowPlaying state<commit_after>/** @jsx React.DOM */
'use strict';

var React = require('react/addons');

var classNames = require('classnames');

var Icon = require('./Icon.js');
var TimeFormatter = require('./TimeFormatter.js');
var GroupAttributes = require('./GroupAttributes.js');

var NowPlayingStore = require('../stores/NowPlayingStore.js');
var NowPlayingActions = require('../actions/NowPlayingActions.js');
var NowPlayingConstants = require('../constants/NowPlayingConstants.js');

var NowPlaying = React.createClass({
  getInitialState: function() {
    return {
      track: NowPlayingStore.getTrack(),
      playing: NowPlayingStore.getPlaying(),
      currentTime: NowPlayingStore.getTime(),
    };
  },

  onPlayerEvent: function(evt) {
    switch (evt.type) {

    case "error":
      console.log("Error received from <audio> tag:");
      console.error(evt);
      break;

    case "progress":
      var range = this.buffered();
      if (range.length > 0) {
        NowPlayingActions.setBuffered(range.end(range.length-1));
      }
      break;

    case "play":
      NowPlayingActions.playing(true);
      break;

    case "pause":
      NowPlayingActions.playing(false);
      break;

    case "ended":
      NowPlayingActions.ended(NowPlayingStore.getSource());
      break;

    case "timeupdate":
      NowPlayingActions.currentTime(this.currentTime());
      break;

    case "loadedmetadata":
      NowPlayingActions.setDuration(this.duration());

      this.setCurrentTime(NowPlayingStore.getTime());
      if (this.state.playing) {
        this.play();
      }
      break;

    case "loadstart":
      NowPlayingActions.reset();
      break;

    default:
      console.warn("unhandled player event:");
      console.warn(evt);
      break;
    }
  },

  audioDOMNode: function() {
    return React.findDOMNode(this.refs.ref_audio);
  },

  buffered: function() {
    return this.audioDOMNode().buffered;
  },

  play: function() {
    this.audioDOMNode().play();
  },

  pause: function() {
    this.audioDOMNode().pause();
  },

  load: function() {
    this.audioDOMNode().load();
  },

  setCurrentTime: function(t) {
    this.audioDOMNode().currentTime = t;
  },

  currentTime: function() {
    return this.audioDOMNode().currentTime;
  },

  setVolume: function(t) {
    this.audioDOMNode().volume = t;
  },

  volume: function() {
    return this.audioDOMNode().volume;
  },

  duration: function() {
    return this.audioDOMNode().duration;
  },

  componentDidMount: function() {
    var audioNode = this.audioDOMNode();
    audioNode.addEventListener('error', this.onPlayerEvent);
    audioNode.addEventListener('progress', this.onPlayerEvent);
    audioNode.addEventListener('play', this.onPlayerEvent);
    audioNode.addEventListener('pause', this.onPlayerEvent);
    audioNode.addEventListener('ended', this.onPlayerEvent);
    audioNode.addEventListener('timeupdate', this.onPlayerEvent);
    audioNode.addEventListener('loadedmetadata', this.onPlayerEvent);
    audioNode.addEventListener('loadstart', this.onPlayerEvent);

    NowPlayingStore.addChangeListener(this._onChange);
    NowPlayingStore.addControlListener(this._onControl);

    var volume = NowPlayingStore.getVolume();
    if (NowPlayingStore.getVolumeMute()) {
      volume = 0.0;
    }
    this.setVolume(volume);
  },

  componentWillUnmount: function() {
    var audioNode = this.audioDOMNode();
    audioNode.removeEventListener('error', this.onPlayerEvent);
    audioNode.removeEventListener('progress', this.onPlayerEvent);
    audioNode.removeEventListener('play', this.onPlayerEvent);
    audioNode.removeEventListener('pause', this.onPlayerEvent);
    audioNode.removeEventListener('ended', this.onPlayerEvent);
    audioNode.removeEventListener('timeupdate', this.onPlayerEvent);
    audioNode.removeEventListener('loadedmetadata', this.onPlayerEvent);
    audioNode.removeEventListener('loadstart', this.onPlayerEvent);

    NowPlayingStore.removeChangeListener(this._onChange);
    NowPlayingStore.removeControlListener(this._onControl);
  },

  componentDidUpdate: function(prevProps, prevState) {
    if (this.state.track) {
      if (prevState.track === null || prevState.track.TrackID !== this.state.track.TrackID) {
        this.load();
        this.play();
      }
    }

    if (prevState.playing != this.state.playing) {
      if (this.state.playing) {
        this.play();
      } else {
        this.pause();
      }
    }

    var volume = NowPlayingStore.getVolume();
    if (this.volume() != volume) {
      this.setVolume(volume);
    }
  },

  render: function() {
    var trackID = "0";
    var source = null;
    var trackInfo = null;

    if (this.state.track) {
      trackID = this.state.track.TrackID;
      source = <source src={"/track/"+trackID} />;
      trackInfo = <TrackInfo />;
    }

    return (

        {trackInfo}
        <audio id={"player_"+trackID} ref="ref_audio">
         {source}
        </audio>

    );
  },

  _onChange: function() {
    this.setState({
      track: NowPlayingStore.getTrack(),
      playing: NowPlayingStore.getPlaying(),
    });

    setTimeout(0, function() {
      this.refs.now_playing.load();
    }.bind(this));
  },

  _onControl: function(type, value) {
    switch (type) {
      case NowPlayingConstants.SET_CURRENT_TIME:
        this.setCurrentTime(value);
        break;
    }
  }
});

function getTrackInfoState() {
  return {
    track: NowPlayingStore.getTrack(),
    buffered: NowPlayingStore.getBuffered(),
    duration: NowPlayingStore.getDuration(),
    currentTime: NowPlayingStore.getTime(),
  };
}

var TrackInfo = React.createClass({
  getInitialState: function() {
    return getTrackInfoState();
  },

  componentDidMount: function() {
    NowPlayingStore.addChangeListener(this._onChange);
  },

  componentWillUnmount: function() {
    NowPlayingStore.removeChangeListener(this._onChange);
  },

  render: function() {
    var track = this.state.track;
    var fields = ['Album', 'Artist', 'Year'];
    var attributeArr = [];
    fields.forEach(function(f) {
      if (track[f]) {
        attributeArr.push(track[f]);
      }
    });

    var attributes = <GroupAttributes list={attributeArr} />;
    var remainingTime = parseInt(this.state.duration) - parseInt(this.state.currentTime);

    return (

        <ArtworkImage path={"/artwork/" + track.TrackID} />
        {track.Name}<Icon icon="share-alt" />
        {attributes}

        <PlayProgress markerWidth={2} current={this.state.currentTime} duration={this.state.duration} buffered={this.state.buffered} setCurrentTime={NowPlayingActions.setCurrentTime} />

          <TimeFormatter className="currentTime" time={this.state.currentTime} />
          <TimeFormatter className="remaining" time={remainingTime} />

    );
  },

  _onChange: function() {
    this.setState(getTrackInfoState());
  }
});

var ArtworkImage = React.createClass({
  getInitialState: function() {
    return {
      visible: false,
    };
  },

  render: function() {
    var classes = {
      'visible': this.state.visible,
    };
    return (

    );
  },

  _onLoad: function() {
    this.setState({visible: true});
  },

  _onError: function() {
    this.setState({visible: false});
  },
});

function _getOffsetLeft(elem) {
    var offsetLeft = 0;
    do {
      if (!isNaN(elem.offsetLeft)) {
          offsetLeft += elem.offsetLeft;
      }
    } while ((elem = elem.offsetParent));
    return offsetLeft;
}

var PlayProgress = React.createClass({
  propTypes: {
    markerWidth: React.PropTypes.number.isRequired,
    current: React.PropTypes.number.isRequired,
    buffered: React.PropTypes.number.isRequired,
    duration: React.PropTypes.number.isRequired,
  },

  render: function() {
    var wpc = (this.props.current / this.props.duration) * 100;
    var w = "calc("+wpc+"% - " + this.props.markerWidth + "px)";
    var bpc = (this.props.buffered / this.props.duration) * 100 - wpc;
    var b = "calc("+bpc+"% - " + this.props.markerWidth + "px)";

    return (

    );
  },

  _onMouseDown: function(evt) {
    var pos = evt.pageX - _getOffsetLeft(evt.currentTarget);
    var width = evt.currentTarget.offsetWidth;
    this.props.setCurrentTime((pos / width) * this.props.duration);
  },

  _onWheel: function(evt) {
    evt.stopPropagation();
    var t = this.props.current + (0.01 * this.props.duration * evt.deltaY);
    if (t > this.props.duration) {
      t = this.props.duration;
    } else if (t < 0.00) {
      t = 0.0;
    }
    this.props.setCurrentTime(t);
  },
});

module.exports = NowPlaying;
<|endoftext|>


<commit_before>// Load in dependencies
var concat = require('concat-stream');
var Layout = require('layout');
var semver = require('semver');
var through2 = require('through2');

// Specify defaults
var engineDefault = 'pixelsmith';
var algorithmDefault = 'binary-tree';
var SPEC_VERSION_RANGE = '>=2.0.0 <3.0.0';

// Define our spritesmith constructor
function Spritesmith(params) {
  // Process our parameters
  var engineName = params.engine || engineDefault;
  var Engine = engineName;

  // If the engine is a `require` path, attempt to load it
  if (typeof engineName === 'string') {
    // Attempt to resolve the engine to verify it is installed at all
    try {
      require.resolve(engineName);
    } catch (err) {
      console.error('Attempted to find spritesmith engine "' + engineName + '" but could not.');
      console.error('Please verify you have installed "' + engineName + '" and saved it to your `package.json`');
      console.error('');
      console.error('    npm install ' + engineName + ' --save-dev');
      console.error('');
      throw err;
    }

    // Attempt to load the engine
    try {
      Engine = require(engineName);
    } catch (err) {
      console.error('Attempted to load spritesmith engine "' + engineName + '" but could not.');
      console.error('Please verify you have installed its dependencies. Documentation should be available at ');
      console.error('');
      // TODO: Consider using pkg.homepage and pkg.repository
      console.error('    https://npm.im/' + encodeURIComponent(engineName));
      console.error('');
      throw err;
    }
  }

  // Verify we are on a matching `specVersion`
  if (!semver.satisfies(Engine.specVersion, SPEC_VERSION_RANGE)) {
    throw new Error('Expected `engine` to have `specVersion` within "' + SPEC_VERSION_RANGE + '" ' +
      'but it was "' + Engine.specVersion + '". Please verify you are on the latest version of your engine: ' +
      '`npm install my-engine@latest`');
  }

  // Create and save our engine for later
  this.engine = new Engine(params.engineOpts || {});
}
// Gist of params: {src: files, engine: 'pixelsmith', algorithm: 'binary-tree'}
// Gist of result: img: buffer, info: {coordinates: {filepath: {x, y, width, height}}, properties: {width, height}}
Spritesmith.run = function (params, callback) {
  // Create a new spritesmith with our parameters
  var spritesmith = new Spritesmith(params);

  // In an async fashion, create our images
  spritesmith.createImages(params.src, function handleImages (err, images) {
    // If there was an error, callback with it
    if (err) {
      return callback(err);
    }

    // Otherwise, process our images, concat our img, and callback
    // DEV: We don't want to risk dropped `data` events due to calling back with a stream
    var spriteData = spritesmith.processImages(images, params);

    // If an error occurs on the image, then callback with it
    spriteData.img.on('error', callback);

    // Concatenate our image into a buffer
    spriteData.img.pipe(concat({encoding: 'buffer'}, function handleImg (buff) {
      // Callback with all our info
      callback(null, {
        info: spriteData.info,
        img: buff
      });
    }));
  });
};
Spritesmith.prototype = {
  createImages: function (files, callback) {
    // Forward image creation to our engine
    this.engine.createImages(files, function handleImags (err, images) {
      // If there was an error, callback with it
      if (err) {
        return callback(err);
      }

      // Otherwise, iterate over the images and save their paths (required for coordinates)
      images.forEach(function saveImagePath (img, i) {
        // DEV: We don't use `Vinyl.isVinyl` since that was introduced in Sep 2015
        //   We want some backwards compatibility with older setups
        var file = files[i];
        img._filepath = typeof file === 'object' ? file.path : file;
      });

      // Callback with our images
      callback(null, images);
    });
  },
  processImages: function (images, options) {
    // Set up our algorithm/layout placement and export configuration
    var algorithmName = options.algorithm || algorithmDefault;
    var layer = new Layout(algorithmName, options.algorithmOpts);
    var padding = options.padding || 0;
    var exportOpts = options.exportOpts || {};
    var packedObj;

    // Generate stream and info for returning
    var imgStream = through2();
    var infoObj = {};

    // Add our images to our canvas (dry run)
    images.forEach(function (img) {
      // Save the non-padded properties as meta data
      var width = img.width;
      var height = img.height;
      var meta = {img: img, actualWidth: width, actualHeight: height};

      // Add the item with padding to our layer
      layer.addItem({
        width: width + padding,
        height: height + padding,
        meta: meta
      });
    });

    // Then, output the coordinates
    // Export and saved packedObj for later
    packedObj = layer['export']();

    // Extract the coordinates
    var coordinates = {};
    var packedItems = packedObj.items;
    packedItems.forEach(function (item) {
      var meta = item.meta;
      var img = meta.img;
      var name = img._filepath;
      coordinates[name] = {
        x: item.x,
        y: item.y,
        width: meta.actualWidth,
        height: meta.actualHeight
      };
    });

    // Save the coordinates
    infoObj.coordinates = coordinates;

    // Then, generate a canvas
    // Grab and fallback the width/height
    var width = Math.max(packedObj.width || 0, 0);
    var height = Math.max(packedObj.height || 0, 0);

    // If there are items
    var itemsExist = packedObj.items.length;
    if (itemsExist) {
      // Remove the last item's padding
      width -= padding;
      height -= padding;
    }

    // Export the total width and height of the generated canvas
    infoObj.properties = {
      width: width,
      height: height
    };

    // After we return the stream and info
    var that = this;
    process.nextTick(function handleNextTick () {
      // If there are no items, return with an empty stream
      var canvas;
      if (!itemsExist) {
        imgStream.push(null);
        return;
      // Otherwise, generate and export our canvas
      } else {
        // Crete our canvas
        canvas = that.engine.createCanvas(width, height);

        // Add the images onto canvas
        try {
          packedObj.items.forEach(function addImage (item) {
            var img = item.meta.img;
            canvas.addImage(img, item.x, item.y);
          });
        } catch (err) {
          imgStream.emit('error', err);
          return;
        }

        // Export our canvas
        var exportStream = canvas['export'](exportOpts);
        exportStream.on('error', function forwardError (err) {
          imgStream.emit('error', err);
        });
        exportStream.pipe(imgStream);
      }
    });

    // Return our stream and info
    return {
      info: infoObj,
      img: imgStream
    };
  }
};

// Export Spritesmith
module.exports = Spritesmith;
<commit_msg>Coming full circle on API<commit_after>// Load in dependencies
var concat = require('concat-stream');
var Layout = require('layout');
var semver = require('semver');
var through2 = require('through2');

// Specify defaults
var engineDefault = 'pixelsmith';
var algorithmDefault = 'binary-tree';
var SPEC_VERSION_RANGE = '>=2.0.0 <3.0.0';

// Define our spritesmith constructor
function Spritesmith(params) {
  // Process our parameters
  var engineName = params.engine || engineDefault;
  var Engine = engineName;

  // If the engine is a `require` path, attempt to load it
  if (typeof engineName === 'string') {
    // Attempt to resolve the engine to verify it is installed at all
    try {
      require.resolve(engineName);
    } catch (err) {
      console.error('Attempted to find spritesmith engine "' + engineName + '" but could not.');
      console.error('Please verify you have installed "' + engineName + '" and saved it to your `package.json`');
      console.error('');
      console.error('    npm install ' + engineName + ' --save-dev');
      console.error('');
      throw err;
    }

    // Attempt to load the engine
    try {
      Engine = require(engineName);
    } catch (err) {
      console.error('Attempted to load spritesmith engine "' + engineName + '" but could not.');
      console.error('Please verify you have installed its dependencies. Documentation should be available at ');
      console.error('');
      // TODO: Consider using pkg.homepage and pkg.repository
      console.error('    https://npm.im/' + encodeURIComponent(engineName));
      console.error('');
      throw err;
    }
  }

  // Verify we are on a matching `specVersion`
  if (!semver.satisfies(Engine.specVersion, SPEC_VERSION_RANGE)) {
    throw new Error('Expected `engine` to have `specVersion` within "' + SPEC_VERSION_RANGE + '" ' +
      'but it was "' + Engine.specVersion + '". Please verify you are on the latest version of your engine: ' +
      '`npm install my-engine@latest`');
  }

  // Create and save our engine for later
  this.engine = new Engine(params.engineOpts || {});
}
// Gist of params: {src: files, engine: 'pixelsmith', algorithm: 'binary-tree'}
// Gist of result: img: buffer, coordinates: {filepath: {x, y, width, height}}, properties: {width, height}
Spritesmith.run = function (params, callback) {
  // Create a new spritesmith with our parameters
  var spritesmith = new Spritesmith(params);

  // In an async fashion, create our images
  spritesmith.createImages(params.src, function handleImages (err, images) {
    // If there was an error, callback with it
    if (err) {
      return callback(err);
    }

    // Otherwise, process our images, concat our img, and callback
    // DEV: We don't want to risk dropped `data` events due to calling back with a stream
    var spriteData = spritesmith.processImages(images, params);

    // If an error occurs on the image, then callback with it
    spriteData.img.on('error', callback);

    // Concatenate our image into a buffer
    spriteData.img.pipe(concat({encoding: 'buffer'}, function handleImg (buff) {
      // Callback with all our info
      callback(null, {
        coordinates: spriteData.coordinates,
        properties: spriteData.properties,
        img: buff
      });
    }));
  });
};
Spritesmith.prototype = {
  createImages: function (files, callback) {
    // Forward image creation to our engine
    this.engine.createImages(files, function handleImags (err, images) {
      // If there was an error, callback with it
      if (err) {
        return callback(err);
      }

      // Otherwise, iterate over the images and save their paths (required for coordinates)
      images.forEach(function saveImagePath (img, i) {
        // DEV: We don't use `Vinyl.isVinyl` since that was introduced in Sep 2015
        //   We want some backwards compatibility with older setups
        var file = files[i];
        img._filepath = typeof file === 'object' ? file.path : file;
      });

      // Callback with our images
      callback(null, images);
    });
  },
  processImages: function (images, options) {
    // Set up our algorithm/layout placement and export configuration
    var algorithmName = options.algorithm || algorithmDefault;
    var layer = new Layout(algorithmName, options.algorithmOpts);
    var padding = options.padding || 0;
    var exportOpts = options.exportOpts || {};
    var packedObj;

    // Generate stream and info for returning
    var imgStream = through2();
    var retObj = {img: imgStream};

    // Add our images to our canvas (dry run)
    images.forEach(function (img) {
      // Save the non-padded properties as meta data
      var width = img.width;
      var height = img.height;
      var meta = {img: img, actualWidth: width, actualHeight: height};

      // Add the item with padding to our layer
      layer.addItem({
        width: width + padding,
        height: height + padding,
        meta: meta
      });
    });

    // Then, output the coordinates
    // Export and saved packedObj for later
    packedObj = layer['export']();

    // Extract the coordinates
    var coordinates = {};
    var packedItems = packedObj.items;
    packedItems.forEach(function (item) {
      var meta = item.meta;
      var img = meta.img;
      var name = img._filepath;
      coordinates[name] = {
        x: item.x,
        y: item.y,
        width: meta.actualWidth,
        height: meta.actualHeight
      };
    });

    // Save the coordinates
    retObj.coordinates = coordinates;

    // Then, generate a canvas
    // Grab and fallback the width/height
    var width = Math.max(packedObj.width || 0, 0);
    var height = Math.max(packedObj.height || 0, 0);

    // If there are items
    var itemsExist = packedObj.items.length;
    if (itemsExist) {
      // Remove the last item's padding
      width -= padding;
      height -= padding;
    }

    // Export the total width and height of the generated canvas
    retObj.properties = {
      width: width,
      height: height
    };

    // After we return the stream and info
    var that = this;
    process.nextTick(function handleNextTick () {
      // If there are no items, return with an empty stream
      var canvas;
      if (!itemsExist) {
        imgStream.push(null);
        return;
      // Otherwise, generate and export our canvas
      } else {
        // Crete our canvas
        canvas = that.engine.createCanvas(width, height);

        // Add the images onto canvas
        try {
          packedObj.items.forEach(function addImage (item) {
            var img = item.meta.img;
            canvas.addImage(img, item.x, item.y);
          });
        } catch (err) {
          imgStream.emit('error', err);
          return;
        }

        // Export our canvas
        var exportStream = canvas['export'](exportOpts);
        exportStream.on('error', function forwardError (err) {
          imgStream.emit('error', err);
        });
        exportStream.pipe(imgStream);
      }
    });

    // Return our info
    return retObj;
  }
};

// Export Spritesmith
module.exports = Spritesmith;
<|endoftext|>


<commit_before>var fs = require("fs"),

    HttpError = require("http_error"),
    filePath = require("file_path");

function normalizeRoot(root) {
    if (!root || root === ".") return "/";
    if (root[0] === ".") root = root.slice(1);
    if (root[0] !== "/") root = "/" + root;
    if (root[root.length - 1] !== "/") root += "/";
    return root;
}

function StaticServe(opts) {
    opts || (opts = {});

    this.root = normalizeRoot(opts.root || "assets");
    this.rootLength = this.root.length;

    this.directory = opts.directory || "./app/assets";
    this.fullDirectory = filePath.join(process.cwd(), this.directory);

    this.index = opts.index || "index.html";

    this.options = {
        maxAge: opts.maxAge || 86400000,
        fallback: opts.fallback != null ? !!opts.fallback : false,
        etag: opts.etag != null ? !!opts.etag : true,
        lastModified: opts.lastModified != null ? !!opts.lastModified : true
    };
}

StaticServe.prototype.middleware = function(req, res, next) {
    var _this = this,
        method = req.method,
        url = req.url,
        fileName;

    if (method !== "GET" && method !== "HEAD") {
        next();
        return;
    }
    if (url.indexOf(this.root) !== 0) {
        next();
        return;
    }

    fileName = filePath.join(this.fullDirectory, url.substring(this.rootLength));

    fs.stat(fileName, function(err, stat) {
        if (err) {
            next(new HttpError(404, err));
            return;
        }
        if (!stat) {
            next();
            return;
        }

        if (stat.isDirectory()) {
            fileName = filePath.join(fileName, _this.index);

            fs.stat(fileName, function(err, stat) {
                if (err || !stat) {
                    next(new HttpError(404, err));
                    return;
                }

                _this.send(res, fileName, stat, next);
            });
        } else {
            _this.send(res, fileName, stat, next);
        }
    });
};

StaticServe.prototype.send = function(res, fileName, stat, callback) {
    var app = res.app,
        opts = this.options,
        modified = false;

    fs.readFile(fileName, function(err, buffer) {
        if (err) {
            callback(new HttpError(err));
            return;
        }
        var ext = filePath.ext(fileName),
            type = app.mime.lookUpType(ext, opts.fallback);

        if (type) {
            modified = res.modified(stat.mtime);

            res.contentLength = type;
            if (opts.maxAge && !res.getHeader("Cache-Control")) res.setHeader("Cache-Control", "public, max-age=" + (opts.maxAge / 1000));
            if (opts.etag && !res.getHeader("ETag")) res.setHeader("ETag", '"' + app.get("etag fn")(buffer) + '"');
            if (modified && opts.lastModified && !res.getHeader("Last-Modified")) res.setHeader("Last-Modified", new Date(stat.mtime));

            res.send(modified ? 200 : 304, buffer);
            callback();
            return;
        }

        callback(new HttpError(415, ext));
    });

    return this;
};

module.exports = StaticServe;
<commit_msg>updates<commit_after>var fs = require("fs"),

    HttpError = require("http_error"),
    filePath = require("file_path");

function normalizeRoot(root) {
    if (!root || root === ".") return "/";
    if (root[0] === ".") root = root.slice(1);
    if (root[0] !== "/") root = "/" + root;
    if (root[root.length - 1] !== "/") root += "/";
    return root;
}

function StaticServe(opts) {
    opts || (opts = {});

    this.root = normalizeRoot(opts.root || "assets");
    this.rootLength = this.root.length;

    this.directory = opts.directory || "./app/assets";
    this.fullDirectory = filePath.join(process.cwd(), this.directory);

    this.index = opts.index || "index.html";

    this.options = {
        maxAge: opts.maxAge || 86400000,
        fallback: opts.fallback != null ? !!opts.fallback : false,
        etag: opts.etag != null ? !!opts.etag : true,
        lastModified: opts.lastModified != null ? !!opts.lastModified : true
    };
}

StaticServe.prototype.middleware = function(req, res, next) {
    var _this = this,
        method = req.method,
        url = req.url,
        fileName;

    if (method !== "GET" && method !== "HEAD") {
        next();
        return;
    }
    if (url.indexOf(this.root) !== 0) {
        next();
        return;
    }

    fileName = filePath.join(this.fullDirectory, url.substring(this.rootLength));

    fs.stat(fileName, function(err, stat) {
        if (err) {
            next(new HttpError(404, err));
            return;
        }
        if (!stat) {
            next();
            return;
        }

        if (stat.isDirectory()) {
            fileName = filePath.join(fileName, _this.index);

            fs.stat(fileName, function(err, stat) {
                if (err || !stat) {
                    next(new HttpError(404, err));
                    return;
                }

                _this.send(res, fileName, stat, next);
            });
        } else {
            _this.send(res, fileName, stat, next);
        }
    });
};

StaticServe.prototype.send = function(res, fileName, stat, callback) {
    var app = res.app,
        opts = this.options,
        modified = false;

    fs.readFile(fileName, function(err, buffer) {
        if (err) {
            callback(new HttpError(err));
            return;
        }
        var ext = filePath.ext(fileName),
            type = app.mime.lookUpType(ext, opts.fallback);

        if (type) {
            modified = res.modified(stat.mtime);

            res.contentType = type;
            if (opts.maxAge && !res.getHeader("Cache-Control")) res.setHeader("Cache-Control", "public, max-age=" + (opts.maxAge / 1000));
            if (opts.etag && !res.getHeader("ETag")) res.setHeader("ETag", '"' + app.get("etag fn")(buffer) + '"');
            if (modified && opts.lastModified && !res.getHeader("Last-Modified")) res.setHeader("Last-Modified", new Date(stat.mtime));

            res.send(modified ? 200 : 304, buffer);
            callback();
            return;
        }

        callback(new HttpError(415, ext));
    });

    return this;
};

module.exports = StaticServe;
<|endoftext|>


<commit_before>var Alexa = require('alexa-sdk');

var APP_ID = 'amzn1.ask.skill.85ae7ea2-b727-4d2a-9765-5c563a5ec379';

var SKILL_NAME = 'Snack Overflow';
var POSSIBLE_RECIPES = ['Chicken Parmesan', 'Spaghetti', 'Turkey Sandwich'];

var currentRecipe, currentRecipeName, currentStep = 0;

var WORKFLOW_STATES = {
    START : 1,
    RECIPE_PROPOSED: 2,
    INGREDIENTS_PROPOSED: 3
};

var currentWorkflowState = WORKFLOW_STATES.START;

exports.handler = function(event, context, callback) {
    var alexa = Alexa.handler(event, context, callback);
    alexa.registerHandlers(getRecipeHandlers);
    alexa.registerHandlers(utilHandlers);
    alexa.execute();
};

var getRecipeHandlers = {
    'whatShouldIMakeIntent': function () {
        suggestRecipe();
   }
};

var utilHandlers = {
    'affirmativeIntent': function () {
        doAffirmativeAction();
    },
    'negativeIntent': function () {
        doNegativeAction();
    },
    'nextStepIntent': function () {
        tellStep(currentRecipe, ++currentStep);
    },
    'repeatStepIntent': function () {
        tellStep(currentRecipe, currentStep);
    }
};

function suggestRecipe() {
    var currentRecipe = getRandomRecipe();

    this.emit(':tell', "Would you like to make ", currentRecipe.recipes.title);
    currentWorkflowState = WORKFLOW_STATES.RECIPE_PROPOSED;
}

function doAffirmativeAction() {
    switch (currentWorkflowState) {
        case (WORKFLOW_STATES.START):
            break;
        case (WORKFLOW_STATES.RECIPE_PROPOSED):
            // user said they wanted to do the proposed recipe. ask if they have ingredients
            currentRecipe = getRandomRecipe(currentRecipeName);
            tellIngredients(currentRecipe);
            currentWorkflowState = WORKFLOW_STATES.INGREDIENTS_PROPOSED;
            break;
        case (WORKFLOW_STATES.INGREDIENTS_PROPOSED):
            // user said they have the ingredients. begin listing steps to recipe
            tellStep(currentRecipe, currentStep);
            break;
    }
}

function doNegativeAction() {
    switch (currentWorkflowState) {
        case (WORKFLOW_STATES.START):
            break;
        case (WORKFLOW_STATES.RECIPE_PROPOSED):
            suggestRecipe();
            break;
        case (WORKFLOW_STATES.INGREDIENTS_PROPOSED):
            // TODO: insert 'would you like to buy ingredients?' logic
            suggestRecipe();
            break;
    }
}

var getFridgeHandlers = {
	'AskWhatsInFridgeIntent': function() {
		// get fridge list
		// var fridge = [...........]

		var strFridge = fridge.join();
		this.emit(':tell', "You currently have " + strFridge);
	}
};

function tellRecipe(recipe) {
    this.emit(":tell", "You will need");

    for (var i = 0; i < recipe.extendedIngredients.length; i++) {
        this.emit(":tell", recipe.extendedIngredients[i].originalString);
    }
<<<<<<< HEAD

    this.emit(":tell", "Do you have these ingredients?");
}

function tellStep(recipe, step) {
    // TODO: insert logic for no more steps
    this.emit(":tell", recipe.instructions[step]);
    this.emit(":tell", "Tell me when you're ready for the next step, or if you need to hear that step again.");
}
=======
    */
}
>>>>>>> 9841240931972f38e0cccd104cc0cc415b91aac6
<commit_msg>Remove merge conflict garbage.<commit_after>var Alexa = require('alexa-sdk');

var APP_ID = 'amzn1.ask.skill.85ae7ea2-b727-4d2a-9765-5c563a5ec379';

var SKILL_NAME = 'Snack Overflow';
var POSSIBLE_RECIPES = ['Chicken Parmesan', 'Spaghetti', 'Turkey Sandwich'];

var currentRecipe, currentRecipeName, currentStep = 0;

var WORKFLOW_STATES = {
    START : 1,
    RECIPE_PROPOSED: 2,
    INGREDIENTS_PROPOSED: 3
};

var currentWorkflowState = WORKFLOW_STATES.START;

exports.handler = function(event, context, callback) {
    var alexa = Alexa.handler(event, context, callback);
    alexa.registerHandlers(getRecipeHandlers);
    alexa.registerHandlers(utilHandlers);
    alexa.execute();
};

var getRecipeHandlers = {
    'whatShouldIMakeIntent': function () {
        suggestRecipe();
   }
};

var utilHandlers = {
    'affirmativeIntent': function () {
        doAffirmativeAction();
    },
    'negativeIntent': function () {
        doNegativeAction();
    },
    'nextStepIntent': function () {
        tellStep(currentRecipe, ++currentStep);
    },
    'repeatStepIntent': function () {
        tellStep(currentRecipe, currentStep);
    }
};

function suggestRecipe() {
    var currentRecipe = getRandomRecipe();

    this.emit(':tell', "Would you like to make ", currentRecipe.recipes.title);
    currentWorkflowState = WORKFLOW_STATES.RECIPE_PROPOSED;
}

function doAffirmativeAction() {
    switch (currentWorkflowState) {
        case (WORKFLOW_STATES.START):
            break;
        case (WORKFLOW_STATES.RECIPE_PROPOSED):
            // user said they wanted to do the proposed recipe. ask if they have ingredients
            currentRecipe = getRandomRecipe(currentRecipeName);
            tellIngredients(currentRecipe);
            currentWorkflowState = WORKFLOW_STATES.INGREDIENTS_PROPOSED;
            break;
        case (WORKFLOW_STATES.INGREDIENTS_PROPOSED):
            // user said they have the ingredients. begin listing steps to recipe
            tellStep(currentRecipe, currentStep);
            break;
    }
}

function doNegativeAction() {
    switch (currentWorkflowState) {
        case (WORKFLOW_STATES.START):
            break;
        case (WORKFLOW_STATES.RECIPE_PROPOSED):
            suggestRecipe();
            break;
        case (WORKFLOW_STATES.INGREDIENTS_PROPOSED):
            // TODO: insert 'would you like to buy ingredients?' logic
            suggestRecipe();
            break;
    }
}

var getFridgeHandlers = {
	'AskWhatsInFridgeIntent': function() {
		// get fridge list
		// var fridge = [...........]

		var strFridge = fridge.join();
		this.emit(':tell', "You currently have " + strFridge);
	}
};

function tellRecipe(recipe) {
    this.emit(":tell", "You will need");

    for (var i = 0; i < recipe.extendedIngredients.length; i++) {
        this.emit(":tell", recipe.extendedIngredients[i].originalString);
    }

    this.emit(":tell", "Do you have these ingredients?");
}

function tellStep(recipe, step) {
    // TODO: insert logic for no more steps
    this.emit(":tell", recipe.instructions[step]);
    this.emit(":tell", "Tell me when you're ready for the next step, or if you need to hear that step again.");
}
<|endoftext|>


<commit_before>const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const fs = require('fs');
app.use(bodyParser.urlencoded({ extended: true }));
const HashMap = require('hashmap');
const dirname = fs.realpathSync('./');
const timeoutInMS = 28800000;

var teams = new HashMap();
var ingredients = JSON.parse(fs.readFileSync(__dirname + '/data/ingredients.json', 'utf8'));
var team_suggestions = new HashMap();

// build api endpoint for getting js files
fs.readdirSync(dirname + '/src/js').forEach(file => {
    app.get('/js/' + file, function (req, res) {
        res.status(200).sendFile(dirname + '/src/js/' + file);
    });
});

// build api endpoint for getting bootstrap files
fs.readdirSync(dirname + '/node_modules/bootstrap/dist/css').forEach(file => {
    app.get('/css/' + file, function (req, res) {
        res.status(200).sendFile(dirname + '/node_modules/bootstrap/dist/css/' + file);
    });
});

app.get('/', function (req, res) {
    res.status(200).sendFile(__dirname + "/index.htm");
});

app.get('/teams', function (req, res) {
    let teamname = req.query.teamname;
    console.log(teamname);
    if (teamname != undefined && teams.has(teamname)) {
        res.status(200).sendFile(__dirname + "/teamPage.html");
    } else {
        res.redirect(302, '/');
    }

});

app.get('/pizzas/amount', function (req, res) {
    let teamname = req.query.teamname;
    if (teamname != undefined && teams.has(teamname)) {
        let amount = {
            amount: teams.get(teamname).pizza_count
        };
        res.status(200).end(JSON.stringify(amount));
    } else {
        res.redirect(303, '/');
    }
});

app.get('/pizzas/ingredients', function (req, res) {
    if (ingredients.length > 0) {
        res.status(200).end(JSON.stringify(ingredients));
    } else {
        res.redirect(303, '/');
    }
});

app.get('/pizzas/suggestions', function (req, res) {
    let teamname = req.query.teamname;
    if (teamname != undefined && team_suggestions.has(teamname)) {
        let suggestions = team_suggestions.get(teamname);
        res.status(200).end(JSON.stringify(suggestions));
    } else {
        res.redirect(303, '/');
    }
});

app.get('/teams/data', function (req, res) {
    let teamname = req.query.teamname;
    if (teamname != undefined && teams.has(teamname)) {
        res.status(200).end(JSON.stringify(teams.get(teamname)));
    } else {
        res.redirect(303, '/');
    }
});

app.post('/teams/create', function (req, res) {
    let teamname = req.body.teamname;
    if (teamname != undefined && !teams.has(teamname) && !team_suggestions.has(teamname)) {
        console.log('Creating team ' + teamname);
        let data = {
            teamsize: {
                number: 0,
                type: null
            },
            pizza_count: 0
        };
        teams.set(teamname, data);
        team_suggestions.set(teamname, []);
        setTimeout(callback => {
            teams.remove(teamname);
            team_suggestions.remove(teamname);
        }, timeoutInMS);
        res.status(200).sendFile(__dirname + '/js/teamPage.js');
        res.redirect(303, '/teams/?teamname=' + teamname);
    } else {
        console.log('Creating Team: Failure because of undefined teamname!');
        res.status(420).send('Team already exists');
    }
});

app.post('/teams/teamsize', function (req, res) {
    let count = parseInt(req.body.count);
    let type = req.body.type;
    let teamname = req.body.teamname;
    if (count != NaN && type != undefined && teamname != undefined) {
        console.log('Update team size for team ' + teamname);
        let pizza_count = computeNumberOfPizzas(count, type);
        let data = {
            teamsize: {
                number: count,
                type: type
            },
            pizza_count: pizza_count
        };
        console.log(data);
        teams.set(teamname, data);
        res.redirect(302, '/teams/?teamname=' + teamname);
        res.status(200).end(JSON.stringify({ teamname: teamname, data: data }));
    } else {
        console.log('Update team size failed');
        res.redirect(303, '/');
    }
});

app.post('/pizzas/suggestions', function (req, res) {
    let teamname = req.body.teamname;
    let ingredients = req.body.ingredients;
    if (teamname != undefined && ingredients.length > 0 && team_suggestions.has(teamname)) {
        console.log('Add suggestion for team ' + teamname);
        let suggestion = {
            id: team_suggestions.get(teamname).length,
            ingredients: ingredients,
            vote: 0
        };
        team_suggestions.get(teamname).push(suggestion);
        res.end(JSON.stringify(suggestion));
    } else {
        console.log('Failed to add suggestion');
        res.redirect(303, '/');
    }
});

app.post('/pizzas/suggestions/vote', function (req, res) {
    let teamname = req.body.teamname;
    let suggestion_id = parseInt(req.body.id);
    let vote = parseInt(req.body.vote);
    if (teamname != undefined && suggestion_id != NaN && vote != NaN && team_suggestions.has(teamname)) {
        console.log('Update vote vor suggestion');
        vote = Math.sign(vote);
        team_suggestions.get(teamname)[suggestion_id].vote += vote;
        res.sendStatus(200);
    } else {
        console.log('Update voting failed');
        res.redirect(303, '/');
    }
});

function computeNumberOfPizzas(count, type) {
    if (type == 'Personen') {
        let number = count * 4;
        return Math.ceil(number / 16);
    } else if (type == 'Pizzastuecke') {
        return Math.ceil(count / 16);
    } else {
        return 0;
    }
};

function saveToFile(data, filename = "tfmap.log", exitOnWrite = false) {
    let folderName = "results";
    if (!fs.existsSync(folderName)) {
        fs.mkdirSync(folderName);
    }
    fs.writeFileSync('results/' + filename, data);
    console.log("The file was saved!");
    if (exitOnWrite) {
        process.exit(0);
    }
}

var server = app.listen(8081, function () {
    var host = server.address().address;
    var port = server.address().port;
    console.log("REST server listening at http://%s:%s", host, port);
});<commit_msg>Add api endpoint to get sweetalert files<commit_after>const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const fs = require('fs');
app.use(bodyParser.urlencoded({ extended: true }));
const HashMap = require('hashmap');
const dirname = fs.realpathSync('./');
const timeoutInMS = 28800000;

var teams = new HashMap();
var ingredients = JSON.parse(fs.readFileSync(__dirname + '/data/ingredients.json', 'utf8'));
var team_suggestions = new HashMap();

// build api endpoint for getting js files
fs.readdirSync(dirname + '/src/js').forEach(file => {
    app.get('/js/' + file, function (req, res) {
        res.status(200).sendFile(dirname + '/src/js/' + file);
    });
});

// build api endpoint for getting bootstrap files
fs.readdirSync(dirname + '/node_modules/bootstrap/dist/css').forEach(file => {
    app.get('/css/' + file, function (req, res) {
        res.status(200).sendFile(dirname + '/node_modules/bootstrap/dist/css/' + file);
    });
});

// build api endpoint for getting sweetalert files
fs.readdirSync(dirname + '/node_modules/sweetalert/dist').forEach(file => {
    app.get('/swal/' + file, function (req, res) {
        res.status(200).sendFile(dirname + '/node_modules/sweetalert/dist/' + file);
    })
});

app.get('/', function (req, res) {
    res.status(200).sendFile(__dirname + "/index.htm");
});

app.get('/teams', function (req, res) {
    let teamname = req.query.teamname;
    console.log(teamname);
    if (teamname != undefined && teams.has(teamname)) {
        res.status(200).sendFile(__dirname + "/teamPage.html");
    } else {
        res.redirect(302, '/');
    }

});

app.get('/pizzas/amount', function (req, res) {
    let teamname = req.query.teamname;
    if (teamname != undefined && teams.has(teamname)) {
        let amount = {
            amount: teams.get(teamname).pizza_count
        };
        res.status(200).end(JSON.stringify(amount));
    } else {
        res.redirect(303, '/');
    }
});

app.get('/pizzas/ingredients', function (req, res) {
    if (ingredients.length > 0) {
        res.status(200).end(JSON.stringify(ingredients));
    } else {
        res.redirect(303, '/');
    }
});

app.get('/pizzas/suggestions', function (req, res) {
    let teamname = req.query.teamname;
    if (teamname != undefined && team_suggestions.has(teamname)) {
        let suggestions = team_suggestions.get(teamname);
        res.status(200).end(JSON.stringify(suggestions));
    } else {
        res.redirect(303, '/');
    }
});

app.get('/teams/data', function (req, res) {
    let teamname = req.query.teamname;
    if (teamname != undefined && teams.has(teamname)) {
        res.status(200).end(JSON.stringify(teams.get(teamname)));
    } else {
        res.redirect(303, '/');
    }
});

app.post('/teams/create', function (req, res) {
    let teamname = req.body.teamname;
    if (teamname != undefined && !teams.has(teamname) && !team_suggestions.has(teamname)) {
        console.log('Creating team ' + teamname);
        let data = {
            teamsize: {
                number: 0,
                type: null
            },
            pizza_count: 0
        };
        teams.set(teamname, data);
        team_suggestions.set(teamname, []);
        setTimeout(callback => {
            teams.remove(teamname);
            team_suggestions.remove(teamname);
        }, timeoutInMS);
        res.status(200).sendFile(__dirname + '/js/teamPage.js');
        res.redirect(303, '/teams/?teamname=' + teamname);
    } else {
        console.log('Creating Team: Failure because of undefined teamname!');
        res.status(420).send('Team already exists');
    }
});

app.post('/teams/teamsize', function (req, res) {
    let count = parseInt(req.body.count);
    let type = req.body.type;
    let teamname = req.body.teamname;
    if (count != NaN && type != undefined && teamname != undefined) {
        console.log('Update team size for team ' + teamname);
        let pizza_count = computeNumberOfPizzas(count, type);
        let data = {
            teamsize: {
                number: count,
                type: type
            },
            pizza_count: pizza_count
        };
        console.log(data);
        teams.set(teamname, data);
        res.redirect(302, '/teams/?teamname=' + teamname);
        res.status(200).end(JSON.stringify({ teamname: teamname, data: data }));
    } else {
        console.log('Update team size failed');
        res.redirect(303, '/');
    }
});

app.post('/pizzas/suggestions', function (req, res) {
    let teamname = req.body.teamname;
    let ingredients = req.body.ingredients;
    if (teamname != undefined && ingredients.length > 0 && team_suggestions.has(teamname)) {
        console.log('Add suggestion for team ' + teamname);
        let suggestion = {
            id: team_suggestions.get(teamname).length,
            ingredients: ingredients,
            vote: 0
        };
        team_suggestions.get(teamname).push(suggestion);
        res.end(JSON.stringify(suggestion));
    } else {
        console.log('Failed to add suggestion');
        res.redirect(303, '/');
    }
});

app.post('/pizzas/suggestions/vote', function (req, res) {
    let teamname = req.body.teamname;
    let suggestion_id = parseInt(req.body.id);
    let vote = parseInt(req.body.vote);
    if (teamname != undefined && suggestion_id != NaN && vote != NaN && team_suggestions.has(teamname)) {
        console.log('Update vote vor suggestion');
        vote = Math.sign(vote);
        team_suggestions.get(teamname)[suggestion_id].vote += vote;
        res.sendStatus(200);
    } else {
        console.log('Update voting failed');
        res.redirect(303, '/');
    }
});

function computeNumberOfPizzas(count, type) {
    if (type == 'Personen') {
        let number = count * 4;
        return Math.ceil(number / 16);
    } else if (type == 'Pizzastuecke') {
        return Math.ceil(count / 16);
    } else {
        return 0;
    }
};

function saveToFile(data, filename = "tfmap.log", exitOnWrite = false) {
    let folderName = "results";
    if (!fs.existsSync(folderName)) {
        fs.mkdirSync(folderName);
    }
    fs.writeFileSync('results/' + filename, data);
    console.log("The file was saved!");
    if (exitOnWrite) {
        process.exit(0);
    }
}

var server = app.listen(8081, function () {
    var host = server.address().address;
    var port = server.address().port;
    console.log("REST server listening at http://%s:%s", host, port);
});<|endoftext|>


<commit_before>//Dependencies
var fs       = require('fs'),
    mongo    = require('mongodb'),
    ObjectID = require('bson').ObjectID,
  	async	 = require('async'),
  	_		 = require('underscore');

/**
 * Helper function that creates a MongoDB ObjectID given a hex string
 * @param {String|ObjectId}  Optional hard-coded Object ID as string
 */
exports.createObjectId = function(id) {
    if (!id) return new ObjectID();

    //Allow cloning ObjectIDs
    if (id.constructor.name == 'ObjectID') id = id.toString();

    return new ObjectID(id);
};

/**
 * Main method for connecting to the database and returning the fixture loader (Loader)
 *
 * @param {String}  Database name
 * @param {Object}  Connection options: host ('localhost'), port (27017)
 */
exports.connect = function(dbName, options) {
    return new Loader(dbName, options);
}

/**
 * Loader constructor
 *
 * @param {String}  Database name
 * @param {Object}  Connection options: host ('localhost'), port (27017)
 */
var Loader = exports.Loader = function(dbName, options) {
    options = options || {};

    var host = options.host || 'localhost',
        port = options.port || 27017;

    //Connect
    this.db = new mongo.Db(dbName, new mongo.Server(host, port, {}));

    // Modifiers
    this.modifiers = [];
};

/**
 * Inserts data
 *
 * @param {Mixed}       The data to load. This parameter accepts either:
 *                          String: Path to a file or directory to load
 *                          Object: Object literal in the form described in docs
 * @param {Function}    Callback(err)
 */
Loader.prototype.load = function(fixtures, cb) {
    var self = this;

    _mixedToObject(fixtures, function(err, data) {
        if (err) return cb(err);

        _loadData(self, data, cb);
    });
};

/**
 * Add a modifier function.
 *
 * Modifier functions get called (in the order in which they were added) for each document, prior to it being loaded.
 * The result from each modifier is fed into the next modifier as its input, and so on until the final result which is
 * then inserted into the db.
 *
 * @param {Function} cb the modifier callback function with signature (collectionName, document, callback).
 */
Loader.prototype.addModifier = function(cb) {
  this.modifiers.push(cb);
};

/**
 * loader.clear(cb) : Clears (drops) the entire database
 *
 * loader.clear(collectionNames, cb) : Clears only the given collection(s)
 *
 * @param {String|Array}    Optional. Name of collection to clear or an array of collection names
 * @param {Function}        Callback(err)
 */
Loader.prototype.clear = function(collectionNames, cb) {
    //Normalise arguments
    if (arguments.length == 1) { //cb
      cb = collectionNames;
      collectionNames = null;
    }

    var self = this;

    var results = {};

    async.series([
        function connect(cb) {
            _connect(self, function(err, db) {
                if (err) return cb(err);

                results.db = db;
                cb();
            })
        },

        function getCollectionNames(cb) {
            //If collectionNames not passed we clear all of them
            if (!collectionNames) {
                results.db.collectionNames(function(err, names) {
                    if (err) return cb(err);

                    //Get the real collection names
                    names = _.map(names, function(nameObj) {
                        var fullName = nameObj.name,
                            parts = fullName.split('.');

                        //Remove DB name
                        parts.shift();

                        //Skip system collections
                        if (parts[0] == 'system' || parts[0] == 'local') return;

                        return parts.join('.');
                    });

                    results.collectionNames = _.compact(names);

                    cb();
                })
            } else {
                //Convert single collection as string to array
                if (!_.isArray(collectionNames)) collectionNames = [collectionNames];

                results.collectionNames = collectionNames;

                cb();
            }
        },

        function clearCollections() {
            async.forEach(results.collectionNames, function(name, cb) {
                results.db.collection(name, function(err, collection) {
                    if (err) return cb(err);

                    collection.remove({}, cb);
                });
            }, cb);
        }
    ], cb)
};

/**
 * Drops the database and inserts data
 *
 * @param {Mixed}           The data to load. This parameter accepts either:
 *                              String: Path to a file or directory to load
 *                              Object: Object literal in the form described in docs
 * @param {Function}        Callback(err)
 */
Loader.prototype.clearAllAndLoad = function(fixtures, cb) {
    var self = this;

    self.clear(function(err) {
	    if (err) return cb(err);

	    self.load(fixtures, function(err) {
	        cb(err);
	    });
	});
};

/**
 * Clears only the collections that have documents to be inserted, then inserts data
 *
 * @param {Mixed}           The data to load. This parameter accepts either:
 *                              String: Path to a file or directory to load
 *                              Object: Object literal in the form described in docs
 * @param {Function}        Callback(err)
 */
Loader.prototype.clearAndLoad = function(fixtures, cb) {
    var self = this;

    _mixedToObject(fixtures, function(err, objData) {
        if (err) return cb(err);

        var collections = Object.keys(objData);

        self.clear(collections, function(err) {
    	    if (err) return cb(err);

    	    _loadData(self, objData, cb);
    	});
    });
};

//PRIVATE METHODS

var noop = function() {};

/**
 * Connects to the database and returns the client. If a connection has already been established it is used.
 *
 * @param {Loader}       The configured loader
 * @param {Function}     Callback(err, client)
 */
var _connect = function(loader, cb) {
  if (loader.client) return cb(null, loader.client);

  loader.db.open(function(err, client) {
    if (err) return cb(err);

    loader.client = client;
    cb(null, client);
  });
};

/**
 * Inserts the given data (object or array) as new documents
 *
 * @param {Loader}       The configured loader
 * @param {Object|Array} The data to load
 * @param {Function}     Callback(err)
 * @api private
 */
var _loadData = function(loader, data, cb) {
	cb = cb || noop;

	var collectionNames = Object.keys(data);

	_connect(loader, function(err, db) {
		if (err) return cb(err);

		async.forEach(collectionNames, function(collectionName, cbForEachCollection) {
			var collectionData = data[collectionName];

      //Convert object to array
      var items;
      if (Array.isArray(collectionData)) {
        items = collectionData.slice();
      } else {
        items = _.values(collectionData);
      }

      var modifiedItems = [];

      async.forEach(items, function(item, cbForEachItem) {
        // apply modifiers
        async.forEach(loader.modifiers, function(modifier, cbForEachModifier) {
          modifier.call(modifier, collectionName, item, function(err, modifiedDoc) {
            if (err) return cbForEachModifier(err);

            item = modifiedDoc;

            cbForEachModifier();
          });
        }, function(err) {
          if (err) return cbForEachItem(err);

          modifiedItems.push(item);

          cbForEachItem();
        });
      }, function(err) {
        if (err) return cbForEachCollection(err);

        db.collection(collectionName, function(err, collection) {
          if (err) return cbForEachCollection(err);

          collection.insert(modifiedItems, { safe: true }, cbForEachCollection);
        });
      });
		}, cb);
	});
};

/**
 * Determine the type of fixtures being passed in (object, array, file, directory) and return
 * an object keyed by collection name.
 *
 * @param {Object|String}       Fixture data (object, filename or dirname)
 * @param {Function}            Optional callback(err, data)
 * @api private
 */
var _mixedToObject = function(fixtures, cb) {
    if (typeof fixtures == 'object') return cb(null, fixtures);

    //As it's not an object, it should now be a file or directory path (string)
    if (typeof fixtures != 'string') {
        return cb(new Error('Data must be an object, array or string (file or dir path)'));
    }

    //Get the absolute dir path if a relative path was given
    if (fixtures.substr(0, 1) !== '/') {
        var parentPath = module.parent.filename.split('/');
        parentPath.pop();
        fixtures = parentPath.join('/') + '/' + fixtures;
    }

    //Determine if fixtures is pointing to a file or directory
    fs.stat(fixtures, function(err, stats) {
        if (err) return cb(err);

        if (stats.isDirectory()) {
            _dirToObject(fixtures, cb);
        } else { //File
            _fileToObject(fixtures, cb);
        }
    });
}

/**
 * Get data from one file as an object
 *
 * @param {String}      The full path to the file to load
 * @param {Function}    Optional callback(err, data)
 * @api private
 */
var _fileToObject = function(file, cb) {
    cb = cb || noop;

    if (file.substr(0, 1) !== '/') {
        var parentPath = module.parent.filename.split('/');
        parentPath.pop();
        file = parentPath.join('/') + '/' + file;
    }

    var data = require(file);

    cb(null, data);
}

/**
 * Get and compile data from all files in a directory, as an object
 *
 * @param {String}      The directory path to load e.g. 'data/fixtures' or '../data'
 * @param {Function}    Optional callback(err)
 * @api private
 */
var _dirToObject = function(dir, cb) {
    cb = cb || noop;

    //Get the absolute dir path if a relative path was given
    if (dir.substr(0, 1) !== '/') {
        var parentPath = module.parent.filename.split('/');
        parentPath.pop();
        dir = parentPath.join('/') + '/' + dir;
    }

    async.waterfall([
        function readDir(cb) {
            fs.readdir(dir, cb)
        },

        function filesToObjects(files, cb) {
            async.map(files, function processFile(file, cb) {
                var path = dir + '/' + file;

                // Determine if it's a file or directory
                fs.stat(path, function(err, stats) {
                    if (err) return cb(err);

                    if (stats.isDirectory()) {
                      cb(null, {});
                    } else { //File
                      _fileToObject(path, cb);
                    }
                });
            }, cb);
        },

        function combineObjects(results, cb) {
            //console.log('RESULTS', results);

            //Where all combined data will be kept, keyed by collection name
            var collections = {};

            results.forEach(function(fileObj) {
                _.each(fileObj, function(docs, name) {
                    //Convert objects to array
                    if (_.isObject(docs)) {
                        docs = _.values(docs);
                    }

                    //Create array for collection if it doesn't exist yet
                    if (!collections[name]) collections[name] = [];

                    //Add docs to collection
                    collections[name] = collections[name].concat(docs);
                });
            });

            cb(null, collections)
        }
    ], function(err, combinedData) {
        if (err) return cb(err);

        cb(null, combinedData);
    });
};
<commit_msg>File path doesn't resolves correctly on Windows. Closes #6.<commit_after>//Dependencies
var fs       = require('fs'),
    path     = require('path'),
    mongo    = require('mongodb'),
    ObjectID = require('bson').ObjectID,
    async    = require('async'),
    _        = require('underscore'),
    basePath = path.dirname(module.parent.filename);

/**
 * Helper function that creates a MongoDB ObjectID given a hex string
 * @param {String|ObjectId}  Optional hard-coded Object ID as string
 */
exports.createObjectId = function(id) {
    if (!id) return new ObjectID();

    //Allow cloning ObjectIDs
    if (id.constructor.name == 'ObjectID') id = id.toString();

    return new ObjectID(id);
};

/**
 * Main method for connecting to the database and returning the fixture loader (Loader)
 *
 * @param {String}  Database name
 * @param {Object}  Connection options: host ('localhost'), port (27017)
 */
exports.connect = function(dbName, options) {
    return new Loader(dbName, options);
}

/**
 * Loader constructor
 *
 * @param {String}  Database name
 * @param {Object}  Connection options: host ('localhost'), port (27017)
 */
var Loader = exports.Loader = function(dbName, options) {
    options = options || {};

    var host = options.host || 'localhost',
        port = options.port || 27017;

    //Connect
    this.db = new mongo.Db(dbName, new mongo.Server(host, port, {}));

    // Modifiers
    this.modifiers = [];
};

/**
 * Inserts data
 *
 * @param {Mixed}       The data to load. This parameter accepts either:
 *                          String: Path to a file or directory to load
 *                          Object: Object literal in the form described in docs
 * @param {Function}    Callback(err)
 */
Loader.prototype.load = function(fixtures, cb) {
    var self = this;

    _mixedToObject(fixtures, function(err, data) {
        if (err) return cb(err);

        _loadData(self, data, cb);
    });
};

/**
 * Add a modifier function.
 *
 * Modifier functions get called (in the order in which they were added) for each document, prior to it being loaded.
 * The result from each modifier is fed into the next modifier as its input, and so on until the final result which is
 * then inserted into the db.
 *
 * @param {Function} cb the modifier callback function with signature (collectionName, document, callback).
 */
Loader.prototype.addModifier = function(cb) {
  this.modifiers.push(cb);
};

/**
 * loader.clear(cb) : Clears (drops) the entire database
 *
 * loader.clear(collectionNames, cb) : Clears only the given collection(s)
 *
 * @param {String|Array}    Optional. Name of collection to clear or an array of collection names
 * @param {Function}        Callback(err)
 */
Loader.prototype.clear = function(collectionNames, cb) {
    //Normalise arguments
    if (arguments.length == 1) { //cb
      cb = collectionNames;
      collectionNames = null;
    }

    var self = this;

    var results = {};

    async.series([
        function connect(cb) {
            _connect(self, function(err, db) {
                if (err) return cb(err);

                results.db = db;
                cb();
            })
        },

        function getCollectionNames(cb) {
            //If collectionNames not passed we clear all of them
            if (!collectionNames) {
                results.db.collectionNames(function(err, names) {
                    if (err) return cb(err);

                    //Get the real collection names
                    names = _.map(names, function(nameObj) {
                        var fullName = nameObj.name,
                            parts = fullName.split('.');

                        //Remove DB name
                        parts.shift();

                        //Skip system collections
                        if (parts[0] == 'system' || parts[0] == 'local') return;

                        return parts.join('.');
                    });

                    results.collectionNames = _.compact(names);

                    cb();
                })
            } else {
                //Convert single collection as string to array
                if (!_.isArray(collectionNames)) collectionNames = [collectionNames];

                results.collectionNames = collectionNames;

                cb();
            }
        },

        function clearCollections() {
            async.forEach(results.collectionNames, function(name, cb) {
                results.db.collection(name, function(err, collection) {
                    if (err) return cb(err);

                    collection.remove({}, cb);
                });
            }, cb);
        }
    ], cb)
};

/**
 * Drops the database and inserts data
 *
 * @param {Mixed}           The data to load. This parameter accepts either:
 *                              String: Path to a file or directory to load
 *                              Object: Object literal in the form described in docs
 * @param {Function}        Callback(err)
 */
Loader.prototype.clearAllAndLoad = function(fixtures, cb) {
    var self = this;

    self.clear(function(err) {
	    if (err) return cb(err);

	    self.load(fixtures, function(err) {
	        cb(err);
	    });
	});
};

/**
 * Clears only the collections that have documents to be inserted, then inserts data
 *
 * @param {Mixed}           The data to load. This parameter accepts either:
 *                              String: Path to a file or directory to load
 *                              Object: Object literal in the form described in docs
 * @param {Function}        Callback(err)
 */
Loader.prototype.clearAndLoad = function(fixtures, cb) {
    var self = this;

    _mixedToObject(fixtures, function(err, objData) {
        if (err) return cb(err);

        var collections = Object.keys(objData);

        self.clear(collections, function(err) {
    	    if (err) return cb(err);

    	    _loadData(self, objData, cb);
    	});
    });
};

//PRIVATE METHODS

var noop = function() {};

/**
 * Connects to the database and returns the client. If a connection has already been established it is used.
 *
 * @param {Loader}       The configured loader
 * @param {Function}     Callback(err, client)
 */
var _connect = function(loader, cb) {
  if (loader.client) return cb(null, loader.client);

  loader.db.open(function(err, client) {
    if (err) return cb(err);

    loader.client = client;
    cb(null, client);
  });
};

/**
 * Inserts the given data (object or array) as new documents
 *
 * @param {Loader}       The configured loader
 * @param {Object|Array} The data to load
 * @param {Function}     Callback(err)
 * @api private
 */
var _loadData = function(loader, data, cb) {
	cb = cb || noop;

	var collectionNames = Object.keys(data);

	_connect(loader, function(err, db) {
		if (err) return cb(err);

		async.forEach(collectionNames, function(collectionName, cbForEachCollection) {
			var collectionData = data[collectionName];

      //Convert object to array
      var items;
      if (Array.isArray(collectionData)) {
        items = collectionData.slice();
      } else {
        items = _.values(collectionData);
      }

      var modifiedItems = [];

      async.forEach(items, function(item, cbForEachItem) {
        // apply modifiers
        async.forEach(loader.modifiers, function(modifier, cbForEachModifier) {
          modifier.call(modifier, collectionName, item, function(err, modifiedDoc) {
            if (err) return cbForEachModifier(err);

            item = modifiedDoc;

            cbForEachModifier();
          });
        }, function(err) {
          if (err) return cbForEachItem(err);

          modifiedItems.push(item);

          cbForEachItem();
        });
      }, function(err) {
        if (err) return cbForEachCollection(err);

        db.collection(collectionName, function(err, collection) {
          if (err) return cbForEachCollection(err);

          collection.insert(modifiedItems, { safe: true }, cbForEachCollection);
        });
      });
		}, cb);
	});
};

/**
 * Determine the type of fixtures being passed in (object, array, file, directory) and return
 * an object keyed by collection name.
 *
 * @param {Object|String}       Fixture data (object, filename or dirname)
 * @param {Function}            Optional callback(err, data)
 * @api private
 */
var _mixedToObject = function(fixtures, cb) {
    if (typeof fixtures == 'object') return cb(null, fixtures);

    //As it's not an object, it should now be a file or directory path (string)
    if (typeof fixtures != 'string') {
        return cb(new Error('Data must be an object, array or string (file or dir path)'));
    }

    // Resolve relative paths if necessary.
    fixtures = path.resolve(basePath, fixtures);

    //Determine if fixtures is pointing to a file or directory
    fs.stat(fixtures, function(err, stats) {
        if (err) return cb(err);

        if (stats.isDirectory()) {
            _dirToObject(fixtures, cb);
        } else { //File
            _fileToObject(fixtures, cb);
        }
    });
}

/**
 * Get data from one file as an object
 *
 * @param {String}      The full path to the file to load
 * @param {Function}    Optional callback(err, data)
 * @api private
 */
var _fileToObject = function(file, cb) {
    cb = cb || noop;

    // Resolve relative paths if necessary.
    file = path.resolve(basePath, file);

    var data = require(file);

    cb(null, data);
}

/**
 * Get and compile data from all files in a directory, as an object
 *
 * @param {String}      The directory path to load e.g. 'data/fixtures' or '../data'
 * @param {Function}    Optional callback(err)
 * @api private
 */
var _dirToObject = function(dir, cb) {
    cb = cb || noop;

    // Resolve relative paths if necessary.
    dir = path.resolve(basePath, dir);

    async.waterfall([
        function readDir(cb) {
            fs.readdir(dir, cb)
        },

        function filesToObjects(files, cb) {
            async.map(files, function processFile(file, cb) {
                var path = dir + '/' + file;

                // Determine if it's a file or directory
                fs.stat(path, function(err, stats) {
                    if (err) return cb(err);

                    if (stats.isDirectory()) {
                      cb(null, {});
                    } else { //File
                      _fileToObject(path, cb);
                    }
                });
            }, cb);
        },

        function combineObjects(results, cb) {
            //console.log('RESULTS', results);

            //Where all combined data will be kept, keyed by collection name
            var collections = {};

            results.forEach(function(fileObj) {
                _.each(fileObj, function(docs, name) {
                    //Convert objects to array
                    if (_.isObject(docs)) {
                        docs = _.values(docs);
                    }

                    //Create array for collection if it doesn't exist yet
                    if (!collections[name]) collections[name] = [];

                    //Add docs to collection
                    collections[name] = collections[name].concat(docs);
                });
            });

            cb(null, collections)
        }
    ], function(err, combinedData) {
        if (err) return cb(err);

        cb(null, combinedData);
    });
};
<|endoftext|>


<commit_before>import Calendar from './Calendar';
import EventWrapper from './EventWrapper';
import BackgroundWrapper from './BackgroundWrapper';
import { set as setLocalizer } from './localizer';
import momentLocalizer from './localizers/moment';
import globalizeLocalizer from './localizers/globalize';
import viewLabel from './utils/viewLabel';
import move from './utils/move';
import { views, navigate } from './utils/constants';

Object.assign(Calendar, {
  setLocalizer,
  globalizeLocalizer,
  momentLocalizer,
  label: viewLabel,
  views,
  Navigate: navigate,
  move,
  components: {
    eventWrapper: EventWrapper,
    dayWrapper: BackgroundWrapper,
    dateCellWrapper: BackgroundWrapper
  }
})

export default Calendar
<commit_msg>Add (duplicate) capitalized namespace for views constants<commit_after>import Calendar from './Calendar';
import EventWrapper from './EventWrapper';
import BackgroundWrapper from './BackgroundWrapper';
import { set as setLocalizer } from './localizer';
import momentLocalizer from './localizers/moment';
import globalizeLocalizer from './localizers/globalize';
import viewLabel from './utils/viewLabel';
import move from './utils/move';
import { views, navigate } from './utils/constants';

Object.assign(Calendar, {
  setLocalizer,
  globalizeLocalizer,
  momentLocalizer,
  label: viewLabel,
  views,
  Views: views,
  Navigate: navigate,
  move,
  components: {
    eventWrapper: EventWrapper,
    dayWrapper: BackgroundWrapper,
    dateCellWrapper: BackgroundWrapper
  }
})

export default Calendar
<|endoftext|>