<commit_before>import React, { Component } from 'react';
import {
  Dimensions,
  Modal,
  DeviceEventEmitter,
  TouchableWithoutFeedback,
  KeyboardAvoidingView,
  PanResponder,
  Animated,
} from 'react-native';
import PropTypes from 'prop-types';
import {
  View,
  initializeRegistryWithDefinitions,
  registerAnimation,
  createAnimation,
} from 'react-native-animatable';
import * as ANIMATION_DEFINITIONS from './animations';

import styles from './index.style.js';

// Override default animations
initializeRegistryWithDefinitions(ANIMATION_DEFINITIONS);

// Utility for creating custom animations
const makeAnimation = (name, obj) => {
  registerAnimation(name, createAnimation(obj));
};

const isObject = obj => {
  return obj !== null && typeof obj === 'object';
};

const horizontalDirections = direction => {
  return direction == 'right' || direction == 'left';
}

export class ReactNativeModal extends Component {
  static propTypes = {
    animationIn: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
    animationInTiming: PropTypes.number,
    animationOut: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
    animationOutTiming: PropTypes.number,
    avoidKeyboard: PropTypes.bool,
    backdropColor: PropTypes.string,
    backdropOpacity: PropTypes.number,
    backdropTransitionInTiming: PropTypes.number,
    backdropTransitionOutTiming: PropTypes.number,
    children: PropTypes.node.isRequired,
    isVisible: PropTypes.bool.isRequired,
    onModalShow: PropTypes.func,
    onModalHide: PropTypes.func,
    onBackButtonPress: PropTypes.func,
    onBackdropPress: PropTypes.func,
    onSwipe: PropTypes.func,
    onSwipeThreshold: PropTypes.number,
    useNativeDriver: PropTypes.bool,
    style: PropTypes.any,
    swipeDirection: PropTypes.string,
  };

  static defaultProps = {
    animationIn: 'slideInUp',
    animationInTiming: 300,
    animationOut: 'slideOutDown',
    animationOutTiming: 300,
    avoidKeyboard: false,
    backdropColor: 'black',
    backdropOpacity: 0.7,
    backdropTransitionInTiming: 300,
    backdropTransitionOutTiming: 300,
    onModalShow: () => null,
    onModalHide: () => null,
    isVisible: false,
    onBackdropPress: () => null,
    onBackButtonPress: () => null,
    onSwipeThreshold: 100,
    useNativeDriver: false,
  };

  // We use an internal state for keeping track of the modal visibility: this allows us to keep
  // the modal visibile during the exit animation, even if the user has already change the
  // isVisible prop to false.
  // We also store in the state the device width and height so that we can update the modal on
  // device rotation.
  state = {
    isVisible: false,
    deviceWidth: Dimensions.get('window').width,
    deviceHeight: Dimensions.get('window').height,
    pan: this.props.swipeDirection ? new Animated.ValueXY() : null,
  };

  transitionLock = null;

  constructor(props) {
    super(props);
    this._buildAnimations(props);
  }

  componentWillReceiveProps(nextProps) {
    if (!this.state.isVisible && nextProps.isVisible) {
      this.setState({ isVisible: true });
    }
    if (
      this.props.animationIn !== nextProps.animationIn ||
      this.props.animationOut !== nextProps.animationOut
    ) {
      this._buildAnimations(nextProps);
    }
  }

  componentWillMount() {
    if (this.props.isVisible) {
      this.setState({ isVisible: true });
    }
    if (this.props.swipeDirection) {
      this._buildPanResponder(this.props);
    }
  }

  componentDidMount() {
    if (this.state.isVisible) {
      this._open();
    }
    DeviceEventEmitter.addListener('didUpdateDimensions', this._handleDimensionsUpdate);
  }

  componentWillUnmount() {
    DeviceEventEmitter.removeListener('didUpdateDimensions', this._handleDimensionsUpdate);
  }

  componentDidUpdate(prevProps, prevState) {
    // On modal open request, we slide the view up and fade in the backdrop
    if (this.props.isVisible && !prevProps.isVisible) {
      this._open();
    }
    // On modal close request, we slide the view down and fade out the backdrop
    else if (!this.props.isVisible && prevProps.isVisible) {
      this._close();
    }
  }

  _buildPanResponder = props => {
    let animEvt = null;

    if (horizontalDirections(this.props.swipeDirection)) {
      animEvt = Animated.event([null,{ dx : this.state.pan.x }]);
    }
    else {
      animEvt = Animated.event([null,{ dy : this.state.pan.y }]);
    }

    this.panResponder = PanResponder.create({
      onStartShouldSetPanResponder: () => true,
      onPanResponderMove: (evt, gestureState) => {
        if (this._isSwipeDirectionAllowed(gestureState)) {
          this.backdropRef.transitionTo({ opacity: this.props.backdropOpacity * (1 - (this._getAccDistancePerDirection(gestureState) / this.state.deviceWidth))});
          animEvt(evt, gestureState);
        }
      },
      onPanResponderRelease: (evt, gestureState) => {
        if (this._getAccDistancePerDirection(gestureState) > this.props.onSwipeThreshold) {
          if ( this.props.onSwipe ) {
            this.inSwipeClosingState = true;
            this.props.onSwipe();
            return;
          }
        }

        //Reset backdrop opacity & modal position
        this.backdropRef.transitionTo({ opacity: this.props.backdropOpacity }, this.props.backdropTransitionInTiming);
        Animated.spring(
          this.state.pan,
          { toValue: {x: 0, y: 0} }
        ).start();
      }
    });
  }

  _getAccDistancePerDirection = gestureState => {
    switch (this.props.swipeDirection) {
      case 'up':
        return -gestureState.dy;
      case 'down':
        return gestureState.dy;
      case 'right':
        return gestureState.dx;
      case 'left':
        return -gestureState.dx;
      default:
        return 0;
    }
  }

  _isSwipeDirectionAllowed = ({dy, dx}) => {
    const draggedDown = dy > 0;
    const draggedUp = dy < 0;
    const draggedLeft = dx < 0;
    const draggedRight = dx > 0;

    switch (this.props.swipeDirection) {
      case 'up':
        if (draggedUp) return true;
        break;
      case 'down':
        if (draggedDown) return true;
        break;
      case 'right':
        if (draggedRight) return true;
        break;
      case 'left':
        if (draggedLeft) return true;
        break;
      default:
        return false;
    }

    return false;
  }

  // User can define custom react-native-animatable animations, see PR #72
  _buildAnimations = props => {
    let animationIn = props.animationIn;
    let animationOut = props.animationOut;

    if (isObject(animationIn)) {
      makeAnimation('animationIn', animationIn);
      animationIn = 'animationIn';
    }

    if (isObject(animationOut)) {
      makeAnimation('animationOut', animationOut);
      animationOut = 'animationOut';
    }

    this.animationIn = animationIn;
    this.animationOut = animationOut;
  };

  _handleDimensionsUpdate = dimensionsUpdate => {
    // Here we update the device dimensions in the state if the layout changed (triggering a render)
    const deviceWidth = Dimensions.get('window').width;
    const deviceHeight = Dimensions.get('window').height;
    if (deviceWidth !== this.state.deviceWidth || deviceHeight !== this.state.deviceHeight) {
      this.setState({ deviceWidth, deviceHeight });
    }
  };

  _open = () => {
    if (this.transitionLock) return;
    this.transitionLock = true;
    this.backdropRef.transitionTo(
      { opacity: this.props.backdropOpacity },
      this.props.backdropTransitionInTiming,
    );

    // This is for reset the pan position, if not modal get stuck
    // at the last release position when you try to open it.
    // Could certainly be improve - no idea for the moment.
    if ( this.state.pan ) {
      this.state.pan.setValue({ x: 0, y: 0});
    }

    this.contentRef[this.animationIn](this.props.animationInTiming).then(() => {
      this.transitionLock = false;
      if (!this.props.isVisible) {
        this._close();
      }
      else {
        this.props.onModalShow();
      }
    });
  };

  _close = () => {
    if (this.transitionLock) return;
    this.transitionLock = true;
    this.backdropRef.transitionTo({ opacity: 0 }, this.props.backdropTransitionOutTiming);

    let animationOut = this.animationOut;

    if ( this.inSwipeClosingState ) {
      this.inSwipeClosingState = false;
      switch (this.props.swipeDirection) {
        case 'up':
          animationOut = 'slideOutUp';
          break;
        case 'down':
          animationOut = 'slideOutDown';
          break;
        case 'right':
          animationOut = 'slideOutRight';
          break;
        case 'left':
          animationOut = 'slideOutLeft';
          break;
      }
    }

    this.contentRef[animationOut](this.props.animationOutTiming).then(() => {
      this.transitionLock = false;
      if (this.props.isVisible) {
        this._open();
      }
      else {
        this.setState({ isVisible: false });
        this.props.onModalHide();
      }
    });
  };

  render() {
    const {
      animationIn,
      animationInTiming,
      animationOut,
      animationOutTiming,
      avoidKeyboard,
      backdropColor,
      backdropOpacity,
      backdropTransitionInTiming,
      backdropTransitionOutTiming,
      children,
      isVisible,
      onModalShow,
      onBackdropPress,
      onBackButtonPress,
      useNativeDriver,
      style,
      ...otherProps
    } = this.props;
    const { deviceWidth, deviceHeight } = this.state;

    const computedStyle = [
      { margin: deviceWidth * 0.05, transform: [{ translateY: 0 }] },
      styles.content,
      style,
    ];

    const panHandlers = this.props.swipeDirection ? { ...this.panResponder.panHandlers } : {};
    const panPosition = this.state.pan ? this.state.pan.getLayout() : {};

    const containerView = (
      <View
        { ...panHandlers }
        ref={ref => (this.contentRef = ref)}
        style={[panPosition, computedStyle]}
        pointerEvents={'box-none'}
        useNativeDriver={useNativeDriver}
        onLayout={this._containerViewOnLayout}
        {...otherProps}
      >
        {children}
      </View>
    );

    return (
      <Modal
        transparent={true}
        animationType={'none'}
        visible={this.state.isVisible}
        onRequestClose={onBackButtonPress}
        {...otherProps}
      >
        <TouchableWithoutFeedback onPress={onBackdropPress}>
          <View
            ref={ref => (this.backdropRef = ref)}
            useNativeDriver={useNativeDriver}
            style={[
              styles.backdrop,
              {
                backgroundColor: backdropColor,
                width: deviceWidth,
                height: deviceHeight,
              },
            ]}
          />
        </TouchableWithoutFeedback>

          {avoidKeyboard && (
            <KeyboardAvoidingView
              behavior={'padding'}
              pointerEvents={'box-none'}
              style={computedStyle.concat([{ margin: 0 }])}
            >
              {containerView}
            </KeyboardAvoidingView>
          )}

          {!avoidKeyboard && containerView}
      </Modal>
    );
  }
}

export default ReactNativeModal;<commit_msg>Remove bounciness when reset position of the modal<commit_after>import React, { Component } from 'react';
import {
  Dimensions,
  Modal,
  DeviceEventEmitter,
  TouchableWithoutFeedback,
  KeyboardAvoidingView,
  PanResponder,
  Animated,
} from 'react-native';
import PropTypes from 'prop-types';
import {
  View,
  initializeRegistryWithDefinitions,
  registerAnimation,
  createAnimation,
} from 'react-native-animatable';
import * as ANIMATION_DEFINITIONS from './animations';

import styles from './index.style.js';

// Override default animations
initializeRegistryWithDefinitions(ANIMATION_DEFINITIONS);

// Utility for creating custom animations
const makeAnimation = (name, obj) => {
  registerAnimation(name, createAnimation(obj));
};

const isObject = obj => {
  return obj !== null && typeof obj === 'object';
};

const horizontalDirections = direction => {
  return direction == 'right' || direction == 'left';
}

export class ReactNativeModal extends Component {
  static propTypes = {
    animationIn: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
    animationInTiming: PropTypes.number,
    animationOut: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
    animationOutTiming: PropTypes.number,
    avoidKeyboard: PropTypes.bool,
    backdropColor: PropTypes.string,
    backdropOpacity: PropTypes.number,
    backdropTransitionInTiming: PropTypes.number,
    backdropTransitionOutTiming: PropTypes.number,
    children: PropTypes.node.isRequired,
    isVisible: PropTypes.bool.isRequired,
    onModalShow: PropTypes.func,
    onModalHide: PropTypes.func,
    onBackButtonPress: PropTypes.func,
    onBackdropPress: PropTypes.func,
    onSwipe: PropTypes.func,
    onSwipeThreshold: PropTypes.number,
    useNativeDriver: PropTypes.bool,
    style: PropTypes.any,
    swipeDirection: PropTypes.string,
  };

  static defaultProps = {
    animationIn: 'slideInUp',
    animationInTiming: 300,
    animationOut: 'slideOutDown',
    animationOutTiming: 300,
    avoidKeyboard: false,
    backdropColor: 'black',
    backdropOpacity: 0.7,
    backdropTransitionInTiming: 300,
    backdropTransitionOutTiming: 300,
    onModalShow: () => null,
    onModalHide: () => null,
    isVisible: false,
    onBackdropPress: () => null,
    onBackButtonPress: () => null,
    onSwipeThreshold: 100,
    useNativeDriver: false,
  };

  // We use an internal state for keeping track of the modal visibility: this allows us to keep
  // the modal visibile during the exit animation, even if the user has already change the
  // isVisible prop to false.
  // We also store in the state the device width and height so that we can update the modal on
  // device rotation.
  state = {
    isVisible: false,
    deviceWidth: Dimensions.get('window').width,
    deviceHeight: Dimensions.get('window').height,
    pan: this.props.swipeDirection ? new Animated.ValueXY() : null,
  };

  transitionLock = null;

  constructor(props) {
    super(props);
    this._buildAnimations(props);
  }

  componentWillReceiveProps(nextProps) {
    if (!this.state.isVisible && nextProps.isVisible) {
      this.setState({ isVisible: true });
    }
    if (
      this.props.animationIn !== nextProps.animationIn ||
      this.props.animationOut !== nextProps.animationOut
    ) {
      this._buildAnimations(nextProps);
    }
  }

  componentWillMount() {
    if (this.props.isVisible) {
      this.setState({ isVisible: true });
    }
    if (this.props.swipeDirection) {
      this._buildPanResponder(this.props);
    }
  }

  componentDidMount() {
    if (this.state.isVisible) {
      this._open();
    }
    DeviceEventEmitter.addListener('didUpdateDimensions', this._handleDimensionsUpdate);
  }

  componentWillUnmount() {
    DeviceEventEmitter.removeListener('didUpdateDimensions', this._handleDimensionsUpdate);
  }

  componentDidUpdate(prevProps, prevState) {
    // On modal open request, we slide the view up and fade in the backdrop
    if (this.props.isVisible && !prevProps.isVisible) {
      this._open();
    }
    // On modal close request, we slide the view down and fade out the backdrop
    else if (!this.props.isVisible && prevProps.isVisible) {
      this._close();
    }
  }

  _buildPanResponder = props => {
    let animEvt = null;

    if (horizontalDirections(this.props.swipeDirection)) {
      animEvt = Animated.event([null,{ dx : this.state.pan.x }]);
    }
    else {
      animEvt = Animated.event([null,{ dy : this.state.pan.y }]);
    }

    this.panResponder = PanResponder.create({
      onStartShouldSetPanResponder: () => true,
      onPanResponderMove: (evt, gestureState) => {
        if (this._isSwipeDirectionAllowed(gestureState)) {
          this.backdropRef.transitionTo({ opacity: this.props.backdropOpacity * (1 - (this._getAccDistancePerDirection(gestureState) / this.state.deviceWidth))});
          animEvt(evt, gestureState);
        }
      },
      onPanResponderRelease: (evt, gestureState) => {
        if (this._getAccDistancePerDirection(gestureState) > this.props.onSwipeThreshold) {
          if ( this.props.onSwipe ) {
            this.inSwipeClosingState = true;
            this.props.onSwipe();
            return;
          }
        }

        //Reset backdrop opacity & modal position
        this.backdropRef.transitionTo({ opacity: this.props.backdropOpacity }, this.props.backdropTransitionInTiming);
        Animated.spring(
          this.state.pan,
          {
            toValue: {x: 0, y: 0},
            bounciness: 0,
          }
        ).start();
      }
    });
  }

  _getAccDistancePerDirection = gestureState => {
    switch (this.props.swipeDirection) {
      case 'up':
        return -gestureState.dy;
      case 'down':
        return gestureState.dy;
      case 'right':
        return gestureState.dx;
      case 'left':
        return -gestureState.dx;
      default:
        return 0;
    }
  }

  _isSwipeDirectionAllowed = ({dy, dx}) => {
    const draggedDown = dy > 0;
    const draggedUp = dy < 0;
    const draggedLeft = dx < 0;
    const draggedRight = dx > 0;

    switch (this.props.swipeDirection) {
      case 'up':
        if (draggedUp) return true;
        break;
      case 'down':
        if (draggedDown) return true;
        break;
      case 'right':
        if (draggedRight) return true;
        break;
      case 'left':
        if (draggedLeft) return true;
        break;
      default:
        return false;
    }

    return false;
  }

  // User can define custom react-native-animatable animations, see PR #72
  _buildAnimations = props => {
    let animationIn = props.animationIn;
    let animationOut = props.animationOut;

    if (isObject(animationIn)) {
      makeAnimation('animationIn', animationIn);
      animationIn = 'animationIn';
    }

    if (isObject(animationOut)) {
      makeAnimation('animationOut', animationOut);
      animationOut = 'animationOut';
    }

    this.animationIn = animationIn;
    this.animationOut = animationOut;
  };

  _handleDimensionsUpdate = dimensionsUpdate => {
    // Here we update the device dimensions in the state if the layout changed (triggering a render)
    const deviceWidth = Dimensions.get('window').width;
    const deviceHeight = Dimensions.get('window').height;
    if (deviceWidth !== this.state.deviceWidth || deviceHeight !== this.state.deviceHeight) {
      this.setState({ deviceWidth, deviceHeight });
    }
  };

  _open = () => {
    if (this.transitionLock) return;
    this.transitionLock = true;
    this.backdropRef.transitionTo(
      { opacity: this.props.backdropOpacity },
      this.props.backdropTransitionInTiming,
    );

    // This is for reset the pan position, if not modal get stuck
    // at the last release position when you try to open it.
    // Could certainly be improve - no idea for the moment.
    if ( this.state.pan ) {
      this.state.pan.setValue({ x: 0, y: 0});
    }

    this.contentRef[this.animationIn](this.props.animationInTiming).then(() => {
      this.transitionLock = false;
      if (!this.props.isVisible) {
        this._close();
      }
      else {
        this.props.onModalShow();
      }
    });
  };

  _close = () => {
    if (this.transitionLock) return;
    this.transitionLock = true;
    this.backdropRef.transitionTo({ opacity: 0 }, this.props.backdropTransitionOutTiming);

    let animationOut = this.animationOut;

    if ( this.inSwipeClosingState ) {
      this.inSwipeClosingState = false;
      switch (this.props.swipeDirection) {
        case 'up':
          animationOut = 'slideOutUp';
          break;
        case 'down':
          animationOut = 'slideOutDown';
          break;
        case 'right':
          animationOut = 'slideOutRight';
          break;
        case 'left':
          animationOut = 'slideOutLeft';
          break;
      }
    }

    this.contentRef[animationOut](this.props.animationOutTiming).then(() => {
      this.transitionLock = false;
      if (this.props.isVisible) {
        this._open();
      }
      else {
        this.setState({ isVisible: false });
        this.props.onModalHide();
      }
    });
  };

  render() {
    const {
      animationIn,
      animationInTiming,
      animationOut,
      animationOutTiming,
      avoidKeyboard,
      backdropColor,
      backdropOpacity,
      backdropTransitionInTiming,
      backdropTransitionOutTiming,
      children,
      isVisible,
      onModalShow,
      onBackdropPress,
      onBackButtonPress,
      useNativeDriver,
      style,
      ...otherProps
    } = this.props;
    const { deviceWidth, deviceHeight } = this.state;

    const computedStyle = [
      { margin: deviceWidth * 0.05, transform: [{ translateY: 0 }] },
      styles.content,
      style,
    ];

    const panHandlers = this.props.swipeDirection ? { ...this.panResponder.panHandlers } : {};
    const panPosition = this.state.pan ? this.state.pan.getLayout() : {};

    const containerView = (
      <View
        { ...panHandlers }
        ref={ref => (this.contentRef = ref)}
        style={[panPosition, computedStyle]}
        pointerEvents={'box-none'}
        useNativeDriver={useNativeDriver}
        onLayout={this._containerViewOnLayout}
        {...otherProps}
      >
        {children}
      </View>
    );

    return (
      <Modal
        transparent={true}
        animationType={'none'}
        visible={this.state.isVisible}
        onRequestClose={onBackButtonPress}
        {...otherProps}
      >
        <TouchableWithoutFeedback onPress={onBackdropPress}>
          <View
            ref={ref => (this.backdropRef = ref)}
            useNativeDriver={useNativeDriver}
            style={[
              styles.backdrop,
              {
                backgroundColor: backdropColor,
                width: deviceWidth,
                height: deviceHeight,
              },
            ]}
          />
        </TouchableWithoutFeedback>

          {avoidKeyboard && (
            <KeyboardAvoidingView
              behavior={'padding'}
              pointerEvents={'box-none'}
              style={computedStyle.concat([{ margin: 0 }])}
            >
              {containerView}
            </KeyboardAvoidingView>
          )}

          {!avoidKeyboard && containerView}
      </Modal>
    );
  }
}

export default ReactNativeModal;<|endoftext|>


<commit_before>'use strict';

var famous = require('famous');
var Consts = require('./Consts.js');
var Game = require('./Game.js');

var FamousEngine = famous.core.FamousEngine;

/*jshint -W121 */
/**
 * Initialize fixed-sized array with incremented values
 * @param {number} length - Length of array
 */
if (!Array.prototype.initialize) {
	Array.prototype.initialize = function (length) {
		var arr = [];
		for (var i = 0; i < length; i++) {
			arr.push(i);
		}
		return arr;
	};
}
Array.prototype.max = function() {
	return Math.max.apply(null, this);
};
Array.prototype.min = function() {
	return Math.min.apply(null, this);
};
/*jshint -W121 */

FamousEngine.init();
var scene = FamousEngine.createScene();
var game = new Game(Consts.ROWS, Consts.COLUMNS);
scene.addChild(game);
<commit_msg>Added Polyfills for Array<commit_after>'use strict';

var famous = require('famous');
var Consts = require('./Consts.js');
var Game = require('./Game.js');

var FamousEngine = famous.core.FamousEngine;

/*jshint -W121 */
/**
 * Initialize fixed-sized array with incremented values
 * @param {number} length - Length of array
 */
if (!Array.prototype.initialize) {
	Array.prototype.initialize = function (length) {
		var arr = [];
		for (var i = 0; i < length; i++) {
			arr.push(i);
		}
		return arr;
	};
}
if (!Array.prototype.every) {
	Array.prototype.every = function (callbackfn, thisArg) {
		'use strict';
		var T, k;

		if (this == null) {
			throw new TypeError('this is null or not defined');
		}

		// 1. Let O be the result of calling ToObject passing the this
		//    value as the argument.
		var O = Object(this);

		// 2. Let lenValue be the result of calling the Get internal method
		//    of O with the argument "length".
		// 3. Let len be ToUint32(lenValue).
		var len = O.length >>> 0;

		// 4. If IsCallable(callbackfn) is false, throw a TypeError exception.
		if (typeof callbackfn !== 'function') {
			throw new TypeError();
		}

		// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
		if (arguments.length > 1) {
			T = thisArg;
		}

		// 6. Let k be 0.
		k = 0;

		// 7. Repeat, while k < len
		while (k < len) {

			var kValue;

			// a. Let Pk be ToString(k).
			//   This is implicit for LHS operands of the in operator
			// b. Let kPresent be the result of calling the HasProperty internal
			//    method of O with argument Pk.
			//   This step can be combined with c
			// c. If kPresent is true, then
			if (k in O) {

				// i. Let kValue be the result of calling the Get internal method
				//    of O with argument Pk.
				kValue = O[k];

				// ii. Let testResult be the result of calling the Call internal method
				//     of callbackfn with T as the this value and argument list
				//     containing kValue, k, and O.
				var testResult = callbackfn.call(T, kValue, k, O);

				// iii. If ToBoolean(testResult) is false, return false.
				if (!testResult) {
					return false;
				}
			}
			k++;
		}
		return true;
	};
}
if (!Array.prototype.filter) {
	Array.prototype.filter = function (fun /*, thisArg*/ ) {
		'use strict';

		if (this === void 0 || this === null) {
			throw new TypeError();
		}

		var t = Object(this);
		var len = t.length >>> 0;
		if (typeof fun !== 'function') {
			throw new TypeError();
		}

		var res = [];
		var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
		for (var i = 0; i < len; i++) {
			if (i in t) {
				var val = t[i];

				// NOTE: Technically this should Object.defineProperty at
				//       the next index, as push can be affected by
				//       properties on Object.prototype and Array.prototype.
				//       But that method's new, and collisions should be
				//       rare, so use the more-compatible alternative.
				if (fun.call(thisArg, val, i, t)) {
					res.push(val);
				}
			}
		}

		return res;
	};
}
if (!Array.prototype.find) {
	Array.prototype.find = function (predicate) {
		if (this === null) {
			throw new TypeError('Array.prototype.find called on null or undefined');
		}
		if (typeof predicate !== 'function') {
			throw new TypeError('predicate must be a function');
		}
		var list = Object(this);
		var length = list.length >>> 0;
		var thisArg = arguments[1];
		var value;

		for (var i = 0; i < length; i++) {
			value = list[i];
			if (predicate.call(thisArg, value, i, list)) {
				return value;
			}
		}
		return undefined;
	};
}
if (!Array.prototype.findIndex) {
	Array.prototype.findIndex = function (predicate) {
		if (this === null) {
			throw new TypeError('Array.prototype.findIndex called on null or undefined');
		}
		if (typeof predicate !== 'function') {
			throw new TypeError('predicate must be a function');
		}
		var list = Object(this);
		var length = list.length >>> 0;
		var thisArg = arguments[1];
		var value;

		for (var i = 0; i < length; i++) {
			value = list[i];
			if (predicate.call(thisArg, value, i, list)) {
				return i;
			}
		}
		return -1;
	};
}
// Production steps of ECMA-262, Edition 5, 15.4.4.18
// Reference: http://es5.github.io/#x15.4.4.18
if (!Array.prototype.forEach) {

	Array.prototype.forEach = function (callback, thisArg) {

		var T, k;

		if (this == null) {
			throw new TypeError(' this is null or not defined');
		}

		// 1. Let O be the result of calling ToObject passing the |this| value as the argument.
		var O = Object(this);

		// 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
		// 3. Let len be ToUint32(lenValue).
		var len = O.length >>> 0;

		// 4. If IsCallable(callback) is false, throw a TypeError exception.
		// See: http://es5.github.com/#x9.11
		if (typeof callback !== "function") {
			throw new TypeError(callback + ' is not a function');
		}

		// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
		if (arguments.length > 1) {
			T = thisArg;
		}

		// 6. Let k be 0
		k = 0;

		// 7. Repeat, while k < len
		while (k < len) {

			var kValue;

			// a. Let Pk be ToString(k).
			//   This is implicit for LHS operands of the in operator
			// b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
			//   This step can be combined with c
			// c. If kPresent is true, then
			if (k in O) {

				// i. Let kValue be the result of calling the Get internal method of O with argument Pk.
				kValue = O[k];

				// ii. Call the Call internal method of callback with T as the this value and
				// argument list containing kValue, k, and O.
				callback.call(T, kValue, k, O);
			}
			// d. Increase k by 1.
			k++;
		}
		// 8. return undefined
	};
}
if (!Array.prototype.includes) {
	Array.prototype.includes = function (searchElement /*, fromIndex*/ ) {
		'use strict';
		var O = Object(this);
		var len = parseInt(O.length) || 0;
		if (len === 0) {
			return false;
		}
		var n = parseInt(arguments[1]) || 0;
		var k;
		if (n >= 0) {
			k = n;
		} else {
			k = len + n;
			if (k < 0) {
				k = 0;
			}
		}
		var currentElement;
		while (k < len) {
			currentElement = O[k];
			if (searchElement === currentElement ||
				(searchElement !== searchElement && currentElement !== currentElement)) {
				return true;
			}
			k++;
		}
		return false;
	};
}
Array.prototype.max = function () {
	return Math.max.apply(null, this);
};
Array.prototype.min = function () {
	return Math.min.apply(null, this);
};
/*jshint -W121 */

FamousEngine.init();
var scene = FamousEngine.createScene();
var game = new Game(Consts.ROWS, Consts.COLUMNS);
scene.addChild(game);
<|endoftext|>


<commit_before>/* eslint-disable no-magic-numbers */
export default {
  install(Vue, opts = {}) {
    const dir = {
      params: ['symbol', 'size'],
      bind(el, binding, vnode) {
        // Get options
        opts.class = opts.class || 'icon';
        opts.url = opts.url || '/assets/svg/sprite.svg';

        // Get params
        // If expression + "symbol" param -> use expression
        const id = vnode.data.attrs.expression || vnode.data.attrs.symbol;
        let { size } = vnode.data.attrs.size;

        // Set viewBox, widht, height attributes ?
        if (size) {
          // Normalize valid separators: / /, /,/
          size = size.replace(/( |, |,)/g, ' ');
          const sizeValues = size.split(' ');
          const l = sizeValues.length;
          const viewBox = [];

          if (l === 3 || l > 4) {
            console.warn('[vue-svg-sprite] size: ', size, ' is not valid');
          } else {
            viewBox[0] = l < 4 ? 0 : sizeValues[0];
            viewBox[1] = l < 4 ? 0 : sizeValues[1];
            /* eslint-disable no-multi-assign */
            const w = viewBox[2] = l < 4 ? sizeValues[0] : sizeValues[2];
            const h = viewBox[3] = sizeValues[l - 1];
            /* eslint-enable no-multi-assign */

            el.setAttribute('viewBox', viewBox.join(' '));
            el.setAttribute('width', w);
            el.setAttribute('height', h);
          }
        }

        // Check for existing class option (also .className--modifier)
        let isClassExisting = false;

        for (let i = 0; i < el.classList.length; i++) {
          if (el.classList.item(i).indexOf(opts.class) !== -1) {
            isClassExisting = true;
          }
        }

        if (!isClassExisting) {
          el.classList.add(opts.class);
        }

        // Add the <use> element to <svg>
        const href = `${opts.url}#${id}`;
        const use = document.createElementNS('http://www.w3.org/2000/svg', 'use');

        use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', href);
        el.appendChild(use);
      },
    };

    Vue.directive('svg', dir);
  },
};
<commit_msg>:bug: :ok_hand: fixed finally…<commit_after>/* eslint-disable no-magic-numbers */
export default {
  install(Vue, opts = {}) {
    const dir = {
      params: ['symbol', 'size'],
      bind(el, binding, vnode) {
        // Get options
        opts.class = opts.class || 'icon';
        opts.url = opts.url || '/assets/svg/sprite.svg';

        // Get params
        // If expression + "symbol" param -> use expression
        const id = binding.expression || vnode.data.attrs.symbol;
        let { size } = vnode.data.attrs;

        // Set viewBox, widht, height attributes ?
        if (size) {
          // Normalize valid separators: / /, /,/
          size = size.replace(/( |, |,)/g, ' ');
          const sizeValues = size.split(' ');
          const l = sizeValues.length;
          const viewBox = [];

          if (l === 3 || l > 4) {
            console.warn('[vue-svg-sprite] size: ', size, ' is not valid');
          } else {
            viewBox[0] = l < 4 ? 0 : sizeValues[0];
            viewBox[1] = l < 4 ? 0 : sizeValues[1];
            /* eslint-disable no-multi-assign */
            const w = viewBox[2] = l < 4 ? sizeValues[0] : sizeValues[2];
            const h = viewBox[3] = sizeValues[l - 1];
            /* eslint-enable no-multi-assign */

            el.setAttribute('viewBox', viewBox.join(' '));
            el.setAttribute('width', w);
            el.setAttribute('height', h);
          }
        }

        // Check for existing class option (also .className--modifier)
        let isClassExisting = false;

        for (let i = 0; i < el.classList.length; i++) {
          if (el.classList.item(i).indexOf(opts.class) !== -1) {
            isClassExisting = true;
          }
        }

        if (!isClassExisting) {
          el.classList.add(opts.class);
        }

        // Add the <use> element to <svg>
        const href = `${opts.url}#${id}`;
        const use = document.createElementNS('http://www.w3.org/2000/svg', 'use');

        use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', href);
        el.appendChild(use);
      },
    };

    Vue.directive('svg', dir);
  },
};
<|endoftext|>


<commit_before>/* pgrunner library */

"use strict";

var Q = require('q');
var merge = require('merge');
var debug = require('nor-debug');

var temp = require('temp');

var is = require('nor-is');
var PATH = require('path');
var fs = require('nor-fs');

/**
 * Function that returns promise of a temporary directory
 */
var mktempdir = Q.denodeify(temp.mkdir);

/** Search command from PATH
 */
function command_exists(paths, name) {
	if(is.string(paths)) {
		paths = paths.split(':');
	}

	debug.assert(paths).is('array');

	return paths.some(function(dir) {
		return fs.sync.exists(PATH.join(dir, name));
	});
}

/* */
var PG_CTL = 'pg_ctl';

if(!command_exists(process.env.PATH, 'pg_ctl')) {
	['/usr/lib/postgresql/9.3/bin', '/usr/lib/postgresql/9.4/bin'].forEach(function(bin_dir) {
		if(fs.sync.exists(PATH.join(bin_dir, 'pg_ctl'))) {
			process.env.PATH = bin_dir + ':' + process.env.PATH;
			PG_CTL = PATH.join(bin_dir, 'pg_ctl');
		}
	});
}

debug.log('pg_ctl detected as ', PG_CTL);

/**
 * Return promise of a spawned command
 */
function spawnProcess(command, args, options) {
	options = options || {};
	var defer = Q.defer();

	debug.log('command = ', command);
	debug.log('args = ', args);
	debug.log('options = ', options);

	options.env = merge(process.env, options.env || {});
	options.detached = true;
	options.stdio = ["ignore", "ignore", "pipe"];

	var stderr = '';

	// Run the process
	var proc = require('child_process').spawn(command, args, options);
	proc.stderr.setEncoding('utf8');
	proc.stderr.on('data', function(data) {
		stderr += data;
	});

	// Handle exit
	proc.on('close', function(retval) {
		if (retval === 0) {
			defer.resolve(retval);
		} else {
			defer.reject({"retval": retval, "stderr": stderr});
		}
	});

	// Handle error
	proc.on('error', function(err){
		defer.reject(err);
	});

	return defer.promise;
}

/** Constructor */
function PGRunnerInstance(opts) {
	opts = opts || {};
	this.settings = opts.settings || {};
	this.env = opts.env || {};
	this.pgconfig = opts.pgconfig || undefined;
}

/** Stop the instance */
PGRunnerInstance.prototype.stop = function pgrunner_stop() {
	var self = this;
	debug.log("Stopping PostgreSQL");
	debug.log("env = ", self.env);
	return spawnProcess(PG_CTL, ["stop", "-w", "-m", "fast"], {"env": self.env}).then(function() {
	});
};

/* The Module */
var pgrunner = module.exports = function pgrunner_create(opts) {

	opts = opts || {};
	var pghost = opts.host || '127.0.0.1';
	var pgport = opts.port || 55432;
	var pguser = opts.user || process.env.USER;
	var pgdatabase = opts.database || pguser;

	var instance = new PGRunnerInstance();

	// Create and start the database
	return mktempdir('nor-pgrunner-data-').then(function(tmpdir) {
		instance.settings = {
			'host': pghost,
			'port': pgport,
			'user': pguser,
			'database': pgdatabase
		};
		instance.env = {
			"PGDATA": tmpdir,
			"PGHOST": pghost,
			"PGPORT": pgport,
			"PGUSER": pguser,
			"PGDATABASE": pgdatabase,
			"PGCLIENTENCODING": "UTF-8",
			"TZ": "UTC"
		};
		instance.pgconfig = "postgresql://" + pguser + "@" + pghost + ":" + pgport + "/" + pgdatabase;
	}).then(function initdb(){
		debug.log("Initializing PostgreSQL database");
		return spawnProcess(PG_CTL, ["init", "-w", "-o", "-N -U " + pguser], {"env": instance.env});
	}).then(function start(){
		debug.log("Starting PostgreSQL");
		return spawnProcess(PG_CTL, ["start", "-w", "-o", "-F --unix-socket-directories=/tmp"], {"env": instance.env});
	}).then(function(){
		return spawnProcess('createdb', ["-w", "-h", pghost, "-p", pgport, "-U", pguser, "-O", pguser, pgdatabase], {"env": instance.env});
	}).then(function(){
		return instance;
	});
};

pgrunner.Instance = PGRunnerInstance;

/** Automatically track and cleanup files at exit */
pgrunner.enableAutoClean = function() {
	temp.track();
	// FIXME: Does not shutdown servers when cleaning up files.
};

/* EOF */
<commit_msg>Removed debug loggings<commit_after>/* pgrunner library */

"use strict";

var Q = require('q');
var merge = require('merge');
var debug = require('nor-debug');

var temp = require('temp');

var is = require('nor-is');
var PATH = require('path');
var fs = require('nor-fs');

/**
 * Function that returns promise of a temporary directory
 */
var mktempdir = Q.denodeify(temp.mkdir);

/** Search command from PATH
 */
function command_exists(paths, name) {
	if(is.string(paths)) {
		paths = paths.split(':');
	}

	debug.assert(paths).is('array');

	return paths.some(function(dir) {
		return fs.sync.exists(PATH.join(dir, name));
	});
}

/* */
var PG_CTL = 'pg_ctl';

if(!command_exists(process.env.PATH, 'pg_ctl')) {
	['/usr/lib/postgresql/9.3/bin', '/usr/lib/postgresql/9.4/bin'].forEach(function(bin_dir) {
		if(fs.sync.exists(PATH.join(bin_dir, 'pg_ctl'))) {
			process.env.PATH = bin_dir + ':' + process.env.PATH;
			PG_CTL = PATH.join(bin_dir, 'pg_ctl');
		}
	});
}

//debug.log('pg_ctl detected as ', PG_CTL);

/**
 * Return promise of a spawned command
 */
function spawnProcess(command, args, options) {
	options = options || {};
	var defer = Q.defer();

	//debug.log('command = ', command);
	//debug.log('args = ', args);
	//debug.log('options = ', options);

	options.env = merge(process.env, options.env || {});
	options.detached = true;
	options.stdio = ["ignore", "ignore", "pipe"];

	var stderr = '';

	// Run the process
	var proc = require('child_process').spawn(command, args, options);
	proc.stderr.setEncoding('utf8');
	proc.stderr.on('data', function(data) {
		stderr += data;
	});

	// Handle exit
	proc.on('close', function(retval) {
		if (retval === 0) {
			defer.resolve(retval);
		} else {
			defer.reject({"retval": retval, "stderr": stderr});
		}
	});

	// Handle error
	proc.on('error', function(err){
		defer.reject(err);
	});

	return defer.promise;
}

/** Constructor */
function PGRunnerInstance(opts) {
	opts = opts || {};
	this.settings = opts.settings || {};
	this.env = opts.env || {};
	this.pgconfig = opts.pgconfig || undefined;
}

/** Stop the instance */
PGRunnerInstance.prototype.stop = function pgrunner_stop() {
	var self = this;
	//debug.log("Stopping PostgreSQL");
	//debug.log("env = ", self.env);
	return spawnProcess(PG_CTL, ["stop", "-w", "-m", "fast"], {"env": self.env}).then(function() {
	});
};

/* The Module */
var pgrunner = module.exports = function pgrunner_create(opts) {

	opts = opts || {};
	var pghost = opts.host || '127.0.0.1';
	var pgport = opts.port || 55432;
	var pguser = opts.user || process.env.USER;
	var pgdatabase = opts.database || pguser;

	var instance = new PGRunnerInstance();

	// Create and start the database
	return mktempdir('nor-pgrunner-data-').then(function(tmpdir) {
		instance.settings = {
			'host': pghost,
			'port': pgport,
			'user': pguser,
			'database': pgdatabase
		};
		instance.env = {
			"PGDATA": tmpdir,
			"PGHOST": pghost,
			"PGPORT": pgport,
			"PGUSER": pguser,
			"PGDATABASE": pgdatabase,
			"PGCLIENTENCODING": "UTF-8",
			"TZ": "UTC"
		};
		instance.pgconfig = "postgresql://" + pguser + "@" + pghost + ":" + pgport + "/" + pgdatabase;
	}).then(function initdb(){
		//debug.log("Initializing PostgreSQL database");
		return spawnProcess(PG_CTL, ["init", "-w", "-o", "-N -U " + pguser], {"env": instance.env});
	}).then(function start(){
		//debug.log("Starting PostgreSQL");
		return spawnProcess(PG_CTL, ["start", "-w", "-o", "-F --unix-socket-directories=/tmp"], {"env": instance.env});
	}).then(function(){
		return spawnProcess('createdb', ["-w", "-h", pghost, "-p", pgport, "-U", pguser, "-O", pguser, pgdatabase], {"env": instance.env});
	}).then(function(){
		return instance;
	});
};

pgrunner.Instance = PGRunnerInstance;

/** Automatically track and cleanup files at exit */
pgrunner.enableAutoClean = function() {
	temp.track();
	// FIXME: Does not shutdown servers when cleaning up files.
};

/* EOF */
<|endoftext|>


<commit_before>import {Api, Client} from 'node-coolq'
import {DB} from './db.js'

let db = new DB(__dirname + '/bot.db')

let app = new Client()
let api = new Api(app)
let code = api.getCode()
let at = q => code.getAt(q)

let server_port = 11235
let local_port = 11666

let CQCode_reg = /\[[^\[]*\]/g
let add_reg = /^\/add ([^=]+)=([\S\s]+)$/
let del_reg = /^\/del ([^=]+)=([\S\s]+)$/
let get_reg = /^\/get#(\d+) ([^=]+)$/
let list_reg = /^\/list ([\S\s]+)$/

let encrypt = str =>
    str.replace(CQCode_reg, str =>
        str.replace('=', '~')
    )
let decrypt = str =>
    str.replace(CQCode_reg, str =>
        str.replace('~', '=')
    )

const SHOW_MAX_RULES = 10
const MSG_HELP = `QBot 使用帮助：
/add key=value，为关键词 key 添加一条自动回复规则 value
/del key=value，为关键词 key 闪出一条自动回复规则 value
/list key，列出关键词 key 对应的规则（至多列出 ${SHOW_MAX_RULES} 条）
/get#i key，列出关键词 key 对应的第 i 条规则（i 是从 0 开始的数字）
/help 获取使用帮助`

let add_s = (q, k, v) =>
    `${at(q)} 添加成功，你说“${k}”，我说“${v}”`
let add_w = (q, k, v) =>
    `${at(q)} 规则 “${k}” => “${v}” 已经存在`
let add_e = (q, k, v) =>
    `${at(q)} 规则 “${k}” => “${v}” 添加失败，请重试`

let del_s = (q, k, v) =>
    `${at(q)} 规则 “${k}” => “${v}” 删除成功`
let del_w = (q, k, v) =>
    `${at(q)} 规则 “${k}” => “${v}” 并不存在`
let del_e = (q, k, v) =>
    `${at(q)} 规则 “${k}” => “${v}” 删除失败，请重试`

let get_s = (q, k, i, v) =>
    `${at(q)} 关键词 “${k}” 的第 ${i} 条规则是 “${v}”`
let get_e = (q, k, i) =>
    `${at(q)} 关键词 “${k}” 可能并不存在第 ${i} 条规则`

let list_e = (q, k) =>
    `${at(q)} 关键词 “${k}” 可能没有绑定任何规则`
let list_s = (q, k, r) => {
    let s = `${at(q)} 关键词 “${k}” 共有 ${r.length} 条规则：`
    let len = Math.min(SHOW_MAX_RULES, r.length)
    if (len !== r.length) {
        s = `${s}\n（只显示前 ${len} 条规则）`
    }
    for (let i = 0; i < len; i++) {
        s = `${s}\n#${i} ${r[i].value}`
    }
    return s
}

app.on('GroupMessage', async data => {
    let gid = data.group
    let qq = data.fromQQ
    let msg = encrypt(data.content)

    if (qq == 1000000) {
        return null //system message
    }

    if (data.content === '/help') {
        await api.GroupMessage(gid, MSG_HELP)
    } else if (add_reg.test(msg)) {
        let $ = msg.match(add_reg)
        let $1 = decrypt($[1])
        let $2 = decrypt($[2])

        if (await db.has(gid, $1, $2)) {
            await api.GroupMessage(gid, add_w(qq, $1, $2))
        } else if (await db.add(gid, $1, $2)) {
            await api.GroupMessage(gid, add_s(qq, $1, $2))
        } else {
            await api.GroupMessage(gid, add_e(qq, $1, $2))
        }
    } else if (del_reg.test(msg)) {
        let $ = msg.match(del_reg)
        let $1 = decrypt($[1])
        let $2 = decrypt($[2])

        if (! await db.has(gid, $1, $2)) {
            await api.GroupMessage(gid, del_w(qq, $1, $2))
        } else if (await db.del(gid, $1, $2)) {
            await api.GroupMessage(gid, del_s(qq, $1, $2))
        } else {
            await api.GroupMessage(gid, del_e(qq, $1, $2))
        }
    } else if (get_reg.test(msg)) {
        let $ = msg.match(get_reg)
        let $2 = decrypt($[1])
        let $1 = decrypt($[2])
        let r = await db.get(gid, $1, $2)

        if (r === undefined) {
            await api.GroupMessage(gid, get_e(qq, $1, $2))
        } else {
            await api.GroupMessage(gid, get_s(qq, $1, $2, r))
        }
    } else if (list_reg.test(msg)) {
        let $ = msg.match(list_reg)
        let $1 = decrypt($[1])
        let r = await db.list(gid, $1)

        if (r.length == 0) {
            await api.GroupMessage(gid, list_e(qq, $1))
        } else {
            await api.GroupMessage(gid, list_s(qq, $1, r))
        }
    } else {
        let r = await db.rand(gid, data.content)
        if (r !== undefined) {
            await api.GroupMessage(gid, r)
        }
    }
})

app.listen(server_port, local_port)
<commit_msg>Add new regex rule<commit_after>import {Api, Client} from 'node-coolq'
import {DB} from './db.js'

let db = new DB(__dirname + '/bot.db')

let app = new Client()
let api = new Api(app)
let code = api.getCode()
let at = q => code.getAt(q)

let server_port = 11235
let local_port = 11666

let CQCode_reg = /\[[^\[]*\]/g
let add_reg = /^[/!]add ([^=]+)=([\S\s]+)$/
let del_reg = /^[/!]del ([^=]+)=([\S\s]+)$/
let get_reg = /^[/!]get#(\d+) ([^=]+)$/
let list_reg = /^[/!]list ([\S\s]+)$/

let encrypt = str =>
    str.replace(CQCode_reg, str =>
        str.replace('=', '~')
    )
let decrypt = str =>
    str.replace(CQCode_reg, str =>
        str.replace('~', '=')
    )

const SHOW_MAX_RULES = 20
const MSG_HELP = `QBot 使用帮助：
/add key=value，为关键词 key 添加一条自动回复规则 value
/del key=value，为关键词 key 闪出一条自动回复规则 value
/list key，列出关键词 key 对应的规则（至多列出 ${SHOW_MAX_RULES} 条）
/get#i key，列出关键词 key 对应的第 i 条规则（i 是从 0 开始的数字）
/help 获取使用帮助`

let add_s = (q, k, v) =>
    `${at(q)} 添加成功，你说“${k}”，我说“${v}”`
let add_w = (q, k, v) =>
    `${at(q)} 规则 “${k}” => “${v}” 已经存在`
let add_e = (q, k, v) =>
    `${at(q)} 规则 “${k}” => “${v}” 添加失败，请重试`

let del_s = (q, k, v) =>
    `${at(q)} 规则 “${k}” => “${v}” 删除成功`
let del_w = (q, k, v) =>
    `${at(q)} 规则 “${k}” => “${v}” 并不存在`
let del_e = (q, k, v) =>
    `${at(q)} 规则 “${k}” => “${v}” 删除失败，请重试`

let get_s = (q, k, i, v) =>
    `${at(q)} 关键词 “${k}” 的第 ${i} 条规则是 “${v}”`
let get_e = (q, k, i) =>
    `${at(q)} 关键词 “${k}” 可能并不存在第 ${i} 条规则`

let list_e = (q, k) =>
    `${at(q)} 关键词 “${k}” 可能没有绑定任何规则`
let list_s = (q, k, r) => {
    let s = `${at(q)} 关键词 “${k}” 共有 ${r.length} 条规则：`
    let len = Math.min(SHOW_MAX_RULES, r.length)
    if (len !== r.length) {
        s = `${s}\n（只显示前 ${len} 条规则）`
    }
    for (let i = 0; i < len; i++) {
        s = `${s}\n#${i} ${r[i].value}`
    }
    return s
}

app.on('GroupMessage', async data => {
    let gid = data.group
    let qq = data.fromQQ
    let msg = encrypt(data.content)

    if (qq == 1000000) {
        return null //system message
    }

    if (data.content === '/help') {
        await api.GroupMessage(gid, MSG_HELP)
    } else if (add_reg.test(msg)) {
        let $ = msg.match(add_reg)
        let $1 = decrypt($[1])
        let $2 = decrypt($[2])

        if (await db.has(gid, $1, $2)) {
            await api.GroupMessage(gid, add_w(qq, $1, $2))
        } else if (await db.add(gid, $1, $2)) {
            await api.GroupMessage(gid, add_s(qq, $1, $2))
        } else {
            await api.GroupMessage(gid, add_e(qq, $1, $2))
        }
    } else if (del_reg.test(msg)) {
        let $ = msg.match(del_reg)
        let $1 = decrypt($[1])
        let $2 = decrypt($[2])

        if (! await db.has(gid, $1, $2)) {
            await api.GroupMessage(gid, del_w(qq, $1, $2))
        } else if (await db.del(gid, $1, $2)) {
            await api.GroupMessage(gid, del_s(qq, $1, $2))
        } else {
            await api.GroupMessage(gid, del_e(qq, $1, $2))
        }
    } else if (get_reg.test(msg)) {
        let $ = msg.match(get_reg)
        let $2 = decrypt($[1])
        let $1 = decrypt($[2])
        let r = await db.get(gid, $1, $2)

        if (r === undefined) {
            await api.GroupMessage(gid, get_e(qq, $1, $2))
        } else {
            await api.GroupMessage(gid, get_s(qq, $1, $2, r))
        }
    } else if (list_reg.test(msg)) {
        let $ = msg.match(list_reg)
        let $1 = decrypt($[1])
        let r = await db.list(gid, $1)

        if (r.length == 0) {
            await api.GroupMessage(gid, list_e(qq, $1))
        } else {
            await api.GroupMessage(gid, list_s(qq, $1, r))
        }
    } else {
        let r = await db.rand(gid, data.content)
        if (r !== undefined) {
            await api.GroupMessage(gid, r)
        }
    }
})

app.listen(server_port, local_port)
<|endoftext|>


<commit_before>import { h, Component } from 'preact';

const routers = [];

export function route(url) {
	if (history) {
		history.pushState(null, null, url);
	}
	routeTo(url);
}

function routeTo(url) {
	routers.forEach( router => router.routeTo(url) );
}

function getCurrentUrl() {
	return `${location.pathname || ''}${location.search || ''}`;
}

if (typeof addEventListener==='function') {
	addEventListener('popstate', () => routeTo(getCurrentUrl()));
}

function handleLinkClick(e) {
	route(this.getAttribute('href'));
	if (e.stopImmediatePropagation) e.stopImmediatePropagation();
	e.stopPropagation();
	e.preventDefault();
	return false;
}

export const Link = ({ children, ...props }) => (
	{ children }
);

export class Router extends Component {
	getInitialState() {
		return { url: getCurrentUrl() };
	}

	routeTo(url) {
		this.setState({ url });
	}

	componentWillMount() {
		routers.push(this);
	}

	componentWillUnmount() {
		routers.splice(routers.indexOf(this), 1);
	}

	render({ children, onChange }, { url }) {
		let active = children.filter( ({ attributes }) => {
			let path = attributes.path,
				matches = exec(url, path);
			if (matches) {
				attributes.url = url;
				attributes.matches = matches;
				return true;
			}
		});
		let previous = this.previousUrl;
		if (url!==previous) {
			this.previousUrl = url;
			if (typeof onChange==='function') {
				onChange({
					router: this,
					url,
					previous,
					active,
					current: active[0]
				});
			}
		}
		return <router style="position:static;display:inline;">{ active }</router>;
	}
}

export const Route = ({ component:RoutedComponent, url, matches }) => (
	<RoutedComponent {...{url, matches}} />
);

/*
export class Route extends Component {
	render({ component:RoutedComponent, url, matches }) {
		return <RoutedComponent { ...{url, matches} } />;
	}
}
*/

function exec(url, route) {
	let reg = /(?:\?([^#]*))?(#.*)?$/,
		c = url.match(reg),
		matches = {};
	if (c && c[1]) {
		let p = c[1].split('&');
		for (let i=0; i<p.length; i++) {
			let r = p[i].split('=');
			matches[decodeURIComponent(r[0])] = decodeURIComponent(r.slice(1).join('='));
		}
	}
	url = segmentize(url.replace(reg, ''));
	route = segmentize(route);
	let max = Math.max(url.length, route.length);
	for (let i=0; i<max; i++) {
		if (route[i] && route[i].charAt(0)===':') {
			matches[route[i].substring(1)] = decodeURIComponent(url[i] || '');
		}
		else {
			if (route[i]!==url[i]) {
				return false;
			}
		}
	}
	return matches;
}

Router.route = route;
Router.Route = Route;
Router.Link = Link;
export default Router;

let segmentize = url => strip(url).split('/');

let strip = url => url.replace(/(^\/+|\/+$)/g, '');
<commit_msg>copy route segment matches onto props without overwriting anything already there<commit_after>import { h, Component } from 'preact';

const routers = [];

export function route(url) {
	if (history) {
		history.pushState(null, null, url);
	}
	routeTo(url);
}

function routeTo(url) {
	routers.forEach( router => router.routeTo(url) );
}

function getCurrentUrl() {
	return `${location.pathname || ''}${location.search || ''}`;
}

if (typeof addEventListener==='function') {
	addEventListener('popstate', () => routeTo(getCurrentUrl()));
}

function handleLinkClick(e) {
	route(this.getAttribute('href'));
	if (e.stopImmediatePropagation) e.stopImmediatePropagation();
	e.stopPropagation();
	e.preventDefault();
	return false;
}

export const Link = ({ children, ...props }) => (
	{ children }
);

export class Router extends Component {
	getInitialState() {
		return { url: getCurrentUrl() };
	}

	routeTo(url) {
		this.setState({ url });
	}

	componentWillMount() {
		routers.push(this);
	}

	componentWillUnmount() {
		routers.splice(routers.indexOf(this), 1);
	}

	render({ children, onChange }, { url }) {
		let active = children.filter( ({ attributes }) => {
			let path = attributes.path,
				matches = exec(url, path);
			if (matches) {
				attributes.url = url;
				attributes.matches = matches;
				// copy matches onto props without overwriting anything already there
				for (let i in matches) {
					if (matches.hasOwnProperty(i) && !attributes.hasOwnProperty(i)) {
						attributes[i] = matches[i];
					}
				}
				return true;
			}
		});
		let previous = this.previousUrl;
		if (url!==previous) {
			this.previousUrl = url;
			if (typeof onChange==='function') {
				onChange({
					router: this,
					url,
					previous,
					active,
					current: active[0]
				});
			}
		}
		return <router style="position:static;display:inline;">{ active }</router>;
	}
}

export const Route = ({ component:RoutedComponent, url, matches }) => (
	<RoutedComponent {...{url, matches}} />
);

/*
export class Route extends Component {
	render({ component:RoutedComponent, url, matches }) {
		return <RoutedComponent { ...{url, matches} } />;
	}
}
*/

function exec(url, route) {
	let reg = /(?:\?([^#]*))?(#.*)?$/,
		c = url.match(reg),
		matches = {};
	if (c && c[1]) {
		let p = c[1].split('&');
		for (let i=0; i<p.length; i++) {
			let r = p[i].split('=');
			matches[decodeURIComponent(r[0])] = decodeURIComponent(r.slice(1).join('='));
		}
	}
	url = segmentize(url.replace(reg, ''));
	route = segmentize(route);
	let max = Math.max(url.length, route.length);
	for (let i=0; i<max; i++) {
		if (route[i] && route[i].charAt(0)===':') {
			matches[route[i].substring(1)] = decodeURIComponent(url[i] || '');
		}
		else {
			if (route[i]!==url[i]) {
				return false;
			}
		}
	}
	return matches;
}

Router.route = route;
Router.Route = Route;
Router.Link = Link;
export default Router;

let segmentize = url => strip(url).split('/');

let strip = url => url.replace(/(^\/+|\/+$)/g, '');
<|endoftext|>


<commit_before>import Stream from 'stream';
import util from 'util';
import crypto from 'crypto';
import path from 'path';
import fs from 'fs';

/**
 * is stream
 */
export function isStream(stream){
  return !!stream && stream instanceof Stream;
}

/**
 * is buffer
 */
export const isBuffer = Buffer.isBuffer;

/**
 * is array
 */
export const isArray = Array.isArray;

/**
 * is function
 */
export function isFunction(obj) {
  return typeof obj === 'function';
}
/**
 * is object
 */
export function isObject(obj){
  return Object.prototype.toString.call(obj) === '[object Object]';
}
/**
 * is string
 */
export function isString(obj){
  return Object.prototype.toString.call(obj) === '[object String]';
}
/**
 * is regexp
 */
export const isRegExp = util.isRegExp;

/**
 * check path is exist
 */
export function isExist(dir) {
  dir = path.normalize(dir);
  if(fs.accessSync){
    try{
      fs.accessSync(dir, fs.R_OK);
      return true;
    }catch(e){
      return false;
    }
  }
  return fs.existsSync(dir);
}

/**
 * check filepath is file
 */
export function isFile(filePath){
  if(!isExist(filePath)){
    return false;
  }
  let stat = fs.statSync(filePath);
  return stat.isFile();
}

/**
 * check path is directory
 */
export function isDirectory(filePath){
  if(!isExist(filePath)){
    return false;
  }
  let stat = fs.statSync(filePath);
  return stat.isDirectory();
}
/**
 * extend
 */
export function extend(target, source){
  let src, copy;
  if(!target){
    target = isArray(source) ? [] : {};
  }
  if(!source){
    return target;
  }
  for(let key in source){
    src = target[key];
    copy = source[key];
    if(src && src === copy){
      continue;
    }
    if(isObject(copy)){
      target[key] = extend(src && isObject(src) ? src : {}, copy);
    }else if(isArray(copy)){
      target[key] = extend([], copy);
    }else{
      target[key] = copy;
    }
  }
  return target;
}

/**
 * get path files
 */
export function getFiles(dir, prefix = ''){
  if(!isExist(dir)){
    return [];
  }
  if(isFile(dir)){
    return [dir];
  }
  let files = fs.readdirSync(dir);
  let result = [];
  files.forEach(item => {
    let stat = fs.statSync(path.join(dir, item));
    if (stat.isFile()) {
      result.push(path.join(prefix, item));
    }else if(stat.isDirectory()){
      let cFiles = getFiles(path.join(dir, item), path.join(prefix, item));
      result = result.concat(cFiles);
    }
  });
  return result;
}

/**
 * make callback to promise
 */
export function promisify(fn, receiver) {
  return (...args) => {
    return new Promise((resolve, reject) => {
      fn.apply(receiver, [...args, (err, res) => {
        return err ? reject(err) : resolve(res);
      }]);
    });
  };
}

/**
 * defer
 */
export function defer(){
  let deferred = {};
  deferred.promise = new Promise((resolve, reject) => {
    deferred.resolve = resolve;
    deferred.reject = reject;
  });
  return deferred;
}

/**
 * md5
 */
export function md5(str){
  return crypto.createHash('md5').update(str + '', 'utf8').digest('hex');
}

/**
 * async replace content
 */
export async function asyncReplace(content = '', replace, callback){
  let match = [];
  content.replace(replace, (...args) => {
    match.push(args);
  });
  if(!match.length){
    return content;
  }
  let promises = match.map(args => {
    return callback(...args);
  });
  let data = await Promise.all(promises);
  let result = '', prevIndex = 0;
  match.forEach((item, idx) => {
    let index = content.indexOf(item[0], prevIndex);
    result += content.substring(prevIndex, index) + data[idx];
    prevIndex = index + item[0].length;
  });
  result += content.substr(prevIndex);
  return result;
}
/**
 * check if is remote url
 */
export function isRemoteUrl(url){
  if(!url){
    return false;
  }
  url = url.toLowerCase();
  return url.indexOf('http://') === 0 || url.indexOf('https://') === 0 || url.indexOf('//') === 0;
}
/**
 * change mode
 */
export function chmod(dir, mode = '0777'){
  if(!isExist(dir)){
    return false;
  }
  try{
    fs.chmodSync(dir, mode);
    return true;
  }catch(e){
    return false;
  }
}
/**
 * make dir
 */
export function mkdir(dir, mode = '0777') {
  if (isExist(dir)) {
    return chmod(dir, mode);
  }
  let pp = path.dirname(dir);
  if (isExist(pp)) {
    try{
      fs.mkdirSync(dir, mode);
      return true;
    }catch(e){
      return false;
    }
  }
  if(mkdir(pp, mode)){
    return mkdir(dir, mode);
  }else{
    return false;
  }
}

/**
 * resource regexp
 */
export const ResourceRegExp = {
  background: /url\s*\(\s*([\'\"]?)([\w\-\/\.\@]+\.(?:png|jpg|gif|jpeg|ico|cur|webp))(?:\?[^\?\'\"\)\s]*)?\1\s*\)/ig,
  font: /url\s*\(\s*([\'\"]?)([^\'\"\?]+\.(?:eot|woff|woff2|ttf|svg))([^\s\)\'\"]*)\1\s*\)/ig,
  filter: /src\s*=\s*([\'\"])?([^\'\"]+\.(?:png|jpg|gif|jpeg|ico|cur|webp))(?:\?[^\?\'\"\)\s]*)?\1\s*/ig,
  cdn: /\{\s*([\'\"]?)cdn\1\s*\:\s*([\'\"])([\w\/\-\.]+)\2\s*\}\.cdn/gi,
  inline: /\{\s*([\'\"]?)inline\1\s*\:\s*([\'\"])([\w\/\-\.]+)\2\s*\}\.inline/gi
}<commit_msg>define BackgroundURLMapper<commit_after>import Stream from 'stream';
import util from 'util';
import crypto from 'crypto';
import path from 'path';
import fs from 'fs';

/**
 * is stream
 */
export function isStream(stream) {
  return !!stream && stream instanceof Stream;
}

/**
 * is buffer
 */
export const isBuffer = Buffer.isBuffer;

/**
 * is array
 */
export const isArray = Array.isArray;

/**
 * is function
 */
export function isFunction(obj) {
  return typeof obj === 'function';
}
/**
 * is object
 */
export function isObject(obj) {
  return Object.prototype.toString.call(obj) === '[object Object]';
}
/**
 * is string
 */
export function isString(obj) {
  return Object.prototype.toString.call(obj) === '[object String]';
}
/**
 * is regexp
 */
export const isRegExp = util.isRegExp;

/**
 * check path is exist
 */
export function isExist(dir) {
  dir = path.normalize(dir);
  if (fs.accessSync) {
    try {
      fs.accessSync(dir, fs.R_OK);
      return true;
    } catch (e) {
      return false;
    }
  }
  return fs.existsSync(dir);
}

/**
 * check filepath is file
 */
export function isFile(filePath) {
  if (!isExist(filePath)) {
    return false;
  }
  let stat = fs.statSync(filePath);
  return stat.isFile();
}

/**
 * check path is directory
 */
export function isDirectory(filePath) {
  if (!isExist(filePath)) {
    return false;
  }
  let stat = fs.statSync(filePath);
  return stat.isDirectory();
}
/**
 * extend
 */
export function extend(target, source) {
  let src, copy;
  if (!target) {
    target = isArray(source) ? [] : {};
  }
  if (!source) {
    return target;
  }
  for (let key in source) {
    src = target[key];
    copy = source[key];
    if (src && src === copy) {
      continue;
    }
    if (isObject(copy)) {
      target[key] = extend(src && isObject(src) ? src : {}, copy);
    } else if (isArray(copy)) {
      target[key] = extend([], copy);
    } else {
      target[key] = copy;
    }
  }
  return target;
}

/**
 * get path files
 */
export function getFiles(dir, prefix = '') {
  if (!isExist(dir)) {
    return [];
  }
  if (isFile(dir)) {
    return [dir];
  }
  let files = fs.readdirSync(dir);
  let result = [];
  files.forEach(item => {
    let stat = fs.statSync(path.join(dir, item));
    if (stat.isFile()) {
      result.push(path.join(prefix, item));
    } else if (stat.isDirectory()) {
      let cFiles = getFiles(path.join(dir, item), path.join(prefix, item));
      result = result.concat(cFiles);
    }
  });
  return result;
}

/**
 * make callback to promise
 */
export function promisify(fn, receiver) {
  return (...args) => {
    return new Promise((resolve, reject) => {
      fn.apply(receiver, [...args, (err, res) => {
        return err ? reject(err) : resolve(res);
      }]);
    });
  };
}

/**
 * defer
 */
export function defer() {
  let deferred = {};
  deferred.promise = new Promise((resolve, reject) => {
    deferred.resolve = resolve;
    deferred.reject = reject;
  });
  return deferred;
}

/**
 * md5
 */
export function md5(str) {
  return crypto.createHash('md5').update(str + '', 'utf8').digest('hex');
}

/**
 * async replace content
 */
export async function asyncReplace(content = '', replace, callback) {
  let match = [];
  content.replace(replace, (...args) => {
    match.push(args);
  });
  if (!match.length) {
    return content;
  }
  let promises = match.map(args => {
    return callback(...args);
  });
  let data = await Promise.all(promises);
  let result = '', prevIndex = 0;
  match.forEach((item, idx) => {
    let index = content.indexOf(item[0], prevIndex);
    result += content.substring(prevIndex, index) + data[idx];
    prevIndex = index + item[0].length;
  });
  result += content.substr(prevIndex);
  return result;
}
/**
 * check if is remote url
 */
export function isRemoteUrl(url) {
  if (!url) {
    return false;
  }
  url = url.toLowerCase();
  return url.indexOf('http://') === 0 || url.indexOf('https://') === 0 || url.indexOf('//') === 0;
}
/**
 * change mode
 */
export function chmod(dir, mode = '0777') {
  if (!isExist(dir)) {
    return false;
  }
  try {
    fs.chmodSync(dir, mode);
    return true;
  } catch (e) {
    return false;
  }
}
/**
 * make dir
 */
export function mkdir(dir, mode = '0777') {
  if (isExist(dir)) {
    return chmod(dir, mode);
  }
  let pp = path.dirname(dir);
  if (isExist(pp)) {
    try {
      fs.mkdirSync(dir, mode);
      return true;
    } catch (e) {
      return false;
    }
  }
  if (mkdir(pp, mode)) {
    return mkdir(dir, mode);
  } else {
    return false;
  }
}

/**
 * resource regexp
 */
export const ResourceRegExp = {
  background: /url\s*\(\s*([\'\"]?)([\w\-\/\.\@]+\.(?:png|jpg|gif|jpeg|ico|cur|webp))(?:\?[^\?\'\"\)\s]*)?\1\s*\)/ig,
  font: /url\s*\(\s*([\'\"]?)([^\'\"\?]+\.(?:eot|woff|woff2|ttf|svg))([^\s\)\'\"]*)\1\s*\)/ig,
  filter: /src\s*=\s*([\'\"])?([^\'\"]+\.(?:png|jpg|gif|jpeg|ico|cur|webp))(?:\?[^\?\'\"\)\s]*)?\1\s*/ig,
  cdn: /\{\s*([\'\"]?)cdn\1\s*\:\s*([\'\"])([\w\/\-\.]+)\2\s*\}\.cdn/gi,
  inline: /\{\s*([\'\"]?)inline\1\s*\:\s*([\'\"])([\w\/\-\.]+)\2\s*\}\.inline/gi
}

/**
 * background url mapper
 * construct from a string
 * can modify url for further changes
 */
export class BackgroundURLMapper {
  constructor(str) {
    this.orginalStr = str;
    this.reg.lastIndex = 0;
    let matches = ResourceRegExp.background.exec(str);
    this.url = matches && matches.length > 2 && matches[2];
    if (!this.url) {
      throw new TypeError("URLMapper: invalid url");
    }
    this.originalUrl = this.url;
    let pivot = str.indexOf(this.url);
    this.prev = str.slice(0, pivot);
    this.next = str.slice(pivot + this.url.length);
    this.type = /(png|jpg|gif|jpeg|ico|cur|webp)$/.exec(this.url)[1];
  }
  reset() {
    this.url = this.originalUrl;
  }
  valueOf() {
    return this.prev + this.url + this.next;
  }
  isRemoteUrl() {
    return isRemoteUrl(this.url);
  }
};<|endoftext|>


<commit_before>export { default as connectRouter } from './components/connectRouter';
export { default as connectRouteTo } from './components/connectRouteTo';
export { default as Router } from './components/Router';
export { default as RouterContainer } from './components/RouterContainer';

export { default as createRouterMiddleware } from './middleware/createRouterMiddleware';

export { default as mapUrlToRoute } from './utils/mapUrlToRoute';
export { default as matchRoutes } from './utils/matchRoutes';
export { default as routeKeyToRouteValue } from './utils/routeKeyToRouteValue';

export { default as RouterActions } from './Actions';
export * from './Actions';

export { default as RouterActionTypes } from './ActionTypes';
export * from './ActionTypes';

export { default as routerReducer } from './reducer';
<commit_msg>export findRoutes<commit_after>export { default as connectRouter } from './components/connectRouter';
export { default as connectRouteTo } from './components/connectRouteTo';
export { default as Router } from './components/Router';
export { default as RouterContainer } from './components/RouterContainer';

export { default as createRouterMiddleware } from './middleware/createRouterMiddleware';

export { default as mapUrlToRoute } from './utils/mapUrlToRoute';
export { default as matchRoutes } from './utils/matchRoutes';
export { default as routeKeyToRouteValue } from './utils/routeKeyToRouteValue';
export { default as findRoutes } from './utils/findRoutes';

export { default as RouterActions } from './Actions';
export * from './Actions';

export { default as RouterActionTypes } from './ActionTypes';
export * from './ActionTypes';

export { default as routerReducer } from './reducer';
<|endoftext|>


<commit_before>'use strict';

const aws = require('aws-sdk');
const rds = new aws.RDS();
const DBInstanceIdentifier = process.env.AWS_DB_INSTANCE_IDENTIFIER;

const plpr = require('plpr');
const logLinePrefix = process.env.PSQL_LOG_LINE_PREFIX;

const backend = process.env.BACKEND_SERVICE;

const fs = require('fs');

exports.handler = (event, context, callback) => {
  dataReceiver().then(data => {
    if (typeof logLinePrefix === 'undefined') throw new Error('You have to set PostgreSQL log_line_prefix in PSQL_LOG_LINE_PREFIX');

    const logs = plpr(data, logLinePrefix);
    console.log('Insert data length: ' + logs.length);

    var inserter = null;
    switch (backend) {
      case 'es':
        inserter = require('./elasticsearch');
        break;
      case 'bq':
        inserter = require('./bq');
        break;
      default:
        throw new Error('You have to export Backend Service "es" (Elasticsearch) or "bq" (BigQuery) to "BACKEND_SERVICE"');
        break;
    }

    inserter(logs, DBInstanceIdentifier).then(() => {
      return callback(null, 'success');
    }).catch(error => {
      return callback(error, 'error');
    });
  }).catch(error => {
    return callback(error, 'error');
  });
}

function dataReceiver() {
  const filepath = process.env.LOCAL_LOGFILE_PATH;
  if (typeof filepath === "undefined") {
    return downloadLogFile();
  }
  const data = fs.readFileSync(filepath, 'utf-8');
  return Promise.resolve(data);
}

async function downloadLogFile() {
  let params = {
    DBInstanceIdentifier: DBInstanceIdentifier,
  };
  if (typeof DBInstanceIdentifier === 'undefined') throw new Error('You have to export AWS RDS DB instance name to "AWS_DB_INSTANCE_IDENTIFIER"');

  try {
    const describeDBLogFilesPromise = rds.describeDBLogFiles(params).promise();
    const data = await describeDBLogFilesPromise;
    let obj = JSON.parse(JSON.stringify(data))['DescribeDBLogFiles'];
    const files = obj.map((value, index, array) => {
      return value['LogFileName'];
    });

    const filename = process.env.AWS_DB_LOGFILE_NAME;
    params['LogFileName'] = filename;
    if (typeof filename === 'undefined') {
      params['LogFileName'] = files[files.length-2];
    }

    console.log('Downloading: ' + params['LogFileName'] + '...');
    let next = true;
    let marker = '0';
    let raw = '';
    while(next) {
      params['Marker'] = marker;
      const downloadLogFilePortionPromise = rds.downloadDBLogFilePortion(params).promise();
      const resp = await downloadLogFilePortionPromise;

      obj = JSON.parse(JSON.stringify(resp))
      next = obj['AdditionalDataPending'];
      marker = obj['Marker'];
      raw = raw + obj['LogFileData'];
    }
    return raw;
  } catch(error) {
    throw error;
  }
}
<commit_msg>Update to normalize queries<commit_after>'use strict';

const aws = require('aws-sdk');
const rds = new aws.RDS();
const DBInstanceIdentifier = process.env.AWS_DB_INSTANCE_IDENTIFIER;

const plpr = require('plpr');
const logLinePrefix = process.env.PSQL_LOG_LINE_PREFIX;

const backend = process.env.BACKEND_SERVICE;

const fs = require('fs');
const pgn = require('pg-query-normalizer');

exports.handler = (event, context, callback) => {
  dataReceiver().then(data => {
    if (typeof logLinePrefix === 'undefined') throw new Error('You have to set PostgreSQL log_line_prefix in PSQL_LOG_LINE_PREFIX');

    const logs = plpr(data, logLinePrefix);
    console.log('Insert data length: ' + logs.length);

    var inserter = null;
    switch (backend) {
      case 'es':
        inserter = require('./elasticsearch');
        break;
      case 'bq':
        inserter = require('./bq');
        break;
      default:
        throw new Error('You have to export Backend Service "es" (Elasticsearch) or "bq" (BigQuery) to "BACKEND_SERVICE"');
        break;
    }

    const normalized = normalizeQueries(logs);
    inserter(normalized, DBInstanceIdentifier).then(() => {
      return callback(null, 'success');
    }).catch(error => {
      return callback(error, 'error');
    });
  }).catch(error => {
    return callback(error, 'error');
  });
}

function dataReceiver() {
  const filepath = process.env.LOCAL_LOGFILE_PATH;
  if (typeof filepath === "undefined") {
    return downloadLogFile();
  }
  const data = fs.readFileSync(filepath, 'utf-8');
  return Promise.resolve(data);
}

async function downloadLogFile() {
  let params = {
    DBInstanceIdentifier: DBInstanceIdentifier,
  };
  if (typeof DBInstanceIdentifier === 'undefined') throw new Error('You have to export AWS RDS DB instance name to "AWS_DB_INSTANCE_IDENTIFIER"');

  try {
    const describeDBLogFilesPromise = rds.describeDBLogFiles(params).promise();
    const data = await describeDBLogFilesPromise;
    let obj = JSON.parse(JSON.stringify(data))['DescribeDBLogFiles'];
    const files = obj.map((value, index, array) => {
      return value['LogFileName'];
    });

    const filename = process.env.AWS_DB_LOGFILE_NAME;
    params['LogFileName'] = filename;
    if (typeof filename === 'undefined') {
      params['LogFileName'] = files[files.length-2];
    }

    console.log('Downloading: ' + params['LogFileName'] + '...');
    let next = true;
    let marker = '0';
    let raw = '';
    while(next) {
      params['Marker'] = marker;
      const downloadLogFilePortionPromise = rds.downloadDBLogFilePortion(params).promise();
      const resp = await downloadLogFilePortionPromise;

      obj = JSON.parse(JSON.stringify(resp))
      next = obj['AdditionalDataPending'];
      marker = obj['Marker'];
      raw = raw + obj['LogFileData'];
    }
    return raw;
  } catch(error) {
    throw error;
  }
}

function normalizeQueries(logs) {
  for (let i = 0, len = logs.length; i < len; i++) {
    const normalized = pgn(logs[i]['query']);
    console.log(normalized)
    logs[i]['normalized_query'] = normalized;
    console.log(logs[i])
  }
  return logs
}
<|endoftext|>


<commit_before>/*******************************************************************************
 * Ceres
 *
 * @author       Isaac Suttell <isaac_suttell@playstation.sony.com>
 * @file         Framework constructor
 ******************************************************************************/

var path = require('path');
var winston = require('winston');
var Setup = require('./setup');

function Ceres() {
  this.startTime = process.hrtime();

  this.config = {};
}

Ceres.prototype.load = function(options) {
  // Bootstrap config
  this.config = Setup.config(options);

  if (this.config.env === 'production') {
    // Save uncaught exceptions to their own file in production
    winston.handleExceptions(new winston.transports.DailyRotateFile({
      filename: this.config.folders.logs + '/exceptions.log',
      tailable: true
    }));
  }

  // Setup logging app
  this.log = require('./setup/logs')(this.config);
  // Setup internal framework logger so we can tell if its an app or framework erro
  this.log._ceres = require('./setup/logs')(this.config, 'ceres');
  this.log._ceres.silly('Logging setup');

  // Bind the correct context
  if (this.config.folders.middleware) {
    this.config.middleware = Setup.directory(this.config.folders.middleware, {
      config: this.config
    });
  }

  /**
   * Base Rest Controller API
   *
   * @type {Object}
   */
  this.Rest = {

    /**
     * Base Controller
     *
     * @type {Object}
     */
    Controller: require(path.resolve(__dirname + '/rest/Controller')),

    /**
     * Base Model
     *
     * @type {Object}
     */
    Model: require(path.resolve(__dirname + '/rest/models/' + this.config.db.type))
  };

  this.Pipeline = require(path.resolve(__dirname + '/render/Pipeline'));

  // Bind the correct context
  this.Pipeline.create = this.Pipeline.create.bind(this);
  this.Rest.Controller.extend = this.Rest.Controller.extend.bind(this);
  this.Rest.Model.extend = this.Rest.Model.extend.bind(this);

  return new Promise(function(resolve, reject){
    this.log._ceres.silly('Setting up ' + this.config.db.type);
    var Database = require(__dirname + '/db')(this.config, this);
    return Database.then(function(db){
        this.Database = db;
        return this;
      }.bind(this))
      .then(resolve)
      .catch(function(err){
        this.log._ceres.error(err)
        reject(err);
      });
  }.bind(this));
}

module.exports = Ceres
<commit_msg>Fixed daily log rotate<commit_after>/*******************************************************************************
 * Ceres
 *
 * @author       Isaac Suttell <isaac_suttell@playstation.sony.com>
 * @file         Framework constructor
 ******************************************************************************/

var path = require('path');
var winston = require('winston');
var Setup = require('./setup');
var DailyRotateFile = require('winston-daily-rotate-file');

function Ceres() {
  this.startTime = process.hrtime();

  this.config = {};
}

Ceres.prototype.load = function(options) {
  // Bootstrap config
  this.config = Setup.config(options);

  if (this.config.env === 'production') {
    // Save uncaught exceptions to their own file in production
    winston.handleExceptions(new DailyRotateFile({
      filename: this.config.folders.logs + '/exceptions.log',
      tailable: true
    }));
  }

  // Setup logging app
  this.log = require('./setup/logs')(this.config);
  // Setup internal framework logger so we can tell if its an app or framework erro
  this.log._ceres = require('./setup/logs')(this.config, 'ceres');
  this.log._ceres.silly('Logging setup');

  // Bind the correct context
  if (this.config.folders.middleware) {
    this.config.middleware = Setup.directory(this.config.folders.middleware, {
      config: this.config
    });
  }

  /**
   * Base Rest Controller API
   *
   * @type {Object}
   */
  this.Rest = {

    /**
     * Base Controller
     *
     * @type {Object}
     */
    Controller: require(path.resolve(__dirname + '/rest/Controller')),

    /**
     * Base Model
     *
     * @type {Object}
     */
    Model: require(path.resolve(__dirname + '/rest/models/' + this.config.db.type))
  };

  this.Pipeline = require(path.resolve(__dirname + '/render/Pipeline'));

  // Bind the correct context
  this.Pipeline.create = this.Pipeline.create.bind(this);
  this.Rest.Controller.extend = this.Rest.Controller.extend.bind(this);
  this.Rest.Model.extend = this.Rest.Model.extend.bind(this);

  return new Promise(function(resolve, reject){
    this.log._ceres.silly('Setting up ' + this.config.db.type);
    var Database = require(__dirname + '/db')(this.config, this);
    return Database.then(function(db){
        this.Database = db;
        return this;
      }.bind(this))
      .then(resolve)
      .catch(function(err){
        this.log._ceres.error(err)
        reject(err);
      });
  }.bind(this));
}

module.exports = Ceres
<|endoftext|>


<commit_before>'use strict';

const childProcess = require('child-process-promise');
const express = require('express');
const path = require('path');
const fs = require('fs');

const configPath = path.resolve(process.cwd(), process.argv.slice().pop());
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
const app = express();

async function build (target, args) {
    const commands = args.commands;
    const options = {
        cwd: args.path,
    };

    console.log(`Deploying ${ target }...`);

    for (let i = 0; i < commands.length; i++) {
        const date = (new Date()).toLocaleDateString('sv-SE', {
            hour: 'numeric',
            minute: 'numeric',
            second: 'numeric',
        });

        console.log(`${ date } Running ${ commands[i] }...`);
        await childProcess.exec(commands[i], options);
        console.log('Done');
    }
}

app.post('/', (req, res) => {
    const target = req.query.target;

    if (config.repos[target]) {
        if (req.get('x-github-event') && req.get('x-github-event') === 'push') {
            build(target, config.repos[target]);
            res.status(200).send();
        } else {
            res.status(401).send();
        }
    } else {
        res.status(400).send();
    }
});

app.listen(config.port, config.host);
<commit_msg>Re-order dependencies for consistency<commit_after>'use strict';

const path = require('path');
const fs = require('fs');

const childProcess = require('child-process-promise');
const express = require('express');

const configPath = path.resolve(process.cwd(), process.argv.slice().pop());
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
const app = express();

async function build (target, args) {
    const commands = args.commands;
    const options = {
        cwd: args.path,
    };

    console.log(`Deploying ${ target }...`);

    for (let i = 0; i < commands.length; i++) {
        const date = (new Date()).toLocaleDateString('sv-SE', {
            hour: 'numeric',
            minute: 'numeric',
            second: 'numeric',
        });

        console.log(`${ date } Running ${ commands[i] }...`);
        await childProcess.exec(commands[i], options);
        console.log('Done');
    }
}

app.post('/', (req, res) => {
    const target = req.query.target;

    if (config.repos[target]) {
        if (req.get('x-github-event') && req.get('x-github-event') === 'push') {
            build(target, config.repos[target]);
            res.status(200).send();
        } else {
            res.status(401).send();
        }
    } else {
        res.status(400).send();
    }
});

app.listen(config.port, config.host);
<|endoftext|>