<commit_before>import _isObject from 'lodash/isObject'
import _isInteger from 'lodash/isInteger'
import _isFunction from 'lodash/isFunction'
import _isFinite from 'lodash/isFinite'
import _debounce from 'lodash/debounce'
import _throttle from 'lodash/throttle'
import _get from 'lodash/get'

export default (function () {
  const listeners = new Map();

  const SCROLL = 'scroll';

  function addEventListener (element, event, funcs, opt) {

    function fn (e) {
      let data;
      let target = e.target || e.srcElement;
      e = e || window.e;
      e.target = target

      if (e.type === SCROLL) {
        if (target === document) {
          data = { scrollTop: _get(document, 'body.scrollTop', 0), scrollLeft: _get(document, 'body.scrollLeft', 0) }
        } else {
          data = { scrollTop: _get(target, 'scrollTop', 0), scrollLeft: _get(target, 'scrollLeft', 0) }
        }
      }

      funcs.forEach(function (f) {
        f(e, data);
      })
    }

    if (_isObject(opt)) {
      if (_isInteger(opt.throttle) && _isFinite(opt.throttle) && opt.throttle > -1) {
        console.log('Set throttle as ' + opt.throttle);
        fn = _throttle(fn, opt.throttle);
      }

      if (_isInteger(opt.debounce) && _isFinite(opt.debounce) && opt.debounce > -1) {
        console.log('Set debounce as ' + opt.debounce);
        fn = _debounce(fn, opt.debounce);
      }
    }

    // https://github.com/wangpin34/vue-scroll/issues/1
    if (event === SCROLL) {
      if(element === document.body || element === document || element === window) {
        document.onscroll = fn;
      } else {
        if (element.addEventListener) {
          element.addEventListener(event, fn);
        } else {
          element.attachEvent('on' + event, fn);
        }
      }
    }

  }

  function bind (element, event, fn, opt) {

    let funcs, eventFuncs;

    if (!_isFunction(fn)) {
      throw new Error('Scroll handler is not a function');
    }

    if (!listeners.has(element)) {
      listeners.set(element, new Map());
    }

    funcs = listeners.get(element);

    if (!funcs.has(event)) {
      funcs.set(event, []);
    }

    eventFuncs = funcs.get(event);

    if (!eventFuncs.length) {
      addEventListener(element, event, eventFuncs, opt);
    }

    eventFuncs.push(fn);

  }

  function unbind (element, event, fn) {

    let funcs, eventFuncs;

    if (!_isFunction(fn)) {
      return;
    }

    if (!listeners.has(element)) {
      listeners.set(element, new Map());
    }

    funcs = listeners.get(element);

    if (!funcs.has(event)) {
      funcs.set(event, []);
    }

    eventFuncs = funcs.get(event);

    if (eventFuncs.indexOf(fn) > -1) {
      eventFuncs.splice(eventFuncs.indexOf(fn), 1)
      return true;
    }

    return false;

  }

  return {
    bind: bind,
    unbind: unbind
  }

})()
<commit_msg>fix: Should not reassign readonly property event.target<commit_after>import _isObject from 'lodash/isObject'
import _isInteger from 'lodash/isInteger'
import _isFunction from 'lodash/isFunction'
import _isFinite from 'lodash/isFinite'
import _debounce from 'lodash/debounce'
import _throttle from 'lodash/throttle'
import _get from 'lodash/get'

export default (function () {
  const listeners = new Map();

  const SCROLL = 'scroll';

  function addEventListener (element, event, funcs, opt) {

    function fn (e) {
      let data;
      let target = e.target || e.srcElement;
      e = e || window.e;

      if (e.type === SCROLL) {
        if (target === document) {
          data = { scrollTop: _get(document, 'body.scrollTop', 0), scrollLeft: _get(document, 'body.scrollLeft', 0) }
        } else {
          data = { scrollTop: _get(target, 'scrollTop', 0), scrollLeft: _get(target, 'scrollLeft', 0) }
        }
      }

      funcs.forEach(function (f) {
        f(e, data);
      })
    }

    if (_isObject(opt)) {
      if (_isInteger(opt.throttle) && _isFinite(opt.throttle) && opt.throttle > -1) {
        console.log('Set throttle as ' + opt.throttle);
        fn = _throttle(fn, opt.throttle);
      }

      if (_isInteger(opt.debounce) && _isFinite(opt.debounce) && opt.debounce > -1) {
        console.log('Set debounce as ' + opt.debounce);
        fn = _debounce(fn, opt.debounce);
      }
    }

    // https://github.com/wangpin34/vue-scroll/issues/1
    if (event === SCROLL) {
      if(element === document.body || element === document || element === window) {
        document.onscroll = fn;
      } else {
        if (element.addEventListener) {
          element.addEventListener(event, fn);
        } else {
          element.attachEvent('on' + event, fn);
        }
      }
    }

  }

  function bind (element, event, fn, opt) {

    let funcs, eventFuncs;

    if (!_isFunction(fn)) {
      throw new Error('Scroll handler is not a function');
    }

    if (!listeners.has(element)) {
      listeners.set(element, new Map());
    }

    funcs = listeners.get(element);

    if (!funcs.has(event)) {
      funcs.set(event, []);
    }

    eventFuncs = funcs.get(event);

    if (!eventFuncs.length) {
      addEventListener(element, event, eventFuncs, opt);
    }

    eventFuncs.push(fn);

  }

  function unbind (element, event, fn) {

    let funcs, eventFuncs;

    if (!_isFunction(fn)) {
      return;
    }

    if (!listeners.has(element)) {
      listeners.set(element, new Map());
    }

    funcs = listeners.get(element);

    if (!funcs.has(event)) {
      funcs.set(event, []);
    }

    eventFuncs = funcs.get(event);

    if (eventFuncs.indexOf(fn) > -1) {
      eventFuncs.splice(eventFuncs.indexOf(fn), 1)
      return true;
    }

    return false;

  }

  return {
    bind: bind,
    unbind: unbind
  }

})()
<|endoftext|>


<commit_before>// @flow
import React, { Component } from 'react';
import SVGInline from 'react-svg-inline';
import { observer } from 'mobx-react';
import { defineMessages, intlShape } from 'react-intl';
import classNames from 'classnames';
import Button from 'react-polymorph/lib/components/Button';
import SimpleButtonSkin from 'react-polymorph/lib/skins/simple/raw/ButtonSkin';
import SystemTimeErrorOverlay from './SystemTimeErrorOverlay';
import LoadingSpinner from '../widgets/LoadingSpinner';
import daedalusLogo from '../../assets/images/daedalus-logo-loading-grey.inline.svg';
import styles from './Loading.scss';
import type { ReactIntlMessage } from '../../types/i18nTypes';
import environment from '../../../../common/environment';

const REPORT_ISSUE_TIME_TRIGGER = 5 * 60; // 5 minutes
let connectingInterval = null;
let syncingInterval = null;

const messages = defineMessages({
  connecting: {
    id: 'loading.screen.connectingToNetworkMessage',
    defaultMessage: '!!!Connecting to network',
    description: 'Message "Connecting to network" on the loading screen.'
  },
  waitingForSyncToStart: {
    id: 'loading.screen.waitingForSyncToStart',
    defaultMessage: '!!!Connected - waiting for block syncing to start',
    description: 'Message "Connected - waiting for block syncing to start" on the loading screen.'
  },
  reconnecting: {
    id: 'loading.screen.reconnectingToNetworkMessage',
    defaultMessage: '!!!Network connection lost - reconnecting',
    description: 'Message "Network connection lost - reconnecting" on the loading screen.'
  },
  syncing: {
    id: 'loading.screen.syncingBlocksMessage',
    defaultMessage: '!!!Syncing blocks',
    description: 'Message "Syncing blocks" on the loading screen.'
  },
  reportConnectingIssueText: {
    id: 'loading.screen.reportIssue.connecting.text',
    defaultMessage: '!!!Having trouble connecting to network?',
    description: 'Report connecting issue text on the loading screen.'
  },
  reportSyncingIssueText: {
    id: 'loading.screen.reportIssue.syncing.text',
    defaultMessage: '!!!Having trouble syncing?',
    description: 'Report syncing issue text on the loading screen.'
  },
  reportIssueButtonLabel: {
    id: 'loading.screen.reportIssue.buttonLabel',
    defaultMessage: '!!!Report an issue',
    description: 'Report an issue button label on the loading .'
  },
});

type State = {
  connectingTime: number,
  syncingTime: number,
  syncPercentage: string,
};

type Props = {
  currencyIcon: string,
  apiIcon: string,
  isConnecting: boolean,
  hasBeenConnected: boolean,
  hasBlockSyncingStarted: boolean,
  isSyncing: boolean,
  syncPercentage: number,
  isLoadingDataForNextScreen: boolean,
  loadingDataForNextScreenMessage: ReactIntlMessage,
  hasLoadedCurrentLocale: boolean,
  hasLoadedCurrentTheme: boolean,
  localTimeDifference: number,
  isSystemTimeCorrect: boolean,
  currentLocale: string,
  handleReportIssue: Function,
  onProblemSolutionClick: Function,
};

@observer
export default class Loading extends Component<Props, State> {

  constructor() {
    super();
    this.state = {
      connectingTime: 0,
      syncingTime: 0,
      syncPercentage: '0',
    };
  }

  componentWillReceiveProps(nextProps: Props) {
    const trackConnecting = nextProps.isConnecting && !connectingInterval;
    const stopConnectingTracker = this.props.isConnecting
      && !nextProps.isConnecting
      && connectingInterval;

    const trackSyncing = nextProps.isSyncing && !syncingInterval;
    const stopSyncingTracker = this.props.isSyncing
      && !nextProps.isSyncing
      && syncingInterval;

    if (trackConnecting) {
      connectingInterval = setInterval(this.connectingTimer, 1000);
    } else if (stopConnectingTracker) {
      this.resetConnectingTimer();
    }

    if (trackSyncing) {
      syncingInterval = setInterval(this.syncingTimer, 1000);
    } else if (stopSyncingTracker) {
      this.resetSyncingTimer();
    }
  }

  static contextTypes = {
    intl: intlShape.isRequired,
  };

  render() {
    const { intl } = this.context;
    const {
      currencyIcon,
      apiIcon,
      isConnecting,
      isSyncing,
      syncPercentage,
      isLoadingDataForNextScreen,
      loadingDataForNextScreenMessage,
      hasBeenConnected,
      hasBlockSyncingStarted,
      hasLoadedCurrentLocale,
      hasLoadedCurrentTheme,
      localTimeDifference,
      isSystemTimeCorrect,
      currentLocale,
      handleReportIssue,
      onProblemSolutionClick,
    } = this.props;

    const { connectingTime, syncingTime } = this.state;

    const componentStyles = classNames([
      styles.component,
      hasLoadedCurrentTheme ? null : styles['is-loading-theme'],
      isConnecting ? styles['is-connecting'] : null,
      isSyncing ? styles['is-syncing'] : null,
    ]);
    const daedalusLogoStyles = classNames([
      styles.daedalusLogo,
      isConnecting ? styles.connectingLogo : styles.syncingLogo,
    ]);
    const currencyLogoStyles = classNames([
      styles[`${environment.API}-logo`],
      isConnecting ? styles.connectingLogo : styles.syncingLogo,
    ]);
    const apiLogoStyles = classNames([
      styles[`${environment.API}-apiLogo`],
      isConnecting ? styles.connectingLogo : styles.syncingLogo,
    ]);

    const daedalusLoadingLogo = daedalusLogo;
    const currencyLoadingLogo = currencyIcon;
    const apiLoadingLogo = apiIcon;

    let connectingMessage;
    if (hasBeenConnected) {
      connectingMessage = messages.reconnecting;
    } else {
      connectingMessage = (
        hasBlockSyncingStarted ? messages.waitingForSyncToStart : messages.connecting
      );
    }

    const canReportConnectingIssue = isConnecting && connectingTime >= REPORT_ISSUE_TIME_TRIGGER;
    const canReportSyncingIssue = isSyncing && syncingTime >= REPORT_ISSUE_TIME_TRIGGER;
    const showReportIssue = canReportConnectingIssue || canReportSyncingIssue;

    const buttonClasses = classNames([
      'primary',
      styles.reportIssueButton,
    ]);

    return (

        {showReportIssue && (

              {isConnecting ?
                intl.formatMessage(messages.reportConnectingIssueText) :
                intl.formatMessage(messages.reportSyncingIssueText)
              }

            <Button
              className={buttonClasses}
              label={intl.formatMessage(messages.reportIssueButtonLabel)}
              onClick={handleReportIssue}
              skin={<SimpleButtonSkin />}
            />

        )}

          <SVGInline svg={currencyLoadingLogo} className={currencyLogoStyles} />
          <SVGInline svg={daedalusLoadingLogo} className={daedalusLogoStyles} />
          <SVGInline svg={apiLoadingLogo} className={apiLogoStyles} />

        {hasLoadedCurrentLocale && (

            {isConnecting && (

                  {intl.formatMessage(connectingMessage)}

            )}
            {isSyncing && (

                  {intl.formatMessage(messages.syncing)} {syncPercentage.toFixed(2)}%

            )}
            {!isSyncing && !isConnecting && isLoadingDataForNextScreen && (

                  {intl.formatMessage(loadingDataForNextScreenMessage)}

                <LoadingSpinner />

            )}
            {!isSystemTimeCorrect && (
              <SystemTimeErrorOverlay
                localTimeDifference={localTimeDifference}
                currentLocale={currentLocale}
                onProblemSolutionClick={onProblemSolutionClick}
              />
            )}

        )}

    );
  }
  connectingTimer = () => {
    this.setState({ connectingTime: this.state.connectingTime + 1 });
  };

  syncingTimer = () => {
    const syncPercentage = this.props.syncPercentage.toFixed(2);

    if (syncPercentage === this.state.syncPercentage) {
      // syncPercentage not increased, increase syncing time
      this.setState({ syncingTime: this.state.syncingTime + 1 });
    } else {
      // reset syncingTime and set new max percentage
      this.setState({ syncingTime: 0, syncPercentage });
    }
  };

  resetConnectingTimer = () => {
    if (connectingInterval) {
      clearInterval(connectingInterval);
      connectingInterval = null;
    }
    this.setState({ connectingTime: 0 });
  };

  resetSyncingTimer = () => {
    if (syncingInterval) {
      clearInterval(syncingInterval);
      syncingInterval = null;
    }
    this.setState({ syncingTime: 0 });
  };
}
<commit_msg>[DDW-163] Code cleanup<commit_after>// @flow
import React, { Component } from 'react';
import SVGInline from 'react-svg-inline';
import { observer } from 'mobx-react';
import { defineMessages, intlShape } from 'react-intl';
import classNames from 'classnames';
import Button from 'react-polymorph/lib/components/Button';
import SimpleButtonSkin from 'react-polymorph/lib/skins/simple/raw/ButtonSkin';
import SystemTimeErrorOverlay from './SystemTimeErrorOverlay';
import LoadingSpinner from '../widgets/LoadingSpinner';
import daedalusLogo from '../../assets/images/daedalus-logo-loading-grey.inline.svg';
import styles from './Loading.scss';
import type { ReactIntlMessage } from '../../types/i18nTypes';
import environment from '../../../../common/environment';

const REPORT_ISSUE_TIME_TRIGGER = 5 * 60; // 5 minutes
let connectingInterval = null;
let syncingInterval = null;

const messages = defineMessages({
  connecting: {
    id: 'loading.screen.connectingToNetworkMessage',
    defaultMessage: '!!!Connecting to network',
    description: 'Message "Connecting to network" on the loading screen.'
  },
  waitingForSyncToStart: {
    id: 'loading.screen.waitingForSyncToStart',
    defaultMessage: '!!!Connected - waiting for block syncing to start',
    description: 'Message "Connected - waiting for block syncing to start" on the loading screen.'
  },
  reconnecting: {
    id: 'loading.screen.reconnectingToNetworkMessage',
    defaultMessage: '!!!Network connection lost - reconnecting',
    description: 'Message "Network connection lost - reconnecting" on the loading screen.'
  },
  syncing: {
    id: 'loading.screen.syncingBlocksMessage',
    defaultMessage: '!!!Syncing blocks',
    description: 'Message "Syncing blocks" on the loading screen.'
  },
  reportConnectingIssueText: {
    id: 'loading.screen.reportIssue.connecting.text',
    defaultMessage: '!!!Having trouble connecting to network?',
    description: 'Report connecting issue text on the loading screen.'
  },
  reportSyncingIssueText: {
    id: 'loading.screen.reportIssue.syncing.text',
    defaultMessage: '!!!Having trouble syncing?',
    description: 'Report syncing issue text on the loading screen.'
  },
  reportIssueButtonLabel: {
    id: 'loading.screen.reportIssue.buttonLabel',
    defaultMessage: '!!!Report an issue',
    description: 'Report an issue button label on the loading .'
  },
});

type State = {
  connectingTime: number,
  syncingTime: number,
  syncPercentage: string,
};

type Props = {
  currencyIcon: string,
  apiIcon: string,
  isConnecting: boolean,
  hasBeenConnected: boolean,
  hasBlockSyncingStarted: boolean,
  isSyncing: boolean,
  syncPercentage: number,
  isLoadingDataForNextScreen: boolean,
  loadingDataForNextScreenMessage: ReactIntlMessage,
  hasLoadedCurrentLocale: boolean,
  hasLoadedCurrentTheme: boolean,
  localTimeDifference: number,
  isSystemTimeCorrect: boolean,
  currentLocale: string,
  handleReportIssue: Function,
  onProblemSolutionClick: Function,
};

@observer
export default class Loading extends Component<Props, State> {

  constructor() {
    super();
    this.state = {
      connectingTime: 0,
      syncingTime: 0,
      syncPercentage: '0',
    };
  }

  componentWillReceiveProps(nextProps: Props) {
    const startConnectingTimer = nextProps.isConnecting && (connectingInterval === null);
    const stopConnectingTimer = (
      this.props.isConnecting &&
      !nextProps.isConnecting &&
      (connectingInterval !== null)
    );

    if (startConnectingTimer) {
      connectingInterval = setInterval(this.connectingTimer, 1000);
    } else if (stopConnectingTimer) {
      this.resetConnectingTimer();
    }

    const startSyncingTimer = nextProps.isSyncing && (syncingInterval === null);
    const stopSyncingTimer = (
      this.props.isSyncing &&
      !nextProps.isSyncing &&
      (syncingInterval !== null)
    );

    if (startSyncingTimer) {
      syncingInterval = setInterval(this.syncingTimer, 1000);
    } else if (stopSyncingTimer) {
      this.resetSyncingTimer();
    }
  }

  static contextTypes = {
    intl: intlShape.isRequired,
  };

  render() {
    const { intl } = this.context;
    const {
      currencyIcon,
      apiIcon,
      isConnecting,
      isSyncing,
      syncPercentage,
      isLoadingDataForNextScreen,
      loadingDataForNextScreenMessage,
      hasBeenConnected,
      hasBlockSyncingStarted,
      hasLoadedCurrentLocale,
      hasLoadedCurrentTheme,
      localTimeDifference,
      isSystemTimeCorrect,
      currentLocale,
      handleReportIssue,
      onProblemSolutionClick,
    } = this.props;

    const { connectingTime, syncingTime } = this.state;

    const componentStyles = classNames([
      styles.component,
      hasLoadedCurrentTheme ? null : styles['is-loading-theme'],
      isConnecting ? styles['is-connecting'] : null,
      isSyncing ? styles['is-syncing'] : null,
    ]);
    const daedalusLogoStyles = classNames([
      styles.daedalusLogo,
      isConnecting ? styles.connectingLogo : styles.syncingLogo,
    ]);
    const currencyLogoStyles = classNames([
      styles[`${environment.API}-logo`],
      isConnecting ? styles.connectingLogo : styles.syncingLogo,
    ]);
    const apiLogoStyles = classNames([
      styles[`${environment.API}-apiLogo`],
      isConnecting ? styles.connectingLogo : styles.syncingLogo,
    ]);

    const daedalusLoadingLogo = daedalusLogo;
    const currencyLoadingLogo = currencyIcon;
    const apiLoadingLogo = apiIcon;

    let connectingMessage;
    if (hasBeenConnected) {
      connectingMessage = messages.reconnecting;
    } else {
      connectingMessage = (
        hasBlockSyncingStarted ? messages.waitingForSyncToStart : messages.connecting
      );
    }

    const canReportConnectingIssue = isConnecting && connectingTime >= REPORT_ISSUE_TIME_TRIGGER;
    const canReportSyncingIssue = isSyncing && syncingTime >= REPORT_ISSUE_TIME_TRIGGER;
    const showReportIssue = canReportConnectingIssue || canReportSyncingIssue;

    const buttonClasses = classNames([
      'primary',
      styles.reportIssueButton,
    ]);

    return (

        {showReportIssue && (

              {isConnecting ?
                intl.formatMessage(messages.reportConnectingIssueText) :
                intl.formatMessage(messages.reportSyncingIssueText)
              }

            <Button
              className={buttonClasses}
              label={intl.formatMessage(messages.reportIssueButtonLabel)}
              onClick={handleReportIssue}
              skin={<SimpleButtonSkin />}
            />

        )}

          <SVGInline svg={currencyLoadingLogo} className={currencyLogoStyles} />
          <SVGInline svg={daedalusLoadingLogo} className={daedalusLogoStyles} />
          <SVGInline svg={apiLoadingLogo} className={apiLogoStyles} />

        {hasLoadedCurrentLocale && (

            {isConnecting && (

                  {intl.formatMessage(connectingMessage)}

            )}
            {isSyncing && (

                  {intl.formatMessage(messages.syncing)} {syncPercentage.toFixed(2)}%

            )}
            {!isSyncing && !isConnecting && isLoadingDataForNextScreen && (

                  {intl.formatMessage(loadingDataForNextScreenMessage)}

                <LoadingSpinner />

            )}
            {!isSystemTimeCorrect && (
              <SystemTimeErrorOverlay
                localTimeDifference={localTimeDifference}
                currentLocale={currentLocale}
                onProblemSolutionClick={onProblemSolutionClick}
              />
            )}

        )}

    );
  }

  connectingTimer = () => {
    this.setState({ connectingTime: this.state.connectingTime + 1 });
  };

  resetConnectingTimer = () => {
    if (connectingInterval !== null) {
      clearInterval(connectingInterval);
      connectingInterval = null;
    }
    this.setState({ connectingTime: 0 });
  };

  syncingTimer = () => {
    const syncPercentage = this.props.syncPercentage.toFixed(2);
    if (syncPercentage === this.state.syncPercentage) {
      // syncPercentage not increased, increase syncing time
      this.setState({ syncingTime: this.state.syncingTime + 1 });
    } else {
      // reset syncingTime and set new max percentage
      this.setState({ syncingTime: 0, syncPercentage });
    }
  };

  resetSyncingTimer = () => {
    if (syncingInterval !== null) {
      clearInterval(syncingInterval);
      syncingInterval = null;
    }
    this.setState({ syncingTime: 0 });
  };
}
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';

import Caption from './Caption';
import Navbar from './Navbar';
import Month from './Month';
import Day from './Day';

import * as Helpers from './Helpers';
import * as DateUtils from './DateUtils';
import * as LocaleUtils from './LocaleUtils';

import keys from './keys';
import DayPickerPropTypes from './PropTypes';
export default class DayPicker extends Component {
  static VERSION = '2.0.0-beta';

  static propTypes = {
    initialMonth: PropTypes.instanceOf(Date),
    numberOfMonths: PropTypes.number,
    selectedDays: PropTypes.func,
    disabledDays: PropTypes.func,

    modifiers: PropTypes.object,

    locale: PropTypes.string,
    localeUtils: DayPickerPropTypes.localeUtils,

    enableOutsideDays: PropTypes.bool,
    canChangeMonth: PropTypes.bool,
    reverseMonths: PropTypes.bool,
    fromMonth: PropTypes.instanceOf(Date),
    toMonth: PropTypes.instanceOf(Date),

    onKeyDown: PropTypes.func,
    onDayClick: PropTypes.func,
    onDayKeyDown: PropTypes.func,
    onDayMouseEnter: PropTypes.func,
    onDayMouseLeave: PropTypes.func,
    onDayTouchStart: PropTypes.func,
    onDayTouchEnd: PropTypes.func,
    onMonthChange: PropTypes.func,
    onCaptionClick: PropTypes.func,

    renderDay: PropTypes.func,

    captionElement: PropTypes.element,

    dir: PropTypes.string,
    tabIndex: PropTypes.number,

  };

  static defaultProps = {
    tabIndex: 0,
    initialMonth: new Date(),
    numberOfMonths: 1,
    locale: 'en',
    localeUtils: LocaleUtils,
    enableOutsideDays: false,
    canChangeMonth: true,
    reverseMonths: false,
    renderDay: day => day.getDate(),
    captionElement: <Caption />,
  };

  constructor(props) {
    super(props);

    this.renderDayInMonth = this.renderDayInMonth.bind(this);
    this.showNextMonth = this.showNextMonth.bind(this);
    this.showPreviousMonth = this.showPreviousMonth.bind(this);

    this.handleKeyDown = this.handleKeyDown.bind(this);
    this.handleDayClick = this.handleDayClick.bind(this);
    this.handleDayKeyDown = this.handleDayKeyDown.bind(this);

    this.state = this.getStateFromProps(props);
  }

  componentWillReceiveProps(nextProps) {
    if (this.props.initialMonth !== nextProps.initialMonth) {
      this.setState(this.getStateFromProps(nextProps));
    }
  }

  getStateFromProps = props => ({
    currentMonth: Helpers.startOfMonth(props.initialMonth),
  })

  getModifiersFromProps(props) {
    const modifiers = { ...props.modifiers };
    if (props.selectedDays) {
      modifiers.selected = props.selectedDays;
    }
    if (props.disabledDays) {
      modifiers.disabled = props.disabledDays;
    }
    return modifiers;
  }

  getDayNodes() {
    return this.refs.dayPicker.querySelectorAll('.DayPicker-Day:not(.DayPicker-Day--outside)');
  }

  allowPreviousMonth() {
    const previousMonth = DateUtils.addMonths(this.state.currentMonth, -1);
    return this.allowMonth(previousMonth);
  }

  allowNextMonth() {
    const nextMonth = DateUtils.addMonths(this.state.currentMonth, this.props.numberOfMonths);
    return this.allowMonth(nextMonth);
  }

  allowMonth(d) {
    const { fromMonth, toMonth } = this.props;
    if ((fromMonth && Helpers.getMonthsDiff(fromMonth, d) < 0) ||
      (toMonth && Helpers.getMonthsDiff(toMonth, d) > 0)) {
      return false;
    }
    return true;
  }

  showMonth(d, callback) {
    if (!this.allowMonth(d)) {
      return;
    }
    this.setState({ currentMonth: Helpers.startOfMonth(d) }, callback);
  }

  showMonthAndCallHandler(d, callback) {
    this.showMonth(d, () => {
      if (callback) {
        callback();
      }
      if (this.props.onMonthChange) {
        this.props.onMonthChange(this.state.currentMonth);
      }
    });
  }

  showNextMonth(callback) {
    if (this.allowNextMonth()) {
      const nextMonth = DateUtils.addMonths(this.state.currentMonth, 1);
      this.showMonthAndCallHandler(nextMonth, callback);
    }
  }

  showPreviousMonth(callback) {
    if (this.allowPreviousMonth()) {
      const previousMonth = DateUtils.addMonths(this.state.currentMonth, -1);
      this.showMonthAndCallHandler(previousMonth, callback);
    }
  }

  showNextYear(callback) {
    const nextMonth = DateUtils.addMonths(this.state.currentMonth, 12);
    this.showMonthAndCallHandler(nextMonth, callback);
  }

  showPreviousYear(callback) {
    const nextMonth = DateUtils.addMonths(this.state.currentMonth, -12);
    this.showMonthAndCallHandler(nextMonth, callback);
  }

  focusFirstDayOfMonth() {
    this.getDayNodes()[0].focus();
  }

  focusLastDayOfMonth() {
    const dayNodes = this.getDayNodes();
    dayNodes[dayNodes.length - 1].focus();
  }

  focusPreviousDay(dayNode) {
    const dayNodes = this.getDayNodes();
    const dayNodeIndex = [...dayNodes].indexOf(dayNode);

    if (dayNodeIndex === 0) {
      this.showPreviousMonth(() => this.focusLastDayOfMonth());
    } else {
      dayNodes[dayNodeIndex - 1].focus();
    }
  }

  focusNextDay(dayNode) {
    const dayNodes = this.getDayNodes();
    const dayNodeIndex = [...dayNodes].indexOf(dayNode);

    if (dayNodeIndex === dayNodes.length - 1) {
      this.showNextMonth(() => this.focusFirstDayOfMonth());
    } else {
      dayNodes[dayNodeIndex + 1].focus();
    }
  }

  focusNextWeek(dayNode) {
    const dayNodes = this.getDayNodes();
    const dayNodeIndex = [...dayNodes].indexOf(dayNode);
    const isInLastWeekOfMonth = dayNodeIndex > dayNodes.length - 8;

    if (isInLastWeekOfMonth) {
      this.showNextMonth(() => {
        const daysAfterIndex = dayNodes.length - dayNodeIndex;
        const nextMonthDayNodeIndex = 7 - daysAfterIndex;
        this.getDayNodes()[nextMonthDayNodeIndex].focus();
      });
    } else {
      dayNodes[dayNodeIndex + 7].focus();
    }
  }

  focusPreviousWeek(dayNode) {
    const dayNodes = this.getDayNodes();
    const dayNodeIndex = [...dayNodes].indexOf(dayNode);
    const isInFirstWeekOfMonth = dayNodeIndex <= 6;

    if (isInFirstWeekOfMonth) {
      this.showPreviousMonth(() => {
        const previousMonthDayNodes = this.getDayNodes();
        const startOfLastWeekOfMonth = previousMonthDayNodes.length - 7;
        const previousMonthDayNodeIndex = startOfLastWeekOfMonth + dayNodeIndex;
        previousMonthDayNodes[previousMonthDayNodeIndex].focus();
      });
    } else {
      dayNodes[dayNodeIndex - 7].focus();
    }
  }

  // Event handlers

  handleKeyDown(e) {
    e.persist();
    const { canChangeMonth, onKeyDown } = this.props;

    if (!canChangeMonth && onKeyDown) {
      onKeyDown(e);
      return;
    }

    if (canChangeMonth) {
      switch (e.keyCode) {
        case keys.LEFT:
          this.showPreviousMonth(onKeyDown);
          break;
        case keys.RIGHT:
          this.showNextMonth(onKeyDown);
          break;
        case keys.UP:
          this.showPreviousYear(onKeyDown);
          break;
        case keys.DOWN:
          this.showNextYear(onKeyDown);
          break;
        default:
          if (onKeyDown) {
            onKeyDown(e);
          }
      }
    }
  }

  handleDayKeyDown(e, day, modifiers) {
    e.persist();
    switch (e.keyCode) {
      case keys.LEFT:
        Helpers.cancelEvent(e);
        this.focusPreviousDay(e.target);
        break;
      case keys.RIGHT:
        Helpers.cancelEvent(e);
        this.focusNextDay(e.target);
        break;
      case keys.UP:
        Helpers.cancelEvent(e);
        this.focusPreviousWeek(e.target);
        break;
      case keys.DOWN:
        Helpers.cancelEvent(e);
        this.focusNextWeek(e.target);
        break;
      case keys.ENTER:
      case keys.SPACE:
        Helpers.cancelEvent(e);
        if (this.props.onDayClick) {
          this.handleDayClick(e, day, modifiers);
        }
        break;
      default:
        break;
    }
    if (this.props.onDayKeyDown) {
      this.props.onDayKeyDown(e, day, modifiers);
    }
  }

  handleDayClick(e, day, modifiers) {
    e.persist();
    if (modifiers.outside) {
      this.handleOutsideDayClick(day);
    }
    this.props.onDayClick(e, day, modifiers);
  }

  handleOutsideDayClick(day) {
    const { currentMonth } = this.state;
    const { numberOfMonths } = this.props;
    const diffInMonths = Helpers.getMonthsDiff(currentMonth, day);
    if (diffInMonths > 0 && diffInMonths >= numberOfMonths) {
      this.showNextMonth();
    } else if (diffInMonths < 0) {
      this.showPreviousMonth();
    }
  }

  renderDayInMonth(day, month) {
    let dayModifiers = [];
    if (DateUtils.isSameDay(day, new Date())) {
      dayModifiers.push('today');
    }
    if (day.getMonth() !== month.getMonth()) {
      dayModifiers.push('outside');
    }
    dayModifiers = [
      ...dayModifiers,
      ...Helpers.getModifiersForDay(day, this.getModifiersFromProps(this.props)),
    ];

    const isOutside = day.getMonth() !== month.getMonth();
    let tabIndex = null;
    if (this.props.onDayClick && !isOutside) {
      tabIndex = -1;
      // Focus on the first day of the month
      if (day.getDate() === 1) {
        tabIndex = this.props.tabIndex;
      }
    }
    const key = `${day.getFullYear()}${day.getMonth()}${day.getDate()}`;
    return (
      <Day
        key={`${isOutside ? 'outside-' : ''}${key}`}
        day={day}
        modifiers={dayModifiers}
        empty={isOutside && !this.props.enableOutsideDays}
        tabIndex={tabIndex}
        ariaLabel={this.props.localeUtils.formatDay(day, this.props.locale)}
        ariaDisabled={isOutside || dayModifiers.indexOf('disabled') > -1}
        ariaSelected={dayModifiers.indexOf('selected') > -1}
        onMouseEnter={this.props.onDayMouseEnter}
        onMouseLeave={this.props.onDayMouseLeave}
        onKeyDown={this.handleDayKeyDown}
        onTouchStart={this.props.onDayTouchStart}
        onTouchEnd={this.props.onDayTouchEnd}
        onClick={this.props.onDayClick ? this.handleDayClick : undefined}
      >
        {this.props.renderDay(day)}
      </Day>
    );
  }

  renderMonths() {
    const months = [];
    const firstDayOfWeek = this.props.localeUtils.getFirstDayOfWeek(this.props.locale);

    for (let i = 0; i < this.props.numberOfMonths; i++) {
      const month = DateUtils.addMonths(this.state.currentMonth, i);

      months.push(
        <Month
          className="DayPicker-Month"
          wrapperClassName="DayPicker-Body"
          weekClassName="DayPicker-Week"
          locale={this.props.locale}
          localeUtils={this.props.localeUtils}
          key={i}
          month={month}
          firstDayOfWeek={firstDayOfWeek}
          captionElement={this.props.captionElement}
          onCaptionClick={this.props.onCaptionClick}
        >
          {this.renderDayInMonth}
        </Month>);
    }

    if (this.props.reverseMonths) {
      months.reverse();
    }
    return months;
  }

  render() {
    const {
      locale,
      canChangeMonth,
      onDayClick,
    ...attributes } = this.props;
    let className = `DayPicker DayPicker--${locale}`;

    if (!onDayClick) {
      className = `${className} DayPicker--interactionDisabled`;
    }
    if (attributes.className) {
      className = `${className} ${attributes.className}`;
    }

    return (
      <div
        {...attributes}
        className={className}
        ref="dayPicker"
        role="application"
        tabIndex={canChangeMonth && attributes.tabIndex}
        onKeyDown={this.handleKeyDown}
      >
        {canChangeMonth &&
          <Navbar
            showPreviousButton={this.allowPreviousMonth()}
            showNextButton={this.allowNextMonth()}
            onNextClick={this.showNextMonth}
            onPreviousClick={this.showPreviousMonth}
            dir={attributes.dir}
          />
        }
        {this.renderMonths()}
      </div>
    );
  }
}
<commit_msg>Bump version<commit_after>import React, { Component, PropTypes } from 'react';

import Caption from './Caption';
import Navbar from './Navbar';
import Month from './Month';
import Day from './Day';

import * as Helpers from './Helpers';
import * as DateUtils from './DateUtils';
import * as LocaleUtils from './LocaleUtils';

import keys from './keys';
import DayPickerPropTypes from './PropTypes';
export default class DayPicker extends Component {
  static VERSION = '2.0.0';

  static propTypes = {
    initialMonth: PropTypes.instanceOf(Date),
    numberOfMonths: PropTypes.number,
    selectedDays: PropTypes.func,
    disabledDays: PropTypes.func,

    modifiers: PropTypes.object,

    locale: PropTypes.string,
    localeUtils: DayPickerPropTypes.localeUtils,

    enableOutsideDays: PropTypes.bool,
    canChangeMonth: PropTypes.bool,
    reverseMonths: PropTypes.bool,
    fromMonth: PropTypes.instanceOf(Date),
    toMonth: PropTypes.instanceOf(Date),

    onKeyDown: PropTypes.func,
    onDayClick: PropTypes.func,
    onDayKeyDown: PropTypes.func,
    onDayMouseEnter: PropTypes.func,
    onDayMouseLeave: PropTypes.func,
    onDayTouchStart: PropTypes.func,
    onDayTouchEnd: PropTypes.func,
    onMonthChange: PropTypes.func,
    onCaptionClick: PropTypes.func,

    renderDay: PropTypes.func,

    captionElement: PropTypes.element,

    dir: PropTypes.string,
    tabIndex: PropTypes.number,

  };

  static defaultProps = {
    tabIndex: 0,
    initialMonth: new Date(),
    numberOfMonths: 1,
    locale: 'en',
    localeUtils: LocaleUtils,
    enableOutsideDays: false,
    canChangeMonth: true,
    reverseMonths: false,
    renderDay: day => day.getDate(),
    captionElement: <Caption />,
  };

  constructor(props) {
    super(props);

    this.renderDayInMonth = this.renderDayInMonth.bind(this);
    this.showNextMonth = this.showNextMonth.bind(this);
    this.showPreviousMonth = this.showPreviousMonth.bind(this);

    this.handleKeyDown = this.handleKeyDown.bind(this);
    this.handleDayClick = this.handleDayClick.bind(this);
    this.handleDayKeyDown = this.handleDayKeyDown.bind(this);

    this.state = this.getStateFromProps(props);
  }

  componentWillReceiveProps(nextProps) {
    if (this.props.initialMonth !== nextProps.initialMonth) {
      this.setState(this.getStateFromProps(nextProps));
    }
  }

  getStateFromProps = props => ({
    currentMonth: Helpers.startOfMonth(props.initialMonth),
  })

  getModifiersFromProps(props) {
    const modifiers = { ...props.modifiers };
    if (props.selectedDays) {
      modifiers.selected = props.selectedDays;
    }
    if (props.disabledDays) {
      modifiers.disabled = props.disabledDays;
    }
    return modifiers;
  }

  getDayNodes() {
    return this.refs.dayPicker.querySelectorAll('.DayPicker-Day:not(.DayPicker-Day--outside)');
  }

  allowPreviousMonth() {
    const previousMonth = DateUtils.addMonths(this.state.currentMonth, -1);
    return this.allowMonth(previousMonth);
  }

  allowNextMonth() {
    const nextMonth = DateUtils.addMonths(this.state.currentMonth, this.props.numberOfMonths);
    return this.allowMonth(nextMonth);
  }

  allowMonth(d) {
    const { fromMonth, toMonth } = this.props;
    if ((fromMonth && Helpers.getMonthsDiff(fromMonth, d) < 0) ||
      (toMonth && Helpers.getMonthsDiff(toMonth, d) > 0)) {
      return false;
    }
    return true;
  }

  showMonth(d, callback) {
    if (!this.allowMonth(d)) {
      return;
    }
    this.setState({ currentMonth: Helpers.startOfMonth(d) }, callback);
  }

  showMonthAndCallHandler(d, callback) {
    this.showMonth(d, () => {
      if (callback) {
        callback();
      }
      if (this.props.onMonthChange) {
        this.props.onMonthChange(this.state.currentMonth);
      }
    });
  }

  showNextMonth(callback) {
    if (this.allowNextMonth()) {
      const nextMonth = DateUtils.addMonths(this.state.currentMonth, 1);
      this.showMonthAndCallHandler(nextMonth, callback);
    }
  }

  showPreviousMonth(callback) {
    if (this.allowPreviousMonth()) {
      const previousMonth = DateUtils.addMonths(this.state.currentMonth, -1);
      this.showMonthAndCallHandler(previousMonth, callback);
    }
  }

  showNextYear(callback) {
    const nextMonth = DateUtils.addMonths(this.state.currentMonth, 12);
    this.showMonthAndCallHandler(nextMonth, callback);
  }

  showPreviousYear(callback) {
    const nextMonth = DateUtils.addMonths(this.state.currentMonth, -12);
    this.showMonthAndCallHandler(nextMonth, callback);
  }

  focusFirstDayOfMonth() {
    this.getDayNodes()[0].focus();
  }

  focusLastDayOfMonth() {
    const dayNodes = this.getDayNodes();
    dayNodes[dayNodes.length - 1].focus();
  }

  focusPreviousDay(dayNode) {
    const dayNodes = this.getDayNodes();
    const dayNodeIndex = [...dayNodes].indexOf(dayNode);

    if (dayNodeIndex === 0) {
      this.showPreviousMonth(() => this.focusLastDayOfMonth());
    } else {
      dayNodes[dayNodeIndex - 1].focus();
    }
  }

  focusNextDay(dayNode) {
    const dayNodes = this.getDayNodes();
    const dayNodeIndex = [...dayNodes].indexOf(dayNode);

    if (dayNodeIndex === dayNodes.length - 1) {
      this.showNextMonth(() => this.focusFirstDayOfMonth());
    } else {
      dayNodes[dayNodeIndex + 1].focus();
    }
  }

  focusNextWeek(dayNode) {
    const dayNodes = this.getDayNodes();
    const dayNodeIndex = [...dayNodes].indexOf(dayNode);
    const isInLastWeekOfMonth = dayNodeIndex > dayNodes.length - 8;

    if (isInLastWeekOfMonth) {
      this.showNextMonth(() => {
        const daysAfterIndex = dayNodes.length - dayNodeIndex;
        const nextMonthDayNodeIndex = 7 - daysAfterIndex;
        this.getDayNodes()[nextMonthDayNodeIndex].focus();
      });
    } else {
      dayNodes[dayNodeIndex + 7].focus();
    }
  }

  focusPreviousWeek(dayNode) {
    const dayNodes = this.getDayNodes();
    const dayNodeIndex = [...dayNodes].indexOf(dayNode);
    const isInFirstWeekOfMonth = dayNodeIndex <= 6;

    if (isInFirstWeekOfMonth) {
      this.showPreviousMonth(() => {
        const previousMonthDayNodes = this.getDayNodes();
        const startOfLastWeekOfMonth = previousMonthDayNodes.length - 7;
        const previousMonthDayNodeIndex = startOfLastWeekOfMonth + dayNodeIndex;
        previousMonthDayNodes[previousMonthDayNodeIndex].focus();
      });
    } else {
      dayNodes[dayNodeIndex - 7].focus();
    }
  }

  // Event handlers

  handleKeyDown(e) {
    e.persist();
    const { canChangeMonth, onKeyDown } = this.props;

    if (!canChangeMonth && onKeyDown) {
      onKeyDown(e);
      return;
    }

    if (canChangeMonth) {
      switch (e.keyCode) {
        case keys.LEFT:
          this.showPreviousMonth(onKeyDown);
          break;
        case keys.RIGHT:
          this.showNextMonth(onKeyDown);
          break;
        case keys.UP:
          this.showPreviousYear(onKeyDown);
          break;
        case keys.DOWN:
          this.showNextYear(onKeyDown);
          break;
        default:
          if (onKeyDown) {
            onKeyDown(e);
          }
      }
    }
  }

  handleDayKeyDown(e, day, modifiers) {
    e.persist();
    switch (e.keyCode) {
      case keys.LEFT:
        Helpers.cancelEvent(e);
        this.focusPreviousDay(e.target);
        break;
      case keys.RIGHT:
        Helpers.cancelEvent(e);
        this.focusNextDay(e.target);
        break;
      case keys.UP:
        Helpers.cancelEvent(e);
        this.focusPreviousWeek(e.target);
        break;
      case keys.DOWN:
        Helpers.cancelEvent(e);
        this.focusNextWeek(e.target);
        break;
      case keys.ENTER:
      case keys.SPACE:
        Helpers.cancelEvent(e);
        if (this.props.onDayClick) {
          this.handleDayClick(e, day, modifiers);
        }
        break;
      default:
        break;
    }
    if (this.props.onDayKeyDown) {
      this.props.onDayKeyDown(e, day, modifiers);
    }
  }

  handleDayClick(e, day, modifiers) {
    e.persist();
    if (modifiers.outside) {
      this.handleOutsideDayClick(day);
    }
    this.props.onDayClick(e, day, modifiers);
  }

  handleOutsideDayClick(day) {
    const { currentMonth } = this.state;
    const { numberOfMonths } = this.props;
    const diffInMonths = Helpers.getMonthsDiff(currentMonth, day);
    if (diffInMonths > 0 && diffInMonths >= numberOfMonths) {
      this.showNextMonth();
    } else if (diffInMonths < 0) {
      this.showPreviousMonth();
    }
  }

  renderDayInMonth(day, month) {
    let dayModifiers = [];
    if (DateUtils.isSameDay(day, new Date())) {
      dayModifiers.push('today');
    }
    if (day.getMonth() !== month.getMonth()) {
      dayModifiers.push('outside');
    }
    dayModifiers = [
      ...dayModifiers,
      ...Helpers.getModifiersForDay(day, this.getModifiersFromProps(this.props)),
    ];

    const isOutside = day.getMonth() !== month.getMonth();
    let tabIndex = null;
    if (this.props.onDayClick && !isOutside) {
      tabIndex = -1;
      // Focus on the first day of the month
      if (day.getDate() === 1) {
        tabIndex = this.props.tabIndex;
      }
    }
    const key = `${day.getFullYear()}${day.getMonth()}${day.getDate()}`;
    return (
      <Day
        key={`${isOutside ? 'outside-' : ''}${key}`}
        day={day}
        modifiers={dayModifiers}
        empty={isOutside && !this.props.enableOutsideDays}
        tabIndex={tabIndex}
        ariaLabel={this.props.localeUtils.formatDay(day, this.props.locale)}
        ariaDisabled={isOutside || dayModifiers.indexOf('disabled') > -1}
        ariaSelected={dayModifiers.indexOf('selected') > -1}
        onMouseEnter={this.props.onDayMouseEnter}
        onMouseLeave={this.props.onDayMouseLeave}
        onKeyDown={this.handleDayKeyDown}
        onTouchStart={this.props.onDayTouchStart}
        onTouchEnd={this.props.onDayTouchEnd}
        onClick={this.props.onDayClick ? this.handleDayClick : undefined}
      >
        {this.props.renderDay(day)}
      </Day>
    );
  }

  renderMonths() {
    const months = [];
    const firstDayOfWeek = this.props.localeUtils.getFirstDayOfWeek(this.props.locale);

    for (let i = 0; i < this.props.numberOfMonths; i++) {
      const month = DateUtils.addMonths(this.state.currentMonth, i);

      months.push(
        <Month
          className="DayPicker-Month"
          wrapperClassName="DayPicker-Body"
          weekClassName="DayPicker-Week"
          locale={this.props.locale}
          localeUtils={this.props.localeUtils}
          key={i}
          month={month}
          firstDayOfWeek={firstDayOfWeek}
          captionElement={this.props.captionElement}
          onCaptionClick={this.props.onCaptionClick}
        >
          {this.renderDayInMonth}
        </Month>);
    }

    if (this.props.reverseMonths) {
      months.reverse();
    }
    return months;
  }

  render() {
    const {
      locale,
      canChangeMonth,
      onDayClick,
    ...attributes } = this.props;
    let className = `DayPicker DayPicker--${locale}`;

    if (!onDayClick) {
      className = `${className} DayPicker--interactionDisabled`;
    }
    if (attributes.className) {
      className = `${className} ${attributes.className}`;
    }

    return (
      <div
        {...attributes}
        className={className}
        ref="dayPicker"
        role="application"
        tabIndex={canChangeMonth && attributes.tabIndex}
        onKeyDown={this.handleKeyDown}
      >
        {canChangeMonth &&
          <Navbar
            showPreviousButton={this.allowPreviousMonth()}
            showNextButton={this.allowNextMonth()}
            onNextClick={this.showNextMonth}
            onPreviousClick={this.showPreviousMonth}
            dir={attributes.dir}
          />
        }
        {this.renderMonths()}
      </div>
    );
  }
}
<|endoftext|>


<commit_before>var through2 = require('through2');
var hyperquest = require('hyperquest');
var bl = require('bl');
var workshopper = require('workshopper');
var exercise = require('workshopper-exercise')();
var filecheck = require('workshopper-exercise/filecheck');
var execute = require('workshopper-exercise/execute');
var comparestdout = require('workshopper-exercise/comparestdout');

// the output will be long lines so make the comparison take that into account
exercise.longCompareOutput = true;

// checks that the submission file actually exists
exercise = filecheck(exercise);

// execute the solution and submission in parallel with spawn()
exercise = execute(exercise);

function rndport() {

    return 1024 + Math.floor(Math.random() * 64511);
}

// set up the data file to be passed to the submission
exercise.addSetup(function (mode, callback) {

    this.submissionPort = rndport();
    this.solutionPort = this.submissionPort + 1;

    this.submissionArgs = [this.submissionPort];
    this.solutionArgs = [this.solutionPort];

    process.nextTick(callback);
});

// add a processor for both run and verify calls, added *before*
// the comparestdout processor so we can mess with the stdouts
exercise.addProcessor(function (mode, callback) {

    this.submissionStdout.pipe(process.stdout);

    // replace stdout with our own streams
    this.submissionStdout = through2();
    if (mode == 'verify') {
        this.solutionStdout = through2();
    }

    setTimeout(query.bind(this, mode), 2000);

    process.nextTick(function () {
        callback(null, true);
    });
});

// delayed for 500ms to wait for servers to start so we can start
// playing with them
function query (mode) {

    var exercise = this;

    function verify (port, stream) {

        var url = 'http://localhost:' + port + '/';

        function error (err) {
            exercise.emit('fail', 'Error connecting to http://localhost:' + port + ': ' + err.code);
        }

        hyperquest.get(url)
            .on('error', error)
            .on('response', function(res) {
                console.log(res);
                if (res.statusCode == 404 && mode == 'verify') {
                    exercise.emit('fail', 'Page not found at ' + url );
                    workshopper.prototype.exerciseFail(null, exercise);
                }
            })
            .pipe(bl(function (err, data) {

                if (err)
                    return stream.emit('error', err);

                stream.write(data.toString() + '\n');
                stream.end();
            }));
    }

    verify(this.submissionPort, this.submissionStdout);

    if (mode == 'verify') {
        verify(this.solutionPort, this.solutionStdout);
    }
}

// compare stdout of solution and submission
exercise = comparestdout(exercise);
module.exports = exercise;<commit_msg>remove console.log<commit_after>var through2 = require('through2');
var hyperquest = require('hyperquest');
var bl = require('bl');
var workshopper = require('workshopper');
var exercise = require('workshopper-exercise')();
var filecheck = require('workshopper-exercise/filecheck');
var execute = require('workshopper-exercise/execute');
var comparestdout = require('workshopper-exercise/comparestdout');

// the output will be long lines so make the comparison take that into account
exercise.longCompareOutput = true;

// checks that the submission file actually exists
exercise = filecheck(exercise);

// execute the solution and submission in parallel with spawn()
exercise = execute(exercise);

function rndport() {

    return 1024 + Math.floor(Math.random() * 64511);
}

// set up the data file to be passed to the submission
exercise.addSetup(function (mode, callback) {

    this.submissionPort = rndport();
    this.solutionPort = this.submissionPort + 1;

    this.submissionArgs = [this.submissionPort];
    this.solutionArgs = [this.solutionPort];

    process.nextTick(callback);
});

// add a processor for both run and verify calls, added *before*
// the comparestdout processor so we can mess with the stdouts
exercise.addProcessor(function (mode, callback) {

    this.submissionStdout.pipe(process.stdout);

    // replace stdout with our own streams
    this.submissionStdout = through2();
    if (mode == 'verify') {
        this.solutionStdout = through2();
    }

    setTimeout(query.bind(this, mode), 2000);

    process.nextTick(function () {
        callback(null, true);
    });
});

// delayed for 500ms to wait for servers to start so we can start
// playing with them
function query (mode) {

    var exercise = this;

    function verify (port, stream) {

        var url = 'http://localhost:' + port + '/';

        function error (err) {
            exercise.emit('fail', 'Error connecting to http://localhost:' + port + ': ' + err.code);
        }

        hyperquest.get(url)
            .on('error', error)
            .on('response', function(res) {
                if (res.statusCode == 404 && mode == 'verify') {
                    exercise.emit('fail', 'Page not found at ' + url );
                    workshopper.prototype.exerciseFail(null, exercise);
                }
            })
            .pipe(bl(function (err, data) {

                if (err)
                    return stream.emit('error', err);

                stream.write(data.toString() + '\n');
                stream.end();
            }));
    }

    verify(this.submissionPort, this.submissionStdout);

    if (mode == 'verify') {
        verify(this.solutionPort, this.solutionStdout);
    }
}

// compare stdout of solution and submission
exercise = comparestdout(exercise);
module.exports = exercise;<|endoftext|>


<commit_before>var keystone = require('keystone');
var Entrevista = keystone.list('Entrevista');
var Candidatura = keystone.list('Candidatura');
const https = require('https');
//var $  = require('jquery');
//var dt = require('datatables.net')( window, $ );

exports = module.exports = function(req, res) {

    var view = new keystone.View(req, res);
    var locals = res.locals;

    // Load all members
    view.on('init', function(next) {

        Candidatura.model.find({}, '_id name numero_up entrevista').sort('numero_up').exec(function(err, results) {

            if (err || !results.length) {
                return next(err);
            } else {
              locals.candidatos = results;
            }

            next();
      });
    });

    //$('#table_id').DataTable();

    // Render the view
    view.render('entrevistas');
};

exports.approve = function(req, res) {

  for (var i = 0; i < req.length; i++) {
    var url = 'https://slack.com/api/users.admin.invite?token=' + process.env.SLACK_INVITE  + '&email=consordlbaw@gmail.com'; // mudar para o email da pessoa

    // send request for send slack invitation using slack Web API
    https.get(url,(resp) => {
        let data = '';
        resp.on('data', (chunk) => {
          data += chunk;
        });

        resp.on('end', () => {
          console.log(JSON.parse(data).explanation);
        });

      }).on("error", (err) => {
        console.log("Error: " + err.message);
      });

      // send email with invites for google groups and google drive
    new keystone.Email({
      templateName: 'convite.pug',
      transport: 'mailgun',
    }).send({
      name: req.body['name.first'],
      surname: req.body['name.last'],
      link_google_groups: process.env.GOOGLE_GROUPS_INVITE,
      link_google_drive: process.env.GOOGLE_DRIVE_INVITE,
    },{
      to: 'pount@sapo.pt', //req.body['email']
      from: {
        name: 'NIAEFEUP',
        email: 'excited@samples.mailgun.org',
      },
      subject: 'Convite para Google Groups e Google Drive',

    }, function (err, result) {
      if (err) {
        console.error('Mailgun test failed with error:\n', err);
      } else {
        console.log('Successfully sent Mailgun test with result:\n', result);
      }
    });

  }
    //TODO Passar os membros para User Recruta e enviar os dados para slack e etc por email
    //TODO se for apenas 1 entao accept não é uma array mas sim um valor (id do candidato)
    console.log(req.body);
    res.redirect('/entrevistas');
}
<commit_msg>already send the invitations<commit_after>var keystone = require('keystone');
var Entrevista = keystone.list('Entrevista');
var Candidatura = keystone.list('Candidatura');
const https = require('https');
//var $  = require('jquery');
//var dt = require('datatables.net')( window, $ );

exports = module.exports = function(req, res) {

    var view = new keystone.View(req, res);
    var locals = res.locals;

    // Load all members
    view.on('init', function(next) {

        Candidatura.model.find({}, '_id name numero_up entrevista').sort('numero_up').exec(function(err, results) {

            if (err || !results.length) {
                return next(err);
            } else {
              locals.candidatos = results;
            }

            next();
      });
    });

    //$('#table_id').DataTable();

    // Render the view
    view.render('entrevistas');
};

exports.approve = function(req, res) {

   var request_ID;

  Candidatura.model.find({"_id":req.body['accept']}, 'name email').exec(function(err, results){

    for (var i = 0; i < results.length; i++) {
      var url = 'https://slack.com/api/users.admin.invite?token=' + process.env.SLACK_INVITE  + '&email=up201405323@fe.up.pt'; // mudar para o email da pessoa

      // send request for send slack invitation using slack Web API
      https.get(url,(resp) => {
          let data = '';
          resp.on('data', (chunk) => {
            data += chunk;
          });

          resp.on('end', () => {
            console.log(data);
            }
          });

        }).on("error", (err) => {
          console.log("Error: " + err.message);
        });

        // send email with invites for google groups and google drive
      new keystone.Email({
        templateName: 'convite.pug',
        transport: 'mailgun',
      }).send({
        name: results[i]['name']['first'],
        surname: results[i]['name']['last'],
        link_google_groups: process.env.GOOGLE_GROUPS_INVITE,
        link_google_drive: process.env.GOOGLE_DRIVE_INVITE,
      },{
        to: 'pount@sapo.pt', //req.body['email']
        from: {
          name: 'NIAEFEUP',
          email: 'excited@samples.mailgun.org',
        },
        subject: 'Convite para Google Groups e Google Drive',

      }, function (err, result) {
        if (err) {
          console.error('Mailgun test failed with error:\n', err);
        } else {
          console.log('Successfully sent Mailgun test with result:\n', result);
        }
      });
    }
  });

    //TODO Passar os membros para User Recruta e enviar os dados para slack e etc por email
    //TODO se for apenas 1 entao accept não é uma array mas sim um valor (id do candidato)

    res.redirect('/entrevistas');
}
<|endoftext|>


<commit_before>var path = require('path'),
    webpack = require('webpack');

module.exports = {
  devtool: 'eval',
  entry: [
    'webpack-hot-middleware/client',
    './src/index'
  ],
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js',
    publicPath: '/static/'
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin()
  ],
  module: {
    loaders: [{
      test: /\.jsx?$/,
      loader: 'babel',
      include: path.join(__dirname, 'src'),
        query: {
        plugins: ['react-transform'],
        extra: {
          'react-transform': {
            transforms: [{
              transform: 'react-transform-hmr',
              imports: ['react'],
              locals: ['module']
            }, {
              transform: 'react-transform-catch-errors',
              imports: ['react', 'redbox-react']
            }]
          }
        }
      }
    }, {
      test: /\.css$/,
      loader: 'style-loader!css-loader!postcss-loader'
    }]
  },
  postcss: function() {
    return [require('postcss-nested')];
  }
};
<commit_msg>Ignore vendor CSS #169<commit_after>var path = require('path'),
    webpack = require('webpack');

module.exports = {
  devtool: 'eval',
  entry: [
    'webpack-hot-middleware/client',
    './src/index'
  ],
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js',
    publicPath: '/static/'
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin()
  ],
  module: {
    loaders: [{
      test: /\.jsx?$/,
      loader: 'babel',
      include: path.join(__dirname, 'src'),
        query: {
        plugins: ['react-transform'],
        extra: {
          'react-transform': {
            transforms: [{
              transform: 'react-transform-hmr',
              imports: ['react'],
              locals: ['module']
            }, {
              transform: 'react-transform-catch-errors',
              imports: ['react', 'redbox-react']
            }]
          }
        }
      }
    }, {
      test: /\.css$/,
      loader: 'style-loader!css-loader!postcss-loader',
      include: path.join(__dirname, 'src')
    }]
  },
  postcss: function() {
    return [require('postcss-nested')];
  }
};
<|endoftext|>


<commit_before>/* Persian (Farsi) Translation for the jQuery UI date picker plugin. */
/* Javad Mowlanezhad -- jmowla@gmail.com */
/* Jalali calendar should supported soon! (Its implemented but I have to test it) */
jQuery(function($) {
	$.datepicker.regional['fa'] = {
		closeText: 'بستن',
		prevText: '<قبلي',
		nextText: 'بعدي>',
		currentText: 'امروز',
		monthNames: ['فروردين','ارديبهشت','خرداد','تير','مرداد','شهريور',
		'مهر','آبان','آذر','دي','بهمن','اسفند'],
		monthNamesShort: ['1','2','3','4','5','6','7','8','9','10','11','12'],
		dayNames: ['يکشنبه','دوشنبه','سه‌شنبه','چهارشنبه','پنجشنبه','جمعه','شنبه'],
		dayNamesShort: ['ي','د','س','چ','پ','ج', 'ش'],
		dayNamesMin: ['ي','د','س','چ','پ','ج', 'ش'],
		weekHeader: 'هف',
		dateFormat: 'yy/mm/dd',
		firstDay: 6,
		isRTL: true,
		showMonthAfterYear: false,
		yearSuffix: ''};
	$.datepicker.setDefaults($.datepicker.regional['fa']);
});<commit_msg>Datepicker: Fixed nextText, prevText, and Sunday and split words onto multiple lines for readability. Fixes #8225 - Datepicker: Incorrect values in Persian localization.<commit_after>/* Persian (Farsi) Translation for the jQuery UI date picker plugin. */
/* Javad Mowlanezhad -- jmowla@gmail.com */
/* Jalali calendar should supported soon! (Its implemented but I have to test it) */
jQuery(function($) {
	$.datepicker.regional['fa'] = {
		closeText: 'بستن',
		prevText: '<قبلی',
		nextText: 'بعدی>',
		currentText: 'امروز',
		monthNames: [
			'فروردين',
			'ارديبهشت',
			'خرداد',
			'تير',
			'مرداد',
			'شهريور',
			'مهر',
			'آبان',
			'آذر',
			'دی',
			'بهمن',
			'اسفند'
		],
		monthNamesShort: ['1','2','3','4','5','6','7','8','9','10','11','12'],
		dayNames: [
			'يکشنبه',
			'دوشنبه',
			'سه‌شنبه',
			'چهارشنبه',
			'پنجشنبه',
			'جمعه',
			'شنبه'
		],
		dayNamesShort: [
			'ی',
			'د',
			'س',
			'چ',
			'پ',
			'ج',
			'ش'
		],
		dayNamesMin: [
			'ی',
			'د',
			'س',
			'چ',
			'پ',
			'ج',
			'ش'
		],
		weekHeader: 'هف',
		dateFormat: 'yy/mm/dd',
		firstDay: 6,
		isRTL: true,
		showMonthAfterYear: false,
		yearSuffix: ''};
	$.datepicker.setDefaults($.datepicker.regional['fa']);
});<|endoftext|>


<commit_before>/***
 *
 * Basic Publish/Subscribe library for Named WebSockets
 * ------------------------------------------------------------------------
 * ------------------------------------------------------------------------
 * https://github.com/richtr/namedwebsockets//tree/master/examples/pubsub
 * ------------------------------------------------------------------------
 *
 * For an example of usage, please see `pubsub.html`.
 *
 */
var NamedWebSockets_Basic_PubSub = function(namedWebSocketObj) {
	this.ws = namedWebSocketObj;
	this.ws.addEventListener("open", function() {
		for(var msg in this.sendQueue) {
			this.ws.send(this.sendQueue[msg]);
			this.sendQueue = [];
		}
	}.bind(this));

	this.nodeId = Math.floor( Math.random() * 1e16);

	this.topicSubscriptions = [];

	this.sendQueue = [];

	this.ws.onmessage = function(messageEvent) {
		// Distribute received message to subscriber
		try {
			var msg = JSON.parse(messageEvent.data);

			if (msg.action && msg.action == "publish") {
				for (var subscribedNodeId in this.topicSubscriptions[msg.topicURI]) {
					for (var callback in this.topicSubscriptions[msg.topicURI][subscribedNodeId]) {
						(this.topicSubscriptions[msg.topicURI][subscribedNodeId][callback]).call(this, msg.payload);
					}
				}
			}
		} catch (e) {
			console.error("Could not process publish message");
		}
	}.bind(this);
};

NamedWebSockets_Basic_PubSub.prototype.constructor = NamedWebSockets_Basic_PubSub;

NamedWebSockets_Basic_PubSub.prototype.subscribe = function(topicURI, successCallback)	{
	var topicSubscriptionsContainer = this.topicSubscriptions[topicURI] || {};
	var topicSubscriptionsContainerNode = topicSubscriptionsContainer[this.nodeId] || [];

	topicSubscriptionsContainerNode.push(successCallback);

	topicSubscriptionsContainer[this.nodeId] = topicSubscriptionsContainerNode;
	this.topicSubscriptions[topicURI] = topicSubscriptionsContainer;
};

NamedWebSockets_Basic_PubSub.prototype.unsubscribe = function(topicURI, successCallback)	{
	var topicSubscriptionsContainer = this.topicSubscriptions[topicURI] || {};
	var topicSubscriptionsContainerNode = topicSubscriptionsContainer[this.nodeId] || [];

	for (var i in topicSubscriptionsContainerNode) {
		if (successCallbackBack == topicSubscriptionsContainerNode[i]) {
			topicSubscriptionsContainerNode.splice(i, 1);
			break;
		}
	}

	topicSubscriptionsContainer[this.nodeId] = topicSubscriptionsContainerNode;
	this.topicSubscriptions[topicURI] = topicSubscriptionsContainer;
}

NamedWebSockets_Basic_PubSub.prototype.publish = function(topicURI, payload, successCallback, advancedOptions)	{
	// Send over websocket
	var publishMsg = {
		action: "publish",
		topicURI: topicURI || "",
		payload: payload || {}
	};

	this.send(publishMsg);
};

NamedWebSockets_Basic_PubSub.prototype.send = function(json) {
	var msg = JSON.stringify(json)

	if (this.ws.readyState != 1) {
		this.sendQueue.push(msg);
	} else {
		this.ws.send(msg);
	}
};
<commit_msg>Refactor basic PubSubHub JavaScript code<commit_after>/***
 *
 * Basic Publish/Subscribe library for Named WebSockets
 * ------------------------------------------------------------------------
 * ------------------------------------------------------------------------
 * https://github.com/richtr/namedwebsockets/tree/master/examples/pubsub
 * ------------------------------------------------------------------------
 *
 * For an example of usage, please see `pubsub.html`.
 *
 */
var NamedWebSockets_Basic_PubSub = function(namedWebSocketObj) {
	this.ws = namedWebSocketObj;
	this.ws.addEventListener("open", function() {
		for(var msg in this.sendQueue) {
			this.ws.send(this.sendQueue[msg]);
			this.sendQueue = [];
		}
	}.bind(this));

	this.nodeId = Math.floor( Math.random() * 1e16);

	this.topicSubscriptions = [];

	this.sendQueue = [];

	this.ws.onmessage = function(messageEvent) {
		// Distribute received message to subscriber
		try {
			var msg = JSON.parse(messageEvent.data);

			if (msg.action && msg.action == "publish") {
				var subscriptions = this.topicSubscriptions[msg.topicURI];
				for (var nodeId in subscriptions) {
					var nodeSubscriptions = subscriptions[nodeId];
					for (var callback in nodeSubscriptions) {
						(nodeSubscriptions[callback]).call(this, msg.payload);
					}
				}
			}
		} catch (e) {
			console.error("Could not process publish message");
		}
	}.bind(this);
};

NamedWebSockets_Basic_PubSub.prototype.constructor = NamedWebSockets_Basic_PubSub;

NamedWebSockets_Basic_PubSub.prototype.subscribe = function(topicURI, successCallback)	{
	var subscriptions = this.topicSubscriptions[topicURI] || {};
	var nodeSubscriptions = subscriptions[this.nodeId] || [];

	nodeSubscriptions.push(successCallback);

	subscriptions[this.nodeId] = nodeSubscriptions;
	this.topicSubscriptions[topicURI] = subscriptions;
};

NamedWebSockets_Basic_PubSub.prototype.unsubscribe = function(topicURI, successCallback)	{
	var subscriptions = this.topicSubscriptions[topicURI] || {};
	var nodeSubscriptions = subscriptions[this.nodeId] || [];

	for (var i in nodeSubscriptions) {
		if (successCallbackBack == nodeSubscriptions[i]) {
			nodeSubscriptions.splice(i, 1);
			break;
		}
	}

	subscriptions[this.nodeId] = nodeSubscriptions;
	this.topicSubscriptions[topicURI] = subscriptions;
}

NamedWebSockets_Basic_PubSub.prototype.publish = function(topicURI, payload, successCallback, advancedOptions)	{
	// Send over websocket
	var publishMsg = {
		action: "publish",
		topicURI: topicURI || "",
		payload: payload || {}
	};

	this.send(publishMsg);
};

NamedWebSockets_Basic_PubSub.prototype.send = function(json) {
	var msg = JSON.stringify(json)

	if (this.ws.readyState != 1) {
		this.sendQueue.push(msg);
	} else {
		this.ws.send(msg);
	}
};
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012 Aalto University and University of Helsinki
 * MIT License
 * see LICENSE.txt for more information
 */

function buildGroupTree(response) {
  var data = [];
  for (var uri in response) {
    var group = createGroupNode(uri, response[uri]);
    if (group.text)
      data.push(group);
  }
  $('.group-hierarchy').jstree({
    'plugins' : ['sort'],
    'core' : {
      'data' : data,
      'animation' : 0,
      'themes' : { 'icons': false },
    } });
}

function createGroupNode(uri, groupObject) {
  var node = {'id' : uri, 'parent' : '#', children : []};
  node.text = groupObject.label;
  if (groupObject.members) {
    for (var memberUri in node.members) {
      var child = createGroupNode(memberUri, node.members[memberUri]);
      child.parent = uri;
      if (child.text)
        node.children.push(child);
    }
  }
  return node;
}
<commit_msg>adding some hrefs to the group tree<commit_after>/*
 * Copyright (c) 2012 Aalto University and University of Helsinki
 * MIT License
 * see LICENSE.txt for more information
 */

function buildGroupTree(response) {
  var data = [];
  for (var uri in response) {
    var group = createGroupNode(uri, response[uri]);
    if (group.text)
      data.push(group);
  }

  $('.group-hierarchy').jstree({
    'plugins' : ['sort'],
    'core' : {
      'data' : data,
      'animation' : 0,
      'themes' : { 'icons': false },
    } });
}

function createGroupNode(uri, groupObject) {
  var node = {'id' : uri, 'parent' : '#', children : [], a_attr : { "href" : uri }};
  node.text = groupObject.label;
  if (groupObject.members) {
    for (var memberUri in groupObject.members) {
      var child = { 'id' : memberUri, 'text' : groupObject.members[memberUri], 'parent' : uri };
      if (child.text)
        node.children.push(child);
    }
  }
  return node;
}
<|endoftext|>


<commit_before>var fs = require("fs"),
    path = require("path"),
    colors = require("colors"),
    minimatch = require("minimatch");

module.exports = function(options) {
    var lineCount = 0,
        limit = 400; // chars per line

    if (!options.color) {
        options.color = "cyan";
    }

    var flags = "g"; // global multiline
    if (options.ignoreCase) {
        flags += "i";
    }
    if (options.multiline) {
        flags += "m";
    }

    var regex;
    if (options.regex instanceof RegExp) {
        regex = options.regex;
    }
    else {
        regex = new RegExp(options.regex, flags);
    }
    var canReplace = !options.preview && options.replacement !== undefined;

    var includes;
    if (options.include) {
        includes = options.include.split(",");
    }
    var excludes = [];
    if (options.exclude) {
        excludes = options.exclude.split(",");
    }
    var ignoreFile = options.excludeList || path.join(__dirname, '/defaultignore');
    var ignores = fs.readFileSync(ignoreFile, "utf-8").split("\n");
    excludes = excludes.concat(ignores);

    var replaceFunc;
    if (options.funcFile) {
        eval('replaceFunc = ' + fs.readFileSync(options.funcFile, "utf-8"));
    }

    for (var i = 0; i < options.paths.length; i++) {
        if (options.async) {
            replacizeFile(options.paths[i]);
        }
        else {
            replacizeFileSync(options.paths[i]);
        }
    }

    function canSearch(file, isFile) {
      var inIncludes = includes && includes.some(function(include) {
          return minimatch(file, include, { matchBase: true });
      })
      var inExcludes = excludes.some(function(exclude) {
          return minimatch(file, exclude, { matchBase: true });
      })

      return ((!includes || !isFile || inIncludes) && (!excludes || !inExcludes));
    }

    function replacizeFile(file) {
      fs.lstat(file, function(err, stats) {
          if (err) throw err;

          if (stats.isSymbolicLink()) {
              // don't follow symbolic links for now
              return;
          }
          var isFile = stats.isFile();
          if (!canSearch(file, isFile)) {
              return;
          }
          if (isFile) {
              fs.readFile(file, "utf-8", function(err, text) {
                  if (err) {
                      if (err.code == 'EMFILE') {
                          console.log('Too many files, try running `replace` without --async');
                          process.exit(1);
                      }
                      throw err;
                  }

                  text = replacizeText(text, file);
                  if (canReplace && text !== null) {
                      fs.writeFile(file, text, function(err) {
                          if (err) throw err;
                      });
                  }
              });
          }
          else if (stats.isDirectory() && options.recursive) {
              fs.readdir(file, function(err, files) {
                  if (err) throw err;
                  for (var i = 0; i < files.length; i++) {
                      replacizeFile(path.join(file, files[i]));
                  }
              });
          }
       });
    }

    function replacizeFileSync(file) {
      var stats = fs.lstatSync(file);
      if (stats.isSymbolicLink()) {
          // don't follow symbolic links for now
          return;
      }
      var isFile = stats.isFile();
      if (!canSearch(file, isFile)) {
          return;
      }
      if (isFile) {
          var text = fs.readFileSync(file, "utf-8");

          text = replacizeText(text, file);
          if (canReplace && text !== null) {
              fs.writeFileSync(file, text);
          }
      }
      else if (stats.isDirectory() && options.recursive) {
          var files = fs.readdirSync(file);
          for (var i = 0; i < files.length; i++) {
              replacizeFileSync(path.join(file, files[i]));
          }
      }
    }

    function replacizeText(text, file) {
        var match = text.match(regex);
        if (!match) {
            return null;
        }

        if (!options.silent) {
            var printout = file[options.fileColor];
            if (options.count) {
                printout += (" (" + match.length + ")").grey;
            }
            console.log(printout);
        }
        if (!options.silent && !options.quiet
           && !(lineCount > options.maxLines)
           && options.multiline) {
            var lines = text.split("\n");
            for (var i = 0; i < lines.length; i++) {
                var line = lines[i];
                if (line.match(regex)) {
                    if (++lineCount > options.maxLines) {
                        break;
                    }
                    var replacement = options.replacement || "$&";
                    line = line.replace(regex, replaceFunc || replacement[options.color]);
                    console.log(" " + (i + 1) + ": " + line.slice(0, limit));
                }
            }
        }
        if (canReplace) {
            return text.replace(regex, replaceFunc || options.replacement);
        }
    }
}
<commit_msg>Fix output error when no `fileColor` option was specified pragmatically.<commit_after>var fs = require("fs"),
    path = require("path"),
    colors = require("colors"),
    minimatch = require("minimatch");

module.exports = function(options) {
    var lineCount = 0,
        limit = 400; // chars per line

    if (!options.color) {
        options.color = "cyan";
    }

    var flags = "g"; // global multiline
    if (options.ignoreCase) {
        flags += "i";
    }
    if (options.multiline) {
        flags += "m";
    }

    var regex;
    if (options.regex instanceof RegExp) {
        regex = options.regex;
    }
    else {
        regex = new RegExp(options.regex, flags);
    }
    var canReplace = !options.preview && options.replacement !== undefined;

    var includes;
    if (options.include) {
        includes = options.include.split(",");
    }
    var excludes = [];
    if (options.exclude) {
        excludes = options.exclude.split(",");
    }
    var ignoreFile = options.excludeList || path.join(__dirname, '/defaultignore');
    var ignores = fs.readFileSync(ignoreFile, "utf-8").split("\n");
    excludes = excludes.concat(ignores);

    var replaceFunc;
    if (options.funcFile) {
        eval('replaceFunc = ' + fs.readFileSync(options.funcFile, "utf-8"));
    }

    for (var i = 0; i < options.paths.length; i++) {
        if (options.async) {
            replacizeFile(options.paths[i]);
        }
        else {
            replacizeFileSync(options.paths[i]);
        }
    }

    function canSearch(file, isFile) {
      var inIncludes = includes && includes.some(function(include) {
          return minimatch(file, include, { matchBase: true });
      })
      var inExcludes = excludes.some(function(exclude) {
          return minimatch(file, exclude, { matchBase: true });
      })

      return ((!includes || !isFile || inIncludes) && (!excludes || !inExcludes));
    }

    function replacizeFile(file) {
      fs.lstat(file, function(err, stats) {
          if (err) throw err;

          if (stats.isSymbolicLink()) {
              // don't follow symbolic links for now
              return;
          }
          var isFile = stats.isFile();
          if (!canSearch(file, isFile)) {
              return;
          }
          if (isFile) {
              fs.readFile(file, "utf-8", function(err, text) {
                  if (err) {
                      if (err.code == 'EMFILE') {
                          console.log('Too many files, try running `replace` without --async');
                          process.exit(1);
                      }
                      throw err;
                  }

                  text = replacizeText(text, file);
                  if (canReplace && text !== null) {
                      fs.writeFile(file, text, function(err) {
                          if (err) throw err;
                      });
                  }
              });
          }
          else if (stats.isDirectory() && options.recursive) {
              fs.readdir(file, function(err, files) {
                  if (err) throw err;
                  for (var i = 0; i < files.length; i++) {
                      replacizeFile(path.join(file, files[i]));
                  }
              });
          }
       });
    }

    function replacizeFileSync(file) {
      var stats = fs.lstatSync(file);
      if (stats.isSymbolicLink()) {
          // don't follow symbolic links for now
          return;
      }
      var isFile = stats.isFile();
      if (!canSearch(file, isFile)) {
          return;
      }
      if (isFile) {
          var text = fs.readFileSync(file, "utf-8");

          text = replacizeText(text, file);
          if (canReplace && text !== null) {
              fs.writeFileSync(file, text);
          }
      }
      else if (stats.isDirectory() && options.recursive) {
          var files = fs.readdirSync(file);
          for (var i = 0; i < files.length; i++) {
              replacizeFileSync(path.join(file, files[i]));
          }
      }
    }

    function replacizeText(text, file) {
        var match = text.match(regex);
        if (!match) {
            return null;
        }

        if (!options.silent) {
            var printout = file[options.fileColor] || file;
            if (options.count) {
                printout += (" (" + match.length + ")").grey;
            }
            console.log(printout);
        }
        if (!options.silent && !options.quiet
           && !(lineCount > options.maxLines)
           && options.multiline) {
            var lines = text.split("\n");
            for (var i = 0; i < lines.length; i++) {
                var line = lines[i];
                if (line.match(regex)) {
                    if (++lineCount > options.maxLines) {
                        break;
                    }
                    var replacement = options.replacement || "$&";
                    line = line.replace(regex, replaceFunc || replacement[options.color]);
                    console.log(" " + (i + 1) + ": " + line.slice(0, limit));
                }
            }
        }
        if (canReplace) {
            return text.replace(regex, replaceFunc || options.replacement);
        }
    }
}
<|endoftext|>


<commit_before>OF.JobMonitor = function(jobRetrievalUrl, onComplete) {
	this.jobRetrievalUrl = jobRetrievalUrl;
	this.onComplete = onComplete;

	this.service = new Collect.AbstractService();
	this.job = null;
	this.timer = null;
	this.init();
};

//Events
OF.JobMonitor.JOB_PROGRESS = "jobProgress";
OF.JobMonitor.CANCEL_JOB = "cancelJob";

//internal
OF.JobMonitor._JOB_UPDATE_INTERVAL = 2000;

OF.JobMonitor.prototype.init = function() {
	var $this = this;
	var startTimer = function() {
		$this.timer = setTimeout(function() {
			$this.loadJob(function() {
				var job = $this.job;
				EventBus.dispatch(OF.JobMonitor.JOB_PROGRESS, $this, job);
				switch(job.status) {
				case "RUNNING":
					startTimer();
					break;
				case "COMPLETED":
					if ($this.onComplete) {
						$this.onComplete();
					}
					break;
				}

			});
		}, OF.JobMonitor._JOB_UPDATE_INTERVAL);
	};
	startTimer();

	EventBus.addEventListener(OF.JobMonitor.CANCEL_JOB, $.proxy($this.cancelJobHandler, $this));
};

OF.JobMonitor.prototype.loadJob = function(onSuccess) {
	var $this = this;
	$this.service.send($this.jobRetrievalUrl, null, "GET", function(job) {
		if (job != null) {
			$this.job = job;
			onSuccess();
		} else if ($this.job != null) {
			//monitoring a survey or application locking job that is completed, retrieve it using job ID
			$this.service.send("job.json", {jobId: $this.job.id}, "GET", function(job) {
				$this.job = job;
				onSuccess();
			});
		}
	});
};

OF.JobMonitor.prototype.cancelJobHandler = function() {
	var $this = this;
	$this.service.send($this.jobRetrievalUrl, null, "DELETE", function() {
		EventBus.removeEventListener(OF.JobMonitor.CANCEL_JOB, $this.cancelJobHandler);
	});
};
<commit_msg>Consider job as completed when it ends immediately<commit_after>OF.JobMonitor = function(jobRetrievalUrl, onComplete) {
	this.jobRetrievalUrl = jobRetrievalUrl;
	this.onComplete = onComplete;

	this.service = new Collect.AbstractService();
	this.job = null;
	this.timer = null;
	this.init();
};

//Events
OF.JobMonitor.JOB_PROGRESS = "jobProgress";
OF.JobMonitor.CANCEL_JOB = "cancelJob";

//internal
OF.JobMonitor._JOB_UPDATE_INTERVAL = 2000;

OF.JobMonitor.prototype.init = function() {
	var $this = this;
	var startTimer = function() {
		$this.timer = setTimeout(function() {
			$this.loadJob(function() {
				var job = $this.job;
				EventBus.dispatch(OF.JobMonitor.JOB_PROGRESS, $this, job);
				switch(job.status) {
				case "RUNNING":
					startTimer();
					break;
				case "COMPLETED":
					if ($this.onComplete) {
						$this.onComplete();
					}
					break;
				}

			});
		}, OF.JobMonitor._JOB_UPDATE_INTERVAL);
	};
	startTimer();

	EventBus.addEventListener(OF.JobMonitor.CANCEL_JOB, $.proxy($this.cancelJobHandler, $this));
};

OF.JobMonitor.prototype.loadJob = function(onSuccess) {
	var $this = this;
	$this.service.send($this.jobRetrievalUrl, null, "GET", function(job) {
		if (job != null) {
			$this.job = job;
			onSuccess();
		} else if ($this.job == null) {
			//job completed immediately
			if ($this.onComplete) {
				$this.onComplete();
			}
		} else {
			//monitoring a survey or application locking job that is completed, retrieve it using job ID
			$this.service.send("job.json", {jobId: $this.job.id}, "GET", function(job) {
				$this.job = job;
				onSuccess();
			});
		}
	});
};

OF.JobMonitor.prototype.cancelJobHandler = function() {
	var $this = this;
	$this.service.send($this.jobRetrievalUrl, null, "DELETE", function() {
		EventBus.removeEventListener(OF.JobMonitor.CANCEL_JOB, $this.cancelJobHandler);
	});
};
<|endoftext|>