<commit_before>'use strict';

const kData = Symbol('data-store');
const fs = require('fs');
const os = require('os');
const path = require('path');
const assert = require('assert');
const utils = require('./utils');

/**
 * Module dependencies
 */

const get = require('get-value');
const set = require('set-value');

/**
 * Initialize a new `Store` with the given `name`, `options` and `default` data.
 *
 * ```js
 * const store = require('data-store')('abc');
 * //=> '~/data-store/a.json'
 *
 * const store = require('data-store')('abc', { cwd: 'test/fixtures' });
 * //=> './test/fixtures/abc.json'
 * ```
 * @name Store
 * @param {String} `name` Store name to use for the basename of the `.json` file.
 * @param {object} `options` See all [available options](#options).
 * @param {object} `defaults` An object to initialize the store with.
 * @api public
 */

class Store {
  constructor(name, options = {}, defaults = {}) {
    if (typeof name !== 'string') {
      defaults = options;
      options = name || {};
      name = options.name;
    }

    if (!options.path) {
      assert.equal(typeof name, 'string', 'expected store name to be a string');
    }

    const opts = { debounce: 0, indent: 2, home: os.homedir(), name, ...options };
    const file = opts.name || (opts.path ? utils.stem(opts.path) : 'data-store');

    this.path = opts.path || path.join(opts.home, `${file}.json`);
    this.indent = opts.indent;
    this.debounce = opts.debounce;
    this.defaults = defaults || opts.default;
    this.timeouts = {};
  }

  /**
   * Assign `value` to `key` and save to the file system. Can be a key-value pair,
   * array of objects, or an object.
   *
   * ```js
   * // key, value
   * store.set('a', 'b');
   * //=> {a: 'b'}
   *
   * // extend the store with an object
   * store.set({a: 'b'});
   * //=> {a: 'b'}
   * ```
   * @name .set
   * @param {String} `key`
   * @param {any} `val` The value to save to `key`. Must be a valid JSON type: String, Number, Array or Object.
   * @return {Object} `Store` for chaining
   * @api public
   */

  set(key, val) {
    if (typeof key === 'string' && typeof val === 'undefined') {
      return this.del(key);
    }

    if (utils.isObject(key)) {
      for (const k of Object.keys(key)) {
        this.set(k.split(/\\?\./).join('\\.'), key[k]);
      }
    } else {
      assert.equal(typeof key, 'string', 'expected key to be a string');
      set(this.data, key, val);
    }

    this.save();
    return this;
  }

  /**
   * Add the given `value` to the array at `key`. Creates a new array if one
   * doesn't exist, and only adds unique values to the array.
   *
   * ```js
   * store.union('a', 'b');
   * store.union('a', 'c');
   * store.union('a', 'd');
   * store.union('a', 'c');
   * console.log(store.get('a'));
   * //=> ['b', 'c', 'd']
   * ```
   * @name .union
   * @param  {String} `key`
   * @param  {any} `val` The value to union to `key`. Must be a valid JSON type: String, Number, Array or Object.
   * @return {Object} `Store` for chaining
   * @api public
   */

  union(key, ...rest) {
    assert.equal(typeof key, 'string', 'expected key to be a string');
    const vals = this.get(key);
    const values = [].concat(utils.isEmptyPrimitive(vals) ? [] : vals);
    this.set(key, utils.unique(utils.flatten(...values, ...rest)));
    return this;
  }

  /**
   * Get the stored `value` of `key`.
   *
   * ```js
   * store.set('a', {b: 'c'});
   * store.get('a');
   * //=> {b: 'c'}
   *
   * store.get();
   * //=> {a: {b: 'c'}}
   * ```
   * @name .get
   * @param {String} `key`
   * @return {any} The value to store for `key`.
   * @api public
   */

  get(key, fallback) {
    assert.equal(typeof key, 'string', 'expected key to be a string');
    const value = get(this.data, key);
    if (typeof value === 'undefined') {
      return fallback;
    }
    return value;
  }

  /**
   * Returns `true` if the specified `key` has a value.
   *
   * ```js
   * store.set('a', 42);
   * store.set('c', null);
   *
   * store.has('a'); //=> true
   * store.has('c'); //=> true
   * store.has('d'); //=> false
   * ```
   * @name .has
   * @param {String} `key`
   * @return {Boolean} Returns true if `key` has
   * @api public
   */

  has(key) {
    return typeof this.get(key) !== 'undefined';
  }

  /**
   * Returns `true` if the specified `key` exists.
   *
   * ```js
   * store.set('a', 'b');
   * store.set('b', false);
   * store.set('c', null);
   * store.set('d', true);
   * store.set('e', undefined);
   *
   * store.hasOwn('a'); //=> true
   * store.hasOwn('b'); //=> true
   * store.hasOwn('c'); //=> true
   * store.hasOwn('d'); //=> true
   * store.hasOwn('e'); //=> true
   * store.hasOwn('foo'); //=> false
   * ```
   * @name .hasOwn
   * @param {String} `key`
   * @return {Boolean} Returns true if `key` exists
   * @api public
   */

  hasOwn(key) {
    assert.equal(typeof key, 'string', 'expected key to be a string');
    return utils.hasOwn(this.data, key);
  }

  /**
   * Delete one or more properties from the store.
   *
   * ```js
   * store.set('foo.bar', 'baz');
   * console.log(store.data); //=> { foo: { bar: 'baz' } }
   * store.del('foo.bar');
   * console.log(store.data); //=> { foo: {} }
   * store.del('foo');
   * console.log(store.data); //=> {}
   * ```
   * @name .del
   * @param {String|Array} `keys` One or more properties to delete.
   * @api public
   */

  del(key) {
    if (Array.isArray(key)) {
      for (const k of key) this.del(k);
      return this;
    }

    assert.equal(typeof key, 'string', 'expected key to be a string, use .clear() to delete all properties');
    if (utils.del(this.data, key)) {
      this.save();
    }
    return this;
  }

  /**
   * Return a clone of the `store.data` object.
   *
   * ```js
   * console.log(store.clone());
   * ```
   * @name .clone
   * @return {Object}
   * @api public
   */

  clone() {
    return utils.cloneDeep(this.data);
  }

  /**
   * Clear `store.data` to an empty object.
   *
   * ```js
   * store.clear();
   * ```
   * @name .clear
   * @return {undefined}
   * @api public
   */

  clear() {
    this.data = {};
    this.save();
  }

  /**
   * Stringify the store. Takes the same arguments as `JSON.stringify`.
   *
   * ```js
   * console.log(store.json(null, 2));
   * ```
   * @name .json
   * @param {Function} `replacer` Replacer function.
   * @param {String} `indent` Indentation to use. Default is 2 spaces.
   * @return {String}
   * @api public
   */

  json(replacer = null, indent = this.indent) {
    return JSON.stringify(this.data, replacer, indent);
  }

  /**
   * Immediately write the store to the file system. This method should probably
   * not be called directly. Unless you are familiar with the inner workings of
   * the code it's recommended that you use .save() instead.
   *
   * ```js
   * store.writeFile();
   * ```
   * @name .writeFile
   * @return {undefined}
   */

  writeFile() {
    utils.mkdir(path.dirname(this.path));
    fs.writeFileSync(this.path, this.json(), { mode: 0o0600 });
  }

  /**
   * Calls [.writeFile()](#writefile) to persist the store to the file system,
   * after an optional [debounce](#options) period. This method should probably
   * not be called directly as it's used internally by other methods.
   *
   * ```js
   * store.save();
   * ```
   * @name .save
   * @return {undefined}
   * @api public
   */

  save() {
    if (!this.debounce) return this.writeFile();
    if (this.timeouts.save) clearTimeout(this.timeouts.save);
    this.timeouts.save = setTimeout(this.writeFile.bind(this), this.debounce);
  }

  /**
   * Delete the store from the file system.
   *
   * ```js
   * store.unlink();
   * ```
   * @name .unlink
   * @return {undefined}
   * @api public
   */

  unlink() {
    clearTimeout(this.timeouts.save);
    utils.tryUnlink(this.path);
  }

  /**
   * Load the store.
   * @return {Object}
   */

  load() {
    try {
      return (this[kData] = JSON.parse(fs.readFileSync(this.path)));
    } catch (err) {
      if (err.code === 'EACCES') {
        err.message += '\ndata-store does not have permission to load this file\n';
        throw err;
      }
      // (re-)initialize if file doesn't exist or is corrupted
      if (err.code === 'ENOENT' || err.name === 'SyntaxError') {
        this[kData] = {};
        return {};
      }
    }
  }

  /**
   * Getter/setter for the `store.data` object, which holds the values
   * that are persisted to the file system.
   *
   * ```js
   * console.log(store.data); //=> {}
   * store.data.foo = 'bar';
   * console.log(store.get('foo')); //=> 'bar'
   * ```
   * @name .data
   * @return {Object}
   */

  set data(data) {
    this[kData] = data;
    this.save();
  }
  get data() {
    let data = this[kData] || this.load();
    if (!this.saved) {
      data = { ...this.defaults, ...data };
    }
    this[kData] = data;
    return data;
  }
}

/**
 * Expose `Store`
 */

module.exports = (...args) => new Store(...args);
module.exports.Store = Store;
<commit_msg>expose `name`<commit_after>'use strict';

const kData = Symbol('data-store');
const fs = require('fs');
const os = require('os');
const path = require('path');
const assert = require('assert');
const utils = require('./utils');

/**
 * Module dependencies
 */

const get = require('get-value');
const set = require('set-value');

/**
 * Initialize a new `Store` with the given `name`, `options` and `default` data.
 *
 * ```js
 * const store = require('data-store')('abc');
 * //=> '~/data-store/a.json'
 *
 * const store = require('data-store')('abc', { cwd: 'test/fixtures' });
 * //=> './test/fixtures/abc.json'
 * ```
 * @name Store
 * @param {String} `name` Store name to use for the basename of the `.json` file.
 * @param {object} `options` See all [available options](#options).
 * @param {object} `defaults` An object to initialize the store with.
 * @api public
 */

class Store {
  constructor(name, options = {}, defaults = {}) {
    if (typeof name !== 'string') {
      defaults = options;
      options = name || {};
      name = options.name;
    }

    if (!options.path) {
      assert.equal(typeof name, 'string', 'expected store name to be a string');
    }

    const opts = { debounce: 0, indent: 2, home: os.homedir(), name, ...options };

    this.name = opts.name || (opts.path ? utils.stem(opts.path) : 'data-store')
    this.path = opts.path || path.join(opts.home, `${this.name}.json`);
    this.indent = opts.indent;
    this.debounce = opts.debounce;
    this.defaults = defaults || opts.default;
    this.timeouts = {};
  }

  /**
   * Assign `value` to `key` and save to the file system. Can be a key-value pair,
   * array of objects, or an object.
   *
   * ```js
   * // key, value
   * store.set('a', 'b');
   * //=> {a: 'b'}
   *
   * // extend the store with an object
   * store.set({a: 'b'});
   * //=> {a: 'b'}
   * ```
   * @name .set
   * @param {String} `key`
   * @param {any} `val` The value to save to `key`. Must be a valid JSON type: String, Number, Array or Object.
   * @return {Object} `Store` for chaining
   * @api public
   */

  set(key, val) {
    if (typeof key === 'string' && typeof val === 'undefined') {
      return this.del(key);
    }

    if (utils.isObject(key)) {
      for (const k of Object.keys(key)) {
        this.set(k.split(/\\?\./).join('\\.'), key[k]);
      }
    } else {
      assert.equal(typeof key, 'string', 'expected key to be a string');
      set(this.data, key, val);
    }

    this.save();
    return this;
  }

  /**
   * Add the given `value` to the array at `key`. Creates a new array if one
   * doesn't exist, and only adds unique values to the array.
   *
   * ```js
   * store.union('a', 'b');
   * store.union('a', 'c');
   * store.union('a', 'd');
   * store.union('a', 'c');
   * console.log(store.get('a'));
   * //=> ['b', 'c', 'd']
   * ```
   * @name .union
   * @param  {String} `key`
   * @param  {any} `val` The value to union to `key`. Must be a valid JSON type: String, Number, Array or Object.
   * @return {Object} `Store` for chaining
   * @api public
   */

  union(key, ...rest) {
    assert.equal(typeof key, 'string', 'expected key to be a string');
    const vals = this.get(key);
    const values = [].concat(utils.isEmptyPrimitive(vals) ? [] : vals);
    this.set(key, utils.unique(utils.flatten(...values, ...rest)));
    return this;
  }

  /**
   * Get the stored `value` of `key`.
   *
   * ```js
   * store.set('a', {b: 'c'});
   * store.get('a');
   * //=> {b: 'c'}
   *
   * store.get();
   * //=> {a: {b: 'c'}}
   * ```
   * @name .get
   * @param {String} `key`
   * @return {any} The value to store for `key`.
   * @api public
   */

  get(key, fallback) {
    assert.equal(typeof key, 'string', 'expected key to be a string');
    const value = get(this.data, key);
    if (typeof value === 'undefined') {
      return fallback;
    }
    return value;
  }

  /**
   * Returns `true` if the specified `key` has a value.
   *
   * ```js
   * store.set('a', 42);
   * store.set('c', null);
   *
   * store.has('a'); //=> true
   * store.has('c'); //=> true
   * store.has('d'); //=> false
   * ```
   * @name .has
   * @param {String} `key`
   * @return {Boolean} Returns true if `key` has
   * @api public
   */

  has(key) {
    return typeof this.get(key) !== 'undefined';
  }

  /**
   * Returns `true` if the specified `key` exists.
   *
   * ```js
   * store.set('a', 'b');
   * store.set('b', false);
   * store.set('c', null);
   * store.set('d', true);
   * store.set('e', undefined);
   *
   * store.hasOwn('a'); //=> true
   * store.hasOwn('b'); //=> true
   * store.hasOwn('c'); //=> true
   * store.hasOwn('d'); //=> true
   * store.hasOwn('e'); //=> true
   * store.hasOwn('foo'); //=> false
   * ```
   * @name .hasOwn
   * @param {String} `key`
   * @return {Boolean} Returns true if `key` exists
   * @api public
   */

  hasOwn(key) {
    assert.equal(typeof key, 'string', 'expected key to be a string');
    return utils.hasOwn(this.data, key);
  }

  /**
   * Delete one or more properties from the store.
   *
   * ```js
   * store.set('foo.bar', 'baz');
   * console.log(store.data); //=> { foo: { bar: 'baz' } }
   * store.del('foo.bar');
   * console.log(store.data); //=> { foo: {} }
   * store.del('foo');
   * console.log(store.data); //=> {}
   * ```
   * @name .del
   * @param {String|Array} `keys` One or more properties to delete.
   * @api public
   */

  del(key) {
    if (Array.isArray(key)) {
      for (const k of key) this.del(k);
      return this;
    }

    assert.equal(typeof key, 'string', 'expected key to be a string, use .clear() to delete all properties');
    if (utils.del(this.data, key)) {
      this.save();
    }
    return this;
  }

  /**
   * Return a clone of the `store.data` object.
   *
   * ```js
   * console.log(store.clone());
   * ```
   * @name .clone
   * @return {Object}
   * @api public
   */

  clone() {
    return utils.cloneDeep(this.data);
  }

  /**
   * Clear `store.data` to an empty object.
   *
   * ```js
   * store.clear();
   * ```
   * @name .clear
   * @return {undefined}
   * @api public
   */

  clear() {
    this.data = {};
    this.save();
  }

  /**
   * Stringify the store. Takes the same arguments as `JSON.stringify`.
   *
   * ```js
   * console.log(store.json(null, 2));
   * ```
   * @name .json
   * @param {Function} `replacer` Replacer function.
   * @param {String} `indent` Indentation to use. Default is 2 spaces.
   * @return {String}
   * @api public
   */

  json(replacer = null, indent = this.indent) {
    return JSON.stringify(this.data, replacer, indent);
  }

  /**
   * Immediately write the store to the file system. This method should probably
   * not be called directly. Unless you are familiar with the inner workings of
   * the code it's recommended that you use .save() instead.
   *
   * ```js
   * store.writeFile();
   * ```
   * @name .writeFile
   * @return {undefined}
   */

  writeFile() {
    utils.mkdir(path.dirname(this.path));
    fs.writeFileSync(this.path, this.json(), { mode: 0o0600 });
  }

  /**
   * Calls [.writeFile()](#writefile) to persist the store to the file system,
   * after an optional [debounce](#options) period. This method should probably
   * not be called directly as it's used internally by other methods.
   *
   * ```js
   * store.save();
   * ```
   * @name .save
   * @return {undefined}
   * @api public
   */

  save() {
    if (!this.debounce) return this.writeFile();
    if (this.timeouts.save) clearTimeout(this.timeouts.save);
    this.timeouts.save = setTimeout(this.writeFile.bind(this), this.debounce);
  }

  /**
   * Delete the store from the file system.
   *
   * ```js
   * store.unlink();
   * ```
   * @name .unlink
   * @return {undefined}
   * @api public
   */

  unlink() {
    clearTimeout(this.timeouts.save);
    utils.tryUnlink(this.path);
  }

  /**
   * Load the store.
   * @return {Object}
   */

  load() {
    try {
      return (this[kData] = JSON.parse(fs.readFileSync(this.path)));
    } catch (err) {
      if (err.code === 'EACCES') {
        err.message += '\ndata-store does not have permission to load this file\n';
        throw err;
      }
      // (re-)initialize if file doesn't exist or is corrupted
      if (err.code === 'ENOENT' || err.name === 'SyntaxError') {
        this[kData] = {};
        return {};
      }
    }
  }

  /**
   * Getter/setter for the `store.data` object, which holds the values
   * that are persisted to the file system.
   *
   * ```js
   * console.log(store.data); //=> {}
   * store.data.foo = 'bar';
   * console.log(store.get('foo')); //=> 'bar'
   * ```
   * @name .data
   * @return {Object}
   */

  set data(data) {
    this[kData] = data;
    this.save();
  }
  get data() {
    let data = this[kData] || this.load();
    if (!this.saved) {
      data = { ...this.defaults, ...data };
    }
    this[kData] = data;
    return data;
  }
}

/**
 * Expose `Store`
 */

module.exports = function(...args) {
  return new Store(...args);
};

module.exports.Store = Store;
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import {
  ListView,
  StyleSheet,
  Text,
  TextInput,
  View
} from 'react-native';

class AutoComplete extends Component {
  static propTypes = {
    ...TextInput.propTypes,
    /**
     * These styles will be applied to the container which
     * surrounds the autocomplete component.
     */
    containerStyle: View.propTypes.style,
    /**
     * Assign an array of data objects which should be
     * rendered in respect to the entered text.
     */
    data: PropTypes.array,
    /*
     * These styles will be applied to the container which surrounds
     * the textInput component.
     */
    inputContainerStyle: View.propTypes.style,
    /**
     * These style will be applied to the result list view.
     */
    listStyle: ListView.propTypes.style,
    /**
     * `renderItem` will be called to render the data objects
     * which will be displayed in the result view below the
     * text input.
     */
    renderItem: PropTypes.func,
    /**
     * `onShowResults` will be called when list is going to
     * show/hide results.
     */
    onShowResults: PropTypes.func,
    /**
     * renders custom TextInput. All props passed to this function.
     */
    renderTextInput: PropTypes.func
  };

  static defaultProps = {
    data: [],
    defaultValue: '',
    renderItem: rowData => <Text>{rowData}</Text>
  };

  constructor(props) {
    super(props);
    const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
    this.state = {
      dataSource: ds.cloneWithRows(props.data),
      showResults: props.data && props.data.length > 0
    };
  }

  componentWillReceiveProps(nextProps) {
    const dataSource = this.state.dataSource.cloneWithRows(nextProps.data);
    this._showResults(dataSource.getRowCount() > 0);
    this.setState({ dataSource });
  }

  /**
   * Proxy `blur()` to autocomplete's text input.
   */
  blur() {
    const { textInput } = this;
    textInput && textInput.blur();
  }

  /**
   * Proxy `focus()` to autocomplete's text input.
   */
  focus() {
    const { textInput } = this;
    textInput && textInput.focus();
  }

  _renderItems() {
    const { listStyle, renderItem } = this.props;
    const { dataSource } = this.state;
    return (
      <ListView
        dataSource={dataSource}
        keyboardShouldPersistTaps={true}
        renderRow={renderItem}
        style={[styles.list, listStyle]}
      />
    );
  }

  _showResults(show) {
    const { showResults } = this.state;
    const { onShowResults } = this.props;

    if (!showResults && show) {
      this.setState({ showResults: true });
      onShowResults && onShowResults(true);
    } else if (showResults && !show) {
      this.setState({ showResults: false });
      onShowResults && onShowResults(false);
    }
  }

  _renderTextInput() {
    const { onEndEditing, renderTextInput, style } = this.props;
    const props = {
      style: [styles.input, style],
      ref: ref => (this.textInput = ref),
      onEndEditing: e =>
        this._showResults(false) || (onEndEditing && onEndEditing(e)),
      ...this.props
    };

    return renderTextInput
      ? renderTextInput(props)
      : (<TextInput {...props} />);
  }

  render() {
    const { showResults } = this.state;
    const { containerStyle, inputContainerStyle } = this.props;
    return (
      <View style={[styles.container, containerStyle]}>
        <View style={[styles.inputContainer, inputContainerStyle]}>
          {this._renderTextInput()}
        </View>
        {showResults && this._renderItems()}
      </View>
    );
  }
}

const border = {
  borderColor: '#b9b9b9',
  borderRadius: 1,
  borderWidth: 1
};

const styles = StyleSheet.create({
  container: {
    zIndex: 1
  },
  inputContainer: {
    ...border,
    marginBottom: 0
  },
  input: {
    backgroundColor: 'white',
    height: 40,
    paddingLeft: 3
  },
  list: {
    ...border,
    backgroundColor: 'white',
    borderTopWidth: 0,
    left: 0,
    position: 'absolute',
    right: 0
  }
});

export default AutoComplete;
<commit_msg>Position the result list above content<commit_after>import React, { Component, PropTypes } from 'react';
import {
  ListView,
  StyleSheet,
  Text,
  TextInput,
  View
} from 'react-native';

class AutoComplete extends Component {
  static propTypes = {
    ...TextInput.propTypes,
    /**
     * These styles will be applied to the container which
     * surrounds the autocomplete component.
     */
    containerStyle: View.propTypes.style,
    /**
     * Assign an array of data objects which should be
     * rendered in respect to the entered text.
     */
    data: PropTypes.array,
    /*
     * These styles will be applied to the container which surrounds
     * the textInput component.
     */
    inputContainerStyle: View.propTypes.style,
    /**
     * These style will be applied to the result list view.
     */
    listStyle: ListView.propTypes.style,
    /**
     * `renderItem` will be called to render the data objects
     * which will be displayed in the result view below the
     * text input.
     */
    renderItem: PropTypes.func,
    /**
     * `onShowResults` will be called when list is going to
     * show/hide results.
     */
    onShowResults: PropTypes.func,
    /**
     * renders custom TextInput. All props passed to this function.
     */
    renderTextInput: PropTypes.func
  };

  static defaultProps = {
    data: [],
    defaultValue: '',
    renderItem: rowData => <Text>{rowData}</Text>
  };

  constructor(props) {
    super(props);
    const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
    this.state = {
      dataSource: ds.cloneWithRows(props.data),
      showResults: props.data && props.data.length > 0
    };
  }

  componentWillReceiveProps(nextProps) {
    const dataSource = this.state.dataSource.cloneWithRows(nextProps.data);
    this._showResults(dataSource.getRowCount() > 0);
    this.setState({ dataSource });
  }

  /**
   * Proxy `blur()` to autocomplete's text input.
   */
  blur() {
    const { textInput } = this;
    textInput && textInput.blur();
  }

  /**
   * Proxy `focus()` to autocomplete's text input.
   */
  focus() {
    const { textInput } = this;
    textInput && textInput.focus();
  }

  _renderItems() {
    const { listStyle, renderItem } = this.props;
    const { dataSource } = this.state;
    return (
      <ListView
        dataSource={dataSource}
        keyboardShouldPersistTaps={true}
        renderRow={renderItem}
        style={[styles.list, listStyle]}
      />
    );
  }

  _showResults(show) {
    const { showResults } = this.state;
    const { onShowResults } = this.props;

    if (!showResults && show) {
      this.setState({ showResults: true });
      onShowResults && onShowResults(true);
    } else if (showResults && !show) {
      this.setState({ showResults: false });
      onShowResults && onShowResults(false);
    }
  }

  _renderTextInput() {
    const { onEndEditing, renderTextInput, style } = this.props;
    const props = {
      style: [styles.input, style],
      ref: ref => (this.textInput = ref),
      onEndEditing: e =>
        this._showResults(false) || (onEndEditing && onEndEditing(e)),
      ...this.props
    };

    return renderTextInput
      ? renderTextInput(props)
      : (<TextInput {...props} />);
  }

  render() {
    const { showResults } = this.state;
    const { containerStyle, inputContainerStyle } = this.props;
    return (
      <View style={[styles.container, containerStyle]}>
        <View style={[styles.inputContainer, inputContainerStyle]}>
          {this._renderTextInput()}
        </View>
        {showResults && this._renderItems()}
      </View>
    );
  }
}

const border = {
  borderColor: '#b9b9b9',
  borderRadius: 1,
  borderWidth: 1
};

const styles = StyleSheet.create({
  container: {
    zIndex: 1
  },
  inputContainer: {
    ...border
  },
  input: {
    backgroundColor: 'white',
    height: 40,
    paddingLeft: 3
  },
  list: {
    ...border,
    backgroundColor: 'white',
    borderTopWidth: 0,
    left: 0,
    position: 'absolute',
    right: 0
  }
});

export default AutoComplete;
<|endoftext|>


<commit_before>let express = require('express');
let bodyParser = require('body-parser');
let cors = require('cors');
let fs  = require('fs');

let Web3 = require("web3");
let web3 = new Web3();

let app = express();

let wrapper = require("./wrappers/wrapper.js");

/* Begin convenience constants block */
const VOTER_1 = 1; // box for your stempas
const VOTER_2 = 2;
const VOTER_3 = 3;

const NOISE_1 = 4;
const NOISE_2 = 5;

const STEMPAS = 6;
const STEMBILJET = 7;

const BALLOT_offset = 7;
const BALLOT_1 = 1+ BALLOT_offset;
const BALLOT_2 = 2+ BALLOT_offset;
const BALLOT_3 = 3+ BALLOT_offset;

const CANDIDATE_offset = 10;

const CANDIDATE_1 = 11;
const CANDIDATE_2 = 12;

const BALLOTS = [BALLOT_1, BALLOT_2, BALLOT_3];
const CANDIDATES = [CANDIDATE_1, CANDIDATE_2];
const VOTERS = [VOTER_1, VOTER_2, VOTER_3];

let get_wallet = (idx) => { return web3.eth.accounts[idx+1]; };

let balance = (acct) => { return web3.fromWei(web3.eth.getBalance(acct), 'ether').toNumber()};

var stempas;
var stembiljet;

(function setup()  {
    app.use(cors());
    app.set('port', (process.env.PORT || 3000));
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: true }));

    web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'));

    stempas = get_wallet(STEMPAS);
    stembiljet = get_wallet(STEMBILJET);
    //let stempas = get_wallet(STEMPAS);
    //let stembiljet = get_wallet(STEMBILJET);
    if (balance(stempas) <= 100){
        // assume that we started with a default initialised testrpc blockchain.
        for (var address of web3.eth.accounts) {
            let num = balance(address);
            console.log("bal of", address, num);
            web3.eth.sendTransaction({from: address, to:stempas, value: web3.toWei(num), gasLimit: 21000, gasPrice: 0});
            console.log("bal of", stempas, balance(stempas));
        }
        //let half_bal = balance(stempas)/2;
        //web3.eth.sendTransaction({from: stempas, to: stembiljet, value: web3.toWei(half_bal), gasLimit: 21000, gasPrice: 0});
        console.log("bal of stempas", stempas, balance(stempas));
        console.log("bal of stembiljet", stempas, balance(stembiljet));
    }

    //check funds:

    // setup listener for deposits (stempast)

    // let contractAddress = "0x80507828ab1323056cbadf3fa297048be61b7499";
    // var filter = web3.eth.filter({fromBlock:0, toBlock: 'latest', address: contractAddress,
    //                           'topics':[web3.sha3('Deposit(bytes32,address)')]});

    // filter.watch(function(error, result) {
    // console.log("filter - attached");
    // console.log(error);
    // console.log(result);
// });
})();

/* End convenience constants block */

app.post('/api/cashStempas', function (req, res) {
    // Exchange your valid stempas for a (anonymous :D)
    // stembiljet structure is:

    // stempas_id : 1 | 2 | 3 (or whatever you received from /verifyPerson)

    // tx: (would normally be a blind-signing raw tx to an actual address you
    // control), but for now we can just pass along a wallet idx that the client
    // can use. so for demo: BALLOT_1 | BALLOT_2 | BALLOT_3

    // response structure:
    // id: 1 | 2 | 3

    // TODO: Everything. Mostly the one-time blind signing, and administrating
    // your very own wallet.
    console.log('request user action', req.body);

    var tx = parseInt(req.body.tx);
    var stempas_id = parseInt(req.body.stempas_id);

    if (BALLOTS.includes(tx + BALLOT_offset) && VOTERS.includes(stempas_id)){
        let voter_wallet = get_wallet(stempas_id);
        let ballot_wallet = get_wallet(tx + BALLOT_offset);

        // TODO integrate with contract
        //voter_wallet = get_wallet(req.body.id); // TODO should actually be certified by client in prod.
        web3.eth.sendTransaction({from: voter_wallet, to: stembiljet, value: web3.toWei(100), gasLimit: 21000, gasPrice: 0},
            function(error, result){
                if(!error) {
                    console.log(result)
                } else {
                    console.error(error);
                }
            });
        // TODO: Validate the validity of the vote token.

        web3.eth.sendTransaction({from: stembiljet, to: ballot_wallet, value: web3.toWei(100), gasLimit: 21000, gasPrice: 0},
            function(error, result){
                if(!error) {
                    console.log(result)
                } else {
                    console.error(error);
                }
            });
        // ^- this should be the blind signed transaction instead. It should
        // only be _signed_ server side, and then completed and uploaded to the
        // blockchain by the client/voter
	    res.send({id: tx});

    } else { // invalid ballot
        // oh noes
        console.error("inaccessable");
        res.status(500).send('You took a wrong turn somewhere...');
    }
});

app.post('/api/verifyPerson', function (req, res) {
    // Dummy call for now: someone just says they are a person and gets a
    // stempas.

    // structure (req.body) is:
    //  id: 1 | 2 | 3
    // response is:
    //  id: 1 | 2 | 3 (probably the same one XD, but this is your "signed" stempas)

	console.log('request user action', req.body);
    var wallet_id = parseInt(req.body.id);
    if (VOTERS.includes(wallet_id)){
        voter_wallet = get_wallet(wallet_id); // TODO should actually be certified by client in prod.
        web3.eth.sendTransaction({from: stempas, to: voter_wallet , value: web3.toWei(100), gasLimit: 21000, gasPrice: 0},
            function(error, result){
                if(!error) {
                    console.log(result)
                } else {
                    console.error(error);
                }
            });
	      res.send({id: wallet_id});
    } else {
        console.error("inaccessable");
        res.status(500).send('You took a wrong turn somewhere...');
    }
});

app.post('/api/vote', function (req, res) {
    // TODO: this would normally be a call from the client (voter) to a
    // smartcontract on the blockchain instead of involving filthy third parties
    /* A vote (body) is structured like:
       kandidaat: 1 | 2
       stembiljet_id: 1 | 2 | 3
       */

    var stembiljet_id = parseInt(req.body.stembiljet_id);
    var kandidaat = parseInt(req.body.kandidaat);

    if (BALLOTS.includes(stembiljet_id + BALLOT_offset) && CANDIDATES.includes(kandidaat + CANDIDATE_offset)){
        let ballot_wallet = get_wallet(stembiljet_id + BALLOT_offset);
        let candidate_wallet = get_wallet(kandidaat + CANDIDATE_offset);

        web3.eth.sendTransaction({from: ballot_wallet, to: candidate_wallet , value: web3.toWei(100), gasLimit: 21000, gasPrice: 0});
	      console.log('request user action', req.body);
	      res.send('YEAAAAAH');
    } else {
        console.error("inaccessable");
        res.status(500).send('You took a wrong turn somewhere...');
    }
});

app.listen(app.get('port'), function() {
    console.log('Server started: http://localhost:' + app.get('port') + '/');
});
<commit_msg>make the linter a bit happy<commit_after>let express = require('express');
let bodyParser = require('body-parser');
let cors = require('cors');
let fs  = require('fs');

let Web3 = require("web3");
let web3 = new Web3();

let app = express();

let wrapper = require("./wrappers/wrapper.js");

/* Begin convenience constants block */
const VOTER_1 = 1; // box for your stempas
const VOTER_2 = 2;
const VOTER_3 = 3;

const NOISE_1 = 4;
const NOISE_2 = 5;

const STEMPAS = 6;
const STEMBILJET = 7;

const BALLOT_offset = 7;
const BALLOT_1 = 1+ BALLOT_offset;
const BALLOT_2 = 2+ BALLOT_offset;
const BALLOT_3 = 3+ BALLOT_offset;

const CANDIDATE_offset = 10;

const CANDIDATE_1 = 11;
const CANDIDATE_2 = 12;

const BALLOTS = [BALLOT_1, BALLOT_2, BALLOT_3];
const CANDIDATES = [CANDIDATE_1, CANDIDATE_2];
const VOTERS = [VOTER_1, VOTER_2, VOTER_3];

let get_wallet = (idx) => { return web3.eth.accounts[idx+1]; };

let balance = (acct) => { return web3.fromWei(web3.eth.getBalance(acct), 'ether').toNumber(); };

var stempas;
var stembiljet;

(function setup()  {
    app.use(cors());
    app.set('port', (process.env.PORT || 3000));
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: true }));

    web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'));

    stempas = get_wallet(STEMPAS);
    stembiljet = get_wallet(STEMBILJET);
    //let stempas = get_wallet(STEMPAS);
    //let stembiljet = get_wallet(STEMBILJET);
    if (balance(stempas) <= 100){
        // assume that we started with a default initialised testrpc blockchain.
        for (var address of web3.eth.accounts) {
            let num = balance(address);
            console.log("bal of", address, num);
            web3.eth.sendTransaction({from: address, to:stempas, value: web3.toWei(num), gasLimit: 21000, gasPrice: 0});
            console.log("bal of", stempas, balance(stempas));
        }
        //let half_bal = balance(stempas)/2;
        //web3.eth.sendTransaction({from: stempas, to: stembiljet, value: web3.toWei(half_bal), gasLimit: 21000, gasPrice: 0});
        console.log("bal of stempas", stempas, balance(stempas));
        console.log("bal of stembiljet", stempas, balance(stembiljet));
    }

    //check funds:

    // setup listener for deposits (stempast)

    // let contractAddress = "0x80507828ab1323056cbadf3fa297048be61b7499";
    // var filter = web3.eth.filter({fromBlock:0, toBlock: 'latest', address: contractAddress,
    //                           'topics':[web3.sha3('Deposit(bytes32,address)')]});

    // filter.watch(function(error, result) {
    // console.log("filter - attached");
    // console.log(error);
    // console.log(result);
// });
})();

/* End convenience constants block */

app.post('/api/cashStempas', function (req, res) {
    // Exchange your valid stempas for a (anonymous :D)
    // stembiljet structure is:

    // stempas_id : 1 | 2 | 3 (or whatever you received from /verifyPerson)

    // tx: (would normally be a blind-signing raw tx to an actual address you
    // control), but for now we can just pass along a wallet idx that the client
    // can use. so for demo: BALLOT_1 | BALLOT_2 | BALLOT_3

    // response structure:
    // id: 1 | 2 | 3

    // TODO: Everything. Mostly the one-time blind signing, and administrating
    // your very own wallet.
    console.log('request user action', req.body);

    var tx = parseInt(req.body.tx);
    var stempas_id = parseInt(req.body.stempas_id);

    if (BALLOTS.includes(tx + BALLOT_offset) && VOTERS.includes(stempas_id)){
        let voter_wallet = get_wallet(stempas_id);
        let ballot_wallet = get_wallet(tx + BALLOT_offset);

        // TODO integrate with contract
        //voter_wallet = get_wallet(req.body.id); // TODO should actually be certified by client in prod.
        web3.eth.sendTransaction({from: voter_wallet, to: stembiljet, value: web3.toWei(100), gasLimit: 21000, gasPrice: 0},
            function(error, result){
                if(!error) {
                    console.log(result);
                } else {
                    console.error(error);
                }
            });
        // TODO: Validate the validity of the vote token.

        web3.eth.sendTransaction({from: stembiljet, to: ballot_wallet, value: web3.toWei(100), gasLimit: 21000, gasPrice: 0},
            function(error, result){
                if(!error) {
                    console.log(result);
                } else {
                    console.error(error);
                }
            });
        // ^- this should be the blind signed transaction instead. It should
        // only be _signed_ server side, and then completed and uploaded to the
        // blockchain by the client/voter
	    res.send({id: tx});

    } else { // invalid ballot
        // oh noes
        console.error("inaccessable");
        res.status(500).send('You took a wrong turn somewhere...');
    }
});

app.post('/api/verifyPerson', function (req, res) {
    // Dummy call for now: someone just says they are a person and gets a
    // stempas.

    // structure (req.body) is:
    //  id: 1 | 2 | 3
    // response is:
    //  id: 1 | 2 | 3 (probably the same one XD, but this is your "signed" stempas)

	console.log('request user action', req.body);
    var wallet_id = parseInt(req.body.id);
    if (VOTERS.includes(wallet_id)){
        voter_wallet = get_wallet(wallet_id); // TODO should actually be certified by client in prod.
        web3.eth.sendTransaction({from: stempas, to: voter_wallet , value: web3.toWei(100), gasLimit: 21000, gasPrice: 0},
            function(error, result){
                if(!error) {
                    console.log(result);
                } else {
                    console.error(error);
                }
            });
	      res.send({id: wallet_id});
    } else {
        console.error("inaccessable");
        res.status(500).send('You took a wrong turn somewhere...');
    }
});

app.post('/api/vote', function (req, res) {
    // TODO: this would normally be a call from the client (voter) to a
    // smartcontract on the blockchain instead of involving filthy third parties
    /* A vote (body) is structured like:
       kandidaat: 1 | 2
       stembiljet_id: 1 | 2 | 3
       */

    var stembiljet_id = parseInt(req.body.stembiljet_id);
    var kandidaat = parseInt(req.body.kandidaat);

    if (BALLOTS.includes(stembiljet_id + BALLOT_offset) && CANDIDATES.includes(kandidaat + CANDIDATE_offset)){
        let ballot_wallet = get_wallet(stembiljet_id + BALLOT_offset);
        let candidate_wallet = get_wallet(kandidaat + CANDIDATE_offset);

        web3.eth.sendTransaction({from: ballot_wallet, to: candidate_wallet , value: web3.toWei(100), gasLimit: 21000, gasPrice: 0});
	      console.log('request user action', req.body);
	      res.send('YEAAAAAH');
    } else {
        console.error("inaccessable");
        res.status(500).send('You took a wrong turn somewhere...');
    }
});

app.listen(app.get('port'), function() {
    console.log('Server started: http://localhost:' + app.get('port') + '/');
});
<|endoftext|>


<commit_before>/**
 * Module dependencies
 */

var Writable = require('stream').Writable;
var fsx = require('fs-extra');
var path = require('path');
var _ = require('lodash');
var ProgressStream = require('progress-stream');

/**
 * skipper-disk
 *
 * @param  {Object} options
 * @return {Object}
 */

module.exports = function DiskStore (options) {
  options = options || {};

  var adapter = {

    rm: function (filepath, cb){
      return fsx.unlink(filepath, function(err) {
        // Ignore "doesn't exist" errors
        if (err && err.code !== 'ENOENT') { return cb(err); }
        else return cb();
      });
    },
    ls: function (dirpath, cb) {
      return fsx.readdir(dirpath, cb);
    },
    read: function (filepath, cb) {
      if (cb) {
        return fsx.readFile(filepath, cb);
      }
      else {
        return fsx.createReadStream(filepath);
      }
    },

    receive: DiskReceiver,
    receiver: DiskReceiver // (synonym for `.receive()`)
  };

  return adapter;

  /**
   * A simple receiver for Skipper that writes Upstreams to
   * disk at the configured path.
   *
   * Includes a garbage-collection mechanism for failed
   * uploads.
   *
   * @param  {Object} options
   * @return {Stream.Writable}
   */
  function DiskReceiver (options) {
    options = options || {};

    // Normalize `saveAs()` option:
    // options.saveAs() <==> options.rename() <==> options.getFilename() <==> options.getFileName()
    options.saveAs = options.saveAs || options.rename;
    options.saveAs = options.saveAs || options.getFileName;
    options.saveAs = options.saveAs || options.getFilename;

    _.defaults(options, {

      // By default, create new files on disk
      // using their uploaded filenames.
      // (no overwrite-checking is performed!!)
      saveAs: function (__newFile) {
        return __newFile.filename;
      },

      // Bind a progress event handler, e.g.:
      // function (milestone) {
      //   milestone.id
      //   milestone.name
      //   milestone.written
      //   milestone.total
      //   milestone.percent
      // },
      onProgress: undefined,

      // Upload limit (in bytes)
      // defaults to ~15MB
      maxBytes: 15000000,

      // By default, upload files to `./.tmp/uploads` (relative to cwd)
      dirname: '.tmp/uploads'
    });

    var receiver__ = Writable({
      objectMode: true
    });

    // if onProgress handler was provided, bind an event automatically:
    if (_.isFunction(options.onProgress)) {
      receiver__.on('progress', options.onProgress);
    }

    // Track the progress of each file upload in this Upstream.
    receiver__._files = [];

    // Keep track of the number total bytes written so that maxBytes can
    // be enforced.
    var totalBytesWritten = 0;

    // Flag to track whether this file upload has been aborted.
    // receiver__._aborted = false;

    // And a function to abort it.
    // (returns true if abort is redundant)
    // var abort = function () {
    //   if (receiver__._aborted) return false;
    //   else receiver__._aborted = true;
    //   console.log('Aborted receiver.');

    //   // Pipe all of our files to /dev/null
    //   _.each(receiver__._files, function (file) {
    //     console.log('piping file ('+file.name+') down the leaky drain');
    //     var leaky = new Writable();
    //     leaky._write = function (chunk,encoding, cb) { console.log(chunk.length,'bytes down the drain, whee!!!'); cb(); };
    //     file.stream.unpipe();
    //     file.stream.pipe( leaky );
    //   });

    //   return true;
    // };

    // This `_write` method is invoked each time a new file is received
    // from the Readable stream (Upstream) which is pumping filestreams
    // into this receiver.  (filename === `__newFile.filename`).
    receiver__._write = function onFile(__newFile, encoding, done) {

      // var _done = done;
      // done = function () {
      //   console.log('CALLED DONE ON RECEIVER WITH ARGS:',Array.prototype.slice.call(arguments));
      //   _done.apply(null, Array.prototype.slice.call(arguments));
      // };

      console.log('new file received:', __newFile.filename);

      // Determine location where file should be written:
      // -------------------------------------------------------
      var filePath, dirPath, filename;
      if (options.id) {
        // If `options.id` was specified, use it directly as the path.
        filePath = options.id;
        dirPath = path.dirname(filePath);
        filename = path.basename(filePath);
      }
      else {
        // Otherwise, use the more sophisiticated options:
        dirPath = path.resolve(options.dirname);
        filename = options.filename || options.saveAs(__newFile);
        filePath = path.join(dirPath, filename);
      }
      // -------------------------------------------------------

      // Garbage-collect the bytes that were already written for this file.
      // (called when a read or write error occurs)
      function gc(err) {

        // console.log('************** Garbage collecting file `' + __newFile.filename + '` located @ ' + filePath + '...');
        adapter.rm(filePath, function (gcErr) {
          if (gcErr) return done([err].concat([gcErr]));
          else return done(err);
        });
      }

      // Ensure necessary parent directories exist:
      fsx.mkdirs(dirPath, function (mkdirsErr) {
        // If we get an error here, it's probably because the Node
        // user doesn't have write permissions at the designated
        // path.
        if (mkdirsErr) {
          return done(mkdirsErr);
        }

        __newFile.on('error', function (err) {
          // var leaky = new Writable();
          // leaky._write = function (chunk,encoding, cb) { cb(); };
          // __newFile.unpipe();
          // __newFile.pipe( leaky );
          console.log('***** READ error on file ' + __newFile.filename, '::', err);
        });

        var outs__ = fsx.createWriteStream(filePath, encoding);
        outs__.on('error', function failedToWriteFile(err) {
          // if ( !abort() ) return;
          console.log('Error on output stream- garbage collecting unfinished uploads...', err);
          gc(err);
        });
        outs__.on('finish', function successfullyWroteFile() {
          console.log('finished file: '+__newFile.filename);
          // if ( !abort() ) return;
          done();
        });

        // Generate a progress stream and unique id for this file
        var localID = _.uniqueId();
        // var __progress__ = ProgressStream({});
        var guessedTotal = 0;
        var writtenSoFar = 0;
        var __progress__ = new require('stream').Transform();
        __progress__._transform = function (chunk,enctype,next) {

          // Update the guessedTotal to make % estimate
          // more accurate:
          guessedTotal += chunk.length;
          writtenSoFar += chunk.length;

          this.push(chunk);
          this.emit('progress', {
            id: localID,
            name: __newFile.name,
            written: writtenSoFar,
            total: guessedTotal,
            percent: (writtenSoFar/guessedTotal)*100 | 0
          });
          next();
        };

        // This event is fired when a single file stream emits a progress event.
        // Each time we receive a file, we must recalculate the TOTAL progress
        // for the aggregate file upload.
        //
        // events emitted look like:
        /*
        {
          percentage: 9.05,
          transferred: 949624,
          length: 10485760,
          remaining: 9536136,
          eta: 10,
          runtime: 0,
          delta: 295396,
          speed: 949624
        }
        */

        // Used to calculate total size of this file (used for estimated %, etc.)
        // var total = (__newFile._readableState && __newFile._readableState.length) || milestone.length;
        // var guessedTotal = 0;
        // var __countBytes__ = require('stream').Transform();
        // __countBytes__._transform = function (chunk, enctype, next) {
        //   guessedTotal += chunk.length;

        //   // Update the length on the progress stream to make % estimate
        //   // more accurate:
        //   __progress__.setLength(guessedTotal);

        //   this.push(chunk);
        //   next();
        // };

        __progress__.on('progress', function singleFileProgress (milestone) {

          // Lookup or create new object to track file progress
          var currentFileProgress = _.find(receiver__._files, {
            id: localID
          });
          if (currentFileProgress) {
            currentFileProgress.written = milestone.written;
            currentFileProgress.total = milestone.total;
            currentFileProgress.percent = milestone.percent;
            currentFileProgress.stream = __newFile;
          }
          else {
            currentFileProgress = {
              id          : localID,
              name        : __newFile.filename,
              written     : milestone.written,
              total       : milestone.total,
              percent     : milestone.percent,
              stream      : __newFile
            };
            receiver__._files.push(currentFileProgress);
          }
          ////////////////////////////////////////////////////////////////

          // Recalculate `totalBytesWritten` so far for this receiver instance
          // (across ALL OF ITS FILES)
          // using the sum of all bytes written to each file in `receiver__._files`
          totalBytesWritten = _.reduce(receiver__._files, function (memo, status) {
            memo += status.written;
            return memo;
          }, 0);

          console.log(currentFileProgress.percent, '::', currentFileProgress.written,'/',currentFileProgress.total, '       (file #'+currentFileProgress.id+'   :: '+/*'update#'+counter*/''+')');//receiver__._files.length+' files)');
          // console.log(totalBytesWritten,currentFileProgress);
          // console.log(__newFile._readableState.length);

          // Emit an event on the receiver
          receiver__.emit('progress', currentFileProgress);

          // and then enforce its `maxBytes`.
          if (options.maxBytes && totalBytesWritten >= options.maxBytes) {
            // if ( !abort() ) return;
            // __progress__.removeAllListeners('progress');

            // TODO:Pipe the remainder of this file to /dev/null
            // _.each(receiver__._files, function (file) {
            //   console.log('piping file ('+file.name+') down the leaky drain');
            //   var leaky = new Writable();
            //   leaky._write = function (chunk,encoding, cb) { console.log(chunk.length,'bytes down the drain, whee!!!'); cb(); };
            //   file.stream.unpipe();
            //   file.stream.pipe( leaky );
            // });

            var err = new Error();
            err.code = 'E_EXCEEDS_UPLOAD_LIMIT';
            err.name = 'Upload Error';
            err.maxBytes = options.maxBytes;
            err.written = totalBytesWritten;
            err.message = 'Upload limit of '+err.maxBytes+' bytes exceeded ('+err.written+' bytes written)';
            // __newFile.emit('error', err);
            console.log('unpiping all the things...');

            // __progress__.unpipe();
            // var memoryhole0 = new Writable();
            // memoryhole0._write = function (chunk,encoding, cb) {
            //   console.log(__newFile.filename, chunk.length,'bytes down the drain to the memory hole (draining __progress__)');
            //   cb();
            // };
            // __progress__.pipe(memoryhole0);
            // receiver__.emit('error', err);
            __progress__.removeAllListeners('progress');
            outs__.emit('error', err);
            return;
            // return done(err);
            // __newFile.unpipe();
            // var memoryhole = new Writable();
            // memoryhole._write = function (chunk,encoding, cb) {
            //   console.log(__newFile.filename, chunk.length,'bytes down the drain to the memory hole (draining __newFile)');
            //   cb();
            // };
            // __newFile.pipe(memoryhole);
            // var x;
            // console.log('past unpipes');
            // __countBytes__.unpipe();
            // outs__.unpipe();
            // console.log('past unpipes');
            // while (x !== null) {
            //   x = __progress__.read();
            // }
            // while (x !== null) {
            //   x = __countBytes__.read();
            // }
            // while (x !== null) {
            //   x = __newFile.read();
            // }
            // console.log('past reads');
            // outs__.end();
            // console.log('made it');

            // __progress__.on('data', function () {});
            // __progress__.resume();

            // var leaky1 = new Writable();
            // leaky1._write = function (chunk,encoding, cb) { /*console.log(chunk.length,'bytes down the drain, whee!!!');*/ cb(); };
            // __newFile.pipe(leaky1);

            // var leaky2 = new Writable();
            // leaky2._write = function (chunk,encoding, cb) { /*console.log(chunk.length,'bytes down the drain, whee!!!');*/ cb(); };
            // __countBytes__.pipe(leaky2);
            //   file.stream.pipe( leaky );
            // outs__.removeAllListeners();
            // outs__.end();
            // outs__.on('error', function (){});
            // return done(err);
            // return done();
          }

        });

        // Finally pipe the progress THROUGH the progress stream
        // and out to disk.
        __newFile
        // .pipe(__countBytes__)
        .pipe(__progress__)
        .pipe(outs__);

      });

    };

    return receiver__;
  } // </DiskReceiver>

};

<commit_msg>Removed code that emitted writestream error on quota violation, cleaned up comments.<commit_after>/**
 * Module dependencies
 */

var Writable = require('stream').Writable;
var fsx = require('fs-extra');
var path = require('path');
var _ = require('lodash');
var ProgressStream = require('progress-stream');

/**
 * skipper-disk
 *
 * @param  {Object} options
 * @return {Object}
 */

module.exports = function DiskStore (options) {
  options = options || {};

  var adapter = {

    rm: function (filepath, cb){
      return fsx.unlink(filepath, function(err) {
        // Ignore "doesn't exist" errors
        if (err && err.code !== 'ENOENT') { return cb(err); }
        else return cb();
      });
    },
    ls: function (dirpath, cb) {
      return fsx.readdir(dirpath, cb);
    },
    read: function (filepath, cb) {
      if (cb) {
        return fsx.readFile(filepath, cb);
      }
      else {
        return fsx.createReadStream(filepath);
      }
    },

    receive: DiskReceiver,
    receiver: DiskReceiver // (synonym for `.receive()`)
  };

  return adapter;

  /**
   * A simple receiver for Skipper that writes Upstreams to
   * disk at the configured path.
   *
   * Includes a garbage-collection mechanism for failed
   * uploads.
   *
   * @param  {Object} options
   * @return {Stream.Writable}
   */
  function DiskReceiver (options) {
    options = options || {};

    // Normalize `saveAs()` option:
    // options.saveAs() <==> options.rename() <==> options.getFilename() <==> options.getFileName()
    options.saveAs = options.saveAs || options.rename;
    options.saveAs = options.saveAs || options.getFileName;
    options.saveAs = options.saveAs || options.getFilename;

    _.defaults(options, {

      // By default, create new files on disk
      // using their uploaded filenames.
      // (no overwrite-checking is performed!!)
      saveAs: function (__newFile) {
        return __newFile.filename;
      },

      // Bind a progress event handler, e.g.:
      // function (milestone) {
      //   milestone.id
      //   milestone.name
      //   milestone.written
      //   milestone.total
      //   milestone.percent
      // },
      onProgress: undefined,

      // Upload limit (in bytes)
      // defaults to ~15MB
      maxBytes: 15000000,

      // By default, upload files to `./.tmp/uploads` (relative to cwd)
      dirname: '.tmp/uploads'
    });

    var receiver__ = Writable({
      objectMode: true
    });

    // if onProgress handler was provided, bind an event automatically:
    if (_.isFunction(options.onProgress)) {
      receiver__.on('progress', options.onProgress);
    }

    // Track the progress of each file upload in this Upstream.
    receiver__._files = [];

    // Keep track of the number total bytes written so that maxBytes can
    // be enforced.
    var totalBytesWritten = 0;

    // This `_write` method is invoked each time a new file is received
    // from the Readable stream (Upstream) which is pumping filestreams
    // into this receiver.  (filename === `__newFile.filename`).
    receiver__._write = function onFile(__newFile, encoding, done) {

      console.log('new file received:', __newFile.filename);

      // Determine location where file should be written:
      // -------------------------------------------------------
      var filePath, dirPath, filename;
      if (options.id) {
        // If `options.id` was specified, use it directly as the path.
        filePath = options.id;
        dirPath = path.dirname(filePath);
        filename = path.basename(filePath);
      }
      else {
        // Otherwise, use the more sophisiticated options:
        dirPath = path.resolve(options.dirname);
        filename = options.filename || options.saveAs(__newFile);
        filePath = path.join(dirPath, filename);
      }
      // -------------------------------------------------------

      // Garbage-collect the bytes that were already written for this file.
      // (called when a read or write error occurs)
      function gc(err) {

        // console.log('************** Garbage collecting file `' + __newFile.filename + '` located @ ' + filePath + '...');
        adapter.rm(filePath, function (gcErr) {
          if (gcErr) return done([err].concat([gcErr]));
          else return done(err);
        });
      }

      // Ensure necessary parent directories exist:
      fsx.mkdirs(dirPath, function (mkdirsErr) {
        // If we get an error here, it's probably because the Node
        // user doesn't have write permissions at the designated
        // path.
        if (mkdirsErr) {
          return done(mkdirsErr);
        }

        // Error reading from the file stream
        __newFile.on('error', function (err) {
          console.log('***** READ error on file ' + __newFile.filename, '::', err);
        });

        // Create a new write stream to write to disk
        var outs__ = fsx.createWriteStream(filePath, encoding);

        // When the file is done writing, call the callback
        outs__.on('finish', function successfullyWroteFile() {
          console.log('finished file: '+__newFile.filename);
          done();
        });

        // Generate a progress stream and unique id for this file
        // We will pipe the incoming file stream to this, which will
        // then pipe the bytes down to the outs___ stream
        var localID = _.uniqueId();
        var guessedTotal = 0;
        var writtenSoFar = 0;
        var __progress__ = new require('stream').Transform();
        __progress__._transform = function (chunk,enctype,next) {

          // Update the guessedTotal to make % estimate
          // more accurate:
          guessedTotal += chunk.length;
          writtenSoFar += chunk.length;

          // Do the actual "writing", which in our case will pipe
          // the bytes to the outs___ stream that writes to disk
          this.push(chunk);

          // Emit an event that will calculate our total upload
          // progress and determine whether we're within quota
          this.emit('progress', {
            id: localID,
            name: __newFile.name,
            written: writtenSoFar,
            total: guessedTotal,
            percent: (writtenSoFar/guessedTotal)*100 | 0
          });
          next();
        };

        // This event is fired when a single file stream emits a progress event.
        // Each time we receive a file, we must recalculate the TOTAL progress
        // for the aggregate file upload.
        //
        // events emitted look like:
        /*
        {
          percentage: 9.05,
          transferred: 949624,
          length: 10485760,
          remaining: 9536136,
          eta: 10,
          runtime: 0,
          delta: 295396,
          speed: 949624
        }
        */
        __progress__.on('progress', function singleFileProgress (milestone) {

          // Lookup or create new object to track file progress
          var currentFileProgress = _.find(receiver__._files, {
            id: localID
          });
          if (currentFileProgress) {
            currentFileProgress.written = milestone.written;
            currentFileProgress.total = milestone.total;
            currentFileProgress.percent = milestone.percent;
            currentFileProgress.stream = __newFile;
          }
          else {
            currentFileProgress = {
              id          : localID,
              name        : __newFile.filename,
              written     : milestone.written,
              total       : milestone.total,
              percent     : milestone.percent,
              stream      : __newFile
            };
            receiver__._files.push(currentFileProgress);
          }
          ////////////////////////////////////////////////////////////////

          // Recalculate `totalBytesWritten` so far for this receiver instance
          // (across ALL OF ITS FILES)
          // using the sum of all bytes written to each file in `receiver__._files`
          totalBytesWritten = _.reduce(receiver__._files, function (memo, status) {
            memo += status.written;
            return memo;
          }, 0);

          console.log(currentFileProgress.percent, '::', currentFileProgress.written,'/',currentFileProgress.total, '       (file #'+currentFileProgress.id+'   :: '+/*'update#'+counter*/''+')');//receiver__._files.length+' files)');

          // Emit an event on the receiver.  Someone using Skipper may listen for this to show
          // a progress bar, for example.
          receiver__.emit('progress', currentFileProgress);

          // and then enforce its `maxBytes`.
          if (options.maxBytes && totalBytesWritten >= options.maxBytes) {

            var err = new Error();
            err.code = 'E_EXCEEDS_UPLOAD_LIMIT';
            err.name = 'Upload Error';
            err.maxBytes = options.maxBytes;
            err.written = totalBytesWritten;
            err.message = 'Upload limit of '+err.maxBytes+' bytes exceeded ('+err.written+' bytes written)';

            // Stop listening for progress events
            __progress__.removeAllListeners('progress');
            // Unpipe the progress stream, which feeds the disk stream, so we don't keep dumping to disk
            __progress__.unpipe();
            // Clean up any files we've already written
            gc(err);

            // Don't do this--it releases the underlying pipes, which confuses node when it's in the middle
            // of a write operation.
            // outs__.emit('error', err);
            return;

          }

        });

        // Finally pipe the progress THROUGH the progress stream
        // and out to disk.
        __newFile
        .pipe(__progress__)
        .pipe(outs__);

      });

    };

    return receiver__;
  } // </DiskReceiver>

};

<|endoftext|>


<commit_before>/* Copyright 2015, Yahoo Inc.
   Copyrights licensed under the MIT License.
   See the accompanying LICENSE file for terms. */

var browserify = require('browserify');
var through = require('through2');
var shasum = require('shasum');
var path = require('path');
var fs = require('fs');
var async = require('async');
var mkdirp = require('mkdirp');
var JSONStream = require('JSONStream');
var falafel = require('falafel');

var config = require('./config')();
logObj((config));

var basePath = path.join(process.cwd(), config.base);
if (!fs.existsSync(basePath)) {
  console.log('base must exist in config');
  process.exit(1);
}

var bundles = Object.keys(config.bundles).map(function(bundleName) {
  var bundle = config.bundles[bundleName];
  bundle.id = bundleName;
  return bundle;
});

logObj(bundles);

var variations = Object.keys(config.variations||[]).map(function(dir) {
  var chain = [dir]
                  .concat(config.variations[dir] || [])
                  .map(variationsDir)
                  .concat([config.base])
                  .filter(existsRelativeDir);
  return {
    id: dir,
    chain: chain,
  };
}).filter(function(variation) {
  return variation.id !== 'base' && variation.chain.length > 1;
});

variations.unshift({
  id: 'base',
  chain: [config.base],
});

variations.forEach(function(variation) {
  variation.matchList = variation.chain.map(function(path) {
    path = path.replace(/(^\/|\/$)/g,'');
    return new RegExp('(.*)/('+path+')/(.*)')
  });
});

logObj(variations);

async.each(bundles, function(rawBundle, doneBundle) {
  var bundleIndexes = {};
  var bundleData = [];
  var bundleManifest = {
    bundleIndexes: bundleIndexes,
    bundles: bundleData,
  };

  function pushBundleManifest(dep) {
    var id = dep.id;
    var variation = dep.variation || 'module';
    var data = JSON.parse(JSON.stringify(dep));

    delete data.file;
    delete data.source;
    delete data.id;
    Object.keys(data.deps).forEach(function(key) {
      var index = bundleIndexes[key];
      if (typeof index !== 'undefined') {
        data.deps[key] = index;
      }
      index = bundleIndexes[data.deps[key]];
      if (typeof index !== 'undefined') {
        data.deps[key] = index;
      }
    });

    if (typeof bundleIndexes[id] === 'undefined') {
      var newDep = {
        id: id,
        variations: [variation],
        data: [data],
      };
      bundleData.push(newDep);
      bundleIndexes[id] = bundleData.indexOf(newDep);
    } else {
      var existingData = bundleData[bundleIndexes[id]];
      var variationIndex = existingData.variations.indexOf(variation);
      if (variationIndex === -1) {
        existingData.variations.push(variation);
        existingData.data.push(data);
      } else if (existingData.data[variationIndex].sha !== dep.sha) {
        throw new Error('Files with same variation and id should have the same SHA');
      }
    }
  }

  async.each(variations, function(variation, doneVariation) {
    var bundle = JSON.parse(JSON.stringify(rawBundle));

    // validate entries honorring chain
    bundle.entries = (bundle.entries||[]).map(function(file) {
      var found;
      variation.chain.some(function(dir) {
        found = path.join(dir, file);
        return fs.existsSync(found);
      });
      return found;
    });
    bundle.bundleExternal = !bundle.external;

    var b = browserify(bundle);

    // Prepare output files
    var bundleFileName = (bundle.dest || bundle.id+'.js');
    var destDir = path.join(process.cwd(), config.dest, variation.id);
    var destBundle = path.join(destDir, bundleFileName);
    var destDeps = path.join(destDir, bundle.id+'.manifest.json');
    mkdirp.sync(destDir);

    var bundleStream = fs.createWriteStream(destBundle);
    var depsStream = JSONStream.stringify();
    depsStream.pipe(fs.createWriteStream(destDeps));

    b.transform(path.join(__dirname, "packages/mendel-treenherit"), {"dirs": variation.chain});

    var mendelify = through.obj(function (row, enc, next) {
      var match = findVariationMatch(row.file);
      if (match) {
        row.id = match[3];
        row.variation = match[2];
      }

      Object.keys(row.deps).forEach(function (key) {
        var rowMatch = findVariationMatch(key);
        if (rowMatch) {
          row.deps[rowMatch[3]] = rowMatch[3];
          delete row.deps[key];
        }
      });

      row.source = replaceRequiresOnSource(row.source, row);

      row.sha = shasum(row.source);

      pushBundleManifest(row);

      this.push(row);
      depsStream.write(row);
      next();
    });
    b.pipeline.get('deps').push(mendelify);

    // bundle
    var bundler = b.bundle();
    bundler.on('end', function(){
      depsStream.end();
      doneVariation();
    });
    bundler.pipe(bundleStream);
  }, function() {
    var manifestPath = path.join(process.cwd(), config.dest, rawBundle.id+'.manifest.json');
    fs.writeFile(manifestPath, JSON.stringify(bundleManifest, null, 2), function (err) {
      if (err) {
        return console.log(err);
      }
      doneBundle();
    });
  });
});

function existsRelativeDir(dir) {
  return fs.existsSync(path.join(process.cwd(), dir));
}

function variationsDir(dir) {
  return path.join(config.variations_root, dir);
}

function logObj(obj) {
  console.log(require('util').inspect(obj,false,null,true));
  return obj;
}

function replaceRequiresOnSource (src, deps, replacer) {
  var opts = {
      ecmaVersion: 6,
      allowReturnOutsideFunction: true
  };
  return falafel(src, opts, function (node) {
    if (isRequire(node)) {
      var value = node.arguments[0].value;
      var match = findVariationMatch(value);
      if (match) {
        if(match) node.update('require(\'' + match[3] + '\')');
      }
    }
  }).toString();
}

function findVariationMatch(path) {
  var match;
  variations.some(function(variation) {
    variation.matchList.some(function(regex) {
      match = path.match(regex);
      return match;
    });
    return match;
  });
  return match;
}

function isRequire (node) {
  var c = node.callee;
  return c
    && node.type === 'CallExpression'
    && c.type === 'Identifier'
    && c.name === 'require'
    && node.arguments[0]
    && node.arguments[0].type === 'Literal'
  ;
}

function has (obj, key) {
    return Object.prototype.hasOwnProperty.call(obj, key);
}
<commit_msg>Exclude all lazy loaded dependencies from bundle; TODO: create external bundles<commit_after>/* Copyright 2015, Yahoo Inc.
   Copyrights licensed under the MIT License.
   See the accompanying LICENSE file for terms. */

var browserify = require('browserify');
var through = require('through2');
var shasum = require('shasum');
var path = require('path');
var fs = require('fs');
var async = require('async');
var mkdirp = require('mkdirp');
var JSONStream = require('JSONStream');
var falafel = require('falafel');

var config = require('./config')();
logObj((config));

var basePath = path.join(process.cwd(), config.base);
if (!fs.existsSync(basePath)) {
  console.log('base must exist in config');
  process.exit(1);
}

var bundles = Object.keys(config.bundles).map(function(bundleName) {
  var bundle = config.bundles[bundleName];
  bundle.id = bundleName;
  return bundle;
});

logObj(bundles);

var variations = Object.keys(config.variations||[]).map(function(dir) {
  var chain = [dir]
                  .concat(config.variations[dir] || [])
                  .map(variationsDir)
                  .concat([config.base])
                  .filter(existsRelativeDir);
  return {
    id: dir,
    chain: chain,
  };
}).filter(function(variation) {
  return variation.id !== 'base' && variation.chain.length > 1;
});

variations.unshift({
  id: 'base',
  chain: [config.base],
});

variations.forEach(function(variation) {
  variation.matchList = variation.chain.map(function(path) {
    path = path.replace(/(^\/|\/$)/g,'');
    return new RegExp('(.*)/('+path+')/(.*)')
  });
});

logObj(variations);

var extractions = {};
bundles.forEach(function(bundle) {
  if (!bundle.extract) return;
  extractions[bundle.id] = Object.keys(bundle.extract).reduce(function(cumulative, key) {
    return cumulative.concat(bundle.extract[key].require);
  }, []);
});

logObj(extractions);

async.each(bundles, function(rawBundle, doneBundle) {
  var bundleIndexes = {};
  var bundleData = [];
  var bundleManifest = {
    bundleIndexes: bundleIndexes,
    bundles: bundleData,
  };

  function pushBundleManifest(dep) {
    var id = dep.id;
    var variation = dep.variation || 'module';
    var data = JSON.parse(JSON.stringify(dep));

    delete data.file;
    delete data.source;
    delete data.id;
    Object.keys(data.deps).forEach(function(key) {
      var index = bundleIndexes[key];
      if (typeof index !== 'undefined') {
        data.deps[key] = index;
      }
      index = bundleIndexes[data.deps[key]];
      if (typeof index !== 'undefined') {
        data.deps[key] = index;
      }
    });

    if (typeof bundleIndexes[id] === 'undefined') {
      var newDep = {
        id: id,
        variations: [variation],
        data: [data],
      };
      bundleData.push(newDep);
      bundleIndexes[id] = bundleData.indexOf(newDep);
    } else {
      var existingData = bundleData[bundleIndexes[id]];
      var variationIndex = existingData.variations.indexOf(variation);
      if (variationIndex === -1) {
        existingData.variations.push(variation);
        existingData.data.push(data);
      } else if (existingData.data[variationIndex].sha !== dep.sha) {
        throw new Error('Files with same variation and id should have the same SHA');
      }
    }
  }

  async.each(variations, function(variation, doneVariation) {
    var bundle = JSON.parse(JSON.stringify(rawBundle));

    // validate entries honorring chain
    bundle.entries = (bundle.entries||[]).map(function(file) {
      var found;
      variation.chain.some(function(dir) {
        found = path.join(dir, file);
        return fs.existsSync(found);
      });
      return found;
    });
    bundle.bundleExternal = !bundle.external;

    // This is undocumented on browserify, but browserify
    // pass all options to modules-deps and filter is supported
    // and documented there.
    if (bundle.extract) {
      bundle.filter = function(id) {
        var idMatch = findVariationMatch(id);
        if (idMatch) {
          return -1 === extractions[bundle.id].indexOf(idMatch[3]);
        }
        return true;
      };
    }

    var b = browserify(bundle);

    // Prepare output files
    var bundleFileName = (bundle.dest || bundle.id+'.js');
    var destDir = path.join(process.cwd(), config.dest, variation.id);
    var destBundle = path.join(destDir, bundleFileName);
    var destDeps = path.join(destDir, bundle.id+'.manifest.json');
    mkdirp.sync(destDir);

    var bundleStream = fs.createWriteStream(destBundle);
    var depsStream = JSONStream.stringify();
    depsStream.pipe(fs.createWriteStream(destDeps));

    b.transform(path.join(__dirname, "packages/mendel-treenherit"), {"dirs": variation.chain});

    var mendelify = through.obj(function (row, enc, next) {
      var match = findVariationMatch(row.file);
      if (match) {
        row.id = match[3];
        row.variation = match[2];
      }

      Object.keys(row.deps).forEach(function (key) {
        var rowMatch = findVariationMatch(key);
        if (rowMatch) {
          row.deps[rowMatch[3]] = rowMatch[3];
          delete row.deps[key];
        }
      });

      row.source = replaceRequiresOnSource(row.source, row);

      row.sha = shasum(row.source);

      pushBundleManifest(row);

      this.push(row);
      depsStream.write(row);
      next();
    });
    b.pipeline.get('deps').push(mendelify);

    // bundle
    var bundler = b.bundle();
    bundler.on('end', function(){
      depsStream.end();
      doneVariation();
    });
    bundler.pipe(bundleStream);
  }, function() {
    var manifestPath = path.join(process.cwd(), config.dest, rawBundle.id+'.manifest.json');
    fs.writeFile(manifestPath, JSON.stringify(bundleManifest, null, 2), function (err) {
      if (err) throw err;
      /*
        Here is the right place to implement the generation of extracted bundles. Simple algorithm
        should be as follows:
          1. Assuming all `bundle.externals` are already parsed with something similar to `findVariationMatch`.
          2. Assuming `bundleManifest` ids are already parsed with `findVariationMatch` during "deps" phase.
          3. Create one array with all `bundle.externals` + all `bundleManifest` ids
          4. Use this array as externals for all the `bundle.externals` bundles
          5. Run mendel through all those bundles
        The reason I prefer not to do this righ now is because we are doing procedural async bundle generation
        and we need to make mendel a plugin. This way we can have the plugin trigger extra bundle generations
        by adding the above algorithm on the wrap phase.
      */
      doneBundle();
    });
  });
});

function existsRelativeDir(dir) {
  return fs.existsSync(path.join(process.cwd(), dir));
}

function variationsDir(dir) {
  return path.join(config.variations_root, dir);
}

function logObj(obj) {
  console.log(require('util').inspect(obj,false,null,true));
  return obj;
}

function replaceRequiresOnSource (src, deps, replacer) {
  var opts = {
      ecmaVersion: 6,
      allowReturnOutsideFunction: true
  };
  return falafel(src, opts, function (node) {
    if (isRequire(node)) {
      var value = node.arguments[0].value;
      var match = findVariationMatch(value);
      if (match) {
        if(match) node.update('require(\'' + match[3] + '\')');
      }
    }
  }).toString();
}

function findVariationMatch(path) {
  var match;
  variations.some(function(variation) {
    variation.matchList.some(function(regex) {
      match = path.match(regex);
      return match;
    });
    return match;
  });
  return match;
}

function isRequire (node) {
  var c = node.callee;
  return c
    && node.type === 'CallExpression'
    && c.type === 'Identifier'
    && c.name === 'require'
    && node.arguments[0]
    && node.arguments[0].type === 'Literal'
  ;
}

function has (obj, key) {
    return Object.prototype.hasOwnProperty.call(obj, key);
}
<|endoftext|>


<commit_before>'use strict';

var through = require('through');
var log = require('fancy-log');
var helper = require('./lib/helper');
var path = require('path');
var spawn = require('child_process').spawn;
var PluginError = require('plugin-error');

var PLUGIN_NAME = 'gulp-nightwatch';

var nightwatchPlugin = function(options) {
  var child,
      stream,
      files = [],
      nightwatchOptions = { config: 'nightwatch.json', env: 'default' };

  options = options || {};

  if (options.configFile) {
    if (typeof options.configFile === 'string') {
      nightwatchOptions.config = path.resolve(options.configFile);
    } else {
      throw new PluginError(PLUGIN_NAME, 'configFile option must be string');
    }
  }

  if (options.cliArgs) {
    helper.merge(nightwatchOptions, helper.parseCliArgs(options.cliArgs));
  }

  function done(code) {
    if (child) {
      child.kill();
    }

    if (stream) {
      if (code) {
        stream.emit('error', new PluginError(PLUGIN_NAME, 'nightwatch exited with code ' + code));
      } else {
        stream.emit('end');
      }
    }
  }

  function startNightwatch() {
    log('Starting nightwatch...');

    child = spawn(
      'node',
      [
        path.join(__dirname, 'lib', 'background.js'),
        JSON.stringify(nightwatchOptions) // Nightwatch args
      ],
      {
        stdio: 'inherit'
      }
    );

    child.on('exit', function(code) {
      done(code);
    });

  }

  function queueFile(file) {
    log("log file");
    if (file) {
      files.push(file.path);
    }
  }

  function endStream() {
    if (files.length) {
      options.files = files;
    }

    startNightwatch();
  }

  stream = through(queueFile, endStream);
  return stream;

};

module.exports = nightwatchPlugin;
<commit_msg>Remove the unnecessary log<commit_after>'use strict';

var through = require('through');
var log = require('fancy-log');
var helper = require('./lib/helper');
var path = require('path');
var spawn = require('child_process').spawn;
var PluginError = require('plugin-error');

var PLUGIN_NAME = 'gulp-nightwatch';

var nightwatchPlugin = function(options) {
  var child,
      stream,
      files = [],
      nightwatchOptions = { config: 'nightwatch.json', env: 'default' };

  options = options || {};

  if (options.configFile) {
    if (typeof options.configFile === 'string') {
      nightwatchOptions.config = path.resolve(options.configFile);
    } else {
      throw new PluginError(PLUGIN_NAME, 'configFile option must be string');
    }
  }

  if (options.cliArgs) {
    helper.merge(nightwatchOptions, helper.parseCliArgs(options.cliArgs));
  }

  function done(code) {
    if (child) {
      child.kill();
    }

    if (stream) {
      if (code) {
        stream.emit('error', new PluginError(PLUGIN_NAME, 'nightwatch exited with code ' + code));
      } else {
        stream.emit('end');
      }
    }
  }

  function startNightwatch() {
    log('Starting nightwatch...');

    child = spawn(
      'node',
      [
        path.join(__dirname, 'lib', 'background.js'),
        JSON.stringify(nightwatchOptions) // Nightwatch args
      ],
      {
        stdio: 'inherit'
      }
    );

    child.on('exit', function(code) {
      done(code);
    });

  }

  function queueFile(file) {
    if (file) {
      files.push(file.path);
    }
  }

  function endStream() {
    if (files.length) {
      options.files = files;
    }

    startNightwatch();
  }

  stream = through(queueFile, endStream);
  return stream;

};

module.exports = nightwatchPlugin;
<|endoftext|>


<commit_before>'use strict';

const EventEmitter = require('events').EventEmitter;
const redis = require('redis');
const { createPool } = require('generic-pool');

const FLUSH_CONNECTION = true;
const DEFAULT_STATUS_INTERVAL = 60000
const DEFAULTS = {
    host: '127.0.0.1',
    port: '6379',
    max: 50,
    idleTimeoutMillis: 10000,
    reapIntervalMillis: 1000,
    noReadyCheck: false,
    returnToHead: false,
    unwatchOnRelease: true,
    name: 'default',
    slowPool: {
        log: false,
        elapsedThreshold: 25
    },
    emitter: {
        statusInterval: DEFAULT_STATUS_INTERVAL
    },
    commands: []
};

/**
 * Create a new multi database Redis pool.
 * It will emit `status` event with information about each created pool.
 *
 * @param {Object} options
 * @returns {RedisPool}
 * @constructor
 */
module.exports = class RedisPool extends EventEmitter {
    constructor (options = {}, logger = console) {
        super();

        this.pools = {};
        this.options = Object.assign({}, DEFAULTS, options);
        this.logger = logger;

        this._addCommands();
        this._emitStatus();
    }

    /**
   * Acquire Redis client
   *
   * @param {String|Number} database redis database name
   * @returns {Promise} with the Redis client
   */
    async acquire (database) {
        let pool = this.pools[database];
        if (!pool) {
            pool = this.pools[database] = makePool(this, database);
        }

        const startTime = Date.now();
        const client = await pool.acquire();
        const elapsedTime = Date.now() - startTime;

        if (this.options.slowPool.log && elapsedTime > this.options.slowPool.elapsedThreshold) {
            this.logger.info({ name: this.options.name, db: database, action: 'acquire', elapsed: elapsedTime, waiting: pool.pending });
        }

        if (client instanceof Error) {
            const err = client;
            err.name = this.options.name;
            err.db = database;
            err.action = 'acquire';
            this.logger.error(err);

            throw err;
        }

        return client;
    }

    /**
   * Release resource.
   *
   * @param {String|Number} database redis database name
   * @param {Object} resource resource object to release
   */
    async release (database, resource) {
        if (this.options.unwatchOnRelease) {
            resource.UNWATCH();
        }

        const pool = this.pools[database];

        if (pool) {
            await pool.release(resource);
        }
    }

    _addCommands () {
        if (this.options.commands.length) {
            this.options.commands.forEach(newCommand => redis.add_command(newCommand));
        }
    }

    _emitStatus () {
        setInterval(() => {
            for (const [poolKey, pool] of Object.entries(this.pools)) {
                this.emit('status', {
                    name: this.options.name,
                    db: poolKey,
                    count: pool.size,
                    unused: pool.available,
                    waiting: pool.pending
                });
            }
        }, this._getStatusDelay());
    }

    _getStatusDelay () {
        return (this.options.emitter && this.options.emitter.statusInterval) || DEFAULT_STATUS_INTERVAL;
    }
};

/**
 * Factory to create new Redis pools for a given Redis database
 * @param redisPool
 * @param database
 * @returns {Pool}
 */
function makePool (redisPool, database) {
    const factory = {
        // create function will loop forever if reject is called or exception is thrown
        // https://github.com/coopernurse/node-pool/issues/175
        create () {
            return new Promise(resolve => {
                let settled = false;

                const client = redis.createClient(redisPool.options.port, redisPool.options.host, {
                    no_ready_check: redisPool.options.noReadyCheck
                });

                client.on('error', (err) => {
                    if (settled) {
                        err.name = redisPool.options.name;
                        return redisPool.logger.error(err);
                    }

                    settled = true;
                    client.end(FLUSH_CONNECTION);

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

                    return resolve(client);
                });

                client.on('ready', () => {
                    client.select(database, err => {
                        if (!settled) {
                            settled = true;

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

                            return resolve(client);
                        }
                    });
                });
            });
        },

        destroy (client) {
            return new Promise((resolve, reject) => {
                client.quit(err => {
                    client.end(FLUSH_CONNECTION);
                    if (err) {
                        return reject(err);
                    }
                    return resolve();
                });
            });
        },

        validate (client) {
            return new Promise(resolve => {
                return resolve(client && client.connected);
            });
        }
    };

    const config = {
        max: redisPool.options.max,
        idleTimeoutMillis: redisPool.options.idleTimeoutMillis,
        reapIntervalMillis: redisPool.options.reapIntervalMillis,
        returnToHead: redisPool.options.returnToHead
    };

    return createPool(factory, config);
}
<commit_msg>force draining pools<commit_after>'use strict';

const EventEmitter = require('events').EventEmitter;
const redis = require('redis');
const { createPool } = require('generic-pool');

const FLUSH_CONNECTION = true;
const DEFAULT_STATUS_INTERVAL = 60000
const DEFAULTS = {
    host: '127.0.0.1',
    port: '6379',
    max: 50,
    idleTimeoutMillis: 10000,
    reapIntervalMillis: 1000,
    noReadyCheck: false,
    returnToHead: false,
    unwatchOnRelease: true,
    name: 'default',
    slowPool: {
        log: false,
        elapsedThreshold: 25
    },
    emitter: {
        statusInterval: DEFAULT_STATUS_INTERVAL
    },
    commands: []
};

/**
 * Create a new multi database Redis pool.
 * It will emit `status` event with information about each created pool.
 *
 * @param {Object} options
 * @returns {RedisPool}
 * @constructor
 */
module.exports = class RedisPool extends EventEmitter {
    constructor (options = {}, logger = console) {
        super();

        this.pools = {};
        this.options = Object.assign({}, DEFAULTS, options);
        this.logger = logger;

        this._addCommands();
        this._emitStatus();
    }

    /**
   * Acquire Redis client
   *
   * @param {String|Number} database redis database name
   * @returns {Promise} with the Redis client
   */
    async acquire (database) {
        let pool = this.pools[database];
        if (!pool) {
            pool = this.pools[database] = makePool(this, database);
        }

        const startTime = Date.now();
        const client = await pool.acquire();
        const elapsedTime = Date.now() - startTime;

        if (this.options.slowPool.log && elapsedTime > this.options.slowPool.elapsedThreshold) {
            this.logger.info({ name: this.options.name, db: database, action: 'acquire', elapsed: elapsedTime, waiting: pool.pending });
        }

        if (client instanceof Error) {
            const err = client;
            err.name = this.options.name;
            err.db = database;
            err.action = 'acquire';
            this.logger.error(err);

            throw err;
        }

        return client;
    }

    /**
   * Release resource.
   *
   * @param {String|Number} database redis database name
   * @param {Object} resource resource object to release
   */
    async release (database, resource) {
        if (this.options.unwatchOnRelease) {
            resource.UNWATCH();
        }

        const pool = this.pools[database];

        if (pool) {
            await pool.release(resource);
        }
    }

    /**
     * Closing all connection pools
     *
     * https://github.com/coopernurse/node-pool/blob/v3.7.1/README.md#draining
     */
    async drain () {
        await Promise.all(Object.values(this.pools).map(p => p.drain().then(() => p.clear())) )
    }

    _addCommands () {
        if (this.options.commands.length) {
            this.options.commands.forEach(newCommand => redis.add_command(newCommand));
        }
    }

    _emitStatus () {
        setInterval(() => {
            for (const [poolKey, pool] of Object.entries(this.pools)) {
                this.emit('status', {
                    name: this.options.name,
                    db: poolKey,
                    count: pool.size,
                    unused: pool.available,
                    waiting: pool.pending
                });
            }
        }, this._getStatusDelay());
    }

    _getStatusDelay () {
        return (this.options.emitter && this.options.emitter.statusInterval) || DEFAULT_STATUS_INTERVAL;
    }
};

/**
 * Factory to create new Redis pools for a given Redis database
 * @param redisPool
 * @param database
 * @returns {Pool}
 */
function makePool (redisPool, database) {
    const factory = {
        // create function will loop forever if reject is called or exception is thrown
        // https://github.com/coopernurse/node-pool/issues/175
        create () {
            return new Promise(resolve => {
                let settled = false;

                const client = redis.createClient(redisPool.options.port, redisPool.options.host, {
                    no_ready_check: redisPool.options.noReadyCheck
                });

                client.on('error', (err) => {
                    if (settled) {
                        err.name = redisPool.options.name;
                        return redisPool.logger.error(err);
                    }

                    settled = true;
                    client.end(FLUSH_CONNECTION);

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

                    return resolve(client);
                });

                client.on('ready', () => {
                    client.select(database, err => {
                        if (!settled) {
                            settled = true;

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

                            return resolve(client);
                        }
                    });
                });
            });
        },

        destroy (client) {
            return new Promise((resolve, reject) => {
                client.quit(err => {
                    client.end(FLUSH_CONNECTION);
                    if (err) {
                        return reject(err);
                    }
                    return resolve();
                });
            });
        },

        validate (client) {
            return new Promise(resolve => {
                return resolve(client && client.connected);
            });
        }
    };

    const config = {
        max: redisPool.options.max,
        idleTimeoutMillis: redisPool.options.idleTimeoutMillis,
        reapIntervalMillis: redisPool.options.reapIntervalMillis,
        returnToHead: redisPool.options.returnToHead
    };

    return createPool(factory, config);
}
<|endoftext|>