<commit_before>var async = require('async');
var Padlock = require('padlock').Padlock;
var lupBatch = require('levelup/lib/batch');
var util = require('util');
var through = require('through');
var concat = require('concat-stream');

function Batch(db) {
    this.db = db;
    lupBatch.call(this, db);
}

util.inherits(Batch, lupBatch);

Batch.prototype.put = function (key, value, opts) {
    key = this._levelup.preProcessKey(key, opts);
    return lupBatch.prototype.put.call(this, key, value, opts);
};

Batch.prototype.del = function (key, opts) {
    key = this._levelup.preProcessKey(key, opts);
    return lupBatch.prototype.del.call(this, key, opts);
}

function AtomicHooks(indb) {

    function DB () {}
    DB.prototype = indb
    var db = new DB()

    db.parent = indb;

    var putHooks = [];
    var delHooks = [];
    var getOverride = null;
    var readStreamOverride = null;
    var keyPreProcessors = [];
    var keyPostProcessors = [];

    db.atomichooks = true;

    db.writeLock = new Padlock();

    db.registerPutHook = function (hook) {
        putHooks.push(hook);
    };

    db.registerGetOverride = function (hook) {
        getOverride = hook;
    };

    db.registerReadStreamOverride = function (hook) {
        readStreamOverride = hook;
    };

    db.registerDelHook = function (hook) {
        delHooks.push(hook);
    };

    db.registerKeyPreProcessor = function (hook) {
        keyPreProcessors.push(hook);
    };

    db.registerKeyPostProcessor = function (hook) {
        keyPostProcessors.unshift(hook);
    };

    db.batch = function (arr, opts, callback) {
        var outarrs;
        var batch;
        if (typeof arr !== 'undefined') {
            outarrs = arr.map(function (item) {
                item.key = db.preProcessKey(item.key, opts);
                return item;
            });
            return db.parent.batch.call(db, outarrs, opts, callback);
        }
        return new Batch(db);
    }

    db.preProcessKey = function (key, opts) {
        key = key || '';
        for (var i = 0, l = keyPreProcessors.length; i < l; i++) {
            key = keyPreProcessors[i](key, opts);
        }
        return key;
    };

    db.postProcessKey = function (key, opts) {
        for (var i = 0, l = keyPostProcessors.length;
             i < l;
             key = keyPostProcessors[i](key, opts), i++);
        return key;
    };

    db.preProcessKV = function (kv, opts, callback) {
        async.reduce(kvPreProcessors, kv, function (kv, processor, rcb) {
            processor(kv, opts, rcb);
        }, callback);
    };

    db.postProcessKV = function (kv, opts, callback) {
        async.reduce(kvPreProcessors, kv, function (kv, processor, rcb) {
            processor(kv, opts, rcb);
        }, callback);
    };

    db.nonlockPut = function (key, value, opts, callback) {
        key = db.preProcessKey(key, opts);
        db.parent.put(key, value, opts, callback);
    }

    db.nonlockDel = function (key, value, opts, callback) {
        key = db.preProcessKey(key, opts);
        db.parent.del(key, opts, callback);
    }

    db.put = function (key, value, opts, callback) {
        if (typeof opts === 'function') {
            callback = opts;
            opts = {};
        }
        db.writeLock.runwithlock(function () {
            var batch = db.batch();
            //batch preprocesses key for us
            batch.put(key, value, opts);
            async.each(putHooks,
                function (hook, ecb) {
                    hook(key, value, opts, batch, ecb);
                },
                function (err) {
                    if (err) {
                        db.writeLock.release();
                        callback(err);
                    } else {
                        batch.write(function (err) {
                            db.writeLock.release();
                            callback(err);
                        });
                    }
                }
            );
        });
    };

    db.get = function (key, opts, callback) {
        if (typeof opts === 'function') {
            callback = opts;
            opts = {};
        }
        key = db.preProcessKey(key, opts);
        if (typeof getOverride === 'function') {
            getOverride(key, opts, callback);
        } else {
            db.parent.get.call(db, key, opts, callback);
        }
    };

    db.del = function (key, opts, callback) {
        if (typeof opts === 'function') {
            callback = opts;
            opts = {};
        }

        db.writeLock.runwithlock(function () {
            var batch = db.batch();
            batch.del(key, opts);
            async.each(delHooks,
                function (hook, ecb) {
                    hook(key, opts, batch, ecb);
                },
                function (err) {
                    if (err) {
                        db.writeLock.release();
                        callback(err);
                    } else {
                        batch.write(function (err) {
                            db.writeLock.release();
                            callback(err);
                        });
                    }
                }
            );
        });
    };

    db.createReadStream = function (opts) {
        opts.start = db.preProcessKey(opts.start, opts);
        opts.end = db.preProcessKey(opts.end, opts);

        var readStreamTransform = through(function (data) {
            console.log("data", data);
            if (typeof data === 'object') {
                if (data.hasOwnProperty('key')) {
                    data.key = db.postProcessKey(data.key, opts);
                }
            } else if (opts.keys === true) {
                data = db.postProcessKey(data, opts);
            }
            this.emit('data', data);
        }, undefined, {objectMode: true});
        var rs;
        if (typeof readStreamOverride === 'function') {
            rs = readStreamOverride(opts);
        } else {
            rs = db.parent.createReadStream(opts);
        }
        return rs.pipe(readStreamTransform);
    };

    db.createWriteStream = function (opts) {
        var writeStreamTransform = through(function (data) {
            data.key = db.postProcessKey(data.key, opts);
            this.emit('data', data);
        }, undefined, {objectMode: true});
        var rs = db.parent.createWriteStream(opts);
        return rs.pipe(writeStreamTransform);
    };

    return db;
}

module.exports = AtomicHooks;
<commit_msg>bugfixes<commit_after>var async = require('async');
var Padlock = require('padlock').Padlock;
var lupBatch = require('levelup/lib/batch');
var util = require('util');
var through = require('through');
var concat = require('concat-stream');

function Batch(db) {
    this.db = db;
    lupBatch.call(this, db);
}

util.inherits(Batch, lupBatch);

Batch.prototype.put = function (key, value, opts) {
    key = this.db.preProcessKeyRecursive(key, opts);
    return lupBatch.prototype.put.call(this, key, value, opts);
};

Batch.prototype.del = function (key, opts) {
    key = this._levelup.preProcessKeyRecursive(key, opts);
    return lupBatch.prototype.del.call(this, key, opts);
};

function AtomicHooks(indb) {

    function DB () {}
    DB.prototype = indb
    var db = new DB()

    db.parent = indb;

    var putHooks = [];
    var delHooks = [];
    var getOverride = null;
    var readStreamOverride = null;
    var keyPreProcessors = [];
    var keyPostProcessors = [];

    db.atomichooks = true;

    db.writeLock = new Padlock();

    db.registerPutHook = function (hook) {
        putHooks.push(hook);
    };

    db.registerGetOverride = function (hook) {
        getOverride = hook;
    };

    db.registerReadStreamOverride = function (hook) {
        readStreamOverride = hook;
    };

    db.registerDelHook = function (hook) {
        delHooks.push(hook);
    };

    db.registerKeyPreProcessor = function (hook) {
        keyPreProcessors.push(hook);
    };

    db.registerKeyPostProcessor = function (hook) {
        keyPostProcessors.unshift(hook);
    };

    db.batch = function (arr, opts, callback) {
        var outarrs;
        var batch;
        if (typeof arr !== 'undefined') {
            outarrs = arr.map(function (item) {
                item.key = db.preProcessKey(item.key, opts);
                return item;
            });
            return db.parent.batch.call(db, outarrs, opts, callback);
        }
        return new Batch(db);
    }

    db.preProcessKey = function (key, opts) {
        key = key || '';
        for (var i = 0, l = keyPreProcessors.length; i < l; i++) {
            key = keyPreProcessors[i](key, opts);
        }
        return key;
    };

    db.preProcessKeyRecursive = function (key, opts) {
        key = db.preProcessKey(key, opts);
        if (db.parent && db.parent.preProcessKeyRecursive) {
            key = db.parent.preProcessKeyRecursive(key, opts);
        }
        return key;
    }

    db.postProcessKey = function (key, opts) {
        for (var i = 0, l = keyPostProcessors.length;
             i < l;
             key = keyPostProcessors[i](key, opts), i++);
        return key;
    };

    db.preProcessKV = function (kv, opts, callback) {
        async.reduce(kvPreProcessors, kv, function (kv, processor, rcb) {
            processor(kv, opts, rcb);
        }, callback);
    };

    db.postProcessKV = function (kv, opts, callback) {
        async.reduce(kvPreProcessors, kv, function (kv, processor, rcb) {
            processor(kv, opts, rcb);
        }, callback);
    };

    db.nonlockPut = function (key, value, opts, callback) {
        key = db.preProcessKey(key, opts);
        db.parent.put(key, value, opts, callback);
    }

    db.nonlockDel = function (key, value, opts, callback) {
        key = db.preProcessKey(key, opts);
        db.parent.del(key, opts, callback);
    }

    db.put = function (key, value, opts, callback) {
        if (typeof opts === 'function') {
            callback = opts;
            opts = {};
        }
        db.writeLock.runwithlock(function () {
            var batch = db.batch();
            //batch preprocesses key for us
            batch.put(key, value, opts);
            async.each(putHooks,
                function (hook, ecb) {
                    hook(key, value, opts, batch, ecb);
                },
                function (err) {
                    if (err) {
                        db.writeLock.release();
                        callback(err);
                    } else {
                        batch.write(function (err) {
                            db.writeLock.release();
                            callback(err);
                        });
                    }
                }
            );
        });
    };

    db.get = function (key, opts, callback) {
        if (typeof opts === 'function') {
            callback = opts;
            opts = {};
        }
        key = db.preProcessKey(key, opts);
        if (typeof getOverride === 'function') {
            getOverride(key, opts, callback);
        } else {
            db.parent.get.call(db, key, opts, callback);
        }
    };

    db.del = function (key, opts, callback) {
        if (typeof opts === 'function') {
            callback = opts;
            opts = {};
        }

        db.writeLock.runwithlock(function () {
            var batch = db.batch();
            batch.del(key, opts);
            async.each(delHooks,
                function (hook, ecb) {
                    hook(key, opts, batch, ecb);
                },
                function (err) {
                    if (err) {
                        db.writeLock.release();
                        callback(err);
                    } else {
                        batch.write(function (err) {
                            db.writeLock.release();
                            callback(err);
                        });
                    }
                }
            );
        });
    };

    db.createReadStream = function (opts) {
        opts.start = db.preProcessKey(opts.start, opts);
        opts.end = db.preProcessKey(opts.end, opts);

        var readStreamTransform = through(function (data) {
            if (typeof data === 'object') {
                if (data.hasOwnProperty('key')) {
                    data.key = db.postProcessKey(data.key, opts);
                }
            } else if (opts.keys === true) {
                data = db.postProcessKey(data, opts);
            }
            this.emit('data', data);
        }, undefined, {objectMode: true});
        var rs;
        if (typeof readStreamOverride === 'function') {
            rs = readStreamOverride(opts);
        } else {
            rs = db.parent.createReadStream(opts);
        }
        return rs.pipe(readStreamTransform);
    };

    db.createWriteStream = function (opts) {
        var writeStreamTransform = through(function (data) {
            data.key = db.postProcessKey(data.key, opts);
            this.emit('data', data);
        }, undefined, {objectMode: true});
        var rs = db.parent.createWriteStream(opts);
        return rs.pipe(writeStreamTransform);
    };

    return db;
}

module.exports = AtomicHooks;
<|endoftext|>


<commit_before>const React = require('react');
const { Component } = React;
const { ViewPropTypes } = ReactNative = require('react-native');
const createReactClass = require('create-react-class');
const PropTypes = require('prop-types');
const {
  Dimensions,
  View,
  Animated,
  ScrollView,
  Platform,
  StyleSheet,
  ViewPagerAndroid,
  InteractionManager,
} = ReactNative;
const TimerMixin = require('react-timer-mixin');

const SceneComponent = require('./SceneComponent');
const DefaultTabBar = require('./DefaultTabBar');
const ScrollableTabBar = require('./ScrollableTabBar');

const AnimatedViewPagerAndroid = Platform.OS === 'android' ?
  Animated.createAnimatedComponent(ViewPagerAndroid) :
  undefined;

const ScrollableTabView = createReactClass({
  mixins: [TimerMixin, ],
  statics: {
    DefaultTabBar,
    ScrollableTabBar,
  },
  scrollOnMountCalled: false,

  propTypes: {
    tabBarPosition: PropTypes.oneOf(['top', 'bottom', 'overlayTop', 'overlayBottom', ]),
    initialPage: PropTypes.number,
    page: PropTypes.number,
    onChangeTab: PropTypes.func,
    onScroll: PropTypes.func,
    renderTabBar: PropTypes.any,
    style: ViewPropTypes.style,
    contentProps: PropTypes.object,
    scrollWithoutAnimation: PropTypes.bool,
    locked: PropTypes.bool,
    prerenderingSiblingsNumber: PropTypes.number,
  },

  getDefaultProps() {
    return {
      tabBarPosition: 'top',
      initialPage: 0,
      page: -1,
      onChangeTab: () => {},
      onScroll: () => {},
      contentProps: {},
      scrollWithoutAnimation: false,
      locked: false,
      prerenderingSiblingsNumber: 0,
    };
  },

  getInitialState() {
    const containerWidth = Dimensions.get('window').width;
    let scrollValue;
    let scrollXIOS;
    let positionAndroid;
    let offsetAndroid;

    if (Platform.OS === 'ios') {
      scrollXIOS = new Animated.Value(this.props.initialPage * containerWidth);
      const containerWidthAnimatedValue = new Animated.Value(containerWidth);
      // Need to call __makeNative manually to avoid a native animated bug. See
      // https://github.com/facebook/react-native/pull/14435
      containerWidthAnimatedValue.__makeNative();
      scrollValue = Animated.divide(scrollXIOS, containerWidthAnimatedValue);

      const callListeners = this._polyfillAnimatedValue(scrollValue);
      scrollXIOS.addListener(
        ({ value, }) => callListeners(value / this.state.containerWidth)
      );
    } else {
      positionAndroid = new Animated.Value(this.props.initialPage);
      offsetAndroid = new Animated.Value(0);
      scrollValue = Animated.add(positionAndroid, offsetAndroid);

      const callListeners = this._polyfillAnimatedValue(scrollValue);
      let positionAndroidValue = this.props.initialPage;
      let offsetAndroidValue = 0;
      positionAndroid.addListener(({ value, }) => {
        positionAndroidValue = value;
        callListeners(positionAndroidValue + offsetAndroidValue);
      });
      offsetAndroid.addListener(({ value, }) => {
        offsetAndroidValue = value;
        callListeners(positionAndroidValue + offsetAndroidValue);
      });
    }

    return {
      currentPage: this.props.initialPage,
      scrollValue,
      scrollXIOS,
      positionAndroid,
      offsetAndroid,
      containerWidth,
      sceneKeys: this.newSceneKeys({ currentPage: this.props.initialPage, }),
    };
  },

  componentWillReceiveProps(props) {
    if (props.children !== this.props.children) {
      this.updateSceneKeys({ page: this.state.currentPage, children: props.children, });
    }

    if (props.page >= 0 && props.page !== this.state.currentPage) {
      this.goToPage(props.page);
    }
  },

  componentWillUnmount() {
    if (Platform.OS === 'ios') {
      this.state.scrollXIOS.removeAllListeners();
    } else {
      this.state.positionAndroid.removeAllListeners();
      this.state.offsetAndroid.removeAllListeners();
    }
  },

  goToPage(pageNumber) {
    if (Platform.OS === 'ios') {
      const offset = pageNumber * this.state.containerWidth;
      if (this.scrollView) {
        this.scrollView.getNode().scrollTo({x: offset, y: 0, animated: !this.props.scrollWithoutAnimation, });
      }
    } else {
      if (this.scrollView) {
        if (this.props.scrollWithoutAnimation) {
          this.scrollView.getNode().setPageWithoutAnimation(pageNumber);
        } else {
          this.scrollView.getNode().setPage(pageNumber);
        }
      }
    }

    const currentPage = this.state.currentPage;
    this.updateSceneKeys({
      page: pageNumber,
      callback: this._onChangeTab.bind(this, currentPage, pageNumber),
    });
  },

  renderTabBar(props) {
    if (this.props.renderTabBar === false) {
      return null;
    } else if (this.props.renderTabBar) {
      return React.cloneElement(this.props.renderTabBar(props), props);
    } else {
      return <DefaultTabBar {...props} />;
    }
  },

  updateSceneKeys({ page, children = this.props.children, callback = () => {}, }) {
    let newKeys = this.newSceneKeys({ previousKeys: this.state.sceneKeys, currentPage: page, children, });
    this.setState({currentPage: page, sceneKeys: newKeys, }, callback);
  },

  newSceneKeys({ previousKeys = [], currentPage = 0, children = this.props.children, }) {
    let newKeys = [];
    this._children(children).forEach((child, idx) => {
      let key = this._makeSceneKey(child, idx);
      if (this._keyExists(previousKeys, key) ||
        this._shouldRenderSceneKey(idx, currentPage)) {
        newKeys.push(key);
      }
    });
    return newKeys;
  },

  // Animated.add and Animated.divide do not currently support listeners so
  // we have to polyfill it here since a lot of code depends on being able
  // to add a listener to `scrollValue`. See https://github.com/facebook/react-native/pull/12620.
  _polyfillAnimatedValue(animatedValue) {

    const listeners = new Set();
    const addListener = (listener) => {
      listeners.add(listener);
    };

    const removeListener = (listener) => {
      listeners.delete(listener);
    };

    const removeAllListeners = () => {
      listeners.clear();
    };

    animatedValue.addListener = addListener;
    animatedValue.removeListener = removeListener;
    animatedValue.removeAllListeners = removeAllListeners;

    return (value) => listeners.forEach(listener => listener({ value, }));
  },

  _shouldRenderSceneKey(idx, currentPageKey) {
    let numOfSibling = this.props.prerenderingSiblingsNumber;
    return (idx < (currentPageKey + numOfSibling + 1) &&
      idx > (currentPageKey - numOfSibling - 1));
  },

  _keyExists(sceneKeys, key) {
    return sceneKeys.find((sceneKey) => key === sceneKey);
  },

  _makeSceneKey(child, idx) {
    return child.props.tabLabel + '_' + idx;
  },

  renderScrollableContent() {
    if (Platform.OS === 'ios') {
      const scenes = this._composeScenes();
      return <Animated.ScrollView
        horizontal
        pagingEnabled
        automaticallyAdjustContentInsets={false}
        contentOffset={{ x: this.props.initialPage * this.state.containerWidth, }}
        ref={(scrollView) => { this.scrollView = scrollView; }}
        onScroll={Animated.event(
          [{ nativeEvent: { contentOffset: { x: this.state.scrollXIOS, }, }, }, ],
          { useNativeDriver: true, listener: this._onScroll, }
        )}
        onMomentumScrollBegin={this._onMomentumScrollBeginAndEnd}
        onMomentumScrollEnd={this._onMomentumScrollBeginAndEnd}
        scrollEventThrottle={16}
        scrollsToTop={false}
        showsHorizontalScrollIndicator={false}
        scrollEnabled={!this.props.locked}
        directionalLockEnabled
        alwaysBounceVertical={false}
        keyboardDismissMode="on-drag"
        {...this.props.contentProps}
      >
          {scenes}
      </Animated.ScrollView>;
    } else {
      const scenes = this._composeScenes();
      return <AnimatedViewPagerAndroid
        key={this._children().length}
        style={styles.scrollableContentAndroid}
        initialPage={this.props.initialPage}
        onPageSelected={this._updateSelectedPage}
        keyboardDismissMode="on-drag"
        scrollEnabled={!this.props.locked}
        onPageScroll={Animated.event(
          [{
            nativeEvent: {
              position: this.state.positionAndroid,
              offset: this.state.offsetAndroid,
            },
          }, ],
          {
            useNativeDriver: true,
            listener: this._onScroll,
          },
        )}
        ref={(scrollView) => { this.scrollView = scrollView; }}
        {...this.props.contentProps}
      >
        {scenes}
      </AnimatedViewPagerAndroid>;
    }
  },

  _composeScenes() {
    return this._children().map((child, idx) => {
      let key = this._makeSceneKey(child, idx);
      return <SceneComponent
        key={child.key}
        shouldUpdated={this._shouldRenderSceneKey(idx, this.state.currentPage)}
        style={{width: this.state.containerWidth, }}
      >
        {this._keyExists(this.state.sceneKeys, key) ? child : <View tabLabel={child.props.tabLabel}/>}
      </SceneComponent>;
    });
  },

  _onMomentumScrollBeginAndEnd(e) {
    const offsetX = e.nativeEvent.contentOffset.x;
    const page = Math.round(offsetX / this.state.containerWidth);
    if (this.state.currentPage !== page) {
      this._updateSelectedPage(page);
    }
  },

  _updateSelectedPage(nextPage) {
    let localNextPage = nextPage;
    if (typeof localNextPage === 'object') {
      localNextPage = nextPage.nativeEvent.position;
    }

    const currentPage = this.state.currentPage;
    this.updateSceneKeys({
      page: localNextPage,
      callback: this._onChangeTab.bind(this, currentPage, localNextPage),
    });
  },

  _onChangeTab(prevPage, currentPage) {
    this.props.onChangeTab({
      i: currentPage,
      ref: this._children()[currentPage],
      from: prevPage,
    });
  },

  _onScroll(e) {
    if (Platform.OS === 'ios') {
      const offsetX = e.nativeEvent.contentOffset.x;
      if (offsetX === 0 && !this.scrollOnMountCalled) {
        this.scrollOnMountCalled = true;
      } else {
        this.props.onScroll(offsetX / this.state.containerWidth);
      }
    } else {
      const { position, offset, } = e.nativeEvent;
      this.props.onScroll(position + offset);
    }
  },

  _handleLayout(e) {
    const { width, } = e.nativeEvent.layout;

    if (width > 0 && Math.round(width) !== Math.round(this.state.containerWidth)) {
      if (Platform.OS === 'ios') {
        const containerWidthAnimatedValue = new Animated.Value(width);
        // Need to call __makeNative manually to avoid a native animated bug. See
        // https://github.com/facebook/react-native/pull/14435
        containerWidthAnimatedValue.__makeNative();
        scrollValue = Animated.divide(this.state.scrollXIOS, containerWidthAnimatedValue);
        this.setState({ containerWidth: width, scrollValue, });
      } else {
        this.setState({ containerWidth: width, });
      }
      this.requestAnimationFrame(() => {
        this.goToPage(this.state.currentPage);
      });
    }
  },

  _children(children = this.props.children) {
    return React.Children.map(children, (child) => child);
  },

  render() {
    let overlayTabs = (this.props.tabBarPosition === 'overlayTop' || this.props.tabBarPosition === 'overlayBottom');
    let tabBarProps = {
      goToPage: this.goToPage,
      tabs: this._children().map((child) => child.props.tabLabel),
      activeTab: this.state.currentPage,
      scrollValue: this.state.scrollValue,
      containerWidth: this.state.containerWidth,
    };

    if (this.props.tabBarBackgroundColor) {
      tabBarProps.backgroundColor = this.props.tabBarBackgroundColor;
    }
    if (this.props.tabBarActiveTextColor) {
      tabBarProps.activeTextColor = this.props.tabBarActiveTextColor;
    }
    if (this.props.tabBarInactiveTextColor) {
      tabBarProps.inactiveTextColor = this.props.tabBarInactiveTextColor;
    }
    if (this.props.tabBarTextStyle) {
      tabBarProps.textStyle = this.props.tabBarTextStyle;
    }
    if (this.props.tabBarUnderlineStyle) {
      tabBarProps.underlineStyle = this.props.tabBarUnderlineStyle;
    }
    if (overlayTabs) {
      tabBarProps.style = {
        position: 'absolute',
        left: 0,
        right: 0,
        [this.props.tabBarPosition === 'overlayTop' ? 'top' : 'bottom']: 0,
      };
    }

    return <View style={[styles.container, this.props.style, ]} onLayout={this._handleLayout}>
      {this.props.tabBarPosition === 'top' && this.renderTabBar(tabBarProps)}
      {this.renderScrollableContent()}
      {(this.props.tabBarPosition === 'bottom' || overlayTabs) && this.renderTabBar(tabBarProps)}
    </View>;
  },
});

module.exports = ScrollableTabView;

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  scrollableContentAndroid: {
    flex: 1,
  },
});
<commit_msg>Return early.<commit_after>const React = require('react');
const { Component } = React;
const { ViewPropTypes } = ReactNative = require('react-native');
const createReactClass = require('create-react-class');
const PropTypes = require('prop-types');
const {
  Dimensions,
  View,
  Animated,
  ScrollView,
  Platform,
  StyleSheet,
  ViewPagerAndroid,
  InteractionManager,
} = ReactNative;
const TimerMixin = require('react-timer-mixin');

const SceneComponent = require('./SceneComponent');
const DefaultTabBar = require('./DefaultTabBar');
const ScrollableTabBar = require('./ScrollableTabBar');

const AnimatedViewPagerAndroid = Platform.OS === 'android' ?
  Animated.createAnimatedComponent(ViewPagerAndroid) :
  undefined;

const ScrollableTabView = createReactClass({
  mixins: [TimerMixin, ],
  statics: {
    DefaultTabBar,
    ScrollableTabBar,
  },
  scrollOnMountCalled: false,

  propTypes: {
    tabBarPosition: PropTypes.oneOf(['top', 'bottom', 'overlayTop', 'overlayBottom', ]),
    initialPage: PropTypes.number,
    page: PropTypes.number,
    onChangeTab: PropTypes.func,
    onScroll: PropTypes.func,
    renderTabBar: PropTypes.any,
    style: ViewPropTypes.style,
    contentProps: PropTypes.object,
    scrollWithoutAnimation: PropTypes.bool,
    locked: PropTypes.bool,
    prerenderingSiblingsNumber: PropTypes.number,
  },

  getDefaultProps() {
    return {
      tabBarPosition: 'top',
      initialPage: 0,
      page: -1,
      onChangeTab: () => {},
      onScroll: () => {},
      contentProps: {},
      scrollWithoutAnimation: false,
      locked: false,
      prerenderingSiblingsNumber: 0,
    };
  },

  getInitialState() {
    const containerWidth = Dimensions.get('window').width;
    let scrollValue;
    let scrollXIOS;
    let positionAndroid;
    let offsetAndroid;

    if (Platform.OS === 'ios') {
      scrollXIOS = new Animated.Value(this.props.initialPage * containerWidth);
      const containerWidthAnimatedValue = new Animated.Value(containerWidth);
      // Need to call __makeNative manually to avoid a native animated bug. See
      // https://github.com/facebook/react-native/pull/14435
      containerWidthAnimatedValue.__makeNative();
      scrollValue = Animated.divide(scrollXIOS, containerWidthAnimatedValue);

      const callListeners = this._polyfillAnimatedValue(scrollValue);
      scrollXIOS.addListener(
        ({ value, }) => callListeners(value / this.state.containerWidth)
      );
    } else {
      positionAndroid = new Animated.Value(this.props.initialPage);
      offsetAndroid = new Animated.Value(0);
      scrollValue = Animated.add(positionAndroid, offsetAndroid);

      const callListeners = this._polyfillAnimatedValue(scrollValue);
      let positionAndroidValue = this.props.initialPage;
      let offsetAndroidValue = 0;
      positionAndroid.addListener(({ value, }) => {
        positionAndroidValue = value;
        callListeners(positionAndroidValue + offsetAndroidValue);
      });
      offsetAndroid.addListener(({ value, }) => {
        offsetAndroidValue = value;
        callListeners(positionAndroidValue + offsetAndroidValue);
      });
    }

    return {
      currentPage: this.props.initialPage,
      scrollValue,
      scrollXIOS,
      positionAndroid,
      offsetAndroid,
      containerWidth,
      sceneKeys: this.newSceneKeys({ currentPage: this.props.initialPage, }),
    };
  },

  componentWillReceiveProps(props) {
    if (props.children !== this.props.children) {
      this.updateSceneKeys({ page: this.state.currentPage, children: props.children, });
    }

    if (props.page >= 0 && props.page !== this.state.currentPage) {
      this.goToPage(props.page);
    }
  },

  componentWillUnmount() {
    if (Platform.OS === 'ios') {
      this.state.scrollXIOS.removeAllListeners();
    } else {
      this.state.positionAndroid.removeAllListeners();
      this.state.offsetAndroid.removeAllListeners();
    }
  },

  goToPage(pageNumber) {
    if (Platform.OS === 'ios') {
      const offset = pageNumber * this.state.containerWidth;
      if (this.scrollView) {
        this.scrollView.getNode().scrollTo({x: offset, y: 0, animated: !this.props.scrollWithoutAnimation, });
      }
    } else {
      if (this.scrollView) {
        if (this.props.scrollWithoutAnimation) {
          this.scrollView.getNode().setPageWithoutAnimation(pageNumber);
        } else {
          this.scrollView.getNode().setPage(pageNumber);
        }
      }
    }

    const currentPage = this.state.currentPage;
    this.updateSceneKeys({
      page: pageNumber,
      callback: this._onChangeTab.bind(this, currentPage, pageNumber),
    });
  },

  renderTabBar(props) {
    if (this.props.renderTabBar === false) {
      return null;
    } else if (this.props.renderTabBar) {
      return React.cloneElement(this.props.renderTabBar(props), props);
    } else {
      return <DefaultTabBar {...props} />;
    }
  },

  updateSceneKeys({ page, children = this.props.children, callback = () => {}, }) {
    let newKeys = this.newSceneKeys({ previousKeys: this.state.sceneKeys, currentPage: page, children, });
    this.setState({currentPage: page, sceneKeys: newKeys, }, callback);
  },

  newSceneKeys({ previousKeys = [], currentPage = 0, children = this.props.children, }) {
    let newKeys = [];
    this._children(children).forEach((child, idx) => {
      let key = this._makeSceneKey(child, idx);
      if (this._keyExists(previousKeys, key) ||
        this._shouldRenderSceneKey(idx, currentPage)) {
        newKeys.push(key);
      }
    });
    return newKeys;
  },

  // Animated.add and Animated.divide do not currently support listeners so
  // we have to polyfill it here since a lot of code depends on being able
  // to add a listener to `scrollValue`. See https://github.com/facebook/react-native/pull/12620.
  _polyfillAnimatedValue(animatedValue) {

    const listeners = new Set();
    const addListener = (listener) => {
      listeners.add(listener);
    };

    const removeListener = (listener) => {
      listeners.delete(listener);
    };

    const removeAllListeners = () => {
      listeners.clear();
    };

    animatedValue.addListener = addListener;
    animatedValue.removeListener = removeListener;
    animatedValue.removeAllListeners = removeAllListeners;

    return (value) => listeners.forEach(listener => listener({ value, }));
  },

  _shouldRenderSceneKey(idx, currentPageKey) {
    let numOfSibling = this.props.prerenderingSiblingsNumber;
    return (idx < (currentPageKey + numOfSibling + 1) &&
      idx > (currentPageKey - numOfSibling - 1));
  },

  _keyExists(sceneKeys, key) {
    return sceneKeys.find((sceneKey) => key === sceneKey);
  },

  _makeSceneKey(child, idx) {
    return child.props.tabLabel + '_' + idx;
  },

  renderScrollableContent() {
    if (Platform.OS === 'ios') {
      const scenes = this._composeScenes();
      return <Animated.ScrollView
        horizontal
        pagingEnabled
        automaticallyAdjustContentInsets={false}
        contentOffset={{ x: this.props.initialPage * this.state.containerWidth, }}
        ref={(scrollView) => { this.scrollView = scrollView; }}
        onScroll={Animated.event(
          [{ nativeEvent: { contentOffset: { x: this.state.scrollXIOS, }, }, }, ],
          { useNativeDriver: true, listener: this._onScroll, }
        )}
        onMomentumScrollBegin={this._onMomentumScrollBeginAndEnd}
        onMomentumScrollEnd={this._onMomentumScrollBeginAndEnd}
        scrollEventThrottle={16}
        scrollsToTop={false}
        showsHorizontalScrollIndicator={false}
        scrollEnabled={!this.props.locked}
        directionalLockEnabled
        alwaysBounceVertical={false}
        keyboardDismissMode="on-drag"
        {...this.props.contentProps}
      >
          {scenes}
      </Animated.ScrollView>;
    } else {
      const scenes = this._composeScenes();
      return <AnimatedViewPagerAndroid
        key={this._children().length}
        style={styles.scrollableContentAndroid}
        initialPage={this.props.initialPage}
        onPageSelected={this._updateSelectedPage}
        keyboardDismissMode="on-drag"
        scrollEnabled={!this.props.locked}
        onPageScroll={Animated.event(
          [{
            nativeEvent: {
              position: this.state.positionAndroid,
              offset: this.state.offsetAndroid,
            },
          }, ],
          {
            useNativeDriver: true,
            listener: this._onScroll,
          },
        )}
        ref={(scrollView) => { this.scrollView = scrollView; }}
        {...this.props.contentProps}
      >
        {scenes}
      </AnimatedViewPagerAndroid>;
    }
  },

  _composeScenes() {
    return this._children().map((child, idx) => {
      let key = this._makeSceneKey(child, idx);
      return <SceneComponent
        key={child.key}
        shouldUpdated={this._shouldRenderSceneKey(idx, this.state.currentPage)}
        style={{width: this.state.containerWidth, }}
      >
        {this._keyExists(this.state.sceneKeys, key) ? child : <View tabLabel={child.props.tabLabel}/>}
      </SceneComponent>;
    });
  },

  _onMomentumScrollBeginAndEnd(e) {
    const offsetX = e.nativeEvent.contentOffset.x;
    const page = Math.round(offsetX / this.state.containerWidth);
    if (this.state.currentPage !== page) {
      this._updateSelectedPage(page);
    }
  },

  _updateSelectedPage(nextPage) {
    let localNextPage = nextPage;
    if (typeof localNextPage === 'object') {
      localNextPage = nextPage.nativeEvent.position;
    }

    const currentPage = this.state.currentPage;
    this.updateSceneKeys({
      page: localNextPage,
      callback: this._onChangeTab.bind(this, currentPage, localNextPage),
    });
  },

  _onChangeTab(prevPage, currentPage) {
    this.props.onChangeTab({
      i: currentPage,
      ref: this._children()[currentPage],
      from: prevPage,
    });
  },

  _onScroll(e) {
    if (Platform.OS === 'ios') {
      const offsetX = e.nativeEvent.contentOffset.x;
      if (offsetX === 0 && !this.scrollOnMountCalled) {
        this.scrollOnMountCalled = true;
      } else {
        this.props.onScroll(offsetX / this.state.containerWidth);
      }
    } else {
      const { position, offset, } = e.nativeEvent;
      this.props.onScroll(position + offset);
    }
  },

  _handleLayout(e) {
    const { width, } = e.nativeEvent.layout;

    if (!width || width <= 0 || Math.round(width) === Math.round(this.state.containerWidth)) {
      return;
    }

    if (Platform.OS === 'ios') {
      const containerWidthAnimatedValue = new Animated.Value(width);
      // Need to call __makeNative manually to avoid a native animated bug. See
      // https://github.com/facebook/react-native/pull/14435
      containerWidthAnimatedValue.__makeNative();
      scrollValue = Animated.divide(this.state.scrollXIOS, containerWidthAnimatedValue);
      this.setState({ containerWidth: width, scrollValue, });
    } else {
      this.setState({ containerWidth: width, });
    }
    this.requestAnimationFrame(() => {
      this.goToPage(this.state.currentPage);
    });
  },

  _children(children = this.props.children) {
    return React.Children.map(children, (child) => child);
  },

  render() {
    let overlayTabs = (this.props.tabBarPosition === 'overlayTop' || this.props.tabBarPosition === 'overlayBottom');
    let tabBarProps = {
      goToPage: this.goToPage,
      tabs: this._children().map((child) => child.props.tabLabel),
      activeTab: this.state.currentPage,
      scrollValue: this.state.scrollValue,
      containerWidth: this.state.containerWidth,
    };

    if (this.props.tabBarBackgroundColor) {
      tabBarProps.backgroundColor = this.props.tabBarBackgroundColor;
    }
    if (this.props.tabBarActiveTextColor) {
      tabBarProps.activeTextColor = this.props.tabBarActiveTextColor;
    }
    if (this.props.tabBarInactiveTextColor) {
      tabBarProps.inactiveTextColor = this.props.tabBarInactiveTextColor;
    }
    if (this.props.tabBarTextStyle) {
      tabBarProps.textStyle = this.props.tabBarTextStyle;
    }
    if (this.props.tabBarUnderlineStyle) {
      tabBarProps.underlineStyle = this.props.tabBarUnderlineStyle;
    }
    if (overlayTabs) {
      tabBarProps.style = {
        position: 'absolute',
        left: 0,
        right: 0,
        [this.props.tabBarPosition === 'overlayTop' ? 'top' : 'bottom']: 0,
      };
    }

    return <View style={[styles.container, this.props.style, ]} onLayout={this._handleLayout}>
      {this.props.tabBarPosition === 'top' && this.renderTabBar(tabBarProps)}
      {this.renderScrollableContent()}
      {(this.props.tabBarPosition === 'bottom' || overlayTabs) && this.renderTabBar(tabBarProps)}
    </View>;
  },
});

module.exports = ScrollableTabView;

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  scrollableContentAndroid: {
    flex: 1,
  },
});
<|endoftext|>


<commit_before>import app from 'app';
import BrowserWindow from 'browser-window';

import {createLogFile} from './src/init';

let mainWindow = null;

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  if (process.platform != 'darwin') {
    app.quit();
  }
});

app.on('ready', () => {
  //TODO: verify this is needed, hs log wather module may well do this already
  createLogFile();

  mainWindow = new BrowserWindow({
    height: 600,
    width: 800
  });

  mainWindow.loadURL('file://' + __dirname + '/app/index.html');

  // Emitted when the window is closed.
  mainWindow.on('closed', () => {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
  });
});
<commit_msg>Wire up the log watcher<commit_after>import app from 'app';
import BrowserWindow from 'browser-window';
import LogWatcher from 'hearthstone-log-watcher';

import {dataLogger} from './src/log-watcher';

let mainWindow = null;

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  if (process.platform != 'darwin') {
    app.quit();
  }
});

app.on('ready', () => {
  let watcher = new LogWatcher();
  let logWatcher = dataLogger(watcher);
  logWatcher.start();
  mainWindow = new BrowserWindow({
    height: 600,
    width: 800
  });

  mainWindow.loadURL('file://' + __dirname + '/app/index.html');

  // Emitted when the window is closed.
  mainWindow.on('closed', () => {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
  });
});
<|endoftext|>


<commit_before>// Dependencies
var Overlap = require("overlap")
  , Box = require("cli-box")
  , Ul = require("ul")
  ;

/**
 * LeTable
 * Creates a new instance of `LeTable`.
 *
 * @name exports
 * @function
 * @param {Object} options An object containing the table configuration:
 *  - `cell`: object containing
 *    - `hAlign` (default: `"center"`): One of the following values: `"left"`, `"center"` and `"right"`
 *    - `vAlign` (default: `"middle"`): One of the following values: `"top"`, `"middle"` and `"bottom"`
 *    - `autoEOL` (default: `true`): if true, the lines are wrapped inside of the cell
 *    - `stretch` (default: `true`): if true, the size of the box will not be fixed
 *  - `marks`: object containing the mark characters (see example)
 * @return {LeTable} The `LeTable` instance.
 */
function LeTable(options) {
    var self = this;
    self.data = [];

    options = Ul.merge(options, {
        mark: LeTable.defaults.marks
      , cell: LeTable.defaults.cell
    });

    self.cell_ops = options.cell;
    self.marks = options.mark;
}

/**
 * addRow
 * Adds a new row in table.
 *
 * @name addRow
 * @function
 * @param {Array} columns Row data (as array)
 * @param {Object} ops Options for cell content
 * @return {LeTable} The `LeTable` instance.
 */
LeTable.prototype.addRow = function (columns, ops) {

    var self = this
      , computedColumns = []
      , cColumn = null
      , comCol = null
      , cellOps = self.cell_ops
      ;

    columns.forEach(function (cColumn) {
        comCol = {
            text: (cColumn.text || cColumn).toString()
          , data: {
                stretch: cellOps.stretch
              , autoEOL: cellOps.autoEOL
              , vAlign:  cellOps.vAlign
              , hAlign:  cellOps.hAlign
            }
        };

        // Override with ops
        comCol.data = Ul.merge(ops, cColumn.data, comCol.data);
        computedColumns.push(comCol);
    });

    self.data.push(computedColumns);
    return self;
};

/**
 * toString
 * Stringifies the table.
 *
 * @name toString
 * @function
 * @return {String} Stringified table
 */
LeTable.prototype.toString = function () {

    var self = this
      , output = ""
      , offset = {
            x: 0
          , y: 0
        }
      , cellSizes = []
      , cRow = null
      , cColumn =  null
      , cell = null
      , cCell = null
      , splits = null
      , wMax = null
      , hMax = null
      , mrks = null
      , marks = self.marks
      ;

    function createCell(cColumn, wMax, hMax, marks) {
        return Box({
            w: cColumn.data.w || cColumn.data.width || wMax
          , h: cColumn.data.h || cColumn.data.height || hMax
          , marks: marks
        }, {
            text: cColumn.text
          , stretch: cColumn.data.stretch
          , autoEOL: cColumn.data.autoEOL
          , vAlign: cColumn.data.vAlign
          , hAlign: cColumn.data.hAlign
        }).toString();
    }

    // Compute cell sizes internally
    self.data.forEach(function (cRow, i) {
        cellSizes.push([]);
        cRow.forEach(function (cColumn) {
            cell = createCell(cColumn, 1, 1, {});
            splits = cell.split("\n");
            cCell = {
                w: splits[0].trim().length
              , h: splits.length - 2
            };
            cellSizes[i].push(cCell);
        });
    });

    // Each row
    self.data.forEach(function (cRow, i) {

        // Compute row
        wMax = -1;
        hMax = -1;

        cellSizes[i].forEach(function (cCell) {
            if (cCell.h > hMax) { hMax = cCell.h; }
        });

        // Each column from current row
        cRow.forEach(function (cColumn, ii) {

            // Compute current column
            cellSizes.forEach(function (cCell, iii) {
                cCell = cellSizes[iii][ii];
                if (cCell.w > wMax) { wMax = cCell.w; }
            });

            mrks = {
                nw: ((!i && !ii)
                    ? marks.nw : (!i && ii < cRow.length)
                    ? marks.mt : (!ii && i < self.data.length)
                    ? marks.ml : marks.mm)
              , n:  marks.n
              , ne: (!i && ii === cRow.length - 1)
                    ? marks.ne : marks.mr
              , e:  marks.e
              , se: marks.se
              , s:  marks.s
              , sw: (i === self.data.length - 1 && !ii)
                    ? marks.sw : marks.mb
              , w:  marks.w
              , b: " "
            };

            // Add stringified cell to output
            output = Overlap({
                who: output
              , with: createCell(cColumn, wMax, hMax, mrks)
              , where: offset
            });

            offset.x += wMax + mrks.w.length - 2;
        });

        offset.x = 0;
        offset.y += hMax + 1;
    });

    return output.trim();
};

// Defaults
LeTable.defaults = {
    marks: {
        nw: "+"
      , n:  "-"
      , ne: "+"
      , e:  "|"
      , se: "+"
      , s:  "-"
      , sw: "+"
      , w:  "|"
      , b: " "
      , mt: "+"
      , ml: "+"
      , mr: "+"
      , mb: "+"
      , mm: "+"
    }
  , cell: {
        vAlign: "top"
      , hAlign: "left"
      , autoEOL: true
      , stretch: true
    }
};

module.exports = LeTable;
<commit_msg>JSDoc fixes and fixed the options merging.<commit_after>// Dependencies
var Overlap = require("overlap")
  , Box = require("cli-box")
  , Ul = require("ul")
  ;

/**
 * LeTable
 * Creates a new instance of `LeTable`.
 *
 * @name LeTable
 * @function
 * @param {Object} options An object containing the table configuration:
 *  - `cell`: object containing
 *    - `hAlign` (default: `"center"`): One of the following values: `"left"`, `"center"` and `"right"`
 *    - `vAlign` (default: `"middle"`): One of the following values: `"top"`, `"middle"` and `"bottom"`
 *    - `autoEOL` (default: `true`): if true, the lines are wrapped inside of the cell
 *    - `stretch` (default: `true`): if true, the size of the box will not be fixed
 *  - `marks`: object containing the mark characters (see example)
 * @return {LeTable} The `LeTable` instance.
 */
function LeTable(options) {
    var self = this;
    self.data = [];

    options = Ul.merge(options, {
        mark: LeTable.defaults.marks
      , cell: LeTable.defaults.cell
    });

    self.cell_ops = options.cell;
    self.marks = options.mark;
}

/**
 * addRow
 * Adds a new row in table.
 *
 * @name addRow
 * @function
 * @param {Array} columns Row data (as array)
 * @param {Object} ops Options for cell content
 * @return {LeTable} The `LeTable` instance.
 */
LeTable.prototype.addRow = function (columns, ops) {

    var self = this
      , computedColumns = []
      , cColumn = null
      , comCol = null
      , cellOps = self.cell_ops
      ;

    columns.forEach(function (cColumn) {
        comCol = {
            text: (cColumn.text || cColumn).toString()
          , data: {
                stretch: cellOps.stretch
              , autoEOL: cellOps.autoEOL
              , vAlign:  cellOps.vAlign
              , hAlign:  cellOps.hAlign
            }
        };

        // Override with ops
        comCol.data = Ul.merge(cColumn.data, ops, comCol.data);
        computedColumns.push(comCol);
    });

    self.data.push(computedColumns);
    return self;
};

/**
 * toString
 * Stringifies the table.
 *
 * @name toString
 * @function
 * @return {String} The stringified table
 */
LeTable.prototype.toString = function () {

    var self = this
      , output = ""
      , offset = {
            x: 0
          , y: 0
        }
      , cellSizes = []
      , cRow = null
      , cColumn =  null
      , cell = null
      , cCell = null
      , splits = null
      , wMax = null
      , hMax = null
      , mrks = null
      , marks = self.marks
      ;

    function createCell(cColumn, wMax, hMax, marks) {
        return Box({
            w: cColumn.data.w || cColumn.data.width || wMax
          , h: cColumn.data.h || cColumn.data.height || hMax
          , marks: marks
        }, {
            text: cColumn.text
          , stretch: cColumn.data.stretch
          , autoEOL: cColumn.data.autoEOL
          , vAlign: cColumn.data.vAlign
          , hAlign: cColumn.data.hAlign
        }).toString();
    }

    // Compute cell sizes internally
    self.data.forEach(function (cRow, i) {
        cellSizes.push([]);
        cRow.forEach(function (cColumn) {
            cell = createCell(cColumn, 1, 1, {});
            splits = cell.split("\n");
            cCell = {
                w: splits[0].trim().length
              , h: splits.length - 2
            };
            cellSizes[i].push(cCell);
        });
    });

    // Each row
    self.data.forEach(function (cRow, i) {

        // Compute row
        wMax = -1;
        hMax = -1;

        cellSizes[i].forEach(function (cCell) {
            if (cCell.h > hMax) { hMax = cCell.h; }
        });

        // Each column from current row
        cRow.forEach(function (cColumn, ii) {

            // Compute current column
            cellSizes.forEach(function (cCell, iii) {
                cCell = cellSizes[iii][ii];
                if (cCell.w > wMax) { wMax = cCell.w; }
            });

            mrks = {
                nw: ((!i && !ii)
                    ? marks.nw : (!i && ii < cRow.length)
                    ? marks.mt : (!ii && i < self.data.length)
                    ? marks.ml : marks.mm)
              , n:  marks.n
              , ne: (!i && ii === cRow.length - 1)
                    ? marks.ne : marks.mr
              , e:  marks.e
              , se: marks.se
              , s:  marks.s
              , sw: (i === self.data.length - 1 && !ii)
                    ? marks.sw : marks.mb
              , w:  marks.w
              , b: " "
            };

            // Add stringified cell to output
            output = Overlap({
                who: output
              , with: createCell(cColumn, wMax, hMax, mrks)
              , where: offset
            });

            offset.x += wMax + mrks.w.length - 2;
        });

        offset.x = 0;
        offset.y += hMax + 1;
    });

    return output.trim();
};

// Defaults
LeTable.defaults = {
    marks: {
        nw: "+"
      , n:  "-"
      , ne: "+"
      , e:  "|"
      , se: "+"
      , s:  "-"
      , sw: "+"
      , w:  "|"
      , b: " "
      , mt: "+"
      , ml: "+"
      , mr: "+"
      , mb: "+"
      , mm: "+"
    }
  , cell: {
        vAlign: "top"
      , hAlign: "left"
      , autoEOL: true
      , stretch: true
    }
};

module.exports = LeTable;
<|endoftext|>


<commit_before>'use strict';

var $ = require('jquery');
var forOwn = require('lodash/object/forOwn');
var isArray = require('lodash/lang/isArray');
var isPlainObject = require('lodash/lang/isPlainObject');
var extend = require('lodash/object/extend');
var transform = require('lodash/object/transform');

module.exports = {
  Modules: {},
  Helpers: {},
  Events: $({}),

  init: function() {
    var self = this;
    forOwn(this.Modules, function(module) {
      if (typeof module.init === 'function') {
        module.base = self;
        module.init();
      }
    });
    // trigger initial render event
    this.Events.trigger('render');
  },

  // safe logging
  log: function() {
    if (window && window.console) {
      window.console.log.apply(console, arguments);
    }
  },

  dir: function() {
    if (window && window.console) {
      window.console.dir.apply(console, arguments);
    }
  },

  use: function(modules) {
    if (isArray(modules)) {
      transform(modules, extend, this.Modules);
    } else if(isPlainObject(modules)) {
      extend(this.Modules, modules);
    } else {
      throw('Pass either single module or an array of modules.\ne.g. `.use(require(\'./modules/some-module\')`');
    }
    return this;
  }
};
<commit_msg>Remove functions that rely on the console object Mainly because console.log isn't a standard JS feature and is implemented differently across browsers, causing problems when trying to alias it.<commit_after>'use strict';

var $ = require('jquery');
var forOwn = require('lodash/object/forOwn');
var isArray = require('lodash/lang/isArray');
var isPlainObject = require('lodash/lang/isPlainObject');
var extend = require('lodash/object/extend');
var transform = require('lodash/object/transform');

module.exports = {
  Modules: {},
  Helpers: {},
  Events: $({}),

  init: function() {
    var self = this;
    forOwn(this.Modules, function(module) {
      if (typeof module.init === 'function') {
        module.base = self;
        module.init();
      }
    });
    // trigger initial render event
    this.Events.trigger('render');
  },

  use: function(modules) {
    if (isArray(modules)) {
      transform(modules, extend, this.Modules);
    } else if(isPlainObject(modules)) {
      extend(this.Modules, modules);
    } else {
      throw('Pass either single module or an array of modules.\ne.g. `.use(require(\'./modules/some-module\')`');
    }
    return this;
  }
};
<|endoftext|>


<commit_before>var http = require("http");
var express = require("express");
var bodyParser = require("body-parser");

var port = process.env.PORT || 1337;
var app = express();

app.use(bodyParser.urlencoded({
	extended: true
}));

app.get("/:id", function(request, response) {
	response.status(200);
	response.set("Content-Type", "text/plain");
	response.send("GET parameter: " + request.params.id);
});

app.post("/", function(request, response)) {
	response.status(200);
	response.set("Content-Type", "text/plain");
	response.send("POST parameters: " + JSON.stringify(request.params));
}

var server = app.listen(port, function () {
  var host = server.address().address;
  console.log("Server listening at http://%s:%s", host, port);
});<commit_msg>syntax error in index.js<commit_after>var http = require("http");
var express = require("express");
var bodyParser = require("body-parser");

var port = process.env.PORT || 1337;
var app = express();

app.use(bodyParser.urlencoded({
	extended: true
}));

app.get("/:id", function(request, response) {
	response.status(200);
	response.set("Content-Type", "text/plain");
	response.send("GET parameter: " + request.params.id);
});

app.post("/", function(request, response) {
	response.status(200);
	response.set("Content-Type", "text/plain");
	response.send("POST parameters: " + JSON.stringify(request.params));
}

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


<commit_before>/*
 * @TODO Makes the callback mandatory or automatically turns synchronous if not present
 *
 */

var _ = require('underscore'),
    findit = require('findit');

/*
 * Default function in case no callback is provided
 *
 */
function noop () {  }

/*
 * Throws if no callback is available or cb is  noop
 *
 */
function _ThrowOrCallback (err, cb) {
  if (cb && cb !== noop) {
    cb(err);
  } else {
    throw err;
  }
}

/*
 * Adds properties to `this`, where `this` is an object literal
 * representing an entry in the filesystem
 *
 */
function _addProperties(file, stat) {

  var type;
  if (stat.isFile())          type = 'file';
  if (stat.isSymbolicLink())  type = 'symlink';
  if (stat.isDirectory()) {
    type = 'directory';
    this.children = [];
  }

  var name = file.split('/').filter(function (e) {
    return e.length;
  }).pop();

  var size = stat.size;

  var fullPath = (require('path')).resolve(file);

  this.name = name;
  this.relativePath = file;
  this.fullPath = fullPath;
  this.size = size;
  this.type = type;
}

module.exports = function () {
  "use strict";

  var _entryProps = ['name', 'relativePath', 'fullPath', 'size', 'type'];

  /*
   * The returned object
   */
  var obj = {
    include: _include,
    describe: _describe,
    traverse: _traverse
  };

  function _include () {
    return obj;
  }

  function _describe () {
    return obj;
  }

  function _traverse (rootPath, cb) {
    if (!cb) {
      cb = noop;
    }
    if (cb && !_.isFunction(cb)) {
      throw new TypeError('The callback must be a function.');
    }
    if (!_.isString(rootPath)) {
      return _ThrowOrCallback(new Error('path must be a String'), cb);
    }

    var finder = findit.find(rootPath);
    var _hasErrors = false;
    var data = {};

    finder.on('path', function (file, stat) {
      var splitPath = file.split('/').filter(function (e) {
        return e.length;
      });
      var relativePathToSearchRoot = file.replace(rootPath, '').replace('/', ''); //a '/' could confuse with the FS root

      var _data = data;
      for (var i = 0; i < relativePathToSearchRoot.length; i++) {
        if (!_data.hasOwnProperty(relativePathToSearchRoot[i])) {
          // @TODO The following sucks monkey nalls
          _data.children = _data.children || [];
          _data.children.push[relativePathToSearchRoot[i]] = {};
        }
        _data = _data[relativePathToSearchRoot[i]];
      }
      _addProperties.call(_data, file, stat);
    });

    finder.on('end', function () {
      if (_hasErrors) {
        return _ThrowOrCallback(_hasErrors, cb);
      } else {
        cb && cb(null, data);
      }
    });

    finder.on('error', function (err) {
      _hasErrors = err;
    });
  }

  return obj;
};
<commit_msg>Fixes typo of an awesome comment<commit_after>/*
 * @TODO Makes the callback mandatory or automatically turns synchronous if not present
 *
 */

var _ = require('underscore'),
    findit = require('findit');

/*
 * Default function in case no callback is provided
 *
 */
function noop () {  }

/*
 * Throws if no callback is available or cb is  noop
 *
 */
function _ThrowOrCallback (err, cb) {
  if (cb && cb !== noop) {
    cb(err);
  } else {
    throw err;
  }
}

/*
 * Adds properties to `this`, where `this` is an object literal
 * representing an entry in the filesystem
 *
 */
function _addProperties(file, stat) {

  var type;
  if (stat.isFile())          type = 'file';
  if (stat.isSymbolicLink())  type = 'symlink';
  if (stat.isDirectory()) {
    type = 'directory';
    this.children = [];
  }

  var name = file.split('/').filter(function (e) {
    return e.length;
  }).pop();

  var size = stat.size;

  var fullPath = (require('path')).resolve(file);

  this.name = name;
  this.relativePath = file;
  this.fullPath = fullPath;
  this.size = size;
  this.type = type;
}

module.exports = function () {
  "use strict";

  var _entryProps = ['name', 'relativePath', 'fullPath', 'size', 'type'];

  /*
   * The returned object
   */
  var obj = {
    include: _include,
    describe: _describe,
    traverse: _traverse
  };

  function _include () {
    return obj;
  }

  function _describe () {
    return obj;
  }

  function _traverse (rootPath, cb) {
    if (!cb) {
      cb = noop;
    }
    if (cb && !_.isFunction(cb)) {
      throw new TypeError('The callback must be a function.');
    }
    if (!_.isString(rootPath)) {
      return _ThrowOrCallback(new Error('path must be a String'), cb);
    }

    var finder = findit.find(rootPath);
    var _hasErrors = false;
    var data = {};

    finder.on('path', function (file, stat) {
      var splitPath = file.split('/').filter(function (e) {
        return e.length;
      });
      var relativePathToSearchRoot = file.replace(rootPath, '').replace('/', ''); //a '/' could confuse with the FS root

      var _data = data;
      for (var i = 0; i < relativePathToSearchRoot.length; i++) {
        if (!_data.hasOwnProperty(relativePathToSearchRoot[i])) {
          // @TODO The following sucks monkey balls
          _data.children = _data.children || [];
          _data.children.push[relativePathToSearchRoot[i]] = {};
        }
        _data = _data[relativePathToSearchRoot[i]];
      }
      _addProperties.call(_data, file, stat);
    });

    finder.on('end', function () {
      if (_hasErrors) {
        return _ThrowOrCallback(_hasErrors, cb);
      } else {
        cb && cb(null, data);
      }
    });

    finder.on('error', function (err) {
      _hasErrors = err;
    });
  }

  return obj;
};
<|endoftext|>


<commit_before>exports.quote = function (xs) {
    return xs.map(function (s) {
        if (s && typeof s === 'object') {
            return s.op.replace(/(.)/g, '\\$1');
        }
        else if (/["\s]/.test(s) && !/'/.test(s)) {
            return "'" + s.replace(/(['\\])/g, '\\$1') + "'";
        }
        else if (/["'\s]/.test(s)) {
            return '"' + s.replace(/(["\\$`(){}!#&*|])/g, '\\$1') + '"';
        }
        else {
            return s.replace(/([\\$`(){}!#&*|])/g, '\\$1');
        }
    }).join(' ');
};

var CONTROL = '(?:' + [
    '\\|\\|', '\\&\\&', ';;', '\\|\\&', '[&;()|<>]'
].join('|') + ')';
var META = '|&;()<> \\t';

exports.parse = function parse (s, env) {
    var chunker = new RegExp([
        '([\'"])((\\\\\\1|[^\\1])*?)\\1', // quotes
        '(\\\\[' + META + ']|[^\\s' + META + '])+', // barewords
        '(' + CONTROL + ')' // control chars
    ].join('|'), 'g');
    var match = s.match(chunker);
    if (!match) return [];
    if (!env) env = {};
    return [].concat.apply([], match.map(function (s) {
        if (/^'/.test(s)) {
            return s
                .replace(/^'|'$/g, '')
                .replace(/\\(["'\\$`(){}!#&*|])/g, '$1')
            ;
        }
        else if (/^"/.test(s) && typeof env === 'function') {
            var res = [];
            s = s.replace(/^"|"$/g, '');

            var begin = 0, bracket = false;
            for (var i = 0; i < s.length; i++) {
                if (s.charAt(i) !== '$' || s.charAt(i-1) === '\\') continue;
                if (s.charAt(i+1) === '{') {
                    i ++;
                    bracket = true;
                }
                if (/^[*@#?$!0_-]$/.test(s.charAt(i+1))
                && (!bracket || (bracket && s.charAt(i+2) === '}'))) {
                    res.push(s.slice(begin, i));
                    var r = env(s.charAt(i+1));
                    if (typeof r === 'object') res.push(r);
                    else res[res.length-1] += r;
                    i ++;
                    if (bracket) i++;
                    begin = i + 1;
                    continue;
                }
                for (var j=i+1; j < s.length && /\w/.test(s.charAt(j)); j++);
                if (j-(i+1) > 1) {
                    res.push(s.slice(begin, i));
                    var r = env(s.slice(i+1, j));
                    if (typeof r === 'object') res.push(r);
                    else res[res.length-1] += r;
                    begin = j;
                }
            }
            res.push(s.slice(begin));
            return res.map(function (c) {
                if (typeof c === 'object') return c;
                return c.replace(/\\([ "'\\$`(){}!#&*|])/g, '$1');
            });
        }
        else if (/^"/.test(s)) {
            return s.replace(/^"|"$/g, '')
                .replace(/(^|[^\\])\$(\w+|[*@#?$!0_-])/g, getVar)
                .replace(/(^|[^\\])\${(\w+|[*@#?$!0_-])}/g, getVar)
                .replace(/\\([ "'\\$`(){}!#&*|])/g, '$1')
            ;
        }
        else if (RegExp('^' + CONTROL + '$').test(s)) {
            return { op: s };
        }
        else return s.replace(
            /(['"])((\\\1|[^\1])*?)\1|[^'"]+/g,
            function (s, q) {
                if (/^['"]/.test(s)) return parse(s, env);
                return parse('"' + s + '"', env);
            }
        );
    }));

    function getVar (_, pre, key) {
        return pre + String(env[key] || '');
    }
};
<commit_msg>hacky tokenizer is much simpler<commit_after>exports.quote = function (xs) {
    return xs.map(function (s) {
        if (s && typeof s === 'object') {
            return s.op.replace(/(.)/g, '\\$1');
        }
        else if (/["\s]/.test(s) && !/'/.test(s)) {
            return "'" + s.replace(/(['\\])/g, '\\$1') + "'";
        }
        else if (/["'\s]/.test(s)) {
            return '"' + s.replace(/(["\\$`(){}!#&*|])/g, '\\$1') + '"';
        }
        else {
            return s.replace(/([\\$`(){}!#&*|])/g, '\\$1');
        }
    }).join(' ');
};

var CONTROL = '(?:' + [
    '\\|\\|', '\\&\\&', ';;', '\\|\\&', '[&;()|<>]'
].join('|') + ')';
var META = '|&;()<> \\t';

var TOKEN = '';
for (var i = 0; i < 4; i++) {
    TOKEN += (Math.pow(16,8)*Math.random()).toString(16);
}

exports.parse = function (s, env) {
    var mapped = parse(s, env);
    if (typeof env !== 'function') return mapped;
    return mapped.reduce(function (acc, s) {
        var xs = s.split(RegExp('(' + TOKEN + '.*?' + TOKEN + ')', 'g'));
        if (xs.length === 1) return acc.concat(xs[0]);
        return acc.concat(xs.filter(Boolean).map(function (x) {
            if (RegExp('^' + TOKEN).test(x)) {
                return JSON.parse(x.split(TOKEN)[1]);
            }
            else return x;
        }));
    }, []);
};

function parse (s, env) {
    var chunker = new RegExp([
        '([\'"])((\\\\\\1|[^\\1])*?)\\1', // quotes
        '(\\\\[' + META + ']|[^\\s' + META + '])+', // barewords
        '(' + CONTROL + ')' // control chars
    ].join('|'), 'g');
    var match = s.match(chunker);
    if (!match) return [];
    if (!env) env = {};
    return match.map(function (s) {
        if (/^'/.test(s)) {
            return s
                .replace(/^'|'$/g, '')
                .replace(/\\(["'\\$`(){}!#&*|])/g, '$1')
            ;
        }
        else if (/^"/.test(s) && typeof env === 'function') {
            return s.replace(/^"|"$/g, '')
                .replace(/(^|[^\\])\$(\w+|[*@#?$!0_-])/g, getVar)
                .replace(/(^|[^\\])\${(\w+|[*@#?$!0_-])}/g, getVar)
                .replace(/\\([ "'\\$`(){}!#&*|])/g, '$1')
            ;
        }
        else if (/^"/.test(s)) {
            return s.replace(/^"|"$/g, '')
                .replace(/(^|[^\\])\$(\w+|[*@#?$!0_-])/g, getVar)
                .replace(/(^|[^\\])\${(\w+|[*@#?$!0_-])}/g, getVar)
                .replace(/\\([ "'\\$`(){}!#&*|])/g, '$1')
            ;
        }
        else if (RegExp('^' + CONTROL + '$').test(s)) {
            return { op: s };
        }
        else return s.replace(
            /(['"])((\\\1|[^\1])*?)\1|[^'"]+/g,
            function (s, q) {
                if (/^['"]/.test(s)) return parse(s, env);
                return parse('"' + s + '"', env);
            }
        );
    });

    function getVar (_, pre, key) {
        var r = typeof env === 'function' ? env(key) : env[key];
        if (r === undefined) r = '';

        if (typeof r === 'object') {
            return pre + TOKEN + JSON.stringify(r) + TOKEN;
        }
        else return pre + r;
    }
};
<|endoftext|>


<commit_before>var http = require('http')
var config = require('./config.json')

var pg = require('pg')

// var writeData =  require('./writedata.js')

// writeData(config.keys, config.timer)

var server = http.createServer(route)

server.listen(process.env.PORT || 5000, function listening() {
  console.log("Server serving...")
})

function route(req, res) {

  // if (req.url === ('/')) {
  //   res.statusCode = 200
  //   res.end("HELLO")
  //   return res
  // }

  if (req.url === ('/db')) {
    pg.connect(process.env.HEROKU_POSTGRESQL_ROSE_URL, function(err, client, done) {
      if (err) return console.error('error fetching client from pool', err)
      client.query('SELECT * FROM test_table', function(err, result) {
        done()
        if (err)
         { console.error(err); res.send("Error " + err) }
        else
         { console.log(result.rows); res.send(result.rows) }
      })
    })
  }
}
<commit_msg>a db starting place...<commit_after>var http = require('http')
var Tabletop = require('tabletop')
var pg = require('pg')

var config = require('./config.json')

var server = http.createServer(route)
pg.defaults.ssl = true

server.listen(process.env.PORT || 5000, function listening() {
  console.log("Server serving...")
})

function route(req, res) {

  if (req.url === ('/')) {
    res.statusCode = 200
    res.end("Hai.")
    return res
  }

  if (req.url === ('/fetch')) {

    config.keys.forEach(function(key) {
      var sskey = Object.keys(key)
      var opts = {key: sskey[0], callback: writeDatabase, simpleSheet: true}
      Tabletop.init(opts)
    })

    // TABLE SPREADSHEETS(SSKEY, SSNAME, SSJSON);
    function writeDatabase(data, tabletop) {
      console.log(tabletop.foundSheetNames)
      pg.connect(process.env.HEROKU_POSTGRESQL_ROSE_URL, function(err, client, done) {
        if (err) return console.error('error fetching client from pool', err)
        var querytext = 'INSERT INTO spreadsheets VALUES ($1,$2,$3)'
        client.query(querytext, [tabletop.key, tabletop.foundSheetNames, JSON.stringify(data)], function(err, result) {
          done()
          if (err)
           { console.error(err); res.end("Error " + err) }
          else
           { res.end("Great. Thanks.") }
        })
      })
    }
  }

}
<|endoftext|>


<commit_before>var fs = require('fs')
var hh = require('http-https')
var ipSet = require('ip-set')
var once = require('once')
var split = require('split')
var url = require('url')
var zlib = require('zlib')

var blocklistRe = /^\s*[^#].*?\s*:\s*([a-f0-9.:]+?)\s*-\s*([a-f0-9.:]+?)\s*$/

module.exports = function loadIPSet (input, cb) {
  cb = once(cb)
  if (Array.isArray(input)) {
    process.nextTick(function () {
      cb(null, new ipSet(input))
    })
  } else if (/^https?:\/\//.test(input)) {
    var p = url.parse(input)
    var opts = {
      hostname: p.hostname,
      port: p.port,
      path: p.path,
      headers: {
        'accept-encoding': 'gzip, deflate'
      }
    }
    hh.get(opts, function (res) {
      res.on('error', cb)
      var encoding = res.headers['content-encoding']
      if (encoding === 'gzip') {
        onStream(res.pipe(zlib.Gunzip()))
      } else if (encoding === 'deflate') {
        onStream(res.pipe(zlib.createInflate().on('error', cb)))
      } else
        onStream(res)
    }).on('error', cb)
  } else {
    var f = fs.createReadStream(input).on('error', cb)
    if (/.gz$/.test(input))
      f = f.pipe(zlib.Gunzip().on('error', cb))
    onStream(f)
  }

  function onStream (stream) {
    var blocklist = []
    stream
      .pipe(split())
      .on('data', function (line) {
        var match = blocklistRe.exec(line)
        if (match) blocklist.push({ start: match[1], end: match[2] })
      })
      .on('end', function () {
        cb(null, new ipSet(blocklist))
      })
  }
}
<commit_msg>support no arg<commit_after>var fs = require('fs')
var hh = require('http-https')
var ipSet = require('ip-set')
var once = require('once')
var split = require('split')
var url = require('url')
var zlib = require('zlib')

var blocklistRe = /^\s*[^#].*?\s*:\s*([a-f0-9.:]+?)\s*-\s*([a-f0-9.:]+?)\s*$/

module.exports = function loadIPSet (input, cb) {
  cb = once(cb)
  if (Array.isArray(input) || !input) {
    process.nextTick(function () {
      cb(null, new ipSet(input))
    })
  } else if (/^https?:\/\//.test(input)) {
    var p = url.parse(input)
    var opts = {
      hostname: p.hostname,
      port: p.port,
      path: p.path,
      headers: {
        'accept-encoding': 'gzip, deflate'
      }
    }
    hh.get(opts, function (res) {
      res.on('error', cb)
      var encoding = res.headers['content-encoding']
      if (encoding === 'gzip') {
        onStream(res.pipe(zlib.Gunzip()))
      } else if (encoding === 'deflate') {
        onStream(res.pipe(zlib.createInflate().on('error', cb)))
      } else
        onStream(res)
    }).on('error', cb)
  } else {
    var f = fs.createReadStream(input).on('error', cb)
    if (/.gz$/.test(input))
      f = f.pipe(zlib.Gunzip().on('error', cb))
    onStream(f)
  }

  function onStream (stream) {
    var blocklist = []
    stream
      .pipe(split())
      .on('data', function (line) {
        var match = blocklistRe.exec(line)
        if (match) blocklist.push({ start: match[1], end: match[2] })
      })
      .on('end', function () {
        cb(null, new ipSet(blocklist))
      })
  }
}
<|endoftext|>


<commit_before>var url    = require('url')
  , client = require('mongodb').MongoClient
;

var beforeEachRegistered = false;

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

  if (typeof uriString == 'function') {
    throw new Error("Module being called to clean the db.  Please call the module with a mongodb url.");
  }

  if (!uriString) {
    console.warn("!WARNING: no mongodb url provided.  Defaulting to mongo://localhost/test");
    uriString = 'mongo://localhost/test';
  }

  var db = null;

  if (!options.noClear && !beforeEachRegistered) {
    if ('function' == typeof beforeEach && beforeEach.length > 0) {
      // we're in a test suite that hopefully supports async operations
      beforeEach(clearDB);
      beforeEachRegistered = true;
    }
  }

  return function(done) {
    clearDB(done);
  };

  function clearDB(done) {
    if (db) return clearCollections(done);

    client.connect(uriString, function(err, newDb){
      if (err) return done(err);

      db = newDb;

      clearCollections(done);
    });
  }

  function clearCollections(done) {
    db.collections(function(err, collections){
      if (err) return done(err);

      var todo = collections.length;
      if (!todo) return done();

      collections.forEach(function(collection){
        if (collection.collectionName.match(/^system\./)) return --todo;

        collection.remove({},{safe: true}, function(){
          if (--todo === 0) done();
        });
      });
    });
  }
};
<commit_msg>Update mongo-connection protocol<commit_after>var url    = require('url')
  , client = require('mongodb').MongoClient
;

var beforeEachRegistered = false;

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

  if (typeof uriString == 'function') {
    throw new Error("Module being called to clean the db.  Please call the module with a mongodb url.");
  }

  if (!uriString) {
    console.warn("!WARNING: no mongodb url provided.  Defaulting to mongodb://localhost/test");
    uriString = 'mongodb://localhost/test';
  }

  var db = null;

  if (!options.noClear && !beforeEachRegistered) {
    if ('function' == typeof beforeEach && beforeEach.length > 0) {
      // we're in a test suite that hopefully supports async operations
      beforeEach(clearDB);
      beforeEachRegistered = true;
    }
  }

  return function(done) {
    clearDB(done);
  };

  function clearDB(done) {
    if (db) return clearCollections(done);

    client.connect(uriString, function(err, newDb){
      if (err) return done(err);

      db = newDb;

      clearCollections(done);
    });
  }

  function clearCollections(done) {
    db.collections(function(err, collections){
      if (err) return done(err);

      var todo = collections.length;
      if (!todo) return done();

      collections.forEach(function(collection){
        if (collection.collectionName.match(/^system\./)) return --todo;

        collection.remove({},{safe: true}, function(){
          if (--todo === 0) done();
        });
      });
    });
  }
};
<|endoftext|>


<commit_before>'use strict';

const assert = require('assert');
const typeOf = require('kind-of');
const define = require('define-property');
const pascal = require('pascalcase');
const merge = require('mixin-deep');
const Cache = require('cache-base');

/**
 * Optionally define a custom `cache` namespace to use.
 */

function namespace(name) {
  const fns = [];

  /**
   * Create an instance of `Base` with the given `cache` and `options`.
   * Learn about the [cache object](#cache-object).
   *
   * ```js
   * // initialize with `cache` and `options`
   * const app = new Base({isApp: true}, {abc: true});
   * app.set('foo', 'bar');
   *
   * // values defined with the given `cache` object will be on the root of the instance
   * console.log(app.baz); //=> undefined
   * console.log(app.foo); //=> 'bar'
   * // or use `.get`
   * console.log(app.get('isApp')); //=> true
   * console.log(app.get('foo')); //=> 'bar'
   *
   * // values defined with the given `options` object will be on `app.options
   * console.log(app.options.abc); //=> true
   * ```
   *
   * @name Base
   * @param {Object} `cache` If supplied, this object is passed to [cache-base][] to merge onto the the instance.
   * @param {Object} `options` If supplied, this object is used to initialize the `base.options` object.
   * @api public
   */

  class Base extends Cache {
    constructor(cache, options) {
      super(name, cache);
      this.is('base');
      this.is('app');
      this.options = merge({}, this.options, options);
      this.cache = this.cache || {};
      this.define('registered', {});

      if (fns.length) {
        this.use(fns);
      }
    }

    /**
     * Set the given `name` on `app._name` and `app.is*` properties. Used for doing
     * lookups in plugins.
     *
     * ```js
     * app.is('collection');
     * console.log(app.type);
     * //=> 'collection'
     * console.log(app.isCollection);
     * //=> true
     * ```
     * @name .is
     * @param {String} `name`
     * @return {Boolean}
     * @api public
     */

    is(type) {
      assert.equal(typeof type, 'string', 'expected "type" to be a string');
      if (type !== 'app') delete this.isApp;
      this.define('type', type.toLowerCase());
      this.define('is' + pascal(type), true);
      return this;
    }

    /**
     * Returns true if a plugin has already been registered on an instance.
     *
     * Plugin implementors are encouraged to use this first thing in a plugin
     * to prevent the plugin from being called more than once on the same
     * instance.
     *
     * ```js
     * const base = new Base();
     * base.use(function(app) {
     *   if (app.isRegistered('myPlugin')) return;
     *   // do stuff to `app`
     * });
     *
     * // to also record the plugin as being registered
     * base.use(function(app) {
     *   if (app.isRegistered('myPlugin', true)) return;
     *   // do stuff to `app`
     * });
     * ```
     * @name .isRegistered
     * @emits `plugin` Emits the name of the plugin being registered. Useful for unit tests, to ensure plugins are only registered once.
     * @param {String} `name` The plugin name.
     * @param {Boolean} `register` If the plugin if not already registered, to record it as being registered pass `true` as the second argument.
     * @return {Boolean} Returns true if a plugin is already registered.
     * @api public
     */

    isRegistered(name, register) {
      assert.equal(typeof name, 'string', 'expected name to be a string');
      if (this.registered.hasOwnProperty(name)) {
        return true;
      }
      if (register !== false) {
        this.registered[name] = true;
        this.emit('plugin', name);
      }
      return false;
    }

    /**
     * Call a plugin function or array of plugin functions on the instance. Plugins
     * are called with an instance of base, and options (if defined).
     *
     * ```js
     * const app = new Base()
     *   .use([foo, bar])
     *   .use(baz)
     * ```
     * @name .use
     * @param {String|Function|Array} `name` (optional) plugin name
     * @param {Function|Array} `plugin` plugin function, or array of functions, to call.
     * @param {...rest} Any additional arguments to pass to plugins(s).
     * @return {Object} Returns the item instance for chaining.
     * @api public
     */

    use(...rest) {
      let name = null;
      let fns = null;

      if (typeof rest[0] === 'string') {
        name = rest.shift();
      }

      if (typeof rest[0] === 'function' || Array.isArray(rest[0])) {
        fns = rest.shift();
      }

      if (Array.isArray(fns)) return fns.forEach(fn => this.use(fn, ...rest));
      assert.equal(typeof fns, 'function', 'expected plugin to be a function');

      const key = name || fns.name;
      if (key && typeof key === 'string' && this.isRegistered(key)) {
        return this;
      }

      fns.call(this, this, ...rest);
      return this;
    }

    /**
     * The `.define` method is used for adding non-enumerable property on the instance.
     * Dot-notation is **not supported** with `define`.
     *
     * ```js
     * // example of a custom arbitrary `render` function created with lodash's `template` method
     * app.define('render', (str, locals) => _.template(str)(locals));
     * ```
     * @name .define
     * @param {String} `key` The name of the property to define.
     * @param {any} `value`
     * @return {Object} Returns the instance for chaining.
     * @api public
     */

    define(key, val) {
      if (typeOf(key) === 'object') {
        return this.visit('define', key);
      }
      define(this, key, val);
      return this;
    }

    /**
     * Getter/setter used when creating nested instances of `Base`, for storing a reference
     * to the first ancestor instance. This works by setting an instance of `Base` on the `parent`
     * property of a "child" instance. The `base` property defaults to the current instance if
     * no `parent` property is defined.
     *
     * ```js
     * // create an instance of `Base`, this is our first ("base") instance
     * const first = new Base();
     * first.foo = 'bar'; // arbitrary property, to make it easier to see what's happening later
     *
     * // create another instance
     * const second = new Base();
     * // create a reference to the first instance (`first`)
     * second.parent = first;
     *
     * // create another instance
     * const third = new Base();
     * // create a reference to the previous instance (`second`)
     * // repeat this pattern every time a "child" instance is created
     * third.parent = second;
     *
     * // we can always access the first instance using the `base` property
     * console.log(first.base.foo);
     * //=> 'bar'
     * console.log(second.base.foo);
     * //=> 'bar'
     * console.log(third.base.foo);
     * //=> 'bar'
     * ```
     * @name .base
     * @api public
     */

    get base() {
      return this.parent ? this.parent.base : this;
    }

    /**
     * Static method for adding global plugin functions that will
     * be added to an instance when created.
     *
     * ```js
     * Base.use(function(app) {
     *   app.foo = 'bar';
     * });
     * const app = new Base();
     * console.log(app.foo);
     * //=> 'bar'
     * ```
     * @name #use
     * @param {Function} `fn` Plugin function to use on each instance.
     * @return {Object} Returns the `Base` constructor for chaining
     * @api public
     */

    static use(fn) {
      assert.equal(typeof fn, 'function', 'expected plugin to be a function');
      fns.push(fn);
      return this;
    }

    /**
     * Delete static mixin method from cache-base, JIT
     */

    static get mixin() {
      return undefined;
    }
  }

  return Base;
}

/**
 * Expose `Base` with default settings
 */

module.exports = namespace();

/**
 * Allow users to define a namespace
 */

module.exports.namespace = namespace;
<commit_msg>don't check fn.name<commit_after>'use strict';

const assert = require('assert');
const typeOf = require('kind-of');
const define = require('define-property');
const pascal = require('pascalcase');
const merge = require('mixin-deep');
const Cache = require('cache-base');

/**
 * Optionally define a custom `cache` namespace to use.
 */

function namespace(name) {
  const fns = [];

  /**
   * Create an instance of `Base` with the given `cache` and `options`.
   * Learn about the [cache object](#cache-object).
   *
   * ```js
   * // initialize with `cache` and `options`
   * const app = new Base({isApp: true}, {abc: true});
   * app.set('foo', 'bar');
   *
   * // values defined with the given `cache` object will be on the root of the instance
   * console.log(app.baz); //=> undefined
   * console.log(app.foo); //=> 'bar'
   * // or use `.get`
   * console.log(app.get('isApp')); //=> true
   * console.log(app.get('foo')); //=> 'bar'
   *
   * // values defined with the given `options` object will be on `app.options
   * console.log(app.options.abc); //=> true
   * ```
   *
   * @name Base
   * @param {Object} `cache` If supplied, this object is passed to [cache-base][] to merge onto the the instance.
   * @param {Object} `options` If supplied, this object is used to initialize the `base.options` object.
   * @api public
   */

  class Base extends Cache {
    constructor(cache, options) {
      super(name, cache);
      this.is('base');
      this.is('app');
      this.options = merge({}, this.options, options);
      this.cache = this.cache || {};
      this.define('registered', {});

      if (fns.length) {
        this.use(fns);
      }
    }

    /**
     * Set the given `name` on `app._name` and `app.is*` properties. Used for doing
     * lookups in plugins.
     *
     * ```js
     * app.is('collection');
     * console.log(app.type);
     * //=> 'collection'
     * console.log(app.isCollection);
     * //=> true
     * ```
     * @name .is
     * @param {String} `name`
     * @return {Boolean}
     * @api public
     */

    is(type) {
      assert.equal(typeof type, 'string', 'expected "type" to be a string');
      if (type !== 'app') delete this.isApp;
      this.define('type', type.toLowerCase());
      this.define('is' + pascal(type), true);
      return this;
    }

    /**
     * Returns true if a plugin has already been registered on an instance.
     *
     * Plugin implementors are encouraged to use this first thing in a plugin
     * to prevent the plugin from being called more than once on the same
     * instance.
     *
     * ```js
     * const base = new Base();
     * base.use(function(app) {
     *   if (app.isRegistered('myPlugin')) return;
     *   // do stuff to `app`
     * });
     *
     * // to also record the plugin as being registered
     * base.use(function(app) {
     *   if (app.isRegistered('myPlugin', true)) return;
     *   // do stuff to `app`
     * });
     * ```
     * @name .isRegistered
     * @emits `plugin` Emits the name of the plugin being registered. Useful for unit tests, to ensure plugins are only registered once.
     * @param {String} `name` The plugin name.
     * @param {Boolean} `register` If the plugin if not already registered, to record it as being registered pass `true` as the second argument.
     * @return {Boolean} Returns true if a plugin is already registered.
     * @api public
     */

    isRegistered(name, register) {
      assert.equal(typeof name, 'string', 'expected name to be a string');
      if (this.registered.hasOwnProperty(name)) {
        return true;
      }
      if (register !== false) {
        this.registered[name] = true;
        this.emit('plugin', name);
      }
      return false;
    }

    /**
     * Call a plugin function or array of plugin functions on the instance. Plugins
     * are called with an instance of base, and options (if defined).
     *
     * ```js
     * const app = new Base()
     *   .use([foo, bar])
     *   .use(baz)
     * ```
     * @name .use
     * @param {String|Function|Array} `name` (optional) plugin name
     * @param {Function|Array} `plugin` plugin function, or array of functions, to call.
     * @param {...rest} Any additional arguments to pass to plugins(s).
     * @return {Object} Returns the item instance for chaining.
     * @api public
     */

    use(...rest) {
      let name = null;
      let fns = null;

      if (typeof rest[0] === 'string') {
        name = rest.shift();
      }

      if (typeof rest[0] === 'function' || Array.isArray(rest[0])) {
        fns = rest.shift();
      }

      if (Array.isArray(fns)) return fns.forEach(fn => this.use(fn, ...rest));
      assert.equal(typeof fns, 'function', 'expected plugin to be a function');

      const key = name;
      if (key && typeof key === 'string' && this.isRegistered(key)) {
        return this;
      }

      fns.call(this, this, ...rest);
      return this;
    }

    /**
     * The `.define` method is used for adding non-enumerable property on the instance.
     * Dot-notation is **not supported** with `define`.
     *
     * ```js
     * // example of a custom arbitrary `render` function created with lodash's `template` method
     * app.define('render', (str, locals) => _.template(str)(locals));
     * ```
     * @name .define
     * @param {String} `key` The name of the property to define.
     * @param {any} `value`
     * @return {Object} Returns the instance for chaining.
     * @api public
     */

    define(key, val) {
      if (typeOf(key) === 'object') {
        return this.visit('define', key);
      }
      define(this, key, val);
      return this;
    }

    /**
     * Getter/setter used when creating nested instances of `Base`, for storing a reference
     * to the first ancestor instance. This works by setting an instance of `Base` on the `parent`
     * property of a "child" instance. The `base` property defaults to the current instance if
     * no `parent` property is defined.
     *
     * ```js
     * // create an instance of `Base`, this is our first ("base") instance
     * const first = new Base();
     * first.foo = 'bar'; // arbitrary property, to make it easier to see what's happening later
     *
     * // create another instance
     * const second = new Base();
     * // create a reference to the first instance (`first`)
     * second.parent = first;
     *
     * // create another instance
     * const third = new Base();
     * // create a reference to the previous instance (`second`)
     * // repeat this pattern every time a "child" instance is created
     * third.parent = second;
     *
     * // we can always access the first instance using the `base` property
     * console.log(first.base.foo);
     * //=> 'bar'
     * console.log(second.base.foo);
     * //=> 'bar'
     * console.log(third.base.foo);
     * //=> 'bar'
     * ```
     * @name .base
     * @api public
     */

    get base() {
      return this.parent ? this.parent.base : this;
    }

    /**
     * Static method for adding global plugin functions that will
     * be added to an instance when created.
     *
     * ```js
     * Base.use(function(app) {
     *   app.foo = 'bar';
     * });
     * const app = new Base();
     * console.log(app.foo);
     * //=> 'bar'
     * ```
     * @name #use
     * @param {Function} `fn` Plugin function to use on each instance.
     * @return {Object} Returns the `Base` constructor for chaining
     * @api public
     */

    static use(fn) {
      assert.equal(typeof fn, 'function', 'expected plugin to be a function');
      fns.push(fn);
      return this;
    }

    /**
     * Delete static mixin method from cache-base, JIT
     */

    static get mixin() {
      return undefined;
    }
  }

  return Base;
}

/**
 * Expose `Base` with default settings
 */

module.exports = namespace();

/**
 * Allow users to define a namespace
 */

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


<commit_before>var sublevel = require('level-sublevel')
var through = require('through')
var inflect = require('inflect')
var extend = require('extend')
var map = require('map-stream')

function LevelREST(db, options) {
  if (!(this instanceof LevelREST)) return new LevelREST(db, options)
  this.db = sublevel(db)
  options = options || {}
  this.id = options.id || 'id'
  this.separator = options.separator || ':'
  this.metaKey = options.metaKey || 'meta'
  this.serialize = options.serialize || function(url) {
    url = url.split('/')
    if (url[1] === 'undefined') url[1] = null
    var singular = inflect.singularize(url[0])
    return { api: url[0], id: url[1] || null, singular: singular }
  }
  this.generateId = options.generateId || function() {
    return +Date.now()
  }.bind(this)
}
module.exports = LevelREST

// Get data from an endpoint, ie: GET posts, GET posts/123
LevelREST.prototype.get = function(api, params) {
  var self = this
  api = this.serialize(api)
  var db = this.db.sublevel(api.api)

  var stream
  if (api.id) {
    stream = db.createReadStream({ start: api.id, limit: 1 })
  } else {
    stream = db.createReadStream()
  }

  var out = through()
  var data = []
  stream.on('data', function(d) {
    data.push(d.value)
  }).on('close', function() {
    var outdata = {}
    if (api.id) {
      outdata[api.singular] = data.shift()
    } else {
      outdata[api.api] = data
    }
    outdata['meta'] = {}
    out.write(outdata)
    out.end()
  })

  return out
}

// Put data into an endpoint, ie: PUT posts/123
LevelREST.prototype.put = function(api, data, params, cb) {
  var self = this
  if (typeof params === 'function') {
    cb = params
    params = {}
  }
  api = this.serialize(api)
  var db = this.db.sublevel(api.api)
  var buffer = []
  var stream = through(function(d) {
    buffer.push(d)
  }, function() {
    var len = buffer.length
    var queue = this.queue
    // TODO: Needs correct response
    var res = { meta: { success: true } }
    function done() {
      len--
      if (len < 1) {
        queue(res)
        queue(null)
        if (typeof cb === 'function') cb(null, res)
      }
    }
    for (var i = 0; i < buffer.length; i++) {
      var d = buffer[i]
      if (typeof d[api.singular] === 'object') d = d[api.singular]
      db.get(api.id, function(err, olddata) {
        extend(olddata, d)
        db.put(api.id, olddata, done)
      })
    }
  })
  if (!api.id) return stream.emit('error', new Error('Must supply a ' + this.id))
  if (typeof cb === 'function') {
    stream.write(data)
    stream.end()
  }
  return stream
}

// Create a new record on an endpoint, ie: POST posts/
LevelREST.prototype.post = function(api, data, params, cb) {
  var self = this
  if (typeof params === 'function') {
    cb = params
    params = {}
  }
  api = this.serialize(api)
  var db = this.db.sublevel(api.api)
  var buffer = []
  var stream = through(function(d) {
    buffer.push(d)
  }, function() {
    var len = buffer.length
    var queue = this.queue
    // TODO: Needs correct response
    var res = { meta: { success: true } }
    function done() {
      len--
      if (len < 1) {
        queue(res)
        queue(null)
        if (typeof cb === 'function') cb(null, res)
      }
    }
    for (var i = 0; i < buffer.length; i++) {
      var d = buffer[i]
      if (typeof d[api.singular] === 'object') d = d[api.singular]
      var id = d[self.id] || self.generateId()
      db.put(id, d, done)
    }
  })
  if (typeof cb === 'function') {
    stream.write(data)
    stream.end()
  }
  return stream
}

// Delete a record on an endpoint, ie: DELETE posts/123
LevelREST.prototype.delete = function(api, params, cb) {
  var self = this
  if (typeof params === 'function') {
    cb = params
    params = {}
  }
  api = this.serialize(api)
  var db = this.db.sublevel(api.api)
  db.del(api.id, cb)
  return this
}
<commit_msg>Simplify post using batch<commit_after>var sublevel = require('level-sublevel')
var through = require('through')
var inflect = require('inflect')
var extend = require('extend')
var map = require('map-stream')

function LevelREST(db, options) {
  if (!(this instanceof LevelREST)) return new LevelREST(db, options)
  this.db = sublevel(db)
  options = options || {}
  this.id = options.id || 'id'
  this.separator = options.separator || ':'
  this.metaKey = options.metaKey || 'meta'
  this.serialize = options.serialize || function(url) {
    url = url.split('/')
    if (url[1] === 'undefined') url[1] = null
    var singular = inflect.singularize(url[0])
    return { api: url[0], id: url[1] || null, singular: singular }
  }
  this.generateId = options.generateId || function() {
    return +Date.now()
  }.bind(this)
}
module.exports = LevelREST

// Get data from an endpoint, ie: GET posts, GET posts/123
LevelREST.prototype.get = function(api, params) {
  var self = this
  api = this.serialize(api)
  var db = this.db.sublevel(api.api)

  var stream
  if (api.id) {
    stream = db.createReadStream({ start: api.id, limit: 1 })
  } else {
    stream = db.createReadStream()
  }

  var out = through()
  var data = []
  stream.on('data', function(d) {
    data.push(d.value)
  }).on('close', function() {
    var outdata = {}
    if (api.id) {
      outdata[api.singular] = data.shift()
    } else {
      outdata[api.api] = data
    }
    outdata['meta'] = {}
    out.write(outdata)
    out.end()
  })

  return out
}

// Put data into an endpoint, ie: PUT posts/123
LevelREST.prototype.put = function(api, data, params, cb) {
  var self = this
  if (typeof params === 'function') {
    cb = params
    params = {}
  }
  api = this.serialize(api)
  var db = this.db.sublevel(api.api)
  var buffer = []
  var stream = through(function(d) {
    buffer.push(d)
  }, function() {
    var len = buffer.length
    var queue = this.queue
    // TODO: Needs correct response
    var res = { meta: { success: true } }
    function done() {
      len--
      if (len < 1) {
        queue(res)
        queue(null)
        if (typeof cb === 'function') cb(null, res)
      }
    }
    for (var i = 0; i < buffer.length; i++) {
      var d = buffer[i]
      if (typeof d[api.singular] === 'object') d = d[api.singular]
      db.get(api.id, function(err, olddata) {
        extend(olddata, d)
        db.put(api.id, olddata, done)
      })
    }
  })
  if (!api.id) return stream.emit('error', new Error('Must supply a ' + this.id))
  if (typeof cb === 'function') {
    stream.write(data)
    stream.end()
  }
  return stream
}

// Create a new record on an endpoint, ie: POST posts/
LevelREST.prototype.post = function(api, data, params, cb) {
  var self = this
  if (typeof params === 'function') {
    cb = params
    params = {}
  }
  api = this.serialize(api)
  var db = this.db.sublevel(api.api)
  var buffer = []
  var stream = through(function(d) {
    if (typeof d[api.singular] === 'object') d = d[api.singular]
    var id = d[self.id] || self.generateId()
    buffer.push({ type: 'put', key: id, value: d })
  }, function() {
    var queue = this.queue
    db.batch(buffer, function(err) {
      // TODO: Needs correct response
      var res = { meta: { success: true } }
      queue(res)
      queue(null)
      if (typeof cb === 'function') cb(null, res)
    })
  })
  if (typeof cb === 'function') {
    stream.write(data)
    stream.end()
  }
  return stream
}

// Delete a record on an endpoint, ie: DELETE posts/123
LevelREST.prototype.delete = function(api, params, cb) {
  var self = this
  if (typeof params === 'function') {
    cb = params
    params = {}
  }
  api = this.serialize(api)
  var db = this.db.sublevel(api.api)
  db.del(api.id, cb)
  return this
}
<|endoftext|>