<commit_before>/*eslint-disable react/no-set-state */
'use strict';

import React from 'react';
import ReactDOM from 'react-dom';
import d3 from 'd3';
import Axis from '../utilities/axis';
import AxisLabel from '../utilities/axisLabel';
import Grid from '../utilities/grid';
import Legend from '../utilities/legend';

class BarGraph extends React.Component {

  constructor(props) {
    super(props);
    this.updateSize = this.updateSize.bind(this);
    this.state = {
      width: this.props.width,
      data: []
    };
  }

  componentWillMount() {
    window.addEventListener('resize', this.updateSize, false);
    this.setState({width: this.props.width});
  }

  componentDidMount() {
    this.reloadBarData();
    this.repaintComponent();
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.updateSize, false);
  }

  updateSize() {
    let node = ReactDOM.findDOMNode(this);
    let parentWidth = node.offsetWidth;
    (parentWidth < this.props.width) ?
      this.setState({width:parentWidth}) :
      this.setState({width:this.props.width});
  }

  repaintComponent() {
    const forceResize = this.updateSize;
    function onRepaint(callback){
      setTimeout(function(){
        window.requestAnimationFrame(callback);
      }, 0);
    }
    onRepaint(forceResize);
  }

  stackType() {
    let tempArray = [];
    for (let i in this.stacked) {
      for (let j in this.stacked[i]) {
        if (this.props.barChartType === "side") {
          tempArray.push(this.stacked[i][j].y);
        } else {
          tempArray.push(this.stacked[i][j].y + this.stacked[i][j].y0);
        }
      }
    }
    return tempArray;
  }

  createChart(_self) {

    if (this.props.colors) {
      this.color = d3.scale.ordinal()
      .range(this.props.colors);
    } else {
      this.color = d3.scale.category10();
    }

    let xLabelHeightOffset = 0;
    let yLabelWidthOffset = 0;

    {this.props.xAxisLabel ? xLabelHeightOffset = 30 : null;}
    {this.props.yAxisLabel ? yLabelWidthOffset = 20 : null;}

    // Width of graph
    this.w = this.state.width - (this.props.margin.left + this.props.margin.right + yLabelWidthOffset);

    // Height of graph
    this.h = this.props.height - (this.props.margin.top + this.props.margin.bottom + xLabelHeightOffset);

    this.stacked = d3.layout.stack()(_self.props.keys.map(function(key){
      return _self.state.data.map(function(d){
        return {x: d[_self.props.xDataKey], y: d[key] };
      });
    }));

    // X0 axis scale
    this.x0Scale = d3.scale.ordinal()
        .rangeRoundBands([0, this.w], this.props.groupSpacing)
        .domain(this.stacked[0].map(function(d) { return d.x; }));

    // X1 axis scale
    this.x1Scale = d3.scale.ordinal()
        .rangeRoundBands([0, this.x0Scale.rangeBand()], this.props.individualSpacing)
        .domain(this.props.keys.map(function(d) { return d; }));

    // Y axis scale
    this.yScale = d3.scale.linear()
        .rangeRound([this.h, 0])
        .domain([0, d3.max(this.stackType())])
        .nice();

    this.yAxis = d3.svg.axis()
      .scale(this.yScale)
      .orient('left')
      .ticks(5);

    this.xAxis = d3.svg.axis()
      .scale(this.x0Scale)
      .orient('bottom')
      .ticks(this.state.data.length);

    this.yGrid = d3.svg.axis()
      .scale(this.yScale)
      .orient('left')
      .ticks(5)
      .tickSize(-this.w, 0, 0)
      .tickFormat("");

    this.transform = 'translate(' + (this.props.margin.left + yLabelWidthOffset) + ',' + this.props.margin.top + ')';
  }

  reloadBarData() {
    let data = this.props.data;
    this.setState({data:data});
  }

  render(){

    this.createChart(this);

    const _self = this;

    let bars = this.stacked.map(function(data,i) {
      let rects;
      if (_self.props.barChartType === "side") {
        rects = data.map(function(d,j) {
          return (<rect
            x={_self.x0Scale(d.x)+(i*(_self.x0Scale.rangeBand() / (_self.stacked.length)))}
            y={_self.h - (_self.yScale(d.y0) - _self.yScale(d.y + d.y0))}
            fill={_self.color(i)}
            height={_self.yScale(d.y0) - _self.yScale(d.y + d.y0)}
            width={_self.x1Scale.rangeBand()}
            key={j}/>
          );
        });
      } else {
        rects = data.map(function(d,j) {
          return (<rect
            x={_self.x0Scale(d.x)}
            y={_self.yScale(d.y + d.y0)}
            fill={_self.color(i)}
            height={_self.yScale(d.y0) - _self.yScale(d.y + d.y0)}
            width={_self.x0Scale.rangeBand()}
            key={j}/>
          );
        });
      }

      return (<g key={i}>{rects}</g>);
    });

    let customClassName = "";

    if(this.props.chartClassName){
      customClassName = " " + this.props.chartClassName;
    }

    const legend = [];

    this.props.keys.forEach((value, i) => {
      const legendObj = {};
      legendObj[_self.props.labelKey] = value;
      legend[i] = legendObj;
    });

    return (

        {this.props.title ?
{this.props.title}
 : null}
        <svg className={"rd3r-chart rd3r-bar-graph" + customClassName} id={this.props.chartId} width={this.state.width} height={this.props.height}>
          <g transform={this.transform}>
            <Grid h={this.h} grid={this.yGrid} gridType="y" />
            <Axis h={this.h} axis={this.yAxis} axisType="y" />
            <Axis h={this.h} axis={this.xAxis} axisType="x" />
            {this.props.xAxisLabel ?
              <AxisLabel key={0} h={this.h} w={this.w} axisLabel={this.props.xAxisLabel} axisType="x" />
            : null}
            {this.props.yAxisLabel ?
              <AxisLabel key={1} h={this.h} w={this.w} axisLabel={this.props.yAxisLabel} axisType="y" />
            : null}
            {bars}
          </g>
        </svg>
        {this.props.legend ?

          <Legend data={legend} labelKey={_self.props.labelKey} colors={_self.color} />

        : null}

    );
  }

}

BarGraph.propTypes = {
  title: React.PropTypes.string,
  width: React.PropTypes.number,
  height: React.PropTypes.number,
  chartId: React.PropTypes.string,
  chartClassName: React.PropTypes.string,
  colors: React.PropTypes.array,
  barChartType: React.PropTypes.oneOf(['stack','side']),
  groupSpacing: React.PropTypes.number,
  individualSpacing: React.PropTypes.number,
  data: React.PropTypes.array.isRequired,
  labelKey: React.PropTypes.string,
  xDataKey: React.PropTypes.string.isRequired,
  xAxisLabel: React.PropTypes.string,
  yAxisLabel: React.PropTypes.string,
  legend: React.PropTypes.bool,
  keys: React.PropTypes.array.isRequired,
  margin: React.PropTypes.object
};

BarGraph.defaultProps = {
  width: 1920,
  height: 400,
  barChartType: "side",
  groupSpacing: .3,
  individualSpacing: .5,
  legend: true,
  labelKey: "label",
  margin: {
    top: 10,
    right: 40,
    bottom: 20,
    left: 40
  }
};

export default BarGraph;<commit_msg>change max finding function name<commit_after>/*eslint-disable react/no-set-state */
'use strict';

import React from 'react';
import ReactDOM from 'react-dom';
import d3 from 'd3';
import Axis from '../utilities/axis';
import AxisLabel from '../utilities/axisLabel';
import Grid from '../utilities/grid';
import Legend from '../utilities/legend';

class BarGraph extends React.Component {

  constructor(props) {
    super(props);
    this.updateSize = this.updateSize.bind(this);
    this.state = {
      width: this.props.width,
      data: []
    };
  }

  componentWillMount() {
    window.addEventListener('resize', this.updateSize, false);
    this.setState({width: this.props.width});
  }

  componentDidMount() {
    this.reloadBarData();
    this.repaintComponent();
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.updateSize, false);
  }

  updateSize() {
    let node = ReactDOM.findDOMNode(this);
    let parentWidth = node.offsetWidth;
    (parentWidth < this.props.width) ?
      this.setState({width:parentWidth}) :
      this.setState({width:this.props.width});
  }

  repaintComponent() {
    const forceResize = this.updateSize;
    function onRepaint(callback){
      setTimeout(function(){
        window.requestAnimationFrame(callback);
      }, 0);
    }
    onRepaint(forceResize);
  }

  stackType() {
    let tempArray = [];
    const d = this.stacked;
    for (let i in d) {
      for (let j in d[i]) {
        if (this.props.barChartType === "side") {
          tempArray.push(d[i][j].y);
        } else {
          tempArray.push(d[i][j].y + d[i][j].y0);
        }
      }
    }
    return tempArray;
  }

  createChart(_self) {

    if (this.props.colors) {
      this.color = d3.scale.ordinal()
      .range(this.props.colors);
    } else {
      this.color = d3.scale.category10();
    }

    let xLabelHeightOffset = 0;
    let yLabelWidthOffset = 0;

    {this.props.xAxisLabel ? xLabelHeightOffset = 30 : null;}
    {this.props.yAxisLabel ? yLabelWidthOffset = 20 : null;}

    // Width of graph
    this.w = this.state.width - (this.props.margin.left + this.props.margin.right + yLabelWidthOffset);

    // Height of graph
    this.h = this.props.height - (this.props.margin.top + this.props.margin.bottom + xLabelHeightOffset);

    this.stacked = d3.layout.stack()(_self.props.keys.map(function(key){
      return _self.state.data.map(function(d){
        return {x: d[_self.props.xDataKey], y: d[key] };
      });
    }));

    // X0 axis scale
    this.x0Scale = d3.scale.ordinal()
        .rangeRoundBands([0, this.w], this.props.groupSpacing)
        .domain(this.stacked[0].map(function(d) { return d.x; }));

    // X1 axis scale
    this.x1Scale = d3.scale.ordinal()
        .rangeRoundBands([0, this.x0Scale.rangeBand()], this.props.individualSpacing)
        .domain(this.props.keys.map(function(d) { return d; }));

    // Y axis scale
    this.yScale = d3.scale.linear()
        .rangeRound([this.h, 0])
        .domain([0, d3.max(this.stackType())])
        .nice();

    this.yAxis = d3.svg.axis()
      .scale(this.yScale)
      .orient('left')
      .ticks(5);

    this.xAxis = d3.svg.axis()
      .scale(this.x0Scale)
      .orient('bottom')
      .ticks(this.state.data.length);

    this.yGrid = d3.svg.axis()
      .scale(this.yScale)
      .orient('left')
      .ticks(5)
      .tickSize(-this.w, 0, 0)
      .tickFormat("");

    this.transform = 'translate(' + (this.props.margin.left + yLabelWidthOffset) + ',' + this.props.margin.top + ')';
  }

  reloadBarData() {
    let data = this.props.data;
    this.setState({data:data});
  }

  render(){

    this.createChart(this);

    const _self = this;

    let bars = this.stacked.map(function(data,i) {
      let rects;
      if (_self.props.barChartType === "side") {
        rects = data.map(function(d,j) {
          return (<rect
            x={_self.x0Scale(d.x)+(i*(_self.x0Scale.rangeBand() / (_self.stacked.length)))}
            y={_self.h - (_self.yScale(d.y0) - _self.yScale(d.y + d.y0))}
            fill={_self.color(i)}
            height={_self.yScale(d.y0) - _self.yScale(d.y + d.y0)}
            width={_self.x1Scale.rangeBand()}
            key={j}/>
          );
        });
      } else {
        rects = data.map(function(d,j) {
          return (<rect
            x={_self.x0Scale(d.x)}
            y={_self.yScale(d.y + d.y0)}
            fill={_self.color(i)}
            height={_self.yScale(d.y0) - _self.yScale(d.y + d.y0)}
            width={_self.x0Scale.rangeBand()}
            key={j}/>
          );
        });
      }

      return (<g key={i}>{rects}</g>);
    });

    let customClassName = "";

    if(this.props.chartClassName){
      customClassName = " " + this.props.chartClassName;
    }

    const legend = [];

    this.props.keys.forEach((value, i) => {
      const legendObj = {};
      legendObj[_self.props.labelKey] = value;
      legend[i] = legendObj;
    });

    return (

        {this.props.title ?
{this.props.title}
 : null}
        <svg className={"rd3r-chart rd3r-bar-graph" + customClassName} id={this.props.chartId} width={this.state.width} height={this.props.height}>
          <g transform={this.transform}>
            <Grid h={this.h} grid={this.yGrid} gridType="y" />
            <Axis h={this.h} axis={this.yAxis} axisType="y" />
            <Axis h={this.h} axis={this.xAxis} axisType="x" />
            {this.props.xAxisLabel ?
              <AxisLabel key={0} h={this.h} w={this.w} axisLabel={this.props.xAxisLabel} axisType="x" />
            : null}
            {this.props.yAxisLabel ?
              <AxisLabel key={1} h={this.h} w={this.w} axisLabel={this.props.yAxisLabel} axisType="y" />
            : null}
            {bars}
          </g>
        </svg>
        {this.props.legend ?

          <Legend data={legend} labelKey={_self.props.labelKey} colors={_self.color} />

        : null}

    );
  }

}

BarGraph.propTypes = {
  title: React.PropTypes.string,
  width: React.PropTypes.number,
  height: React.PropTypes.number,
  chartId: React.PropTypes.string,
  chartClassName: React.PropTypes.string,
  colors: React.PropTypes.array,
  barChartType: React.PropTypes.oneOf(['stack','side']),
  groupSpacing: React.PropTypes.number,
  individualSpacing: React.PropTypes.number,
  data: React.PropTypes.array.isRequired,
  labelKey: React.PropTypes.string,
  xDataKey: React.PropTypes.string.isRequired,
  xAxisLabel: React.PropTypes.string,
  yAxisLabel: React.PropTypes.string,
  legend: React.PropTypes.bool,
  keys: React.PropTypes.array.isRequired,
  margin: React.PropTypes.object
};

BarGraph.defaultProps = {
  width: 1920,
  height: 400,
  barChartType: "side",
  groupSpacing: .3,
  individualSpacing: .5,
  legend: true,
  labelKey: "label",
  margin: {
    top: 10,
    right: 40,
    bottom: 20,
    left: 40
  }
};

export default BarGraph;<|endoftext|>


<commit_before>/**
* Person_ClassBonus.js
*
* @description :: TODO: You might write a short summary of how this model works and what it represents here.
* @docs        :: http://sailsjs.org/#!documentation/models
*/

module.exports = {

  attributes: {
    email:
    {
      type: "string",
      primaryKey: true,
      required: true,
      email: true,
      model: 'person'
    },
    class_bonus_id:
    {
      type: "integer",
      required: true,
      model: 'classbonus',
    }
  }
};

<commit_msg>Attempting to fix assocation between classbonus and person_classbonus<commit_after>/**
* Person_ClassBonus.js
*
* @description :: TODO: You might write a short summary of how this model works and what it represents here.
* @docs        :: http://sailsjs.org/#!documentation/models
*/

module.exports = {

  attributes: {
    email:
    {
      type: "string",
      primaryKey: true,
      required: true,
      email: true,
      model: 'person'
    },
    class_bonus_id:
    {
      type: "integer",
      required: true,
      model: 'classbonus',
      via: 'id'
    }
  }
};

<|endoftext|>


<commit_before>var _ = require('lodash');
var cheerio = require('cheerio');
var moment = require('moment');
var debug = require('debug')('parser:imageAltTag');
var parse = require('./lib/parse');

/*
 * Extract alt text from img tags
 */

var PARSER_COMPLETED_SUCCESSFULLY = false;
var FACEBOOK_ALT_TEXT_START = 'Image may contain:';

function parseAltContent(altText) {
    var content = altText.split(FACEBOOK_ALT_TEXT_START)[1];
    var parsedWords = content.split(',');
    parsedWords = _.map(parsedWords, function (e) { return e.trim() });
    return parsedWords;
}

function implementation(snippet) {

    debug("→ %j", _.omit(snippet, ['html']));

    var $ = cheerio.load(snippet.html);
    var returnValue = [];

    var altTagFounds = $('img[alt^="'+FACEBOOK_ALT_TEXT_START+'"]');

    _.each(altTagFounds, function (e) {
        returnValue.push(parseAltContent(e.attribs.alt));
    })
    returnValue = _.flatten(returnValue);

    PARSER_COMPLETED_SUCCESSFULLY = true;
    return {
        'imageAltTag': returnValue
    }
};

return parse.please({
    'name': 'imageAltTag',
    'requirements': { hrefType: 'photo' },
    'implementation': implementation,
    'since': "2017-02-23",
    'until': moment().toISOString(),
});
<commit_msg>refactor imageAltTag parser implementation<commit_after>var _ = require('lodash');
var cheerio = require('cheerio');
var moment = require('moment');
var debug = require('debug')('parser:imageAltTag');
var parse = require('./lib/parse');

/*
 * Extract alt text from img tags
 */

var PARSER_COMPLETED_SUCCESSFULLY = false;

function implementation(snippet) {

    debug("→ %j", _.omit(snippet, ['html']));

    var $ = cheerio.load(snippet.html);

    var altTagFounds = $('img[alt]');
    altTagFounds = _.map(altTagFounds, function (e) {
      return e.attribs.alt;
    });
    altTagFounds = _.flatten(altTagFounds);
    altTagFounds = _.uniq(altTagFounds);

    PARSER_COMPLETED_SUCCESSFULLY = true;
    return {
        imageAltTag: PARSER_COMPLETED_SUCCESSFULLY,
        altTexts: altTagFounds
    }
};

return parse.please({
    'name': 'imageAltTag',
    'requirements': { hrefType: 'photo' },
    'implementation': implementation,
    'since': "2017-02-23",
    'until': moment().toISOString(),
});
<|endoftext|>


<commit_before>var commands = []

// var checker = require('../../Utils/access_checker')
// var logger = require('../../Utils/error_loggers')
var config = require('../../config.js')
var analytics = require('../../Utils/orwell.js')
var bugsnag = require('bugsnag')
const Dash = require('rethinkdbdash')
const r = new Dash()
const roles = require('../../roles')

bugsnag.register(config.discord.bugsnag)

commands.ping = {
  phantom: true,
  adminOnly: true,
  modOnly: false,
  fn: function (bot, msg) {
    msg.channel.sendMessage('Pong!').then(successmsg => {
      setTimeout(() => bot.Messages.deleteMessages([msg, successmsg]), config.timeouts.messageDelete)
    })
  }
}

commands.help = {
  adminOnly: false,
  modOnly: false,
  fn: function (bot, msg) {
    msg.channel.sendMessage(`Hey ${msg.author.mention}! You can find all the info you need about the bot over at <#268812893087203338>!`).then(successmsg => {
      setTimeout(() => bot.Messages.deleteMessages([msg, successmsg]), config.timeouts.errorMessageDelete)
    })
  }
}

commands.stats = {
  adminOnly: false,
  modOnly: false,
  fn: function (bot, msg) {
    let moment = require('moment') // forgive me father for i have sinned
    analytics.getPoints(msg.member.id).then(data => {
      if (data === null) return msg.reply("you don't have any stats registered right now.")
      let now = new Date()
      let today = new Date(now.getFullYear(), now.getUTCMonth(), now.getUTCDate()).getTime()
      let dataObj = {}
      if (data.messages) Object.entries(data.messages).forEach(m => dataObj[m[0]] ? Object.assign(dataObj[m[0]], { msgs: m[1] }) : dataObj[m[0]] = { msgs: m[1] })
      if (data.commands) Object.entries(data.commands).forEach(c => dataObj[c[0]] ? Object.assign(dataObj[c[0]], { cmds: c[1] }) : dataObj[c[0]] = { cmds: c[1] })
      let dataArr = Object.entries(dataObj).sort()
      let field = []

      for (let i in dataArr) {
        let date = dataArr[i][0]
        if (today - parseInt(date) <= 172800000) {
          let parsed = moment(parseInt(date)).format("MMM Do")
          if (data.messages && z[i][1].msgs) field.push({
            name: `Messages on ${parsed}`,
            value: data.messages[date],
            inline: dataArr[i] ? (dataArr[i][1].cmds ? true : false) : false
          })
          if (data.commands && z[i][1].cmds) field.push({
            name: `Commands on ${parsed}`,
            value: data.commands[date],
            inline: dataArr[i] ? (dataArr[i][1].msgs ? true : false) : false
          })
        }
        // if (field.length === 3) break; <- Pretty sure this line is useless because of the if statement, right?
      }

      let sortRoles = Object.entries(roles).sort((a, b) => a[1].threshold - b[1].threshold)
      let nextRole = sortRoles.find(r => r[1].threshold > data.consecutive.length)
      field.push(
        {
          name: `Consecutive active days`,
          value: data.consecutive.length,
          inline: true
        },
        {
          name: `Days needed for next rank`,
          value: (nextRole) ? nextRole[1].threshold - data.consecutive.length : 'N/A',
          inline: true
        }
      )
      msg.channel.sendMessage('', false, {
        color: 0x59f442,
        title: `${msg.author.username} - Statistics`,
        thumbnail: {
          url: msg.author.avatarURL
        },
        fields: field
      }).catch(bugsnag.notify)
    }).catch(e => {
      msg.reply('an unexpected error occured while getting your stats, try again later.')
      console.error(e)
    })
  }
}

commands['stats-reset'] = {
  adminOnly: true,
  modOnly: false,
  fn: function (bot, msg, suffix) {
    r.db('DFB').table('analytics').get(suffix).then(data => {
      if (data !== null) {
        msg.reply(`you're about to reset the stats for ${suffix}, are you sure?`).then(() => {
          wait(bot, msg).then(resp => {
            if (resp === null) {
              msg.channel.sendMessage('No answer given in time, operation aborted.')
            }
            if (resp === false) {
              msg.channel.sendMessage('Operation aborted.')
            }
            if (resp === true) {
              msg.channel.sendMessage(`Are you **ABSOLUTELY** sure? This can not be undone!`).then(() => {
                wait(bot, msg).then(resp2 => {
                  if (resp2 === null) {
                    msg.channel.sendMessage('No answer given in time, operation aborted.')
                  }
                  if (resp2 === false) {
                    msg.channel.sendMessage('Operation aborted.')
                  }
                  if (resp2 === true) {
                    r.db('DFB').table('analytics').get(suffix).delete().run().then(() => {
                      msg.channel.sendMessage(`Stats for ${suffix} are deleted.`)
                    }).catch(e => {
                      bugsnag.notify(e)
                      msg.channel.sendMessage(`Failed to delete stats for ${suffix}`)
                    })
                  }
                })
              })
            }
          })
        })
      } else {
        msg.reply(`no data for ${suffix} found.`)
      }
    })
  }
}

commands.lookup = {
  adminOnly: true,
  modOnly: false,
  fn: function (bot, msg, suffix) {
    let moment = require('moment') // forgive me father for i have sinned
    analytics.getPoints((msg.mentions.length !== 0) ? msg.mentions[0].id : suffix).then(data => {
      if (data === null) return msg.reply("couldn't find data on this user.")
      let member = msg.guild.members.find(member => member.id === data.id)
      let now = new Date()
      let today = new Date(now.getFullYear(), now.getUTCMonth(), now.getUTCDate()).getTime()
      let dataObj = {}
      if (data.messages) Object.entries(data.messages).forEach(m => dataObj[m[0]] ? Object.assign(dataObj[m[0]], { msgs: m[1] }) : dataObj[m[0]] = { msgs: m[1] })
      if (data.commands) Object.entries(data.commands).forEach(c => dataObj[c[0]] ? Object.assign(dataObj[c[0]], { cmds: c[1] }) : dataObj[c[0]] = { cmds: c[1] })
      let dataArr = Object.entries(dataObj).sort()
      let field = []

      for (let i in dataArr) {
        let date = dataArr[i][0]
        if (today - parseInt(date) <= 172800000) {
          let parsed = moment(parseInt(date)).format("MMM Do")
          if (data.messages && z[i][1].msgs) field.push({
            name: `Messages on ${parsed}`,
            value: data.messages[date],
            inline: dataArr[i] ? (dataArr[i][1].cmds ? true : false) : false
          })
          if (data.commands && z[i][1].cmds) field.push({
            name: `Commands on ${parsed}`,
            value: data.commands[date],
            inline: dataArr[i] ? (dataArr[i][1].msgs ? true : false) : false
          })
        }
        // if (field.length === 3) break; <- Pretty sure this line is useless because of the if statement, right?
      }

      let sortRoles = Object.entries(roles).sort((a, b) => a[1].threshold - b[1].threshold)
      let nextRole = sortRoles.find(r => r[1].threshold > data.consecutive.length)
      field.push(
        {
          name: `Consecutive active days`,
          value: data.consecutive.length,
          inline: true
        },
        {
          name: `Days needed for next rank`,
          value: (nextRole) ? nextRole[1].threshold - data.consecutive.length : 'N/A',
          inline: true
        }
      )
      msg.channel.sendMessage('', false, {
        color: 0x59f442,
        title: `Statistics for ${member.username}##{member.discriminator}`,
        thumbnail: {
          url: msg.author.avatarURL
        },
        fields: field
      })
    }).catch(e => {
      msg.reply('an unexpected error occured while getting your stats, try again later.')
      console.error(e)
    })
  }
}

commands.fetch = {
  phantom: true,
  adminOnly: true,
  modOnly: false,
  fn: function (bot, msg) {
    msg.channel.fetchMessages().then(g => {
      msg.reply(`fetched ${g.messages.length} messages in this channel.`).then(f => {
        setTimeout(() => bot.Messages.deleteMessages([msg, f]), config.timeouts.messageDelete)
      })
    })
  }
}

commands.shutdown = {
  phantom: true,
  adminOnly: true,
  modOnly: false,
  fn: function (bot, msg) {
    msg.reply('shutting down...').then(() => {
      process.exit(0)
    })
  }
}

function wait (bot, msg) {
  let yn = /^y(es)?$|^n(o)?$/i
  return new Promise((resolve, reject) => {
    bot.Dispatcher.on('MESSAGE_CREATE', function doStuff (c) {
      var time = setTimeout(() => {
        resolve(null)
        bot.Dispatcher.removeListener('MESSAGE_CREATE', doStuff)
      }, config.timeouts.duplicateConfirm) // We won't wait forever for the person to anwser
      if (c.message.channel.id !== msg.channel.id) return
      if (c.message.author.id !== msg.author.id) return
      if (c.message.content.match(yn) === null) return
      else {
        resolve((c.message.content.match(/^y(es)?/i) !== null))
        bot.Dispatcher.removeListener('MESSAGE_CREATE', doStuff)
        clearTimeout(time)
      }
    })
  })
}

exports.Commands = commands
<commit_msg>Final one (#91)<commit_after>var commands = []

// var checker = require('../../Utils/access_checker')
// var logger = require('../../Utils/error_loggers')
var config = require('../../config.js')
var analytics = require('../../Utils/orwell.js')
var bugsnag = require('bugsnag')
const Dash = require('rethinkdbdash')
const r = new Dash()
const roles = require('../../roles')

bugsnag.register(config.discord.bugsnag)

commands.ping = {
  phantom: true,
  adminOnly: true,
  modOnly: false,
  fn: function (bot, msg) {
    msg.channel.sendMessage('Pong!').then(successmsg => {
      setTimeout(() => bot.Messages.deleteMessages([msg, successmsg]), config.timeouts.messageDelete)
    })
  }
}

commands.help = {
  adminOnly: false,
  modOnly: false,
  fn: function (bot, msg) {
    msg.channel.sendMessage(`Hey ${msg.author.mention}! You can find all the info you need about the bot over at <#268812893087203338>!`).then(successmsg => {
      setTimeout(() => bot.Messages.deleteMessages([msg, successmsg]), config.timeouts.errorMessageDelete)
    })
  }
}

commands.stats = {
  adminOnly: false,
  modOnly: false,
  fn: function (bot, msg) {
    let moment = require('moment') // forgive me father for i have sinned
    analytics.getPoints(msg.member.id).then(data => {
      if (data === null) return msg.reply("you don't have any stats registered right now.")
      let now = new Date()
      let today = new Date(now.getFullYear(), now.getUTCMonth(), now.getUTCDate()).getTime()
      let dataObj = {}
      if (data.messages) Object.entries(data.messages).forEach(m => dataObj[m[0]] ? Object.assign(dataObj[m[0]], { msgs: m[1] }) : dataObj[m[0]] = { msgs: m[1] })
      if (data.commands) Object.entries(data.commands).forEach(c => dataObj[c[0]] ? Object.assign(dataObj[c[0]], { cmds: c[1] }) : dataObj[c[0]] = { cmds: c[1] })
      let dataArr = Object.entries(dataObj).sort()
      let field = []

      for (let i in dataArr) {
        let date = dataArr[i][0]
        if (today - parseInt(date) <= 172800000) {
          let parsed = moment(parseInt(date)).format("MMM Do")
          if (data.messages && dataArr[i][1].msgs) field.push({
            name: `Messages on ${parsed}`,
            value: data.messages[date],
            inline: dataArr[i] ? (dataArr[i][1].cmds ? true : false) : false
          })
          if (data.commands && dataArr[i][1].cmds) field.push({
            name: `Commands on ${parsed}`,
            value: data.commands[date],
            inline: dataArr[i] ? (dataArr[i][1].msgs ? true : false) : false
          })
        }
        // if (field.length === 3) break; <- Pretty sure this line is useless because of the if statement, right?
      }

      let sortRoles = Object.entries(roles).sort((a, b) => a[1].threshold - b[1].threshold)
      let nextRole = sortRoles.find(r => r[1].threshold > data.consecutive.length)
      field.push(
        {
          name: `Consecutive active days`,
          value: data.consecutive.length,
          inline: true
        },
        {
          name: `Days needed for next rank`,
          value: (nextRole) ? nextRole[1].threshold - data.consecutive.length : 'N/A',
          inline: true
        }
      )
      msg.channel.sendMessage('', false, {
        color: 0x59f442,
        title: `${msg.author.username} - Statistics`,
        thumbnail: {
          url: msg.author.avatarURL
        },
        fields: field
      }).catch(bugsnag.notify)
    }).catch(e => {
      msg.reply('an unexpected error occured while getting your stats, try again later.')
      console.error(e)
    })
  }
}

commands['stats-reset'] = {
  adminOnly: true,
  modOnly: false,
  fn: function (bot, msg, suffix) {
    r.db('DFB').table('analytics').get(suffix).then(data => {
      if (data !== null) {
        msg.reply(`you're about to reset the stats for ${suffix}, are you sure?`).then(() => {
          wait(bot, msg).then(resp => {
            if (resp === null) {
              msg.channel.sendMessage('No answer given in time, operation aborted.')
            }
            if (resp === false) {
              msg.channel.sendMessage('Operation aborted.')
            }
            if (resp === true) {
              msg.channel.sendMessage(`Are you **ABSOLUTELY** sure? This can not be undone!`).then(() => {
                wait(bot, msg).then(resp2 => {
                  if (resp2 === null) {
                    msg.channel.sendMessage('No answer given in time, operation aborted.')
                  }
                  if (resp2 === false) {
                    msg.channel.sendMessage('Operation aborted.')
                  }
                  if (resp2 === true) {
                    r.db('DFB').table('analytics').get(suffix).delete().run().then(() => {
                      msg.channel.sendMessage(`Stats for ${suffix} are deleted.`)
                    }).catch(e => {
                      bugsnag.notify(e)
                      msg.channel.sendMessage(`Failed to delete stats for ${suffix}`)
                    })
                  }
                })
              })
            }
          })
        })
      } else {
        msg.reply(`no data for ${suffix} found.`)
      }
    })
  }
}

commands.lookup = {
  adminOnly: true,
  modOnly: false,
  fn: function (bot, msg, suffix) {
    let moment = require('moment') // forgive me father for i have sinned
    analytics.getPoints((msg.mentions.length !== 0) ? msg.mentions[0].id : suffix).then(data => {
      if (data === null) return msg.reply("couldn't find data on this user.")
      let member = msg.guild.members.find(member => member.id === data.id)
      let now = new Date()
      let today = new Date(now.getFullYear(), now.getUTCMonth(), now.getUTCDate()).getTime()
      let dataObj = {}
      if (data.messages) Object.entries(data.messages).forEach(m => dataObj[m[0]] ? Object.assign(dataObj[m[0]], { msgs: m[1] }) : dataObj[m[0]] = { msgs: m[1] })
      if (data.commands) Object.entries(data.commands).forEach(c => dataObj[c[0]] ? Object.assign(dataObj[c[0]], { cmds: c[1] }) : dataObj[c[0]] = { cmds: c[1] })
      let dataArr = Object.entries(dataObj).sort()
      let field = []

      for (let i in dataArr) {
        let date = dataArr[i][0]
        if (today - parseInt(date) <= 172800000) {
          let parsed = moment(parseInt(date)).format("MMM Do")
          if (data.messages && dataArr[i][1].msgs) field.push({
            name: `Messages on ${parsed}`,
            value: data.messages[date],
            inline: dataArr[i] ? (dataArr[i][1].cmds ? true : false) : false
          })
          if (data.commands && dataArr[i][1].cmds) field.push({
            name: `Commands on ${parsed}`,
            value: data.commands[date],
            inline: dataArr[i] ? (dataArr[i][1].msgs ? true : false) : false
          })
        }
        // if (field.length === 3) break; <- Pretty sure this line is useless because of the if statement, right?
      }

      let sortRoles = Object.entries(roles).sort((a, b) => a[1].threshold - b[1].threshold)
      let nextRole = sortRoles.find(r => r[1].threshold > data.consecutive.length)
      field.push(
        {
          name: `Consecutive active days`,
          value: data.consecutive.length,
          inline: true
        },
        {
          name: `Days needed for next rank`,
          value: (nextRole) ? nextRole[1].threshold - data.consecutive.length : 'N/A',
          inline: true
        }
      )
      msg.channel.sendMessage('', false, {
        color: 0x59f442,
        title: `Statistics for ${member.username}##{member.discriminator}`,
        thumbnail: {
          url: msg.author.avatarURL
        },
        fields: field
      })
    }).catch(e => {
      msg.reply('an unexpected error occured while getting your stats, try again later.')
      console.error(e)
    })
  }
}

commands.fetch = {
  phantom: true,
  adminOnly: true,
  modOnly: false,
  fn: function (bot, msg) {
    msg.channel.fetchMessages().then(g => {
      msg.reply(`fetched ${g.messages.length} messages in this channel.`).then(f => {
        setTimeout(() => bot.Messages.deleteMessages([msg, f]), config.timeouts.messageDelete)
      })
    })
  }
}

commands.shutdown = {
  phantom: true,
  adminOnly: true,
  modOnly: false,
  fn: function (bot, msg) {
    msg.reply('shutting down...').then(() => {
      process.exit(0)
    })
  }
}

function wait (bot, msg) {
  let yn = /^y(es)?$|^n(o)?$/i
  return new Promise((resolve, reject) => {
    bot.Dispatcher.on('MESSAGE_CREATE', function doStuff (c) {
      var time = setTimeout(() => {
        resolve(null)
        bot.Dispatcher.removeListener('MESSAGE_CREATE', doStuff)
      }, config.timeouts.duplicateConfirm) // We won't wait forever for the person to anwser
      if (c.message.channel.id !== msg.channel.id) return
      if (c.message.author.id !== msg.author.id) return
      if (c.message.content.match(yn) === null) return
      else {
        resolve((c.message.content.match(/^y(es)?/i) !== null))
        bot.Dispatcher.removeListener('MESSAGE_CREATE', doStuff)
        clearTimeout(time)
      }
    })
  })
}

exports.Commands = commands
<|endoftext|>


<commit_before>"use strict";

var chai = require('../node_modules/chai/chai.js');
var expect = chai.expect;

var _parse = function(str) {
  delete require.cache[require.resolve('../test/test-data.json')];
  var testArray = require('../test/test-data.json');
  return ODataArrayFilter.parseAndFilter(str, testArray).data;
};

/* global ODataArrayFilter */
describe('ODataFilterParser', function() {

  it('should handle no filter', function() {
    var arr = _parse("$filter='");
    expect(arr.length).to.equal(5);
  });

  it('should handle simple string field filters', function() {
    var arr = _parse("$filter=eyeColor eq 'blue'");
    expect(arr.length).to.equal(2);
    expect(arr[0].index).to.equal(2);
    expect(arr[1].index).to.equal(4);

    arr = _parse("$filter=eyeColor eq null");
    expect(arr.length).to.equal(1);
    expect(arr[0].index).to.equal(3);

    arr = _parse("$filter=eyeColor ne 'blue'");
    expect(arr.length).to.equal(3);
    expect(arr[0].index).to.equal(0);
    expect(arr[1].index).to.equal(1);
    expect(arr[2].index).to.equal(3);

    arr = _parse("$filter=eyeColor ne null");
    expect(arr.length).to.equal(4);
    expect(arr[0].index).to.equal(0);
    expect(arr[1].index).to.equal(1);
    expect(arr[2].index).to.equal(2);
    expect(arr[3].index).to.equal(4);
  });

  it('should handle simple numeric field filters', function() {
    var arr = _parse("$filter=age eq 33");
    expect(arr.length).to.equal(1);
    expect(arr[0].index).to.equal(0);

    arr = _parse("$filter=age ne 33");
    expect(arr.length).to.equal(4);
    expect(arr[0].index).to.equal(1);
    expect(arr[1].index).to.equal(2);
    expect(arr[2].index).to.equal(3);
    expect(arr[3].index).to.equal(4);

    arr = _parse("$filter=age lt 35");
    expect(arr.length).to.equal(2);
    expect(arr[0].index).to.equal(0);
    expect(arr[1].index).to.equal(3);

    arr = _parse("$filter=age le 33");
    expect(arr.length).to.equal(2);
    expect(arr[0].index).to.equal(0);
    expect(arr[1].index).to.equal(3);

    arr = _parse("$filter=age gt 35");
    expect(arr.length).to.equal(2);
    expect(arr[0].index).to.equal(2);
    expect(arr[1].index).to.equal(4);

    arr = _parse("$filter=age ge 33");
    expect(arr.length).to.equal(3);
    expect(arr[0].index).to.equal(0);
    expect(arr[1].index).to.equal(2);
    expect(arr[2].index).to.equal(4);
  });

  it('should handle simple date field filters', function() {
    var arr = _parse("$filter=registered eq datetime'2016-08-08T07:18:17'");
    expect(arr.length).to.equal(1);
    expect(arr[0].index).to.equal(3);

    arr = _parse("$filter=registered ne datetime'2016-08-08T07:18:17'");
    expect(arr.length).to.equal(4);
    expect(arr[0].index).to.equal(0);
    expect(arr[1].index).to.equal(1);
    expect(arr[2].index).to.equal(2);
    expect(arr[3].index).to.equal(4);

    arr = _parse("$filter=registered lt datetime'2015-12-15T00:00:00'");
    expect(arr.length).to.equal(3);
    expect(arr[0].index).to.equal(0);
    expect(arr[1].index).to.equal(1);
    expect(arr[2].index).to.equal(2);

    arr = _parse("$filter=registered le datetime'2014-11-22T09:59:23'");
    expect(arr.length).to.equal(2);
    expect(arr[0].index).to.equal(1);
    expect(arr[1].index).to.equal(2);

    arr = _parse("$filter=registered gt datetime'2015-12-15T00:00:00'");
    expect(arr.length).to.equal(2);
    expect(arr[0].index).to.equal(3);
    expect(arr[1].index).to.equal(4);

    arr = _parse("$filter=registered ge datetime'2014-11-22T09:59:23'");
    expect(arr.length).to.equal(4);
    expect(arr[0].index).to.equal(0);
    expect(arr[1].index).to.equal(2);
    expect(arr[2].index).to.equal(3);
    expect(arr[3].index).to.equal(4);
  });

  it('should handle tolower and toupper', function() {
    var arr = _parse("$filter=tolower(company) eq 'bleeko'");
    expect(arr.length).to.equal(1);
    expect(arr[0].index).to.equal(0);

    arr = _parse("$filter=toupper(eyeColor) eq 'BLUE'");
    expect(arr.length).to.equal(2);
    expect(arr[0].index).to.equal(2);
    expect(arr[1].index).to.equal(4);
  });

  it('should handle substringof', function() {
    var arr = _parse("$filter=substringof('zwit', email) eq true");
    expect(arr.length).to.equal(1);
    expect(arr[0].index).to.equal(4);
  });

  it('should handle the combination of tolower and substringof', function() {
    var arr = _parse("$filter=substringof('entu', tolower(company)) eq true");
    expect(arr.length).to.equal(1);
    expect(arr[0].index).to.equal(3);
  });

  it('should handle ORed expressions', function() {
    var arr = _parse("$filter=age lt 30 or age eq null");
    expect(arr.length).to.equal(2);
    expect(arr[0].index).to.equal(3);
    expect(arr[1].index).to.equal(1);
  });

  it('should handle ANDed expressions', function() {
    var arr = _parse("$filter=registered lt datetime'2016-08-10T00:00:00' and registered gt datetime'2016-08-04T00:00:00'");
    expect(arr.length).to.equal(1);
    expect(arr[0].index).to.equal(3);
  });

  it('should handle a really complicated expression', function() {
    var arr = _parse("$filter=((eyeColor ne null) and " +
      "((substringof('shawna',tolower(name)) eq true) or " +
      "(substringof('shawna',tolower(email)) eq true) or " +
      "(substringof('shawna',tolower(greeting)) eq true))) and " +
      "(favoriteFruit eq 'apple' or favoriteFruit eq null)");
    expect(arr.length).to.equal(1);
    expect(arr[0].index).to.equal(2);
  });

  it('should handle orderby', function() {
    var arr = _parse("$orderby=name desc");
    expect(arr.length).to.equal(5);
    expect(arr[0].index).to.equal(4);
    expect(arr[1].index).to.equal(1);
    expect(arr[2].index).to.equal(2);
    expect(arr[3].index).to.equal(0);
    expect(arr[4].index).to.equal(3);
  });

  it('should handle top', function() {
    var arr = _parse("$top=3");
    expect(arr.length).to.equal(3);
    expect(arr[0].index).to.equal(0);
    expect(arr[1].index).to.equal(1);
    expect(arr[2].index).to.equal(2);
  });

  it('should handle skip', function() {
    var arr = _parse("$skip=3");
    expect(arr.length).to.equal(2);
    expect(arr[0].index).to.equal(3);
    expect(arr[1].index).to.equal(4);
  });

  it('should handle filter, top, skip, and orderby', function() {
    var arr = _parse("$top=2&$skip=1&$filter=age ne null&$orderby=company desc");
    expect(arr.length).to.equal(2);
    expect(arr[0].index).to.equal(2);
    expect(arr[1].index).to.equal(4);
  });

});
<commit_msg>little additional test coverage<commit_after>"use strict";

var chai = require('../node_modules/chai/chai.js');
var expect = chai.expect;

var _getTestArray = function() {
  delete require.cache[require.resolve('../test/test-data.json')];
  return require('../test/test-data.json');
};

var _parse = function(str) {
  return ODataArrayFilter.parseAndFilter(str, _getTestArray()).data;
};

/* global ODataArrayFilter */
describe('ODataFilterParser', function() {

  it('should handle no filter', function() {
    var arr = _parse("$filter='");
    expect(arr.length).to.equal(5);
  });

  it('should handle simple string field filters', function() {
    var arr = _parse("$filter=eyeColor eq 'blue'");
    expect(arr.length).to.equal(2);
    expect(arr[0].index).to.equal(2);
    expect(arr[1].index).to.equal(4);

    arr = _parse("$filter=eyeColor eq null");
    expect(arr.length).to.equal(1);
    expect(arr[0].index).to.equal(3);

    arr = _parse("$filter=eyeColor ne 'blue'");
    expect(arr.length).to.equal(3);
    expect(arr[0].index).to.equal(0);
    expect(arr[1].index).to.equal(1);
    expect(arr[2].index).to.equal(3);

    arr = _parse("$filter=eyeColor ne null");
    expect(arr.length).to.equal(4);
    expect(arr[0].index).to.equal(0);
    expect(arr[1].index).to.equal(1);
    expect(arr[2].index).to.equal(2);
    expect(arr[3].index).to.equal(4);
  });

  it('should handle simple numeric field filters', function() {
    var arr = _parse("$filter=age eq 33");
    expect(arr.length).to.equal(1);
    expect(arr[0].index).to.equal(0);

    arr = _parse("$filter=age ne 33");
    expect(arr.length).to.equal(4);
    expect(arr[0].index).to.equal(1);
    expect(arr[1].index).to.equal(2);
    expect(arr[2].index).to.equal(3);
    expect(arr[3].index).to.equal(4);

    arr = _parse("$filter=age lt 35");
    expect(arr.length).to.equal(2);
    expect(arr[0].index).to.equal(0);
    expect(arr[1].index).to.equal(3);

    arr = _parse("$filter=age le 33");
    expect(arr.length).to.equal(2);
    expect(arr[0].index).to.equal(0);
    expect(arr[1].index).to.equal(3);

    arr = _parse("$filter=age gt 35");
    expect(arr.length).to.equal(2);
    expect(arr[0].index).to.equal(2);
    expect(arr[1].index).to.equal(4);

    arr = _parse("$filter=age ge 33");
    expect(arr.length).to.equal(3);
    expect(arr[0].index).to.equal(0);
    expect(arr[1].index).to.equal(2);
    expect(arr[2].index).to.equal(4);
  });

  it('should handle simple date field filters', function() {
    var arr = _parse("$filter=registered eq datetime'2016-08-08T07:18:17'");
    expect(arr.length).to.equal(1);
    expect(arr[0].index).to.equal(3);

    arr = _parse("$filter=registered ne datetime'2016-08-08T07:18:17'");
    expect(arr.length).to.equal(4);
    expect(arr[0].index).to.equal(0);
    expect(arr[1].index).to.equal(1);
    expect(arr[2].index).to.equal(2);
    expect(arr[3].index).to.equal(4);

    arr = _parse("$filter=registered lt datetime'2015-12-15T00:00:00'");
    expect(arr.length).to.equal(3);
    expect(arr[0].index).to.equal(0);
    expect(arr[1].index).to.equal(1);
    expect(arr[2].index).to.equal(2);

    arr = _parse("$filter=registered le datetime'2014-11-22T09:59:23'");
    expect(arr.length).to.equal(2);
    expect(arr[0].index).to.equal(1);
    expect(arr[1].index).to.equal(2);

    arr = _parse("$filter=registered gt datetime'2015-12-15T00:00:00'");
    expect(arr.length).to.equal(2);
    expect(arr[0].index).to.equal(3);
    expect(arr[1].index).to.equal(4);

    arr = _parse("$filter=registered ge datetime'2014-11-22T09:59:23'");
    expect(arr.length).to.equal(4);
    expect(arr[0].index).to.equal(0);
    expect(arr[1].index).to.equal(2);
    expect(arr[2].index).to.equal(3);
    expect(arr[3].index).to.equal(4);
  });

  it('should handle tolower and toupper', function() {
    var arr = _parse("$filter=tolower(company) eq 'bleeko'");
    expect(arr.length).to.equal(1);
    expect(arr[0].index).to.equal(0);

    arr = _parse("$filter=toupper(eyeColor) eq 'BLUE'");
    expect(arr.length).to.equal(2);
    expect(arr[0].index).to.equal(2);
    expect(arr[1].index).to.equal(4);
  });

  it('should handle substringof', function() {
    var arr = _parse("$filter=substringof('zwit', email) eq true");
    expect(arr.length).to.equal(1);
    expect(arr[0].index).to.equal(4);
  });

  it('should handle the combination of tolower and substringof', function() {
    var arr = _parse("$filter=substringof('entu', tolower(company)) eq true");
    expect(arr.length).to.equal(1);
    expect(arr[0].index).to.equal(3);
  });

  it('should handle ORed expressions', function() {
    var arr = _parse("$filter=age lt 30 or age eq null");
    expect(arr.length).to.equal(2);
    expect(arr[0].index).to.equal(3);
    expect(arr[1].index).to.equal(1);
  });

  it('should handle ANDed expressions', function() {
    var arr = _parse("$filter=registered lt datetime'2016-08-10T00:00:00' and registered gt datetime'2016-08-04T00:00:00'");
    expect(arr.length).to.equal(1);
    expect(arr[0].index).to.equal(3);
  });

  it('should handle a really complicated expression', function() {
    var arr = _parse("$filter=((eyeColor ne null) and " +
      "((substringof('shawna',tolower(name)) eq true) or " +
      "(substringof('shawna',tolower(email)) eq true) or " +
      "(substringof('shawna',tolower(greeting)) eq true))) and " +
      "(favoriteFruit eq 'apple' or favoriteFruit eq null)");
    expect(arr.length).to.equal(1);
    expect(arr[0].index).to.equal(2);
  });

  it('should handle orderby', function() {
    var arr = _parse("$orderby=name desc");
    expect(arr.length).to.equal(5);
    expect(arr[0].index).to.equal(4);
    expect(arr[1].index).to.equal(1);
    expect(arr[2].index).to.equal(2);
    expect(arr[3].index).to.equal(0);
    expect(arr[4].index).to.equal(3);
  });

  it('should handle top', function() {
    var arr = _parse("$top=3");
    expect(arr.length).to.equal(3);
    expect(arr[0].index).to.equal(0);
    expect(arr[1].index).to.equal(1);
    expect(arr[2].index).to.equal(2);
  });

  it('should handle skip', function() {
    var arr = _parse("$skip=3");
    expect(arr.length).to.equal(2);
    expect(arr[0].index).to.equal(3);
    expect(arr[1].index).to.equal(4);
  });

  it('should handle filter, top, skip, and orderby', function() {
    var arr = _parse("$top=2&$skip=1&$filter=age ne null&$orderby=company desc");
    expect(arr.length).to.equal(2);
    expect(arr[0].index).to.equal(2);
    expect(arr[1].index).to.equal(4);
    arr = _parse("$top=2&$skip=1&$filter=age ne null&$orderby=company asc");
    expect(arr.length).to.equal(2);
    expect(arr[0].index).to.equal(4);
    expect(arr[1].index).to.equal(2);
    arr = _parse("$top=2&$skip=1&$filter=age ne null&$orderby=foobar asc");
    expect(arr.length).to.equal(2);
    expect(arr[0].index).to.equal(2);
    expect(arr[1].index).to.equal(3);
  });

});
<|endoftext|>


<commit_before>/**
 * k-d Tree JavaScript - V 1.01
 *
 * https://github.com/ubilabs/kd-tree-javascript
 *
 * @author Mircea Pricop <pricop@ubilabs.net>, 2012
 * @author Martin Kleppe <kleppe@ubilabs.net>, 2012
 * @author Ubilabs http://ubilabs.net, 2012
 * @license MIT License <http://www.opensource.org/licenses/mit-license.php>
 */

 (function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        define(['exports'], factory);
    } else if (typeof exports === 'object') {
        factory(exports);
    } else {
        factory((root.commonJsStrict = {}));
    }
}(this, function (exports) {
  function Node(obj, dimension, parent) {
    this.obj = obj;
    this.left = null;
    this.right = null;
    this.parent = parent;
    this.dimension = dimension;
  }

  function kdTree(points, metric, dimensions) {

    var self = this;

    function buildTree(points, depth, parent) {
      var dim = depth % dimensions.length,
        median,
        node;

      if (points.length === 0) {
        return null;
      }
      if (points.length === 1) {
        return new Node(points[0], dim, parent);
      }

      points.sort(function (a, b) {
        return a[dimensions[dim]] - b[dimensions[dim]];
      });

      median = Math.floor(points.length / 2);
      node = new Node(points[median], dim, parent);
      node.left = buildTree(points.slice(0, median), depth + 1, node);
      node.right = buildTree(points.slice(median + 1), depth + 1, node);

      return node;
    }

    // Reloads a serialied tree
    function loadTree (data) {
      // Just need to restore the `parent` parameter
      self.root = data;

      function restoreParent (root) {
        if (root.left) {
          root.left.parent = root;
          restoreParent(root.left);
        }

        if (root.right) {
          root.right.parent = root;
          restoreParent(root.right);
        }
      }

      restoreParent(self.root);
    }

    // If points is not an array, assume we're loading a pre-built tree
    if (!Array.isArray(points)) loadTree(points, metric, dimensions);
    else this.root = buildTree(points, 0, null);

    // Convert to a JSON serializable structure; this just requires removing
    // the `parent` property
    this.toJSON = function (src) {
      if (!src) src = this.root;
      var dest = new Node(src.obj, src.dimension, null);
      if (src.left) dest.left = self.toJSON(src.left);
      if (src.right) dest.right = self.toJSON(src.right);
      return dest;
    };

    this.insert = function (point) {
      function innerSearch(node, parent) {

        if (node === null) {
          return parent;
        }

        var dimension = dimensions[node.dimension];
        if (point[dimension] < node.obj[dimension]) {
          return innerSearch(node.left, node);
        } else {
          return innerSearch(node.right, node);
        }
      }

      var insertPosition = innerSearch(this.root, null),
        newNode,
        dimension;

      if (insertPosition === null) {
        this.root = new Node(point, 0, null);
        return;
      }

      newNode = new Node(point, (insertPosition.dimension + 1) % dimensions.length, insertPosition);
      dimension = dimensions[insertPosition.dimension];

      if (point[dimension] < insertPosition.obj[dimension]) {
        insertPosition.left = newNode;
      } else {
        insertPosition.right = newNode;
      }
    };

    this.remove = function (point) {
      var node;

      function nodeSearch(node) {
        if (node === null) {
          return null;
        }

        if (node.obj === point) {
          return node;
        }

        var dimension = dimensions[node.dimension];

        if (point[dimension] < node.obj[dimension]) {
          return nodeSearch(node.left, node);
        } else {
          return nodeSearch(node.right, node);
        }
      }

      function removeNode(node) {
        var nextNode,
          nextObj,
          pDimension;

        function findMin(node, dim) {
          var dimension,
            own,
            left,
            right,
            min;

          if (node === null) {
            return null;
          }

          dimension = dimensions[dim];

          if (node.dimension === dim) {
            if (node.left !== null) {
              return findMin(node.left, dim);
            }
            return node;
          }

          own = node.obj[dimension];
          left = findMin(node.left, dim);
          right = findMin(node.right, dim);
          min = node;

          if (left !== null && left.obj[dimension] < own) {
            min = left;
          }
          if (right !== null && right.obj[dimension] < min.obj[dimension]) {
            min = right;
          }
          return min;
        }

        if (node.left === null && node.right === null) {
          if (node.parent === null) {
            self.root = null;
            return;
          }

          pDimension = dimensions[node.parent.dimension];

          if (node.obj[pDimension] < node.parent.obj[pDimension]) {
            node.parent.left = null;
          } else {
            node.parent.right = null;
          }
          return;
        }

        // If the right subtree is not empty, swap with the minimum element on the
        // node's dimension. If it is empty, we swap the left and right subtrees and
        // do the same.
        if (node.right !== null) {
          nextNode = findMin(node.right, node.dimension);
          nextObj = nextNode.obj;
          removeNode(nextNode);
          node.obj = nextObj;
        } else {
          nextNode = findMin(node.left, node.dimension);
          nextObj = nextNode.obj;
          removeNode(nextNode);
          node.right = node.left;
          node.left = null;
          node.obj = nextObj;
        }

      }

      node = nodeSearch(self.root);

      if (node === null) { return; }

      removeNode(node);
    };

    this.nearest = function (point, maxNodes, maxDistance) {
      var i,
        result,
        bestNodes;

      bestNodes = new BinaryHeap(
        function (e) { return -e[1]; }
      );

      function nearestSearch(node) {
        var bestChild,
          dimension = dimensions[node.dimension],
          ownDistance = metric(point, node.obj),
          linearPoint = {},
          linearDistance,
          otherChild,
          i;

        function saveNode(node, distance) {
          bestNodes.push([node, distance]);
          if (bestNodes.size() > maxNodes) {
            bestNodes.pop();
          }
        }

        for (i = 0; i < dimensions.length; i += 1) {
          if (i === node.dimension) {
            linearPoint[dimensions[i]] = point[dimensions[i]];
          } else {
            linearPoint[dimensions[i]] = node.obj[dimensions[i]];
          }
        }

        linearDistance = metric(linearPoint, node.obj);

        if (node.right === null && node.left === null) {
          if (bestNodes.size() < maxNodes || ownDistance < bestNodes.peek()[1]) {
            saveNode(node, ownDistance);
          }
          return;
        }

        if (node.right === null) {
          bestChild = node.left;
        } else if (node.left === null) {
          bestChild = node.right;
        } else {
          if (point[dimension] < node.obj[dimension]) {
            bestChild = node.left;
          } else {
            bestChild = node.right;
          }
        }

        nearestSearch(bestChild);

        if (bestNodes.size() < maxNodes || ownDistance < bestNodes.peek()[1]) {
          saveNode(node, ownDistance);
        }

        if (bestNodes.size() < maxNodes || Math.abs(linearDistance) < bestNodes.peek()[1]) {
          if (bestChild === node.left) {
            otherChild = node.right;
          } else {
            otherChild = node.left;
          }
          if (otherChild !== null) {
            nearestSearch(otherChild);
          }
        }
      }

      if (maxDistance) {
        for (i = 0; i < maxNodes; i += 1) {
          bestNodes.push([null, maxDistance]);
        }
      }

      nearestSearch(self.root);

      result = [];

      for (i = 0; i < Math.min(maxNodes, bestNodes.content.length); i += 1) {
        if (bestNodes.content[i][0]) {
          result.push([bestNodes.content[i][0].obj, bestNodes.content[i][1]]);
        }
      }
      return result;
    };

    this.balanceFactor = function () {
      function height(node) {
        if (node === null) {
          return 0;
        }
        return Math.max(height(node.left), height(node.right)) + 1;
      }

      function count(node) {
        if (node === null) {
          return 0;
        }
        return count(node.left) + count(node.right) + 1;
      }

      return height(self.root) / (Math.log(count(self.root)) / Math.log(2));
    };
  }

  // Binary heap implementation from:
  // http://eloquentjavascript.net/appendix2.html

  function BinaryHeap(scoreFunction){
    this.content = [];
    this.scoreFunction = scoreFunction;
  }

  BinaryHeap.prototype = {
    push: function(element) {
      // Add the new element to the end of the array.
      this.content.push(element);
      // Allow it to bubble up.
      this.bubbleUp(this.content.length - 1);
    },

    pop: function() {
      // Store the first element so we can return it later.
      var result = this.content[0];
      // Get the element at the end of the array.
      var end = this.content.pop();
      // If there are any elements left, put the end element at the
      // start, and let it sink down.
      if (this.content.length > 0) {
        this.content[0] = end;
        this.sinkDown(0);
      }
      return result;
    },

    peek: function() {
      return this.content[0];
    },

    remove: function(node) {
      var len = this.content.length;
      // To remove a value, we must search through the array to find
      // it.
      for (var i = 0; i < len; i++) {
        if (this.content[i] == node) {
          // When it is found, the process seen in 'pop' is repeated
          // to fill up the hole.
          var end = this.content.pop();
          if (i != len - 1) {
            this.content[i] = end;
            if (this.scoreFunction(end) < this.scoreFunction(node))
              this.bubbleUp(i);
            else
              this.sinkDown(i);
          }
          return;
        }
      }
      throw new Error("Node not found.");
    },

    size: function() {
      return this.content.length;
    },

    bubbleUp: function(n) {
      // Fetch the element that has to be moved.
      var element = this.content[n];
      // When at 0, an element can not go up any further.
      while (n > 0) {
        // Compute the parent element's index, and fetch it.
        var parentN = Math.floor((n + 1) / 2) - 1,
            parent = this.content[parentN];
        // Swap the elements if the parent is greater.
        if (this.scoreFunction(element) < this.scoreFunction(parent)) {
          this.content[parentN] = element;
          this.content[n] = parent;
          // Update 'n' to continue at the new position.
          n = parentN;
        }
        // Found a parent that is less, no need to move it further.
        else {
          break;
        }
      }
    },

    sinkDown: function(n) {
      // Look up the target element and its score.
      var length = this.content.length,
          element = this.content[n],
          elemScore = this.scoreFunction(element);

      while(true) {
        // Compute the indices of the child elements.
        var child2N = (n + 1) * 2, child1N = child2N - 1;
        // This is used to store the new position of the element,
        // if any.
        var swap = null;
        // If the first child exists (is inside the array)...
        if (child1N < length) {
          // Look it up and compute its score.
          var child1 = this.content[child1N],
              child1Score = this.scoreFunction(child1);
          // If the score is less than our element's, we need to swap.
          if (child1Score < elemScore)
            swap = child1N;
        }
        // Do the same checks for the other child.
        if (child2N < length) {
          var child2 = this.content[child2N],
              child2Score = this.scoreFunction(child2);
          if (child2Score < (swap == null ? elemScore : child1Score)){
            swap = child2N;
          }
        }

        // If the element needs to be moved, swap it, and continue.
        if (swap != null) {
          this.content[n] = this.content[swap];
          this.content[swap] = element;
          n = swap;
        }
        // Otherwise, we are done.
        else {
          break;
        }
      }
    }
  };

  this.kdTree = kdTree;

  exports.kdTree = kdTree;
  exports.BinaryHeap = BinaryHeap;
}));
<commit_msg>Update kdTree.js<commit_after>/**
 * k-d Tree JavaScript - V 1.01
 *
 * https://github.com/ubilabs/kd-tree-javascript
 *
 * @author Mircea Pricop <pricop@ubilabs.net>, 2012
 * @author Martin Kleppe <kleppe@ubilabs.net>, 2012
 * @author Ubilabs http://ubilabs.net, 2012
 * @license MIT License <http://www.opensource.org/licenses/mit-license.php>
 */

 (function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        define(['exports'], factory);
    } else if (typeof exports === 'object') {
        factory(exports);
    } else {
        factory((root.commonJsStrict = {}));
    }
}(this, function (exports) {
  function Node(obj, dimension, parent) {
    this.obj = obj;
    this.left = null;
    this.right = null;
    this.parent = parent;
    this.dimension = dimension;
  }

  function kdTree(points, metric, dimensions) {

    var self = this;

    function buildTree(points, depth, parent) {
      var dim = depth % dimensions.length,
        median,
        node;

      if (points.length === 0) {
        return null;
      }
      if (points.length === 1) {
        return new Node(points[0], dim, parent);
      }

      points.sort(function (a, b) {
        return a[dimensions[dim]] - b[dimensions[dim]];
      });

      median = Math.floor(points.length / 2);
      node = new Node(points[median], dim, parent);
      node.left = buildTree(points.slice(0, median), depth + 1, node);
      node.right = buildTree(points.slice(median + 1), depth + 1, node);

      return node;
    }

    // Reloads a serialied tree
    function loadTree (data) {
      // Just need to restore the `parent` parameter
      self.root = data;

      function restoreParent (root) {
        if (root.left) {
          root.left.parent = root;
          restoreParent(root.left);
        }

        if (root.right) {
          root.right.parent = root;
          restoreParent(root.right);
        }
      }

      restoreParent(self.root);
    }

    // If points is not an array, assume we're loading a pre-built tree
    if (!Array.isArray(points)) loadTree(points, metric, dimensions);
    else this.root = buildTree(points, 0, null);

    // Convert to a JSON serializable structure; this just requires removing
    // the `parent` property
    this.toJSON = function (src) {
      if (!src) src = this.root;
      var dest = new Node(src.obj, src.dimension, null);
      if (src.left) dest.left = self.toJSON(src.left);
      if (src.right) dest.right = self.toJSON(src.right);
      return dest;
    };

    this.insert = function (point) {
      function innerSearch(node, parent) {

        if (node === null) {
          return parent;
        }

        var dimension = dimensions[node.dimension];
        if (point[dimension] < node.obj[dimension]) {
          return innerSearch(node.left, node);
        } else {
          return innerSearch(node.right, node);
        }
      }

      var insertPosition = innerSearch(this.root, null),
        newNode,
        dimension;

      if (insertPosition === null) {
        this.root = new Node(point, 0, null);
        return;
      }

      newNode = new Node(point, (insertPosition.dimension + 1) % dimensions.length, insertPosition);
      dimension = dimensions[insertPosition.dimension];

      if (point[dimension] < insertPosition.obj[dimension]) {
        insertPosition.left = newNode;
      } else {
        insertPosition.right = newNode;
      }
    };

    this.remove = function (point) {
      var node;

      function nodeSearch(node) {
        if (node === null) {
          return null;
        }

        if (node.obj === point) {
          return node;
        }

        var dimension = dimensions[node.dimension];

        if (point[dimension] < node.obj[dimension]) {
          return nodeSearch(node.left, node);
        } else {
          return nodeSearch(node.right, node);
        }
      }

      function removeNode(node) {
        var nextNode,
          nextObj,
          pDimension;

        function findMin(node, dim) {
          var dimension,
            own,
            left,
            right,
            min;

          if (node === null) {
            return null;
          }

          dimension = dimensions[dim];

          if (node.dimension === dim) {
            if (node.left !== null) {
              return findMin(node.left, dim);
            }
            return node;
          }

          own = node.obj[dimension];
          left = findMin(node.left, dim);
          right = findMin(node.right, dim);
          min = node;

          if (left !== null && left.obj[dimension] < own) {
            min = left;
          }
          if (right !== null && right.obj[dimension] < min.obj[dimension]) {
            min = right;
          }
          return min;
        }

        if (node.left === null && node.right === null) {
          if (node.parent === null) {
            self.root = null;
            return;
          }

          pDimension = dimensions[node.parent.dimension];

          if (node.obj[pDimension] < node.parent.obj[pDimension]) {
            node.parent.left = null;
          } else {
            node.parent.right = null;
          }
          return;
        }

        // If the right subtree is not empty, swap with the minimum element on the
        // node's dimension. If it is empty, we swap the left and right subtrees and
        // do the same.
        if (node.right !== null) {
          nextNode = findMin(node.right, node.dimension);
          nextObj = nextNode.obj;
          removeNode(nextNode);
          node.obj = nextObj;
        } else {
          nextNode = findMin(node.left, node.dimension);
          nextObj = nextNode.obj;
          removeNode(nextNode);
          node.right = node.left;
          node.left = null;
          node.obj = nextObj;
        }

      }

      node = nodeSearch(self.root);

      if (node === null) { return; }

      removeNode(node);
    };

    this.nearest = function (point, maxNodes, maxDistance) {
      var i,
        result,
        bestNodes;

      bestNodes = new BinaryHeap(
        function (e) { return -e[1]; }
      );

      function nearestSearch(node) {
        var bestChild,
          dimension = dimensions[node.dimension],
          ownDistance = metric(point, node.obj),
          linearPoint = {},
          linearDistance,
          otherChild,
          i;

        function saveNode(node, distance) {
          bestNodes.push([node, distance]);
          if (bestNodes.size() > maxNodes) {
            bestNodes.pop();
          }
        }

        for (i = 0; i < dimensions.length; i += 1) {
          if (i === node.dimension) {
            linearPoint[dimensions[i]] = point[dimensions[i]];
          } else {
            linearPoint[dimensions[i]] = node.obj[dimensions[i]];
          }
        }

        linearDistance = metric(linearPoint, node.obj);

        if (node.right === null && node.left === null) {
          if (bestNodes.size() < maxNodes || ownDistance < bestNodes.peek()[1]) {
            saveNode(node, ownDistance);
          }
          return;
        }

        if (node.right === null) {
          bestChild = node.left;
        } else if (node.left === null) {
          bestChild = node.right;
        } else {
          if (point[dimension] < node.obj[dimension]) {
            bestChild = node.left;
          } else {
            bestChild = node.right;
          }
        }

        nearestSearch(bestChild);

        if (bestNodes.size() < maxNodes || ownDistance < bestNodes.peek()[1]) {
          saveNode(node, ownDistance);
        }

        if (bestNodes.size() < maxNodes || Math.abs(linearDistance) < bestNodes.peek()[1]) {
          if (bestChild === node.left) {
            otherChild = node.right;
          } else {
            otherChild = node.left;
          }
          if (otherChild !== null) {
            nearestSearch(otherChild);
          }
        }
      }

      if (maxDistance) {
        for (i = 0; i < maxNodes; i += 1) {
          bestNodes.push([null, maxDistance]);
        }
      }

      if(self.root)
        nearestSearch(self.root);

      result = [];

      for (i = 0; i < Math.min(maxNodes, bestNodes.content.length); i += 1) {
        if (bestNodes.content[i][0]) {
          result.push([bestNodes.content[i][0].obj, bestNodes.content[i][1]]);
        }
      }
      return result;
    };

    this.balanceFactor = function () {
      function height(node) {
        if (node === null) {
          return 0;
        }
        return Math.max(height(node.left), height(node.right)) + 1;
      }

      function count(node) {
        if (node === null) {
          return 0;
        }
        return count(node.left) + count(node.right) + 1;
      }

      return height(self.root) / (Math.log(count(self.root)) / Math.log(2));
    };
  }

  // Binary heap implementation from:
  // http://eloquentjavascript.net/appendix2.html

  function BinaryHeap(scoreFunction){
    this.content = [];
    this.scoreFunction = scoreFunction;
  }

  BinaryHeap.prototype = {
    push: function(element) {
      // Add the new element to the end of the array.
      this.content.push(element);
      // Allow it to bubble up.
      this.bubbleUp(this.content.length - 1);
    },

    pop: function() {
      // Store the first element so we can return it later.
      var result = this.content[0];
      // Get the element at the end of the array.
      var end = this.content.pop();
      // If there are any elements left, put the end element at the
      // start, and let it sink down.
      if (this.content.length > 0) {
        this.content[0] = end;
        this.sinkDown(0);
      }
      return result;
    },

    peek: function() {
      return this.content[0];
    },

    remove: function(node) {
      var len = this.content.length;
      // To remove a value, we must search through the array to find
      // it.
      for (var i = 0; i < len; i++) {
        if (this.content[i] == node) {
          // When it is found, the process seen in 'pop' is repeated
          // to fill up the hole.
          var end = this.content.pop();
          if (i != len - 1) {
            this.content[i] = end;
            if (this.scoreFunction(end) < this.scoreFunction(node))
              this.bubbleUp(i);
            else
              this.sinkDown(i);
          }
          return;
        }
      }
      throw new Error("Node not found.");
    },

    size: function() {
      return this.content.length;
    },

    bubbleUp: function(n) {
      // Fetch the element that has to be moved.
      var element = this.content[n];
      // When at 0, an element can not go up any further.
      while (n > 0) {
        // Compute the parent element's index, and fetch it.
        var parentN = Math.floor((n + 1) / 2) - 1,
            parent = this.content[parentN];
        // Swap the elements if the parent is greater.
        if (this.scoreFunction(element) < this.scoreFunction(parent)) {
          this.content[parentN] = element;
          this.content[n] = parent;
          // Update 'n' to continue at the new position.
          n = parentN;
        }
        // Found a parent that is less, no need to move it further.
        else {
          break;
        }
      }
    },

    sinkDown: function(n) {
      // Look up the target element and its score.
      var length = this.content.length,
          element = this.content[n],
          elemScore = this.scoreFunction(element);

      while(true) {
        // Compute the indices of the child elements.
        var child2N = (n + 1) * 2, child1N = child2N - 1;
        // This is used to store the new position of the element,
        // if any.
        var swap = null;
        // If the first child exists (is inside the array)...
        if (child1N < length) {
          // Look it up and compute its score.
          var child1 = this.content[child1N],
              child1Score = this.scoreFunction(child1);
          // If the score is less than our element's, we need to swap.
          if (child1Score < elemScore)
            swap = child1N;
        }
        // Do the same checks for the other child.
        if (child2N < length) {
          var child2 = this.content[child2N],
              child2Score = this.scoreFunction(child2);
          if (child2Score < (swap == null ? elemScore : child1Score)){
            swap = child2N;
          }
        }

        // If the element needs to be moved, swap it, and continue.
        if (swap != null) {
          this.content[n] = this.content[swap];
          this.content[swap] = element;
          n = swap;
        }
        // Otherwise, we are done.
        else {
          break;
        }
      }
    }
  };

  this.kdTree = kdTree;

  exports.kdTree = kdTree;
  exports.BinaryHeap = BinaryHeap;
}));
<|endoftext|>


<commit_before>var fs = require("fs");
var Emitter = require("events").EventEmitter;

function GPIO(setup) {
  // echo "3" > /sys/class/gpio/export

  this.supportedModes = setup.modes;
  this.mode = setup.analogChannel !== undefined ? 0 : 1;
  this.report = 0;
  this.value = 0;

  // this.fd =
}

GPIO.Pins = {
  "0": "40",
  "1": "41",
  "2": "31",
  "3": "30",
  "4": "28",
  "5": "17",
  "6": "24",
  "7": "27",
  "8": "26",
  "9": "19",
  "10": "16",
  "11": "25",
  "12": "38",
  "13": "39",

  "A0": "37",
  "A1": "36",
  "A2": "23",
  "A3": "22",
  "A4": "29",
  "A5": "20"
};

GPIO.Analog = {
  // TODO:
  // - MUX pins
  Nums: {
    "A0": "0",
    "A1": "1",
    "A2": "2",
    "A3": "3",
    "A4": "4",
    "A5": "5"
  }
};

GPIO.Digital = {
  Nums: {
    "0": "0",
    "1": "1",
    "2": "2",
    "3": "3",
    "4": "4",
    "5": "5",
    "6": "6",
    "7": "7",
    "8": "8",
    "9": "9",
    "10": "10",
    "11": "11",
    "12": "12",
    "13": "13"
  },
  PWM: {
    "3": "3",
    "5": "5",
    "6": "6",
    "9": "1",
    "10": "7",
    "11": "4"
  },
};

GPIO.Modes = [
  "in", "out", "analog", "pwm", "servo"
];

//_PWMDICT    = {'3':"3",'5':"5",'6':"6",'9':"1",'10':"7",'11':"4"};
// {
//   0: "in",
//   1: "out",

// };

GPIO.Port = function() {
  var args = [].slice.call(arguments);
  return "/sys/class/gpio/" + args.join("/");
  // For some reason this makes node choke?
  // return "/sys/class/gpio/" + [].join.call(arguments, "/");
};

module.exports = GPIO;
<commit_msg>Start with a null mode to ensure that pin ports are exported for all initial reads/writes<commit_after>var fs = require("fs");
var Emitter = require("events").EventEmitter;

function GPIO(setup) {
  // echo "3" > /sys/class/gpio/export

  this.supportedModes = setup.modes;
  this.mode = null;
  this.report = 0;
  this.value = 0;

  // this.fd =
}

GPIO.Pins = {
  "0": "40",
  "1": "41",
  "2": "31",
  "3": "30",
  "4": "28",
  "5": "17",
  "6": "24",
  "7": "27",
  "8": "26",
  "9": "19",
  "10": "16",
  "11": "25",
  "12": "38",
  "13": "39",

  "A0": "37",
  "A1": "36",
  "A2": "23",
  "A3": "22",
  "A4": "29",
  "A5": "20"
};

GPIO.Analog = {
  // TODO:
  // - MUX pins
  Nums: {
    "A0": "0",
    "A1": "1",
    "A2": "2",
    "A3": "3",
    "A4": "4",
    "A5": "5"
  }
};

GPIO.Digital = {
  Nums: {
    "0": "0",
    "1": "1",
    "2": "2",
    "3": "3",
    "4": "4",
    "5": "5",
    "6": "6",
    "7": "7",
    "8": "8",
    "9": "9",
    "10": "10",
    "11": "11",
    "12": "12",
    "13": "13"
  },
  PWM: {
    "3": "3",
    "5": "5",
    "6": "6",
    "9": "1",
    "10": "7",
    "11": "4"
  },
};

GPIO.Modes = [
  "in", "out", "analog", "pwm", "servo"
];

//_PWMDICT    = {'3':"3",'5':"5",'6':"6",'9':"1",'10':"7",'11':"4"};
// {
//   0: "in",
//   1: "out",

// };

GPIO.Port = function() {
  var args = [].slice.call(arguments);
  return "/sys/class/gpio/" + args.join("/");
  // For some reason this makes node choke?
  // return "/sys/class/gpio/" + [].join.call(arguments, "/");
};

module.exports = GPIO;
<|endoftext|>


<commit_before>var linz = require('../'),
    async = require('async'),
    moment = require('moment');

var modelExportHelpers = function modelExportHelpers (req, res) {

    var getRecordData = function getRecordData (fields, record) {

        var orderedRecord = {};

        // order field names in the selected order
        fields.forEach(function (fieldName) {
            orderedRecord[fieldName] = prettifyData(fieldName, record[fieldName]);
        });

        return linz.utils.json2CSV(orderedRecord);

    };

    var prettifyData = function prettifyData (fieldName, val) {

        if (val === undefined || val === '' || val === null) {
            return val;
        }

        if (typeof val === 'number') {
            return val;
        }

        var Model = linz.get('models')[req.body.modelName];

        if (Model.schema.tree[fieldName].ref) {
            return val.title;
        }

        if (Array.isArray(val)) {

            if (val.length === 0) {
                return '';
            }

            var strArr = [];

            val.forEach(function (obj) {

                if (typeof obj === 'object') {

                    var arr = [];

                    // tostring embedded object
                    Object.keys(obj).forEach(function (key) {
                        if (key === '_id' || key === 'id' || key === 'dateModified' || key === 'dateCreated' || obj[key] === '' || obj[key] === undefined) {
                            return;
                        }
                        return arr.push(key + ': ' + obj[key].toString());
                    });

                    return strArr.push(arr.join(', '));
                }

                return strArr.push(obj.toString());

            });

            return strArr.join(', ');

        }

        if (typeof val === 'boolean' || 'true,false,yes,no'.indexOf(val) >=0 ) {
            return (linz.utils.asBoolean(val) ? 'Yes' : 'No')
        }

        return val;

    };

    return {

        mongooseToCSV: function mongooseToCSV (fields, form) {

            var count = 0;

            return function (doc) {

                var str = '',
                    record = doc.toObject({virtuals: true }),
                    columnNames = fields.join();

                if (count !== 0) {
                    return getRecordData(fields, record);
                }

                var arr = [];

                // get field labels
                fields.forEach(function (fieldName) {
                    arr.push(form[fieldName].label);
                });

                str = arr.join() + '\n';

                count++;

                return str + getRecordData(fields, record);

            }

        },

        getFilters: function getFilters (cb) {

            if (!req.body.filters.length) {
                return cb(null, {});
            }

            var Model = linz.get('models')[req.body.modelName],
                form = JSON.parse(req.body.filters);

            // check if there are any filters in the form post
            if (!form.selectedFilters) {
                return cb(null, {});
            }

            async.waterfall([

                function (callback) {

                    Model.getGrid(function (err, grid) {

                        if (err) {
                            return cb(err);
                        }

                        return callback(null, grid);

                    });
                },

                function (grid, callback) {

                    var filters = {};

                    async.each(form.selectedFilters.split(','), function (fieldName, filtersDone) {

                        // call the filter renderer and update the content with the result
                        grid.filters[fieldName].filter.filter(fieldName, form, function (err, result) {

                            if (err) {
                                return filtersDone(err);
                            }

                            filters = Model.addSearchFilter(filters, result);

                            return filtersDone(null);

                        });

                    }, function (err) {

                        if (err) {
                            return cb(err);
                        }

                        // consolidate filters into query
                        if (Object.keys(filters).length) {
                            filters = Model.setFiltersAsQuery(filters);
                        }

                        return cb(err, filters);

                    });

                }

            ]);

        },

        addIdFilters: function addIdFilters (filters, cb) {

            if (!req.body.selectedIds.length) {
                return cb(null, filters);
            }

            filters = filters || { '$and': [] };
            filters['$and'] = filters['$and'] || [];

            var ids = [],
                db  = linz.mongoose.connection.db;

            // compile ids into ObjectId type
            req.body.selectedIds.split(',').forEach(function (id) {
                ids.push(new db.bsonLib.ObjectID(id));
            });

            // let's add selected Ids to the filters
            filters['$and'].push({
                _id: { $in: ids}
            });

            return cb(null, filters);

        },

        getForm: function getForm(filters, cb) {

            var Model = linz.get('models')[req.body.modelName];

            Model.getForm(function (err, form) {
                return cb(err, filters, form)
            });

        },

        getGrid: function getGrid (filters, form, cb) {

            var Model = linz.get('models')[req.body.modelName];
            Model.getGrid( function (err, grid) {
                return cb(err, filters, form, grid);
            });

        }

    }

}

// this will retrieve the export object, using Linz's default export handler amongst custom export handlers
// this is based on the knowledge that only Linz's default export handler can have an `action` of `export`
// `exports` should be model.grid.export
var getExport = function (exports) {

    var exp = undefined;

    // retrieve the export object
    exports.forEach(function (_export) {

        // Linz's default export function is called export
        if (_export.action && _export.action === 'export') {
            exp = _export;
        }

    });

    // if the export object could not be found, throw an error
    if (!exp) {
        throw new Error('The export was using Linz default export method, yet the model\'s grid.export object could not be found.');
    }

    return exp;

}

module.exports = {

    get: function (req, res, next) {

        req.linz.model = linz.get('models')[req.params.model];

        req.linz.model.getGrid(function (err, grid) {

            if (err) {
                return next(err);
            }

            // attach our grid object to the model
            req.linz.model.grid = grid;

            // retrieve the export object
            req.linz.export = getExport(grid.export);
            req.linz.export.fields = {};

            // retrieve the form to provide a list of fields to choose from
            req.linz.model.getForm( function (formErr, form){

                if (formErr) {
                    return next(formErr);
                }

                var excludedFieldNames = req.linz.export.exclusions.concat(',__v').split(','),
                    fieldLabels = {};

                // get a list of field names
                req.linz.model.schema.eachPath(function (pathname, schemaType) {

                    if (excludedFieldNames.indexOf(pathname) >= 0) {
                        // exit if current field name is one of the exclusion fields
                        return;
                    }

                    // get a list of fields by the label ready for sorting
                    fieldLabels[form[pathname].label] = pathname;

                });

                // sort fields by label
                var sortedFieldsByLabel = Object.keys(fieldLabels).sort();

                // iterate through sorted label and re-constructs in the order of labels
                sortedFieldsByLabel.forEach(function (label) {
                    req.linz.export.fields[fieldLabels[label]] = label;
                });

                return next(null);

            });

        });

    },

    post: function (req, res, next) {

        var Model = linz.get('models')[req.body.modelName];

        // check if there is custom export function for model
        if (Model.export) {
            return Model.export(req, res, next);
        }

        // since a custom export function is not defined for model, use local export function
        var asyncFn = [],
            helpers = modelExportHelpers(req, res),
            test = 'test';

        asyncFn.push(helpers.getFilters);
        asyncFn.push(helpers.addIdFilters);
        asyncFn.push(helpers.getForm);
        asyncFn.push(helpers.getGrid);

        // get the actual export object
        asyncFn.push(function (filters, form, grid, callback) {

            // retrieve the export
            var _export = getExport(grid.export);
            _export.fields = {};

            return callback(null, filters, form, grid, _export);

        });

        async.waterfall(asyncFn, function (err, filters, form, grid, exportObj) {

            if (err) {
                return next(err);
            }

            var fields = req.body.selectedFields.split(','),
                refFieldNames = [],
                filterFieldNames = [];

            fields.forEach(function (fieldName, index, arr) {

                // remove any property that doesn't exist in the model
                if (!Model.schema.tree[fieldName]) {
                    return arr.splice(index, 1);
                }

                // check if there any ref fields selected to be exported
                if(!Model.schema.tree[fieldName].ref) {
                    return;
                }

                return refFieldNames.push(fieldName);

            });

            // check if _id is excluded
            if (exportObj.exclusions.indexOf('_id') >= 0) {
                filterFieldNames.push('-_id');
            }

            filterFieldNames = filterFieldNames.concat(fields);

            // serve .csv file
            res.setHeader('Content-disposition', 'attachment; filename=' + Model.formtools.model.plural + '-' + moment(Date.now()).format('l').replace(/\//g, '.', 'g') + '.csv');
            res.writeHead(200, { 'Content-Type': 'text/csv' });

            // pipe data to response stream
            Model.find( filters, filterFieldNames.join(' ') ).populate( refFieldNames.join(' '), '-_id -__v -dateCreated -dateModified -createdBy -modifiedBy' ).stream({ transform: helpers.mongooseToCSV(fields, form) }).pipe(res);

        });

    }
}
<commit_msg>Removing the model.export functionality.<commit_after>var linz = require('../'),
    async = require('async'),
    moment = require('moment');

var modelExportHelpers = function modelExportHelpers (req, res) {

    var getRecordData = function getRecordData (fields, record) {

        var orderedRecord = {};

        // order field names in the selected order
        fields.forEach(function (fieldName) {
            orderedRecord[fieldName] = prettifyData(fieldName, record[fieldName]);
        });

        return linz.utils.json2CSV(orderedRecord);

    };

    var prettifyData = function prettifyData (fieldName, val) {

        if (val === undefined || val === '' || val === null) {
            return val;
        }

        if (typeof val === 'number') {
            return val;
        }

        var Model = linz.get('models')[req.body.modelName];

        if (Model.schema.tree[fieldName].ref) {
            return val.title;
        }

        if (Array.isArray(val)) {

            if (val.length === 0) {
                return '';
            }

            var strArr = [];

            val.forEach(function (obj) {

                if (typeof obj === 'object') {

                    var arr = [];

                    // tostring embedded object
                    Object.keys(obj).forEach(function (key) {
                        if (key === '_id' || key === 'id' || key === 'dateModified' || key === 'dateCreated' || obj[key] === '' || obj[key] === undefined) {
                            return;
                        }
                        return arr.push(key + ': ' + obj[key].toString());
                    });

                    return strArr.push(arr.join(', '));
                }

                return strArr.push(obj.toString());

            });

            return strArr.join(', ');

        }

        if (typeof val === 'boolean' || 'true,false,yes,no'.indexOf(val) >=0 ) {
            return (linz.utils.asBoolean(val) ? 'Yes' : 'No')
        }

        return val;

    };

    return {

        mongooseToCSV: function mongooseToCSV (fields, form) {

            var count = 0;

            return function (doc) {

                var str = '',
                    record = doc.toObject({virtuals: true }),
                    columnNames = fields.join();

                if (count !== 0) {
                    return getRecordData(fields, record);
                }

                var arr = [];

                // get field labels
                fields.forEach(function (fieldName) {
                    arr.push(form[fieldName].label);
                });

                str = arr.join() + '\n';

                count++;

                return str + getRecordData(fields, record);

            }

        },

        getFilters: function getFilters (cb) {

            if (!req.body.filters.length) {
                return cb(null, {});
            }

            var Model = linz.get('models')[req.body.modelName],
                form = JSON.parse(req.body.filters);

            // check if there are any filters in the form post
            if (!form.selectedFilters) {
                return cb(null, {});
            }

            async.waterfall([

                function (callback) {

                    Model.getGrid(function (err, grid) {

                        if (err) {
                            return cb(err);
                        }

                        return callback(null, grid);

                    });
                },

                function (grid, callback) {

                    var filters = {};

                    async.each(form.selectedFilters.split(','), function (fieldName, filtersDone) {

                        // call the filter renderer and update the content with the result
                        grid.filters[fieldName].filter.filter(fieldName, form, function (err, result) {

                            if (err) {
                                return filtersDone(err);
                            }

                            filters = Model.addSearchFilter(filters, result);

                            return filtersDone(null);

                        });

                    }, function (err) {

                        if (err) {
                            return cb(err);
                        }

                        // consolidate filters into query
                        if (Object.keys(filters).length) {
                            filters = Model.setFiltersAsQuery(filters);
                        }

                        return cb(err, filters);

                    });

                }

            ]);

        },

        addIdFilters: function addIdFilters (filters, cb) {

            if (!req.body.selectedIds.length) {
                return cb(null, filters);
            }

            filters = filters || { '$and': [] };
            filters['$and'] = filters['$and'] || [];

            var ids = [],
                db  = linz.mongoose.connection.db;

            // compile ids into ObjectId type
            req.body.selectedIds.split(',').forEach(function (id) {
                ids.push(new db.bsonLib.ObjectID(id));
            });

            // let's add selected Ids to the filters
            filters['$and'].push({
                _id: { $in: ids}
            });

            return cb(null, filters);

        },

        getForm: function getForm(filters, cb) {

            var Model = linz.get('models')[req.body.modelName];

            Model.getForm(function (err, form) {
                return cb(err, filters, form)
            });

        },

        getGrid: function getGrid (filters, form, cb) {

            var Model = linz.get('models')[req.body.modelName];
            Model.getGrid( function (err, grid) {
                return cb(err, filters, form, grid);
            });

        }

    }

}

// this will retrieve the export object, using Linz's default export handler amongst custom export handlers
// this is based on the knowledge that only Linz's default export handler can have an `action` of `export`
// `exports` should be model.grid.export
var getExport = function (exports) {

    var exp = undefined;

    // retrieve the export object
    exports.forEach(function (_export) {

        // Linz's default export function is called export
        if (_export.action && _export.action === 'export') {
            exp = _export;
        }

    });

    // if the export object could not be found, throw an error
    if (!exp) {
        throw new Error('The export was using Linz default export method, yet the model\'s grid.export object could not be found.');
    }

    return exp;

}

module.exports = {

    get: function (req, res, next) {

        req.linz.model = linz.get('models')[req.params.model];

        req.linz.model.getGrid(function (err, grid) {

            if (err) {
                return next(err);
            }

            // attach our grid object to the model
            req.linz.model.grid = grid;

            // retrieve the export object
            req.linz.export = getExport(grid.export);
            req.linz.export.fields = {};

            // retrieve the form to provide a list of fields to choose from
            req.linz.model.getForm( function (formErr, form){

                if (formErr) {
                    return next(formErr);
                }

                var excludedFieldNames = req.linz.export.exclusions.concat(',__v').split(','),
                    fieldLabels = {};

                // get a list of field names
                req.linz.model.schema.eachPath(function (pathname, schemaType) {

                    if (excludedFieldNames.indexOf(pathname) >= 0) {
                        // exit if current field name is one of the exclusion fields
                        return;
                    }

                    // get a list of fields by the label ready for sorting
                    fieldLabels[form[pathname].label] = pathname;

                });

                // sort fields by label
                var sortedFieldsByLabel = Object.keys(fieldLabels).sort();

                // iterate through sorted label and re-constructs in the order of labels
                sortedFieldsByLabel.forEach(function (label) {
                    req.linz.export.fields[fieldLabels[label]] = label;
                });

                return next(null);

            });

        });

    },

    post: function (req, res, next) {

        var Model = linz.get('models')[req.body.modelName];

        // since a custom export function is not defined for model, use local export function
        var asyncFn = [],
            helpers = modelExportHelpers(req, res),
            test = 'test';

        asyncFn.push(helpers.getFilters);
        asyncFn.push(helpers.addIdFilters);
        asyncFn.push(helpers.getForm);
        asyncFn.push(helpers.getGrid);

        // get the actual export object
        asyncFn.push(function (filters, form, grid, callback) {

            // retrieve the export
            var _export = getExport(grid.export);
            _export.fields = {};

            return callback(null, filters, form, grid, _export);

        });

        async.waterfall(asyncFn, function (err, filters, form, grid, exportObj) {

            if (err) {
                return next(err);
            }

            var fields = req.body.selectedFields.split(','),
                refFieldNames = [],
                filterFieldNames = [];

            fields.forEach(function (fieldName, index, arr) {

                // remove any property that doesn't exist in the model
                if (!Model.schema.tree[fieldName]) {
                    return arr.splice(index, 1);
                }

                // check if there any ref fields selected to be exported
                if(!Model.schema.tree[fieldName].ref) {
                    return;
                }

                return refFieldNames.push(fieldName);

            });

            // check if _id is excluded
            if (exportObj.exclusions.indexOf('_id') >= 0) {
                filterFieldNames.push('-_id');
            }

            filterFieldNames = filterFieldNames.concat(fields);

            // serve .csv file
            res.setHeader('Content-disposition', 'attachment; filename=' + Model.formtools.model.plural + '-' + moment(Date.now()).format('l').replace(/\//g, '.', 'g') + '.csv');
            res.writeHead(200, { 'Content-Type': 'text/csv' });

            // pipe data to response stream
            Model.find( filters, filterFieldNames.join(' ') ).populate( refFieldNames.join(' '), '-_id -__v -dateCreated -dateModified -createdBy -modifiedBy' ).stream({ transform: helpers.mongooseToCSV(fields, form) }).pipe(res);

        });

    }
}
<|endoftext|>