<commit_before>exports.categories = {
    'Authentication': {
        'bell': {
            url: 'https://github.com/hapijs/bell',
            description: 'Third-party login plugin for hapi with built in Facebook, GitHub, Google, Twitter, Yahoo, Foursquare, and Windows Live support'
        },
        'hapi-auth-basic': {
            url: 'https://github.com/hapijs/hapi-auth-basic',
            description: 'An HTTP Basic authentication scheme'
        },
        'hapi-auth-cookie': {
            url: 'https://github.com/hapijs/hapi-auth-cookie',
            description: 'A cookie-based session authentication scheme'
        },
        'hapi-auth-hawk': {
            url :'https://github.com/hapijs/hapi-auth-hawk',
            description: 'Hawk authentication plugin'
        }
    },
    'Documentation': {
        'lout': {
            url: 'https://github.com/hapijs/lout',
            description: 'A browsable documentation generator'
        }
    },
    'Logging': {
        'good': {
            url: 'https://github.com/hapijs/good',
            description: 'A logging plugin that supports output to console, file and udp/http endpoints'
        }
    },
    'Session', {
        'crumb': {
            url: 'https://github.com/hapijs/crumb',
            description: 'CSRF crumb generation and validation for hapi'
        }
        'yar': {
            url: 'https://github.com/hapijs/yar',
            description: 'A hapi session plugin and cookie jar'
        }
    }
    'Utility': {
        'bassmaster': {
            url: 'https://github.com/hapijs/bassmaster',
            description: 'The batch endpoint makes it easy to combine multiple requests into a single one'
        },
        'poop': {
            url: 'https://github.com/hapijs/poop',
            description: 'Plugin for taking a process dump and cleaning up after an uncaught exception'
        },
        'scooter': {
            url: 'https://github.com/hapijs/scooter',
            description: 'User-agent information plugin'
        }
        'tv': {
            uri: 'https://github.com/hapijs/tv',
            description: 'Interactive debug console plugin for hapi servers'
        }
    }
};
<commit_msg>Update plugins.js<commit_after>exports.categories = {
    'Authentication': {
        'bell': {
            url: 'https://github.com/hapijs/bell',
            description: 'Third-party login plugin for hapi with built in Facebook, GitHub, Google, Twitter, Yahoo, Foursquare, and Windows Live support'
        },
        'hapi-auth-basic': {
            url: 'https://github.com/hapijs/hapi-auth-basic',
            description: 'An HTTP Basic authentication scheme'
        },
        'hapi-auth-cookie': {
            url: 'https://github.com/hapijs/hapi-auth-cookie',
            description: 'A cookie-based session authentication scheme'
        },
        'hapi-auth-hawk': {
            url :'https://github.com/hapijs/hapi-auth-hawk',
            description: 'Hawk authentication plugin'
        }
    },
    'Documentation': {
        'lout': {
            url: 'https://github.com/hapijs/lout',
            description: 'A browsable documentation generator'
        }
    },
    'Logging': {
        'good': {
            url: 'https://github.com/hapijs/good',
            description: 'A logging plugin that supports output to console, file and udp/http endpoints'
        }
    },
    'Session', {
        'crumb': {
            url: 'https://github.com/hapijs/crumb',
            description: 'CSRF crumb generation and validation for hapi'
        }
        'yar': {
            url: 'https://github.com/hapijs/yar',
            description: 'A hapi session plugin and cookie jar'
        }
    },
    'Utility': {
        'bassmaster': {
            url: 'https://github.com/hapijs/bassmaster',
            description: 'The batch endpoint makes it easy to combine multiple requests into a single one'
        },
        'poop': {
            url: 'https://github.com/hapijs/poop',
            description: 'Plugin for taking a process dump and cleaning up after an uncaught exception'
        },
        'scooter': {
            url: 'https://github.com/hapijs/scooter',
            description: 'User-agent information plugin'
        }
        'tv': {
            uri: 'https://github.com/hapijs/tv',
            description: 'Interactive debug console plugin for hapi servers'
        }
    }
};
<|endoftext|>


<commit_before>var EventEmitter = require('events').EventEmitter;
var util = require('util');
var utils = require('../../util/utils');
var sio = require('socket.io');
var Tracer = require('../../util/tracer');

var Acceptor = function(opts, cb){
  EventEmitter.call(this);
  this.bufferMsg = opts.bufferMsg;
  this.interval = opts.interval;  // flush interval in ms
  this.rpcDebugLog = opts.rpcDebugLog;
  this.rpcLogger = opts.rpcLogger;
  this._interval = null;          // interval object
  this.sockets = {};
  this.msgQueues = {};
  this.cb = cb;
};
util.inherits(Acceptor, EventEmitter);

var pro = Acceptor.prototype;

pro.listen = function(port) {
  //check status
  if(!!this.inited) {
    utils.invokeCallback(this.cb, new Error('already inited.'));
    return;
  }
  this.inited = true;

  var self = this;

  this.server = sio.listen(port);

  this.server.set('log level', 0);

  this.server.server.on('error', function(err) {
    self.emit('error', err);
  });

  this.server.sockets.on('connection', function(socket) {
    self.sockets[socket.id] = socket;

    socket.on('message', function(pkg) {
      try {
        if(pkg instanceof Array) {
          processMsgs(socket, self, pkg);
        } else {
          processMsg(socket, self, pkg);
        }
      } catch(e) {
        // socke.io would broken if uncaugth the exception
        console.error('rpc server process message error: ' + e);
      }
    });

    socket.on('disconnect', function(reason) {
      delete self.sockets[socket.id];
      delete self.msgQueues[socket.id];
    });
  });

  if(this.bufferMsg) {
    this._interval = setInterval(function() {
      flush(self);
    }, this.interval);
  }
};

pro.close = function() {
  if(!!this.closed) {
    return;
  }
  this.closed = true;
  if(this._interval) {
    clearInterval(this._interval);
    this._interval = null;
  }
  try {
    this.server.server.close();
  } catch(err){
  }
  this.emit('closed');
};

var cloneError = function(origin) {
  // copy the stack infos for Error instance json result is empty
  var res = {
    msg: origin.msg,
    stack: origin.stack
  };
  return res;
};

var processMsg = function(socket, acceptor, pkg) {
  var tracer = new Tracer(acceptor.rpcLogger, acceptor.rpcDebugLog, pkg.remote, pkg.source, pkg.msg, pkg.traceId, pkg.seqId);
  tracer.info('server', __filename, 'processMsg', 'ws-acceptor receive message and try to process message');
  acceptor.cb.call(null, tracer, pkg.msg, function() {
    var args = Array.prototype.slice.call(arguments, 0);
    for(var i=0, l=args.length; i<l; i++) {
      if(args[i] instanceof Error) {
        args[i] = cloneError(args[i]);
      }
    }
    var resp;
    if(tracer.isEnabled) {
      resp = {traceId: tracer.id, seqId: tracer.seq, source: tracer.source, id: pkg.id, resp: Array.prototype.slice.call(args, 0)};
    }
    else {
      resp = {id: pkg.id, resp: Array.prototype.slice.call(args, 0)};
    }
    if(acceptor.bufferMsg) {
      enqueue(socket, acceptor, resp);
    } else {
      socket.emit('message', resp);
    }
  });
};

var processMsgs = function(socket, acceptor, pkgs) {
  for(var i=0, l=pkgs.length; i<l; i++) {
    processMsg(socket, acceptor, pkgs[i]);
  }
};

var enqueue = function(socket, acceptor, msg) {
  var queue = acceptor.msgQueues[socket.id];
  if(!queue) {
    queue = acceptor.msgQueues[socket.id] = [];
  }
  queue.push(msg);
};

var flush = function(acceptor) {
  var sockets = acceptor.sockets, queues = acceptor.msgQueues, queue, socket;
  for(var socketId in queues) {
    socket = sockets[socketId];
    if(!socket) {
      // clear pending messages if the socket not exist any more
      delete queues[socketId];
      continue;
    }
    queue = queues[socketId];
    if(!queue.length) {
      continue;
    }
    socket.emit('message', queue);
    queues[socketId] = [];
  }
};

/**
 * create acceptor
 *
 * @param opts init params
 * @param cb(tracer, msg, cb) callback function that would be invoked when new message arrives
 */
module.exports.create = function(opts, cb) {
  return new Acceptor(opts || {}, cb);
};
<commit_msg>* add rpc whitelist<commit_after>var EventEmitter = require('events').EventEmitter;
var util = require('util');
var utils = require('../../util/utils');
var sio = require('socket.io');
var Tracer = require('../../util/tracer');

var Acceptor = function(opts, cb){
  EventEmitter.call(this);
  this.bufferMsg = opts.bufferMsg;
  this.interval = opts.interval;  // flush interval in ms
  this.rpcDebugLog = opts.rpcDebugLog;
  this.rpcLogger = opts.rpcLogger;
  this.whitelist = opts.whitelist;
  this._interval = null;          // interval object
  this.sockets = {};
  this.msgQueues = {};
  this.cb = cb;
};
util.inherits(Acceptor, EventEmitter);

var pro = Acceptor.prototype;

pro.listen = function(port) {
  //check status
  if(!!this.inited) {
    utils.invokeCallback(this.cb, new Error('already inited.'));
    return;
  }
  this.inited = true;

  var self = this;

  this.server = sio.listen(port);

  this.server.set('log level', 0);

  this.server.server.on('error', function(err) {
    self.emit('error', err);
  });

  this.server.sockets.on('connection', function(socket) {
    self.sockets[socket.id] = socket;

    self.emit('connection', {id: socket.id, ip: socket.handshake.address.address});

    socket.on('message', function(pkg) {
      try {
        if(pkg instanceof Array) {
          processMsgs(socket, self, pkg);
        } else {
          processMsg(socket, self, pkg);
        }
      } catch(e) {
        // socke.io would broken if uncaugth the exception
        console.error('rpc server process message error: ' + e);
      }
    });

    socket.on('disconnect', function(reason) {
      delete self.sockets[socket.id];
      delete self.msgQueues[socket.id];
    });
  });

  this.on('connection', this.ipFilter.bind(this));

  if(this.bufferMsg) {
    this._interval = setInterval(function() {
      flush(self);
    }, this.interval);
  }
};

pro.ipFilter = function(obj) {
  if(typeof this.whitelist === 'function') {
    var tmpList = this.whitelist();
    if(!Array.isArray(tmpList)) {
      return;
    }
    if(!!obj && !!obj.ip && !!obj.id && (tmpList.indexOf(obj.ip) == -1)){
      var sock = this.sockets[obj.id];
      if(sock) {
        sock.disconnect('unauthorized');
      }
    }
  }
};

pro.close = function() {
  if(!!this.closed) {
    return;
  }
  this.closed = true;
  if(this._interval) {
    clearInterval(this._interval);
    this._interval = null;
  }
  try {
    this.server.server.close();
  } catch(err){
  }
  this.emit('closed');
};

var cloneError = function(origin) {
  // copy the stack infos for Error instance json result is empty
  var res = {
    msg: origin.msg,
    stack: origin.stack
  };
  return res;
};

var processMsg = function(socket, acceptor, pkg) {
  var tracer = new Tracer(acceptor.rpcLogger, acceptor.rpcDebugLog, pkg.remote, pkg.source, pkg.msg, pkg.traceId, pkg.seqId);
  tracer.info('server', __filename, 'processMsg', 'ws-acceptor receive message and try to process message');
  acceptor.cb.call(null, tracer, pkg.msg, function() {
    var args = Array.prototype.slice.call(arguments, 0);
    for(var i=0, l=args.length; i<l; i++) {
      if(args[i] instanceof Error) {
        args[i] = cloneError(args[i]);
      }
    }
    var resp;
    if(tracer.isEnabled) {
      resp = {traceId: tracer.id, seqId: tracer.seq, source: tracer.source, id: pkg.id, resp: Array.prototype.slice.call(args, 0)};
    }
    else {
      resp = {id: pkg.id, resp: Array.prototype.slice.call(args, 0)};
    }
    if(acceptor.bufferMsg) {
      enqueue(socket, acceptor, resp);
    } else {
      socket.emit('message', resp);
    }
  });
};

var processMsgs = function(socket, acceptor, pkgs) {
  for(var i=0, l=pkgs.length; i<l; i++) {
    processMsg(socket, acceptor, pkgs[i]);
  }
};

var enqueue = function(socket, acceptor, msg) {
  var queue = acceptor.msgQueues[socket.id];
  if(!queue) {
    queue = acceptor.msgQueues[socket.id] = [];
  }
  queue.push(msg);
};

var flush = function(acceptor) {
  var sockets = acceptor.sockets, queues = acceptor.msgQueues, queue, socket;
  for(var socketId in queues) {
    socket = sockets[socketId];
    if(!socket) {
      // clear pending messages if the socket not exist any more
      delete queues[socketId];
      continue;
    }
    queue = queues[socketId];
    if(!queue.length) {
      continue;
    }
    socket.emit('message', queue);
    queues[socketId] = [];
  }
};

/**
 * create acceptor
 *
 * @param opts init params
 * @param cb(tracer, msg, cb) callback function that would be invoked when new message arrives
 */
module.exports.create = function(opts, cb) {
  return new Acceptor(opts || {}, cb);
};
<|endoftext|>


<commit_before>/*
 * NTwitBot - process.js
 * Copyright (C) 2016 Jordan Sne
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

const entities = require('html-entities').AllHtmlEntities;

module.exports = class Process {

    constructor(utils) {
        this.utils = utils;
    }

    /*
     * Processes tracked tweets of the bot. (Saves in database, etc.)
     *   tweets  - Array (Strings): The Tweets to be processed.
     *   Returns - Object:          New data to be saved (null if there is no data).
     */
    processTweets(tweets) {
        const newData = {};

        this.utils.log("Processing " + tweets.length + " new tweets (which do not include RTs)");

        // Process tweets
        for (let i = 0; i < tweets.length; i++) {
            const tweet = tweets[i];

            // Process "< > &" symbols
            tweet.text = entities.decode(tweet.text);

            const tweetWords = tweet.text.split(" ");
            const filteredWords = [];

            for (let i = 0; i < tweetWords.length; i++) {
                let word = tweetWords[i];

                // Remove mentions & links
                if (word.startsWith("@") || word.startsWith("http")) {
                    continue;
                }

                word = word.toLowerCase();
                filteredWords.push(word);
            }

            if (filteredWords.length >= 3) {
                // Capitalize the first word
                filteredWords[0] = this.utils.capitalize(filteredWords[0]);

                // Capitalize any words after a sentence
                for (let i = 1; i < filteredWords.length; i++) {
                    if (this.utils.endsWithPunc(filteredWords[i - 1])) {
                        filteredWords[i] = this.utils.capitalize(filteredWords[i]);
                    }
                }

                // Append period if no punctuation present
                let lastWord = filteredWords[filteredWords.length - 1];
                if (!this.utils.endsWithPunc(lastWord) && !lastWord.endsWith(",")) {
                    filteredWords[filteredWords.length - 1] += ".";
                }

                // Process words into data objects
                for (let i = 0; i < filteredWords.length - 2; i++) {
                    let key = filteredWords[i] + " " + filteredWords[i + 1];

                    // If the key doesn't exist, create a new array..
                    if (!(key in newData)) {
                        newData[key] = [{
                            word: filteredWords[i + 2],
                            time: this.utils.getTime()
                        }];
                    // .. otherwise add it to the existing array
                    } else {
                        newData[key].push({
                            word: filteredWords[i + 2],
                            time: this.utils.getTime()
                        });
                    }
                }
            }
        }

        return newData;
    }

};
<commit_msg>Move word filtering to own method<commit_after>/*
 * NTwitBot - process.js
 * Copyright (C) 2016 Jordan Sne
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

const entities = require('html-entities').AllHtmlEntities;

module.exports = class Process {

    constructor(utils) {
        this.utils = utils;
    }

    /*
     * Processes tracked tweets of the bot. (Saves in database, etc.)
     *   tweets  - Array (Strings): The Tweets to be processed.
     *   Returns - Object:          New data to be saved (null if there is no data).
     */
    processTweets(tweets) {
        const newData = {};

        this.utils.log("Processing " + tweets.length + " new tweets (which do not include RTs)");

        // Process tweets
        for (let i = 0; i < tweets.length; i++) {
            const tweet = tweets[i];

            // Process "< > &" symbols
            tweet.text = entities.decode(tweet.text);

            let filteredWords = this.filterWords(tweet.text.split(" "));

            if (filteredWords.length >= 3) {
                // Capitalize the first word
                filteredWords[0] = this.utils.capitalize(filteredWords[0]);

                // Capitalize any words after a sentence
                for (let i = 1; i < filteredWords.length; i++) {
                    if (this.utils.endsWithPunc(filteredWords[i - 1])) {
                        filteredWords[i] = this.utils.capitalize(filteredWords[i]);
                    }
                }

                // Append period if no punctuation present
                let lastWord = filteredWords[filteredWords.length - 1];
                if (!this.utils.endsWithPunc(lastWord) && !lastWord.endsWith(",")) {
                    filteredWords[filteredWords.length - 1] += ".";
                }

                // Process words into data objects
                for (let i = 0; i < filteredWords.length - 2; i++) {
                    let key = filteredWords[i] + " " + filteredWords[i + 1];

                    // If the key doesn't exist, create a new array..
                    if (!(key in newData)) {
                        newData[key] = [{
                            word: filteredWords[i + 2],
                            time: this.utils.getTime()
                        }];
                    // .. otherwise add it to the existing array
                    } else {
                        newData[key].push({
                            word: filteredWords[i + 2],
                            time: this.utils.getTime()
                        });
                    }
                }
            }
        }

        return newData;
    }

    /*
     * Filters a list of words. Removes usernames and links.
     *   words   - Array (String): List of words.
     *   Returns - Array (String): List of filtered words.
     */
    filterWords(words) {
        const filteredWords = [];

        for (let i = 0; i < words.length; i++) {
            let word = words[i];

            // Remove mentions & links
            if (word.startsWith("@") || word.startsWith("http")) {
                continue;
            }

            word = word.toLowerCase();
            filteredWords.push(word);
        }

        return filteredWords;
    }

};
<|endoftext|>


<commit_before>import React, { Component, createElement, cloneElement } from 'react';
import PropTypes from 'prop-types';
import { Decorator as formsy } from 'formsy-react';
import { Form, Dropdown, Select } from 'semantic-ui-react';
import { filterSuirElementProps } from './utils';

@formsy()
export default class FormsyDropdown extends Component {
  static propTypes = {
    name: PropTypes.string.isRequired,
    as: PropTypes.oneOf([
      Dropdown, Select, Form.Dropdown, Form.Select,
    ]),
    defaultValue: PropTypes.oneOfType([
      PropTypes.number,
      PropTypes.string,
      PropTypes.arrayOf(PropTypes.oneOfType([
        PropTypes.string,
        PropTypes.number,
      ])),
    ]),
    required: PropTypes.bool,
    label: PropTypes.string,
    errorLabel: PropTypes.element,
    isValid: PropTypes.func.isRequired,
    isPristine: PropTypes.func.isRequired,
    setValue: PropTypes.func.isRequired,
    onBlur: PropTypes.func,
    getValue: PropTypes.func.isRequired,
    multiple: PropTypes.bool,
    isFormSubmitted: PropTypes.func.isRequired,
    getErrorMessage: PropTypes.func.isRequired,
    validationError: PropTypes.string,
    validationErrors: PropTypes.object,
    validations: PropTypes.oneOfType(
      [PropTypes.string, PropTypes.object]
    ),
  }

  static defaultProps = {
    as: Dropdown,
    rootElement: Form.Field,
  }

  state = { allowError: false };

  componentDidMount() {
    const { defaultValue, setValue } = this.props;
    if (defaultValue) setValue(defaultValue);
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.isFormSubmitted()) this.showError();
  }

  handleChange = (e, { value }) => {
    const { multiple, getValue, setValue } = this.props;
    if (multiple && getValue() && getValue().length > value.length) this.showError();
    setValue(value);
  }

  showError = () => this.setState({ allowError: true });
  handleClose = () => this.showError();

  render() {
    const {
      as,
      required,
      label,
      getValue,
      defaultValue,
      multiple,
      errorLabel,
      getErrorMessage,
      isValid,
      isPristine,
    } = this.props;

    const shortHandMode = (as === Form.Dropdown || as === Form.Select);
    const error = !isPristine() && !isValid() && this.state.allowError;

    const dropdownProps = {
      onChange: this.handleChange,
      onBlur: this.handleBlur,
      onClose: this.handleClose,
      value: getValue() || defaultValue || multiple && [],
      error,
      ...filterSuirElementProps(this.props),
    };

    const dropdownNode = shortHandMode ? createElement(as).props.control : as;

    return (
      <Form.Field required={ required } error={ error }>
        { shortHandMode && <label> { label } </label> }
        { createElement(dropdownNode, { ...dropdownProps }) }
        { error && errorLabel && cloneElement(errorLabel, {}, getErrorMessage()) }
      </Form.Field>
    );
  }
}
<commit_msg>Fixed initial value warning if it is empty and not multiple. (#10)<commit_after>import React, { Component, createElement, cloneElement } from 'react';
import PropTypes from 'prop-types';
import { Decorator as formsy } from 'formsy-react';
import { Form, Dropdown, Select } from 'semantic-ui-react';
import { filterSuirElementProps } from './utils';

@formsy()
export default class FormsyDropdown extends Component {
  static propTypes = {
    name: PropTypes.string.isRequired,
    as: PropTypes.oneOf([
      Dropdown, Select, Form.Dropdown, Form.Select,
    ]),
    defaultValue: PropTypes.oneOfType([
      PropTypes.number,
      PropTypes.string,
      PropTypes.arrayOf(PropTypes.oneOfType([
        PropTypes.string,
        PropTypes.number,
      ])),
    ]),
    required: PropTypes.bool,
    label: PropTypes.string,
    errorLabel: PropTypes.element,
    isValid: PropTypes.func.isRequired,
    isPristine: PropTypes.func.isRequired,
    setValue: PropTypes.func.isRequired,
    onBlur: PropTypes.func,
    getValue: PropTypes.func.isRequired,
    multiple: PropTypes.bool,
    isFormSubmitted: PropTypes.func.isRequired,
    getErrorMessage: PropTypes.func.isRequired,
    validationError: PropTypes.string,
    validationErrors: PropTypes.object,
    validations: PropTypes.oneOfType(
      [PropTypes.string, PropTypes.object]
    ),
  }

  static defaultProps = {
    as: Dropdown,
    rootElement: Form.Field,
  }

  state = { allowError: false };

  componentDidMount() {
    const { defaultValue, setValue } = this.props;
    if (defaultValue) setValue(defaultValue);
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.isFormSubmitted()) this.showError();
  }

  handleChange = (e, { value }) => {
    const { multiple, getValue, setValue } = this.props;
    if (multiple && getValue() && getValue().length > value.length) this.showError();
    setValue(value);
  }

  showError = () => this.setState({ allowError: true });
  handleClose = () => this.showError();

  render() {
    const {
      as,
      required,
      label,
      getValue,
      defaultValue,
      multiple,
      errorLabel,
      getErrorMessage,
      isValid,
      isPristine,
    } = this.props;

    const shortHandMode = (as === Form.Dropdown || as === Form.Select);
    const error = !isPristine() && !isValid() && this.state.allowError;

    const dropdownProps = {
      onChange: this.handleChange,
      onBlur: this.handleBlur,
      onClose: this.handleClose,
      value: getValue() || defaultValue || multiple && [] || '',
      error,
      ...filterSuirElementProps(this.props),
    };

    const dropdownNode = shortHandMode ? createElement(as).props.control : as;

    return (
      <Form.Field required={ required } error={ error }>
        { shortHandMode && <label> { label } </label> }
        { createElement(dropdownNode, { ...dropdownProps }) }
        { error && errorLabel && cloneElement(errorLabel, {}, getErrorMessage()) }
      </Form.Field>
    );
  }
}
<|endoftext|>


<commit_before>// Wraps any value with promise. Not very useful on its own, used internally
// by deferred.js

'use strict';

var curry       = require('es5-ext/lib/Function/curry')
  , isFunction  = require('es5-ext/lib/Function/is-function')
  , noop        = require('es5-ext/lib/Function/noop')
  , sequence    = require('es5-ext/lib/Function/sequence')

  , isPromise   = require('./is-promise')

  , deferred, then, throwError, end;

then = function (value, ignore, callback) {
	var d = deferred();
	setTimeout(callback ?
		sequence(curry(callback, value), d.resolve) :
		d.resolve.bind(d, value), 0);
	return d.promise;
};

throwError = function () {
	throw this;
};

end = function (handler) {
	setTimeout(
		isFunction(handler) ? curry(handler, this) : throwError.bind(this), 0);
};

module.exports = function (value) {
	var r;
	if (isPromise(value)) {
		return value;
	} else if (value instanceof Error) {
		r = curry(then, value);
		r.end = end.bind(value);
	} else {
		r = curry(then, value, null);
		r.end = noop;
	}
	return r.then = r;
};

deferred = require('./deferred');
<commit_msg>es5-ext v0.6 compatibility<commit_after>// Wraps any value with promise. Not very useful on its own, used internally
// by deferred.js

'use strict';

var curry       = require('es5-ext/lib/Function/curry').call
  , isFunction  = require('es5-ext/lib/Function/is-function')
  , noop        = require('es5-ext/lib/Function/noop')
  , sequence    = require('es5-ext/lib/Function/sequence').call

  , isPromise   = require('./is-promise')

  , deferred, then, throwError, end;

then = function (value, ignore, callback) {
	var d = deferred();
	setTimeout(callback ?
		sequence(curry(callback, value), d.resolve) :
		d.resolve.bind(d, value), 0);
	return d.promise;
};

throwError = function () {
	throw this;
};

end = function (handler) {
	setTimeout(
		isFunction(handler) ? curry(handler, this) : throwError.bind(this), 0);
};

module.exports = function (value) {
	var r;
	if (isPromise(value)) {
		return value;
	} else if (value instanceof Error) {
		r = curry(then, value);
		r.end = end.bind(value);
	} else {
		r = curry(then, value, null);
		r.end = noop;
	}
	return r.then = r;
};

deferred = require('./deferred');
<|endoftext|>


<commit_before>/**
 * pseries - a JavaScript micro-library for dealing with asynchronous flow control
 * https://github.com/rBurgett/pseries
 *
 * Copyright (c) 2015 by Ryan Burgett.
 * Licensed under Apache License Version 2.0
 * https://github.com/rBurgett/pseries/blob/master/LICENSE
 */

var pseries = function(funcArr) {
    'use strict';

    return new Promise(function(resolve, reject) {

        if(!Array.isArray(funcArr)) {
            reject('You must pass in an array!');
        }

        var len = funcArr.length;

        function* myGen(funcs) {
            var cnt = 0;
            while (cnt < len) {
                yield funcs[cnt];
                cnt++;
            }
        }

        var resultsArr = [];

        var genFunc = myGen(funcArr);		//initialize the generator

        var run = function() {
            var genRes = genFunc.next();		//proceed to the first yield
            if(!genRes.done) {
                if(typeof genRes.value === 'function') {	//make sure the value returned is a function
                    var runFunc = genRes.value();		//run the yielded function
                    if(typeof runFunc === 'object' &&		//make sure the object returned is a Promise
                       runFunc.then instanceof Function &&
                       runFunc.catch instanceof Function) {
                        runFunc.then(function(res) {
                            resultsArr.push(res || '');		//add the response to the results array
                            run();		//recursively call run() to get & process next function from the generator
                        }).catch(function(err) {
                            reject(err);
                        });
                    } else {
                        reject('Each function must return a promise!');
                    }
                } else {
                    reject('You must pass in a function!');
                }

            } else {
                resolve(resultsArr);
            }
        };
        run();
    });
};

if (typeof exports !== 'undefined') {
    if (typeof module !== 'undefined' && module.exports) {
        module.exports = pseries;
    }
    exports.pseries = pseries;
} else if (typeof define !== 'undefined' && define.amd) {
    define([], function () { return pseries; });
} else {
    global.pseries = pseries;
}
<commit_msg>Simplified code<commit_after>/**
 * pseries - a JavaScript micro-library for dealing with asynchronous flow control
 * https://github.com/rBurgett/pseries
 *
 * Copyright (c) 2015 by Ryan Burgett.
 * Licensed under Apache License Version 2.0
 * https://github.com/rBurgett/pseries/blob/master/LICENSE
 */

 var pseries = function(arr) {
  return new Promise(function(resolve, reject) {

      var runFuncs = function(funcArr, i, resArray) {

          i = i || 0;
          resArray = resArray || [];

          funcArr[i]().then(
              function(res) {
                  resArray.push(res);
                  if(i === funcArr.length - 1) {
                      resolve(resArray);
                  } else {
                      runFuncs(funcArr, i + 1, resArray);
                  }
              },
              function(err) {
                  reject(err);
              }
          )
      }

      runFuncs(arr);

  });
 }

if (typeof exports !== 'undefined') {
    if (typeof module !== 'undefined' && module.exports) {
        module.exports = pseries;
    }
    exports.pseries = pseries;
} else if (typeof define !== 'undefined' && define.amd) {
    define([], function () { return pseries; });
} else {
    global.pseries = pseries;
}
<|endoftext|>


<commit_before>import Promise from 'bluebird';
import _request from 'request';
import R from 'ramda';

const request = Promise.promisify(_request);

function pugbomb(bot, msg, count) {
  count = Number(count) || 5;
  if (count > 15) count = 15;

  let options = {
    url: `https://pugme.herokuapp.com/bomb?count=${count}`,
    json: true
  };

  request(options)
    .then(R.path(['body', 'pugs']))
    .then(R.join('\n'))
    .then(text => bot.sendMessage(msg.channel, text))
    .catch(err => bot.sendMessage(msg.channel, `Error: ${err.message}`));
}

export default {
  pugbomb: pugbomb
};
<commit_msg>add headers to pug bomb<commit_after>import Promise from 'bluebird';
import _request from 'request';
import R from 'ramda';

const request = Promise.promisify(_request);

function pugbomb(bot, msg, count) {
  count = Number(count) || 5;
  if (count > 15) count = 15;

  let options = {
    url: `https://pugme.herokuapp.com/bomb?count=${count}`,
    headers: {
      Accept: 'application/json'
    },
    json: true
  };

  request(options)
    .then(R.path(['body', 'pugs']))
    .then(R.join('\n'))
    .then(text => bot.sendMessage(msg.channel, text))
    .catch(err => bot.sendMessage(msg.channel, `Error: ${err.message}`));
}

export default {
  pugbomb: pugbomb
};
<|endoftext|>


<commit_before>var util = require('util');
var d3 = require('d3-queue');
var classes = require('../support/data_classes');

module.exports = function () {
    this.Then(/^routability should be$/, (table, callback) => {
        this.buildWaysFromTable(table, () => {
            var directions = ['forw','backw','bothw'],
                testedHeaders = ['forw','backw','bothw','forw_rate','backw_rate','bothw_rate'],
                headers = new Set(Object.keys(table.hashes()[0]));

            if (!testedHeaders.some(k => !!headers.has(k))) {
                throw new Error('*** routability table must contain either "forw", "backw", "bothw", "forw_rate" or "backw_rate" column');
            }

            this.reprocessAndLoadData((e) => {
                if (e) return callback(e);
                var testRow = (row, i, cb) => {
                    var outputRow = Object.assign({}, row);
                    // clear the fields that are tested for in the copied response object
                    for (var field in outputRow) {
                        if (testedHeaders.indexOf(field) != -1)
                            outputRow[field] = '';
                    }

                    testRoutabilityRow(i, (err, result) => {
                        if (err) return cb(err);
                        directions.filter(d => headers.has(d + '_rate')).forEach((direction) => {
                            var rate = direction + '_rate';
                            var want = row[rate];
                            switch (true) {
                            case '' === want:
                                outputRow[rate] = result[direction].status ?
                                    result[direction].status.toString() : '';
                                break;
                            case /^\d+$/.test(want):
                                if (result[direction].rate && !isNaN(result[direction].rate)) {
                                    outputRow[rate] = result[direction].rate.toString();
                                } else {
                                    outputRow[rate] = '';
                                }
                                break;
                            default:
                                throw new Error(util.format('*** Unknown expectation format: %s for header %s', want, rate));
                            }
                        });

                        directions.filter(d => headers.has(d)).forEach((direction) => {
                            var usingShortcut = false,
                                want = row[direction];
                            // shortcuts are when a test has mapped a value like `foot` to
                            // a value like `5 km/h`, to represent the speed that one
                            // can travel by foot. we check for these and use the mapped to
                            // value for later comparison.
                            if (this.shortcutsHash[row[direction]]) {
                                want = this.shortcutsHash[row[direction]];
                                usingShortcut = row[direction];
                            }

                            // TODO split out accessible/not accessible value from forw/backw headers
                            // rename forw/backw to forw/backw_speed
                            switch (true) {
                            case '' === want:
                            case 'x' === want:
                                outputRow[direction] = result[direction].status ?
                                    result[direction].status.toString() : '';
                                break;
                            case /^[\d\.]+ s/.test(want):
                                // the result here can come back as a non-number value like
                                // `diff`, but we only want to apply the unit when it comes
                                // back as a number, for tableDiff's literal comparison
                                if (result[direction].time) {
                                    outputRow[direction] = !isNaN(result[direction].time) ?
                                        result[direction].time.toString()+' s' :
                                        result[direction].time.toString() || '';
                                } else {
                                    outputRow[direction] = '';
                                }
                                break;
                            case /^\d+ km\/h/.test(want):
                                if (result[direction].speed) {
                                    outputRow[direction] = !isNaN(result[direction].speed) ?
                                        result[direction].speed.toString()+' km/h' :
                                        result[direction].speed.toString() || '';
                                } else {
                                    outputRow[direction] = '';
                                }
                                break;
                            default:
                                throw new Error(util.format('*** Unknown expectation format: %s', want));
                            }

                            if (this.FuzzyMatch.match(outputRow[direction], want)) {
                                outputRow[direction] = usingShortcut ? usingShortcut : row[direction];
                            }
                        });

                        cb(null, outputRow);
                    });
                };
                this.processRowsAndDiff(table, testRow, callback);
            });
        });
    });

    // makes simple a-b request using the given cucumber test routability conditions
    // result is an object containing the calculated values for 'rate', 'status',
    // 'time', 'distance', and 'speed' for forwards and backwards routing, as well as
    // a bothw object that diffs forwards/backwards
    var testRoutabilityRow = (i, cb) => {
        var result = {};

        var testDirection = (dir, callback) => {
            var a = new classes.Location(this.origin[0] + (1+this.WAY_SPACING*i) * this.zoom, this.origin[1]),
                b = new classes.Location(this.origin[0] + (3+this.WAY_SPACING*i) * this.zoom, this.origin[1]),
                r = {};

            r.which = dir;

            this.requestRoute((dir === 'forw' ? [a, b] : [b, a]), [], this.queryParams, (err, res, body) => {
                if (err) return callback(err);

                r.query = this.query;
                r.json = JSON.parse(body);
                r.status = res.statusCode === 200 ? 'x' : null;
                if (r.status) {
                    r.route = this.wayList(r.json.routes[0]);
                    r.summary = r.json.routes[0].legs.map(l => l.summary).join(',');

                    if (r.route.split(',')[0] === util.format('w%d', i)) {
                        r.time = r.json.routes[0].duration;
                        r.distance = r.json.routes[0].distance;
                        r.rate = Math.round(r.distance / r.json.routes[0].weight);
                        r.speed = r.time > 0 ? parseInt(3.6 * r.distance / r.time) : null;
                    } else {
                        r.status = null;
                    }
                }

                callback(null, r);
            });
        };

        d3.queue(1)
            .defer(testDirection, 'forw')
            .defer(testDirection, 'backw')
            .awaitAll((err, res) => {
                if (err) return cb(err);
                // check if forw and backw returned the same values
                res.forEach((dirRes) => {
                    var which = dirRes.which;
                    delete dirRes.which;
                    result[which] = dirRes;
                });

                result.bothw = {};

                var sq = d3.queue();

                var parseRes = (key, scb) => {
                    if (result.forw[key] === result.backw[key]) {
                        result.bothw[key] = result.forw[key];
                    } else {
                        result.bothw[key] = 'diff';
                    }
                    scb();
                };

                ['rate', 'status', 'time', 'distance', 'speed'].forEach((key) => {
                    sq.defer(parseRes, key);
                });

                sq.awaitAll((err) => { cb(err, result); });
            });
    };
};
<commit_msg>Print 0 rate<commit_after>var util = require('util');
var d3 = require('d3-queue');
var classes = require('../support/data_classes');

module.exports = function () {
    this.Then(/^routability should be$/, (table, callback) => {
        this.buildWaysFromTable(table, () => {
            var directions = ['forw','backw','bothw'],
                testedHeaders = ['forw','backw','bothw','forw_rate','backw_rate','bothw_rate'],
                headers = new Set(Object.keys(table.hashes()[0]));

            if (!testedHeaders.some(k => !!headers.has(k))) {
                throw new Error('*** routability table must contain either "forw", "backw", "bothw", "forw_rate" or "backw_rate" column');
            }

            this.reprocessAndLoadData((e) => {
                if (e) return callback(e);
                var testRow = (row, i, cb) => {
                    var outputRow = Object.assign({}, row);
                    // clear the fields that are tested for in the copied response object
                    for (var field in outputRow) {
                        if (testedHeaders.indexOf(field) != -1)
                            outputRow[field] = '';
                    }

                    testRoutabilityRow(i, (err, result) => {
                        if (err) return cb(err);
                        directions.filter(d => headers.has(d + '_rate')).forEach((direction) => {
                            var rate = direction + '_rate';
                            var want = row[rate];

                            switch (true) {
                            case '' === want:
                                outputRow[rate] = result[direction].status ?
                                    result[direction].status.toString() : '';
                                break;
                            case /^\d+$/.test(want):
                                if (result[direction].rate !== undefined && !isNaN(result[direction].rate)) {
                                    outputRow[rate] = result[direction].rate.toString();
                                } else {
                                    outputRow[rate] = '';
                                }
                                break;
                            default:
                                throw new Error(util.format('*** Unknown expectation format: %s for header %s', want, rate));
                            }
                        });

                        directions.filter(d => headers.has(d)).forEach((direction) => {
                            var usingShortcut = false,
                                want = row[direction];
                            // shortcuts are when a test has mapped a value like `foot` to
                            // a value like `5 km/h`, to represent the speed that one
                            // can travel by foot. we check for these and use the mapped to
                            // value for later comparison.
                            if (this.shortcutsHash[row[direction]]) {
                                want = this.shortcutsHash[row[direction]];
                                usingShortcut = row[direction];
                            }

                            // TODO split out accessible/not accessible value from forw/backw headers
                            // rename forw/backw to forw/backw_speed
                            switch (true) {
                            case '' === want:
                            case 'x' === want:
                                outputRow[direction] = result[direction].status ?
                                    result[direction].status.toString() : '';
                                break;
                            case /^[\d\.]+ s/.test(want):
                                // the result here can come back as a non-number value like
                                // `diff`, but we only want to apply the unit when it comes
                                // back as a number, for tableDiff's literal comparison
                                if (result[direction].time) {
                                    outputRow[direction] = !isNaN(result[direction].time) ?
                                        result[direction].time.toString()+' s' :
                                        result[direction].time.toString() || '';
                                } else {
                                    outputRow[direction] = '';
                                }
                                break;
                            case /^\d+ km\/h/.test(want):
                                if (result[direction].speed) {
                                    outputRow[direction] = !isNaN(result[direction].speed) ?
                                        result[direction].speed.toString()+' km/h' :
                                        result[direction].speed.toString() || '';
                                } else {
                                    outputRow[direction] = '';
                                }
                                break;
                            default:
                                throw new Error(util.format('*** Unknown expectation format: %s', want));
                            }

                            if (this.FuzzyMatch.match(outputRow[direction], want)) {
                                outputRow[direction] = usingShortcut ? usingShortcut : row[direction];
                            }
                        });

                        cb(null, outputRow);
                    });
                };
                this.processRowsAndDiff(table, testRow, callback);
            });
        });
    });

    // makes simple a-b request using the given cucumber test routability conditions
    // result is an object containing the calculated values for 'rate', 'status',
    // 'time', 'distance', and 'speed' for forwards and backwards routing, as well as
    // a bothw object that diffs forwards/backwards
    var testRoutabilityRow = (i, cb) => {
        var result = {};

        var testDirection = (dir, callback) => {
            var a = new classes.Location(this.origin[0] + (1+this.WAY_SPACING*i) * this.zoom, this.origin[1]),
                b = new classes.Location(this.origin[0] + (3+this.WAY_SPACING*i) * this.zoom, this.origin[1]),
                r = {};

            r.which = dir;

            this.requestRoute((dir === 'forw' ? [a, b] : [b, a]), [], this.queryParams, (err, res, body) => {
                if (err) return callback(err);

                r.query = this.query;
                r.json = JSON.parse(body);
                r.status = res.statusCode === 200 ? 'x' : null;
                if (r.status) {
                    r.route = this.wayList(r.json.routes[0]);
                    r.summary = r.json.routes[0].legs.map(l => l.summary).join(',');

                    if (r.route.split(',')[0] === util.format('w%d', i)) {
                        r.time = r.json.routes[0].duration;
                        r.distance = r.json.routes[0].distance;
                        r.rate = Math.round(r.distance / r.json.routes[0].weight);
                        r.speed = r.time > 0 ? parseInt(3.6 * r.distance / r.time) : null;
                    } else {
                        r.status = null;
                    }
                }

                callback(null, r);
            });
        };

        d3.queue(1)
            .defer(testDirection, 'forw')
            .defer(testDirection, 'backw')
            .awaitAll((err, res) => {
                if (err) return cb(err);
                // check if forw and backw returned the same values
                res.forEach((dirRes) => {
                    var which = dirRes.which;
                    delete dirRes.which;
                    result[which] = dirRes;
                });

                result.bothw = {};

                var sq = d3.queue();

                var parseRes = (key, scb) => {
                    if (result.forw[key] === result.backw[key]) {
                        result.bothw[key] = result.forw[key];
                    } else {
                        result.bothw[key] = 'diff';
                    }
                    scb();
                };

                ['rate', 'status', 'time', 'distance', 'speed'].forEach((key) => {
                    sq.defer(parseRes, key);
                });

                sq.awaitAll((err) => { cb(err, result); });
            });
    };
};
<|endoftext|>


<commit_before>
timeline_obj=null;
tl_dataset=null;
timeline_updater_fast=null;
current_event_start=null;
current_event_end=null;
start_end_toggle="start";
can_play_annotation=false;
current_annotation_overrun_block = null;

//mea culpa
new_video_flag=0;

function echo(my_arg){
  console.log(my_arg)
}

function func_logger(){
  var ignore_funcs = ["update_timeline","create_new_timeline"]

  if(ignore_funcs.lastIndexOf(func_logger.caller.name)==-1){
    console.log(func_logger.caller.name +"()");
  }
}

function get_video_duration(){
  return $("video").get(0).duration*1000;
}

function set_video_time(new_video_time){
  $("video").get(0).currentTime=new_video_time+0.0;
  console.log(new_video_time);
}

function get_video_time(){
  return $("video").get(0).currentTime;
}

function is_video_paused(){
  return (($("video").get(0).paused))
}

function get_taskname(){
  var task_name = $("div[id^=tasknamehack_]").attr('id').substring(("tasknamehack_".length));
  return task_name;
}

function get_subject(){
  var subject = $("div[id^=subjecthack_]").attr('id').substring(("subjecthack_".length));
  return subject;
}

function get_video_selection(){
  var videoName = $('#videodropdown>option:selected').text();
  return videoName;
}

function get_annotations_fetch_endpoint(subject, videoName, task_name){
  var annotations_fetch_endpoint = "/fetch_json_annos?subject=" + subject + "&video=" + videoName +"&task_name=" + task_name
  return annotations_fetch_endpoint
}

function get_annotations_push_endpoint(subject, videoName, task_name){
  var annotations_fetch_endpoint = "/push_json_annos?subject=" + subject + "&video=" + videoName +"&task_name=" + task_name
  return annotations_fetch_endpoint
}

function get_gesture_selection(){
  var gesture = $('#gesturedropdown>option:selected').text();
  return gesture;
}

function def_key_combos(e, ui){
    console.log()
    if(e.keyCode == 32 && (($("video").get(0).paused))){
      $("video").get(0).play()
      window.clearInterval(current_annotation_overrun_block);
    } else if(e.keyCode == 32 && !((($("video").get(0).paused))) ) {
      $("video").get(0).pause()
      window.clearInterval(current_annotation_overrun_block);
    } else if(e.keyCode == 113){

        var time_window = timeline_obj.getWindow()
        var time_window_start = Date.parse(time_window.start)+time_window.start.getMilliseconds();
        var time_window_end = Date.parse(time_window.end)+time_window.end.getMilliseconds()
        var time_window_size = time_window_end-time_window_start;
        var step = time_window_size*0.35;
        timeline_obj.setWindow((time_window_start-step), ((time_window_end-step)), {animate:0});

    } else if(e.keyCode == 119){

        var time_window = timeline_obj.getWindow()
        var time_window_start = Date.parse(time_window.start)+time_window.start.getMilliseconds();
        var time_window_end = Date.parse(time_window.end)+time_window.end.getMilliseconds()
        var time_window_size = time_window_end-time_window_start;
        var step = time_window_size*0.35;
        timeline_obj.setWindow((time_window_start+step), ((time_window_end+step)), {animate:0});

    } else if(e.keyCode == 100){
      console.log(current_event_start)
      console.log(current_event_end)
      console.log(e)
      if( start_end_toggle == "start" ){
        set_video_time(current_event_end);
        start_end_toggle = "end";
        console.log("start->end")
      }
      else if( start_end_toggle == "end" ){
        set_video_time(current_event_start);
        start_end_toggle = "start";
        console.log("end->start")
      }
    }else if (e.keyCode == 102 && can_play_annotation && $("video").get(0).paused) {
      $("video").get(0).play();
      current_annotation_overrun_block = setInterval(function(){
        if(get_video_time()>=current_event_end){
          $("video").get(0).pause();
          window.clearInterval(current_annotation_overrun_block);
        }
      }, 50);

    }else{
      console.log(e.keyCode);
    }
}

function get_timeline_options(vid_length_msec){

  var tl_options = {
    width: 'auto',
    height: '400px',
    editable: true,
    max: vid_length_msec,
    min: 0,
    start: 0,
    end: vid_length_msec,
    movable: true,
    selectable: true,
    showCustomTime: true,
    showMajorLabels: true,
    type: "range",
    zoomable: true,
    zoomMax: vid_length_msec,
    zoomMin: 1000,
    showCustomTime: true,
    onRemove: function (item, callback) {
      if (confirm('Remove ' + item.content + '?')) {
        callback(item); // confirm deletion
      }
      else {
        callback(null); // cancel deletion
      }
    },
    onAdd: function (item, callback) {
      item.content = get_gesture_selection();

      console.log(item)
      console.log(item['start'].getMilliseconds())
      callback(item);
    },
  };
  return tl_options;
}

function right_click_set_time(my_event){

  //if((($("video").get(0).paused))){
  if(true){
    event.preventDefault();
    var click_location = (my_event.x)

    var time_window = timeline_obj.getWindow()
    echo("mins: "+time_window.start.getMinutes())
    echo("secs: "+time_window.start.getSeconds())
    echo("ms: "+time_window.start.getMilliseconds())

    var time_window_start = Date.parse(time_window.start)+time_window.start.getMilliseconds();
    var time_window_end = Date.parse(time_window.end)+time_window.end.getMilliseconds()
    var time_window_size = time_window_end-time_window_start;
    echo("time_window_start: " + time_window_start)
    echo("time_window_end: " + time_window_end)
    echo("time_window_size: " + time_window_size)

    var left_phys_edge = $(".vispanel.center").offset().left
    var timeline_div_width = $(".vispanel.center").width()

    var relative_click_location = (click_location-left_phys_edge)/timeline_div_width;
    var new_time = ( relative_click_location * time_window_size ) + time_window_start;
    echo(new_time)

    set_video_time(new_time/1000);
    update_timeline()
    echo("--------")
    return false;
  }

}

function update_timeline(){

  var curr_vid_time = get_video_time();

  if(!is_video_paused()){
    var old_bookends = timeline_obj.getWindow()
    var left_bookend = Date.parse(old_bookends.start)/1000
    var right_bookend = Date.parse(old_bookends.end)/1000
    var window_size = right_bookend-left_bookend;

    if( (curr_vid_time>right_bookend) || (curr_vid_time<left_bookend)){
      timeline_obj.setWindow(curr_vid_time*1000, (curr_vid_time*1000)+(window_size*1000), {animate:0});
    }
  }

  timeline_obj.setCustomTime(curr_vid_time*1000);

  var playback_speed = $("#playbackdropdown").val();
  $("video").get(0).playbackRate=Number(playback_speed);

}

function create_new_dataset_from_JSON(annotations){
  func_logger()

  var new_dataset = new vis.DataSet(annotations.annos);
  var subject = get_subject();
  var task_name = get_taskname();

  new_dataset.on('*', function(event, properties) {
    var tosend = {
      "video": annotations.video,
      "annos": new_dataset.get({
        fields: ['content','end','start','id', 'date'],
        type: {
          start: 'ISODate',
          end: 'ISODate'
        }
      })
    };

    console.log(tosend)

    var push_url = get_annotations_push_endpoint(subject, annotations.video, task_name )

    outbound_request = $.ajax({
      type: 'post',
      url: push_url,
      contentType: 'application/json',
      data: JSON.stringify(tosend),
      dataType:'json'
    });

    outbound_request.fail(function( jqXHR, textStatus, errorThrown ) {
      console.log(errorThrown);

      if(jqXHR.status==200){

      }else{
        alert("Server is down. Stop annotating for now. Email the admin to ask what's wrong. Press Ctrl+Shift+J in chrome and attach a screenshot.");

      }
    });

  });
  return new_dataset;
}

function fetch_annotations(data_url){

  var annotations = null

  inbound_request = $.ajax({ url: data_url,
           async: false,
           dataType: 'json',
           success: function(data) {
                annotations = data;
            }
  });

  inbound_request.fail(function( jqXHR, textStatus ) {
      alert("Server is down. Stop annotating for now. Email the admin to ask what's wrong. Press Ctrl+Shift+J in chrome and attach a screenshot.");
      console.log(jqXHR);
  });

  return annotations;

}

function create_new_timeline(timeline_dataset, timeline_options){
  func_logger()
  var timeline_container = $("#timeline").get(0);
  var new_timeline = new vis.Timeline(timeline_container, timeline_dataset, timeline_options);

  new_timeline.on('select', function (properties) {
    if(properties.items.length>0){

      var selected_event = tl_dataset.get(properties.items[0]);

      if(typeof(selected_event["start"])=="object"){
        event_start = Date.parse((selected_event["start"].toISOString()));
        event_end = Date.parse((selected_event["end"].toISOString()));
      }else{
        event_start = Date.parse(selected_event["start"]);
        event_end = Date.parse(selected_event["end"]);
      }

      var event_start_normalized = (event_start+0.0)/1000;
      var event_end_normalized = (event_end+0.0)/1000;

      current_event_start = event_start_normalized;
      current_event_end = event_end_normalized;

      start_end_toggle="start";
      set_video_time(event_start_normalized);

      can_play_annotation=true;

    }else{
      start_end_toggle = null;
      can_play_annotation = false;
    }
  });

  $("#timeline").get(0).addEventListener('contextmenu', right_click_set_time , false);

  $("video").on("play",function(){timeline_updater_fast = setInterval(update_timeline, 50);});
  $("video").on("pause",function(){clearInterval(timeline_updater_fast)});

  $("video").on("seeking",update_timeline);
  $("video").on("seeked",update_timeline);
  $("video").on("timeupdate",update_timeline);

  return new_timeline;
}

function set_up_annotation_state(){
  func_logger()

  if(new_video_flag==1){
    console.log("New video selected")
    $(window).keypress(def_key_combos)

    var vid_length_msec = get_video_duration();
    var subject = get_subject();
    var videoName = get_video_selection();
    var task_name = get_taskname();
    var annotations_fetch_endpoint = get_annotations_fetch_endpoint(subject, videoName, task_name);

    var annotations = fetch_annotations(annotations_fetch_endpoint);

    tl_dataset = create_new_dataset_from_JSON(annotations)
    var tl_options = get_timeline_options(vid_length_msec);
    timeline_obj = create_new_timeline(tl_dataset, tl_options);
  }
  new_video_flag=0;

}

$(function(){ /* DOM ready */

  function change_video() {

    var vidpane = $("#vidpane")
    var vid_path = $( "#videodropdown" ).val()
    $("video").remove()
    if(!(timeline_obj==null)){
        timeline_obj.destroy();
     //   console.log("destroying timeline")
    }

    var video = $('<video width="600" height="600"></video>').attr("preload","auto").attr("controls","controls")
        .append('<source src="' + vid_path + '"/>')
        .appendTo($("#vidpane"));

    $('#playbackdropdown').val('1');

    new_video_flag=1;

    $("video").on("canplay",set_up_annotation_state);

  }

  $( "#videodropdown" ).change(change_video);
  change_video()

});

<commit_msg>fixed bug where keybindings wouldnt work after changing video in evan - you were attaching a keybinding listener for every video change, so they were cancelling each other out<commit_after>
timeline_obj=null;
tl_dataset=null;
timeline_updater_fast=null;
current_event_start=null;
current_event_end=null;
start_end_toggle="start";
can_play_annotation=false;
current_annotation_overrun_block = null;

//mea culpa
new_video_flag=0;

function echo(my_arg){
  console.log(my_arg)
}

function func_logger(){
  var ignore_funcs = ["update_timeline","create_new_timeline"]

  if(ignore_funcs.lastIndexOf(func_logger.caller.name)==-1){
    console.log(func_logger.caller.name +"()");
  }
}

function get_video_duration(){
  return $("video").get(0).duration*1000;
}

function set_video_time(new_video_time){
  $("video").get(0).currentTime=new_video_time+0.0;
  console.log(new_video_time);
}

function get_video_time(){
  return $("video").get(0).currentTime;
}

function is_video_paused(){
  return (($("video").get(0).paused))
}

function get_taskname(){
  var task_name = $("div[id^=tasknamehack_]").attr('id').substring(("tasknamehack_".length));
  return task_name;
}

function get_subject(){
  var subject = $("div[id^=subjecthack_]").attr('id').substring(("subjecthack_".length));
  return subject;
}

function get_video_selection(){
  var videoName = $('#videodropdown>option:selected').text();
  return videoName;
}

function get_annotations_fetch_endpoint(subject, videoName, task_name){
  var annotations_fetch_endpoint = "/fetch_json_annos?subject=" + subject + "&video=" + videoName +"&task_name=" + task_name
  return annotations_fetch_endpoint
}

function get_annotations_push_endpoint(subject, videoName, task_name){
  var annotations_fetch_endpoint = "/push_json_annos?subject=" + subject + "&video=" + videoName +"&task_name=" + task_name
  return annotations_fetch_endpoint
}

function get_gesture_selection(){
  var gesture = $('#gesturedropdown>option:selected').text();
  return gesture;
}

function def_key_combos(e, ui){
    console.log("key pressed")
    if(e.keyCode == 32 && (($("video").get(0).paused))){
      $("video").get(0).play()
      window.clearInterval(current_annotation_overrun_block);
      e.preventDefault();
    } else if(e.keyCode == 32 && !((($("video").get(0).paused))) ) {
      $("video").get(0).pause()
      window.clearInterval(current_annotation_overrun_block);
      e.preventDefault();
    } else if(e.keyCode == 113){

        var time_window = timeline_obj.getWindow()
        var time_window_start = Date.parse(time_window.start)+time_window.start.getMilliseconds();
        var time_window_end = Date.parse(time_window.end)+time_window.end.getMilliseconds()
        var time_window_size = time_window_end-time_window_start;
        var step = time_window_size*0.35;
        timeline_obj.setWindow((time_window_start-step), ((time_window_end-step)), {animate:0});

    } else if(e.keyCode == 119){

        var time_window = timeline_obj.getWindow()
        var time_window_start = Date.parse(time_window.start)+time_window.start.getMilliseconds();
        var time_window_end = Date.parse(time_window.end)+time_window.end.getMilliseconds()
        var time_window_size = time_window_end-time_window_start;
        var step = time_window_size*0.35;
        timeline_obj.setWindow((time_window_start+step), ((time_window_end+step)), {animate:0});

    } else if(e.keyCode == 100){
      console.log(current_event_start)
      console.log(current_event_end)
      console.log(e)
      if( start_end_toggle == "start" ){
        set_video_time(current_event_end);
        start_end_toggle = "end";
        console.log("start->end")
      }
      else if( start_end_toggle == "end" ){
        set_video_time(current_event_start);
        start_end_toggle = "start";
        console.log("end->start")
      }
    }else if (e.keyCode == 102 && can_play_annotation && $("video").get(0).paused) {
      $("video").get(0).play();
      current_annotation_overrun_block = setInterval(function(){
        if(get_video_time()>=current_event_end+0.05){
          console.log("overrun blocked!")
          $("video").get(0).pause();
          window.clearInterval(current_annotation_overrun_block);
        }
      }, 50);

    }else{
      console.log(e.keyCode);
    }
}

function get_timeline_options(vid_length_msec){

  var tl_options = {
    width: 'auto',
    height: '400px',
    editable: true,
    max: vid_length_msec,
    min: 0,
    start: 0,
    end: vid_length_msec,
    movable: true,
    selectable: true,
    showCustomTime: true,
    showMajorLabels: true,
    type: "range",
    zoomable: true,
    zoomMax: vid_length_msec,
    zoomMin: 1000,
    showCustomTime: true,
    onRemove: function (item, callback) {
      if (confirm('Remove ' + item.content + '?')) {
        callback(item); // confirm deletion
      }
      else {
        callback(null); // cancel deletion
      }
    },
    onAdd: function (item, callback) {
      item.content = get_gesture_selection();

      console.log(item)
      console.log(item['start'].getMilliseconds())
      callback(item);
    },
  };
  return tl_options;
}

function right_click_set_time(my_event){

  //if((($("video").get(0).paused))){
  if(true){
    event.preventDefault();
    var click_location = (my_event.x)

    var time_window = timeline_obj.getWindow()
    echo("mins: "+time_window.start.getMinutes())
    echo("secs: "+time_window.start.getSeconds())
    echo("ms: "+time_window.start.getMilliseconds())

    var time_window_start = Date.parse(time_window.start)+time_window.start.getMilliseconds();
    var time_window_end = Date.parse(time_window.end)+time_window.end.getMilliseconds()
    var time_window_size = time_window_end-time_window_start;
    echo("time_window_start: " + time_window_start)
    echo("time_window_end: " + time_window_end)
    echo("time_window_size: " + time_window_size)

    var left_phys_edge = $(".vispanel.center").offset().left
    var timeline_div_width = $(".vispanel.center").width()

    var relative_click_location = (click_location-left_phys_edge)/timeline_div_width;
    var new_time = ( relative_click_location * time_window_size ) + time_window_start;
    echo(new_time)

    set_video_time(new_time/1000);
    update_timeline()
    echo("--------")
    return false;
  }

}

function update_timeline(){

  var curr_vid_time = get_video_time();

  if(!is_video_paused()){
    var old_bookends = timeline_obj.getWindow()
    var left_bookend = Date.parse(old_bookends.start)/1000
    var right_bookend = Date.parse(old_bookends.end)/1000
    var window_size = right_bookend-left_bookend;

    if( (curr_vid_time>right_bookend) || (curr_vid_time<left_bookend)){
      timeline_obj.setWindow(curr_vid_time*1000, (curr_vid_time*1000)+(window_size*1000), {animate:0});
    }
  }

  timeline_obj.setCustomTime(curr_vid_time*1000);

  var playback_speed = $("#playbackdropdown").val();
  $("video").get(0).playbackRate=Number(playback_speed);

}

function create_new_dataset_from_JSON(annotations){
  func_logger()

  var new_dataset = new vis.DataSet(annotations.annos);
  var subject = get_subject();
  var task_name = get_taskname();

  new_dataset.on('*', function(event, properties) {
    var tosend = {
      "video": annotations.video,
      "annos": new_dataset.get({
        fields: ['content','end','start','id', 'date'],
        type: {
          start: 'ISODate',
          end: 'ISODate'
        }
      })
    };

    console.log(tosend)

    var push_url = get_annotations_push_endpoint(subject, annotations.video, task_name )

    outbound_request = $.ajax({
      type: 'post',
      url: push_url,
      contentType: 'application/json',
      data: JSON.stringify(tosend),
      dataType:'json'
    });

    outbound_request.fail(function( jqXHR, textStatus, errorThrown ) {
      console.log(errorThrown);

      if(jqXHR.status==200){

      }else{
        alert("Server is down. Stop annotating for now. Email the admin to ask what's wrong. Press Ctrl+Shift+J in chrome and attach a screenshot.");

      }
    });

  });
  return new_dataset;
}

function fetch_annotations(data_url){

  var annotations = null

  inbound_request = $.ajax({ url: data_url,
           async: false,
           dataType: 'json',
           success: function(data) {
                annotations = data;
            }
  });

  inbound_request.fail(function( jqXHR, textStatus ) {
      alert("Server is down. Stop annotating for now. Email the admin to ask what's wrong. Press Ctrl+Shift+J in chrome and attach a screenshot.");
      console.log(jqXHR);
  });

  return annotations;

}

function create_new_timeline(timeline_dataset, timeline_options){
  func_logger()
  var timeline_container = $("#timeline").get(0);
  var new_timeline = new vis.Timeline(timeline_container, timeline_dataset, timeline_options);

  new_timeline.on('select', function (properties) {
    if(properties.items.length>0){

      var selected_event = tl_dataset.get(properties.items[0]);

      if(typeof(selected_event["start"])=="object"){
        event_start = Date.parse((selected_event["start"].toISOString()));
        event_end = Date.parse((selected_event["end"].toISOString()));
      }else{
        event_start = Date.parse(selected_event["start"]);
        event_end = Date.parse(selected_event["end"]);
      }

      var event_start_normalized = (event_start+0.0)/1000;
      var event_end_normalized = (event_end+0.0)/1000;

      current_event_start = event_start_normalized;
      current_event_end = event_end_normalized;

      start_end_toggle="start";
      set_video_time(event_start_normalized);

      can_play_annotation=true;

    }else{
      start_end_toggle = null;
      can_play_annotation = false;
    }
  });

  $("#timeline").get(0).addEventListener('contextmenu', right_click_set_time , false);

  $("video").on("play",function(){timeline_updater_fast = setInterval(update_timeline, 50);});
  $("video").on("pause",function(){clearInterval(timeline_updater_fast)});

  $("video").on("seeking",update_timeline);
  $("video").on("seeked",update_timeline);
  $("video").on("timeupdate",update_timeline);

  return new_timeline;
}

function set_up_annotation_state(){
  func_logger()

  if(new_video_flag==1){
    console.log("New video selected")

    var vid_length_msec = get_video_duration();
    var subject = get_subject();
    var videoName = get_video_selection();
    var task_name = get_taskname();
    var annotations_fetch_endpoint = get_annotations_fetch_endpoint(subject, videoName, task_name);

    var annotations = fetch_annotations(annotations_fetch_endpoint);

    tl_dataset = create_new_dataset_from_JSON(annotations)
    var tl_options = get_timeline_options(vid_length_msec);
    timeline_obj = create_new_timeline(tl_dataset, tl_options);
  }
  new_video_flag=0;

}

$(function(){ /* DOM ready */

  function change_video() {

    var vidpane = $("#vidpane")
    var vid_path = $( "#videodropdown" ).val()
    $("video").remove()
    if(!(timeline_obj==null)){
        timeline_obj.destroy();
    }

    window.clearInterval(current_annotation_overrun_block);
    var video = $('<video width="600" height="600"></video>').attr("preload","auto").attr("controls","controls")
        .append('<source src="' + vid_path + '"/>')
        .appendTo($("#vidpane"));

    $('#playbackdropdown').val('1');

    new_video_flag=1;

    $("video").on("canplay",set_up_annotation_state);

  }

  $( "#videodropdown" ).change(change_video);
  change_video();
  $(window).keypress(def_key_combos)

});

<|endoftext|>


<commit_before>var fs = require('fs');
var nodePath = require('path');

var gimletApi = module.exports = {
  init: function() {
    if (files.inRepo()) { return; }

    files.createFilesFromTree({
      ".gimlet": {
        HEAD: "ref: refs/heads/master\n",
        index: "",
        objects: {},
        refs: {
          heads: {},
          remotes: {
            origin: {}
          },
        }
      }
    });
  },

  add: function(path) {
    files.assertInRepo();

    var addedFiles = files.recursiveList(path);
    if (addedFiles.length === 0) {
      throw "fatal: pathspec '" + files.pathFromRepoRoot(path) + "' did not match any files";
    } else {
      for (var i = 0; i < addedFiles.length; i++) {
        this.update_index(addedFiles[i], { add: true });
      }
    }
  },

  update_index: function(path, opts) {
    files.assertInRepo();
    opts = opts || {};

    var pathFromRoot = files.pathFromRepoRoot(path)
    if (!fs.existsSync(path)) {
      throw "error: " + pathFromRoot + ": does not exist\n" +
        "fatal: Unable to process path " + pathFromRoot;
    } else if (fs.statSync(path).isDirectory()) {
      throw "error: " + pathFromRoot + ": is a directory - add files inside instead\n" +
        "fatal: Unable to process path " + pathFromRoot;
    } else if (!index.hasFile(path) && opts.add === undefined) {
      throw "error: " + pathFromRoot  +
        ": cannot add to the index - missing --add option?\n" +
        "fatal: Unable to process path " + pathFromRoot;
    } else {
      index.addFile(path);
    }
  },

  hash_object: function(file, opts) {
    files.assertInRepo();
    opts = opts || {};

    if (!fs.existsSync(file)) {
      throw "fatal: Cannot open '" + file + "': No such file or directory"
    } else {
      var fileContents = files.read(file);
      if (opts.w) {
        return objects.write(fileContents);
      }

      return util.hash(fileContents);
    }
  },

  write_tree: function() {
    files.assertInRepo();
    return objects.writeTree(index.toTree());
  },

  commit: function(opts) {
    files.assertInRepo();

    if (Object.keys(index.get()).length === 0) {
      throw "# On branch master\n#\n# Initial commit\n#\n" +
        "nothing to commit (create/copy files and use 'git add' to track)";
    } else {
      var headHash = refs.toExistentHash("HEAD");
      var treeHash = this.write_tree();

      if (headHash !== undefined &&
          treeHash === objects.getTreeHash(objects.read(headHash))) {
        throw "# On " + head.currentBranchName() + "\n" +
          "nothing to commit, working directory clean";
      } else {
        var isFirstCommit = refs.toExistentHash("HEAD") === undefined;
        var parentHashes = isFirstCommit ? [] : [refs.toExistentHash("HEAD")];
        var commmitHash = objects.write(objects.commitContent(treeHash, opts.m, parentHashes));
        this.update_ref("HEAD", commmitHash);
        return "[" + head.currentBranchName() + " " + commmitHash + "] " + opts.m;
      }
    }
  },

  branch: function(name) {
    files.assertInRepo();

    if (name === undefined) {
      return refs.localHeads().map(function(branchName) {
        var marker = branchName === head.currentBranchName() ? "* " : "  ";
        return marker + branchName;
      }).join("\n") + "\n";
    } else if (refs.toExistentHash("HEAD") === undefined) {
      throw "fatal: Not a valid object name: '" + head.currentBranchName() + "'.";
    } else {
      refs.set(refs.nameToBranchRef(name), refs.toExistentHash("HEAD"));
    }
  },

  update_ref: function(refToUpdate, refToUpdateTo) {
    files.assertInRepo();

    if (!refs.isRef(refToUpdate)) {
      throw "fatal: Cannot lock the ref " + refToUpdate + ".";
    } else {
      var hash = refs.toExistentHash(refToUpdateTo);
      if (!objects.exists(hash)) {
        throw "fatal: " + refToUpdateTo + ": not a valid SHA1";
        throw "error: Trying to write non-commit object " + hash + " to branch " +
          refs.toLocalHead(refToUpdate) + "\n" +
          "fatal: Cannot update the ref " + refToUpdate;
      } else if (!(objects.type(objects.read(hash)) === "commit")) {
      } else {
        refs.set(refs.toLocalHead(refToUpdate), hash);
      }
    }
  },

  checkout: function(ref) {
    files.assertInRepo();

    var finalRef = refs.isRef(ref) ? ref : refs.toFinalRef(ref);
    var hash = refs.toHash(finalRef);

    if (!objects.exists(hash)) {
      throw "error: pathspec " + ref + " did not match any file(s) known to git."
    }
  },

  diff: function(ref1, ref2, opts) {
    files.assertInRepo();

    if (opts["name-only"] !== true) {
      throw "unsupported"; // for now
    }
  }
};

var head = {
  currentBranchName: function() {
    if (this.get().match("refs")) {
      return this.get().match("refs/heads/(.+)")[1];
    }
  },

  get: function() {
    var content = files.read(nodePath.join(files.gimletDir(), "HEAD"));
    var refMatch = content.match("ref: (refs/heads/.+)");
    return refMatch ? refMatch[1] : content;
  },

  set: function(ref) {
    if (refs.isLocalHeadRef(ref)) {
      fs.writeFileSync(nodePath.join(files.gimletDir(), "HEAD"), "ref: " + ref + "\n");
    }
  }
};

var refs = {
  isLocalHeadRef: function(ref) {
    return ref.match("refs/heads/[A-Za-z-]+");
  },

  isRef: function(ref) {
    return ref === "HEAD" || this.isLocalHeadRef(ref);
  },

  toLocalHead: function(ref) {
    if (ref === "HEAD") {
      return head.get();
    } else if (this.isLocalHeadRef(ref)) {
      return ref;
    } else {
      return this.nameToBranchRef(ref);
    }
  },

  toExistentHash: function(ref) {
    if (objects.exists(ref)) {
      return ref;
    } else if (this.exists(this.toLocalHead(ref))) {
      return files.read(nodePath.join(files.gimletDir(), this.toLocalHead(ref)));
    } else if (this.exists(this.nameToBranchRef(ref))) {
      return files.read(nodePath.join(files.gimletDir(), this.nameToBranchRef(ref)));
    }
  },

  nameToBranchRef: function(name) {
    return "refs/heads/" + name;
  },

  set: function(ref, content) {
    if (this.isLocalHeadRef(ref)) {
      fs.writeFileSync(nodePath.join(files.gimletDir(), ref), content);
    }
  },

  localHeads: function() {
    return fs.readdirSync(nodePath.join(files.gimletDir(), "refs/heads/"));
  },

  exists: function(ref) {
    return ref !== undefined &&
      this.isLocalHeadRef(ref) &&
      fs.existsSync(nodePath.join(files.gimletDir(), ref));
  }
};

var index = {
  hasFile: function(path) {
    return index.get()[path] !== undefined;
  },

  addFile: function(path) {
    var index = this.get();
    index[path] = util.hash(files.read(nodePath.join(files.repoDir(), path)));
    gimletApi.hash_object(path, { w: true });
    this.set(index);
  },

  get: function() {
    return files.read(nodePath.join(files.gimletDir(), "index"))
      .split("\n")
      .slice(0, -1) // chuck last empty line
      .reduce(function(index, blobStr) {
        var blobData = blobStr.split(/ /);
        index[blobData[0]] = blobData[1];
        return index;
      }, {});
  },

  set: function(index) {
    var indexStr = Object.keys(index)
        .map(function(path) { return path + " " + index[path]; })
        .join("\n")
        .concat("\n"); // trailing new line
    fs.writeFileSync(nodePath.join(files.gimletDir(), "index"), indexStr);
  },

  toTree: function() {
    var tree = {};
    Object.keys(this.get()).forEach(function(wholePath) {
      util.assocIn(tree, wholePath.split(nodePath.sep).concat(files.read(wholePath)));
    });

    return tree;
  }
};

var objects = {
  writeTree: function(tree) {
    var treeObject = Object.keys(tree).map(function(key) {
      if (util.isString(tree[key])) {
        return "blob " + util.hash(tree[key]) + " " + key;
      } else {
        return "tree " + objects.writeTree(tree[key]) + " " + key;
      }
    }).join("\n") + "\n";

    return this.write(treeObject);
  },

  commitContent: function(treeHash, message, parentHashes) {
    return "commit " + treeHash + "\n" +
      parentHashes.map(function(h) { return "parent " + h + "\n"; }).join("") +
      "Date:  " + new Date().toString() + "\n" +
      "\n" +
      "    " + message;
  },

  write: function(content) {
    var contentHash = util.hash(content);
    if (this.read(contentHash) === undefined) {
      var filePath = nodePath.join(files.gimletDir(), "objects", contentHash);
      files.write(filePath, content);
    }

    return contentHash;
  },

  exists: function(objectHash) {
    return objectHash !== undefined &&
      fs.existsSync(nodePath.join(files.gimletDir(), "objects", objectHash));
  },

  read: function(objectHash) {
    var objectPath = nodePath.join(files.gimletDir(), "objects", objectHash);
    if (fs.existsSync(objectPath)) {
      return files.read(objectPath);
    }
  },

  type: function(content) {
    var firstToken = content.split(" ")[0];
    if (firstToken === "commit") {
      return "commit";
    } else if (firstToken === "tree" || firstToken === "blob") {
      return "tree";
    } else {
      return "blob";
    }
  },

  getTreeHash: function(content) {
    if (this.type(content) === "commit") {
      return content.split(/\s/)[1];
    } else if (this.type(content) === "tree") {
      return hash(content);
    }
  }
};

var files = {
  gimletDir: function(dir) {
    if (dir === undefined) { return this.gimletDir(process.cwd()); }

    if (fs.existsSync(dir)) {
      var potentialGimletDir = nodePath.join(dir, ".gimlet");
      if (fs.existsSync(potentialGimletDir)) {
        return potentialGimletDir;
      } else if (dir !== "/") {
        return this.gimletDir(nodePath.join(dir, ".."));
      }
    }
  },

  repoDir: function() {
    if (this.gimletDir() !== undefined) {
      return nodePath.join(this.gimletDir(), "..")
    }
  },

  inRepo: function(cwd) {
    return this.gimletDir(cwd) !== undefined;
  },

  assertInRepo: function() {
    if (!this.inRepo()) {
      throw "fatal: Not a gimlet repository (or any of the parent directories): .gimlet";
    }
  },

  pathFromRepoRoot: function(path) {
    return nodePath.relative(this.repoDir(), nodePath.join(process.cwd(), path));
  },

  createFilesFromTree: function(structure, prefix) {
    if (prefix === undefined) {
      return files.createFilesFromTree(structure, process.cwd());
    }

    Object.keys(structure).forEach(function(name) {
      var path = nodePath.join(prefix, name);
      if (util.isString(structure[name])) {
        fs.writeFileSync(path, structure[name]);
      } else {
        fs.mkdirSync(path, "777");
        files.createFilesFromTree(structure[name], path);
      }
    });
  },

  read: function(path) {
    return fs.readFileSync(path, "utf8");
  },

  write: function(path, content) {
    fs.writeFileSync(path, content);
  },

  recursiveList: function(path) {
    if (!fs.existsSync(path)) {
      return [];
    } else if (fs.statSync(path).isFile()) {
      return [path];
    } else if (fs.statSync(path).isDirectory()) {
      var self = this;
      return fs.readdirSync(path).reduce(function(files, dirChild) {
        return files.concat(self.recursiveList(nodePath.join(path, dirChild)));
      }, []);
    }
  }
};

var util = {
  isString: function(thing) {
    return typeof thing === "string";
  },

  hash: function(string) {
    var hashInt = 0;
    for (var i = 0; i < string.length; i++) {
      hashInt = hashInt * 31 + string.charCodeAt(i);
      hashInt = hashInt | 0;
    }

    return Math.abs(hashInt).toString(16);
  },

  assocIn: function(obj, arr) {
    if (arr.length === 2) {
      obj[arr[0]] = arr[1];
    } else if (arr.length > 2) {
      obj[arr[0]] = obj[arr[0]] || {};
      this.assocIn(obj[arr[0]], arr.slice(1));
    }
  }
};
<commit_msg>Use files.write wrapper for node write file fn<commit_after>var fs = require('fs');
var nodePath = require('path');

var gimletApi = module.exports = {
  init: function() {
    if (files.inRepo()) { return; }

    files.createFilesFromTree({
      ".gimlet": {
        HEAD: "ref: refs/heads/master\n",
        index: "",
        objects: {},
        refs: {
          heads: {},
          remotes: {
            origin: {}
          },
        }
      }
    });
  },

  add: function(path) {
    files.assertInRepo();

    var addedFiles = files.recursiveList(path);
    if (addedFiles.length === 0) {
      throw "fatal: pathspec '" + files.pathFromRepoRoot(path) + "' did not match any files";
    } else {
      for (var i = 0; i < addedFiles.length; i++) {
        this.update_index(addedFiles[i], { add: true });
      }
    }
  },

  update_index: function(path, opts) {
    files.assertInRepo();
    opts = opts || {};

    var pathFromRoot = files.pathFromRepoRoot(path)
    if (!fs.existsSync(path)) {
      throw "error: " + pathFromRoot + ": does not exist\n" +
        "fatal: Unable to process path " + pathFromRoot;
    } else if (fs.statSync(path).isDirectory()) {
      throw "error: " + pathFromRoot + ": is a directory - add files inside instead\n" +
        "fatal: Unable to process path " + pathFromRoot;
    } else if (!index.hasFile(path) && opts.add === undefined) {
      throw "error: " + pathFromRoot  +
        ": cannot add to the index - missing --add option?\n" +
        "fatal: Unable to process path " + pathFromRoot;
    } else {
      index.addFile(path);
    }
  },

  hash_object: function(file, opts) {
    files.assertInRepo();
    opts = opts || {};

    if (!fs.existsSync(file)) {
      throw "fatal: Cannot open '" + file + "': No such file or directory"
    } else {
      var fileContents = files.read(file);
      if (opts.w) {
        return objects.write(fileContents);
      }

      return util.hash(fileContents);
    }
  },

  write_tree: function() {
    files.assertInRepo();
    return objects.writeTree(index.toTree());
  },

  commit: function(opts) {
    files.assertInRepo();

    if (Object.keys(index.get()).length === 0) {
      throw "# On branch master\n#\n# Initial commit\n#\n" +
        "nothing to commit (create/copy files and use 'git add' to track)";
    } else {
      var headHash = refs.toExistentHash("HEAD");
      var treeHash = this.write_tree();

      if (headHash !== undefined &&
          treeHash === objects.getTreeHash(objects.read(headHash))) {
        throw "# On " + head.currentBranchName() + "\n" +
          "nothing to commit, working directory clean";
      } else {
        var isFirstCommit = refs.toExistentHash("HEAD") === undefined;
        var parentHashes = isFirstCommit ? [] : [refs.toExistentHash("HEAD")];
        var commmitHash = objects.write(objects.commitContent(treeHash, opts.m, parentHashes));
        this.update_ref("HEAD", commmitHash);
        return "[" + head.currentBranchName() + " " + commmitHash + "] " + opts.m;
      }
    }
  },

  branch: function(name) {
    files.assertInRepo();

    if (name === undefined) {
      return refs.localHeads().map(function(branchName) {
        var marker = branchName === head.currentBranchName() ? "* " : "  ";
        return marker + branchName;
      }).join("\n") + "\n";
    } else if (refs.toExistentHash("HEAD") === undefined) {
      throw "fatal: Not a valid object name: '" + head.currentBranchName() + "'.";
    } else {
      refs.set(refs.nameToBranchRef(name), refs.toExistentHash("HEAD"));
    }
  },

  update_ref: function(refToUpdate, refToUpdateTo) {
    files.assertInRepo();

    if (!refs.isRef(refToUpdate)) {
      throw "fatal: Cannot lock the ref " + refToUpdate + ".";
    } else {
      var hash = refs.toExistentHash(refToUpdateTo);
      if (!objects.exists(hash)) {
        throw "fatal: " + refToUpdateTo + ": not a valid SHA1";
        throw "error: Trying to write non-commit object " + hash + " to branch " +
          refs.toLocalHead(refToUpdate) + "\n" +
          "fatal: Cannot update the ref " + refToUpdate;
      } else if (!(objects.type(objects.read(hash)) === "commit")) {
      } else {
        refs.set(refs.toLocalHead(refToUpdate), hash);
      }
    }
  },

  checkout: function(ref) {
    files.assertInRepo();

    var finalRef = refs.isRef(ref) ? ref : refs.toFinalRef(ref);
    var hash = refs.toHash(finalRef);

    if (!objects.exists(hash)) {
      throw "error: pathspec " + ref + " did not match any file(s) known to git."
    }
  },

  diff: function(ref1, ref2, opts) {
    files.assertInRepo();

    if (opts["name-only"] !== true) {
      throw "unsupported"; // for now
    }
  }
};

var head = {
  currentBranchName: function() {
    if (this.get().match("refs")) {
      return this.get().match("refs/heads/(.+)")[1];
    }
  },

  get: function() {
    var content = files.read(nodePath.join(files.gimletDir(), "HEAD"));
    var refMatch = content.match("ref: (refs/heads/.+)");
    return refMatch ? refMatch[1] : content;
  },

  set: function(ref) {
    if (refs.isLocalHeadRef(ref)) {
      files.write(nodePath.join(files.gimletDir(), "HEAD"), "ref: " + ref + "\n");
    }
  }
};

var refs = {
  isLocalHeadRef: function(ref) {
    return ref.match("refs/heads/[A-Za-z-]+");
  },

  isRef: function(ref) {
    return ref === "HEAD" || this.isLocalHeadRef(ref);
  },

  toLocalHead: function(ref) {
    if (ref === "HEAD") {
      return head.get();
    } else if (this.isLocalHeadRef(ref)) {
      return ref;
    } else {
      return this.nameToBranchRef(ref);
    }
  },

  toExistentHash: function(ref) {
    if (objects.exists(ref)) {
      return ref;
    } else if (this.exists(this.toLocalHead(ref))) {
      return files.read(nodePath.join(files.gimletDir(), this.toLocalHead(ref)));
    } else if (this.exists(this.nameToBranchRef(ref))) {
      return files.read(nodePath.join(files.gimletDir(), this.nameToBranchRef(ref)));
    }
  },

  nameToBranchRef: function(name) {
    return "refs/heads/" + name;
  },

  set: function(ref, content) {
    if (this.isLocalHeadRef(ref)) {
      files.write(nodePath.join(files.gimletDir(), ref), content);
    }
  },

  localHeads: function() {
    return fs.readdirSync(nodePath.join(files.gimletDir(), "refs/heads/"));
  },

  exists: function(ref) {
    return ref !== undefined &&
      this.isLocalHeadRef(ref) &&
      fs.existsSync(nodePath.join(files.gimletDir(), ref));
  }
};

var index = {
  hasFile: function(path) {
    return index.get()[path] !== undefined;
  },

  addFile: function(path) {
    var index = this.get();
    index[path] = util.hash(files.read(nodePath.join(files.repoDir(), path)));
    gimletApi.hash_object(path, { w: true });
    this.set(index);
  },

  get: function() {
    return files.read(nodePath.join(files.gimletDir(), "index"))
      .split("\n")
      .slice(0, -1) // chuck last empty line
      .reduce(function(index, blobStr) {
        var blobData = blobStr.split(/ /);
        index[blobData[0]] = blobData[1];
        return index;
      }, {});
  },

  set: function(index) {
    var indexStr = Object.keys(index)
        .map(function(path) { return path + " " + index[path]; })
        .join("\n")
        .concat("\n"); // trailing new line
    files.write(nodePath.join(files.gimletDir(), "index"), indexStr);
  },

  toTree: function() {
    var tree = {};
    Object.keys(this.get()).forEach(function(wholePath) {
      util.assocIn(tree, wholePath.split(nodePath.sep).concat(files.read(wholePath)));
    });

    return tree;
  }
};

var objects = {
  writeTree: function(tree) {
    var treeObject = Object.keys(tree).map(function(key) {
      if (util.isString(tree[key])) {
        return "blob " + util.hash(tree[key]) + " " + key;
      } else {
        return "tree " + objects.writeTree(tree[key]) + " " + key;
      }
    }).join("\n") + "\n";

    return this.write(treeObject);
  },

  commitContent: function(treeHash, message, parentHashes) {
    return "commit " + treeHash + "\n" +
      parentHashes.map(function(h) { return "parent " + h + "\n"; }).join("") +
      "Date:  " + new Date().toString() + "\n" +
      "\n" +
      "    " + message;
  },

  write: function(content) {
    var contentHash = util.hash(content);
    if (this.read(contentHash) === undefined) {
      var filePath = nodePath.join(files.gimletDir(), "objects", contentHash);
      files.write(filePath, content);
    }

    return contentHash;
  },

  exists: function(objectHash) {
    return objectHash !== undefined &&
      fs.existsSync(nodePath.join(files.gimletDir(), "objects", objectHash));
  },

  read: function(objectHash) {
    var objectPath = nodePath.join(files.gimletDir(), "objects", objectHash);
    if (fs.existsSync(objectPath)) {
      return files.read(objectPath);
    }
  },

  type: function(content) {
    var firstToken = content.split(" ")[0];
    if (firstToken === "commit") {
      return "commit";
    } else if (firstToken === "tree" || firstToken === "blob") {
      return "tree";
    } else {
      return "blob";
    }
  },

  getTreeHash: function(content) {
    if (this.type(content) === "commit") {
      return content.split(/\s/)[1];
    } else if (this.type(content) === "tree") {
      return hash(content);
    }
  }
};

var files = {
  gimletDir: function(dir) {
    if (dir === undefined) { return this.gimletDir(process.cwd()); }

    if (fs.existsSync(dir)) {
      var potentialGimletDir = nodePath.join(dir, ".gimlet");
      if (fs.existsSync(potentialGimletDir)) {
        return potentialGimletDir;
      } else if (dir !== "/") {
        return this.gimletDir(nodePath.join(dir, ".."));
      }
    }
  },

  repoDir: function() {
    if (this.gimletDir() !== undefined) {
      return nodePath.join(this.gimletDir(), "..")
    }
  },

  inRepo: function(cwd) {
    return this.gimletDir(cwd) !== undefined;
  },

  assertInRepo: function() {
    if (!this.inRepo()) {
      throw "fatal: Not a gimlet repository (or any of the parent directories): .gimlet";
    }
  },

  pathFromRepoRoot: function(path) {
    return nodePath.relative(this.repoDir(), nodePath.join(process.cwd(), path));
  },

  createFilesFromTree: function(structure, prefix) {
    if (prefix === undefined) {
      return files.createFilesFromTree(structure, process.cwd());
    }

    Object.keys(structure).forEach(function(name) {
      var path = nodePath.join(prefix, name);
      if (util.isString(structure[name])) {
        files.write(path, structure[name]);
      } else {
        fs.mkdirSync(path, "777");
        files.createFilesFromTree(structure[name], path);
      }
    });
  },

  read: function(path) {
    return fs.readFileSync(path, "utf8");
  },

  write: function(path, content) {
    fs.writeFileSync(path, content);
  },

  recursiveList: function(path) {
    if (!fs.existsSync(path)) {
      return [];
    } else if (fs.statSync(path).isFile()) {
      return [path];
    } else if (fs.statSync(path).isDirectory()) {
      var self = this;
      return fs.readdirSync(path).reduce(function(files, dirChild) {
        return files.concat(self.recursiveList(nodePath.join(path, dirChild)));
      }, []);
    }
  }
};

var util = {
  isString: function(thing) {
    return typeof thing === "string";
  },

  hash: function(string) {
    var hashInt = 0;
    for (var i = 0; i < string.length; i++) {
      hashInt = hashInt * 31 + string.charCodeAt(i);
      hashInt = hashInt | 0;
    }

    return Math.abs(hashInt).toString(16);
  },

  assocIn: function(obj, arr) {
    if (arr.length === 2) {
      obj[arr[0]] = arr[1];
    } else if (arr.length > 2) {
      obj[arr[0]] = obj[arr[0]] || {};
      this.assocIn(obj[arr[0]], arr.slice(1));
    }
  }
};
<|endoftext|>