<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import {createFragmentContainer, graphql} from 'react-relay';

import {RemoteSetPropType, BranchSetPropType, EndpointPropType, WorkdirContextPoolPropType} from '../prop-types';
import ReviewsView from '../views/reviews-view';
import PullRequestCheckoutController from '../controllers/pr-checkout-controller';
import addReviewMutation from '../mutations/add-pr-review';
import addReviewCommentMutation from '../mutations/add-pr-review-comment';
import submitReviewMutation from '../mutations/submit-pr-review';
import deleteReviewMutation from '../mutations/delete-pr-review';
import resolveReviewThreadMutation from '../mutations/resolve-review-thread';
import unresolveReviewThreadMutation from '../mutations/unresolve-review-thread';
import updatePrReviewCommentMutation from '../mutations/update-pr-review-comment';
import updatePrReviewSummaryMutation from '../mutations/update-pr-review-summary';
import IssueishDetailItem from '../items/issueish-detail-item';
import {addEvent} from '../reporter-proxy';

// Milliseconds to update highlightedThreadIDs
const FLASH_DELAY = 1500;

export class BareReviewsController extends React.Component {
  static propTypes = {
    // Relay results
    relay: PropTypes.shape({
      environment: PropTypes.object.isRequired,
    }).isRequired,
    viewer: PropTypes.shape({
      id: PropTypes.string.isRequired,
    }).isRequired,
    repository: PropTypes.object.isRequired,
    pullRequest: PropTypes.shape({
      id: PropTypes.string.isRequired,
    }).isRequired,
    summaries: PropTypes.array.isRequired,
    commentThreads: PropTypes.arrayOf(PropTypes.shape({
      thread: PropTypes.object.isRequired,
      comments: PropTypes.arrayOf(PropTypes.object).isRequired,
    })),
    refetch: PropTypes.func.isRequired,

    // Package models
    workdirContextPool: WorkdirContextPoolPropType.isRequired,
    localRepository: PropTypes.object.isRequired,
    isAbsent: PropTypes.bool.isRequired,
    isLoading: PropTypes.bool.isRequired,
    isPresent: PropTypes.bool.isRequired,
    isMerging: PropTypes.bool.isRequired,
    isRebasing: PropTypes.bool.isRequired,
    branches: BranchSetPropType.isRequired,
    remotes: RemoteSetPropType.isRequired,
    multiFilePatch: PropTypes.object.isRequired,
    initThreadID: PropTypes.string,

    // Connection properties
    endpoint: EndpointPropType.isRequired,

    // URL parameters
    owner: PropTypes.string.isRequired,
    repo: PropTypes.string.isRequired,
    number: PropTypes.number.isRequired,
    workdir: PropTypes.string.isRequired,

    // Atom environment
    workspace: PropTypes.object.isRequired,
    config: PropTypes.object.isRequired,
    commands: PropTypes.object.isRequired,
    tooltips: PropTypes.object.isRequired,
    confirm: PropTypes.object.isRequired,

    // Action methods
    reportMutationErrors: PropTypes.func.isRequired,
  }

  constructor(props) {
    super(props);

    this.state = {
      contextLines: 4,
      postingToThreadID: null,
      scrollToThreadID: this.props.initThreadID,
      summarySectionOpen: true,
      commentSectionOpen: true,
      threadIDsOpen: new Set(
        this.props.initThreadID ? [this.props.initThreadID] : [],
      ),
      highlightedThreadIDs: new Set(),
    };
  }

  componentDidMount() {
    const {scrollToThreadID} = this.state;
    if (scrollToThreadID) {
      this.highlightThread(scrollToThreadID);
    }
  }

  componentDidUpdate(prevProps) {
    const {initThreadID} = this.props;
    if (initThreadID && initThreadID !== prevProps.initThreadID) {
      this.setState(prev => {
        prev.threadIDsOpen.add(initThreadID);
        this.highlightThread(initThreadID);
        return {commentSectionOpen: true, scrollToThreadID: initThreadID};
      });
    }
  }

  render() {
    return (
      <PullRequestCheckoutController
        repository={this.props.repository}
        pullRequest={this.props.pullRequest}

        localRepository={this.props.localRepository}
        isAbsent={this.props.isAbsent}
        isLoading={this.props.isLoading}
        isPresent={this.props.isPresent}
        isMerging={this.props.isMerging}
        isRebasing={this.props.isRebasing}
        branches={this.props.branches}
        remotes={this.props.remotes}>

        {checkoutOp => (
          <ReviewsView
            checkoutOp={checkoutOp}
            contextLines={this.state.contextLines}
            postingToThreadID={this.state.postingToThreadID}
            summarySectionOpen={this.state.summarySectionOpen}
            commentSectionOpen={this.state.commentSectionOpen}
            threadIDsOpen={this.state.threadIDsOpen}
            highlightedThreadIDs={this.state.highlightedThreadIDs}
            scrollToThreadID={this.state.scrollToThreadID}

            moreContext={this.moreContext}
            lessContext={this.lessContext}
            openFile={this.openFile}
            openDiff={this.openDiff}
            openPR={this.openPR}
            openIssueish={this.openIssueish}
            showSummaries={this.showSummaries}
            hideSummaries={this.hideSummaries}
            showComments={this.showComments}
            hideComments={this.hideComments}
            showThreadID={this.showThreadID}
            hideThreadID={this.hideThreadID}
            resolveThread={this.resolveThread}
            unresolveThread={this.unresolveThread}
            addSingleComment={this.addSingleComment}
            updateComment={this.updateComment}
            updateSummary={this.updateSummary}
            {...this.props}
          />
        )}

      </PullRequestCheckoutController>
    );
  }

  openFile = async (filePath, lineNumber) => {
    await this.props.workspace.open(
      filePath, {
        initialLine: lineNumber - 1,
        initialColumn: 0,
        pending: true,
      });
    addEvent('reviews-dock-open-file', {package: 'github'});
  }

  openDiff = async (filePath, lineNumber) => {
    const item = await this.getPRDetailItem();
    item.openFilesTab({
      changedFilePath: filePath,
      changedFilePosition: lineNumber,
    });
    addEvent('reviews-dock-open-diff', {package: 'github', component: this.constructor.name});
  }

  openPR = async () => {
    await this.getPRDetailItem();
    addEvent('reviews-dock-open-pr', {package: 'github', component: this.constructor.name});
  }

  getPRDetailItem = () => {
    return this.props.workspace.open(
      IssueishDetailItem.buildURI({
        host: this.props.endpoint.getHost(),
        owner: this.props.owner,
        repo: this.props.repo,
        number: this.props.number,
        workdir: this.props.workdir,
      }), {
        pending: true,
        searchAllPanes: true,
      },
    );
  }

  moreContext = () => {
    this.setState(prev => ({contextLines: prev.contextLines + 1}));
    addEvent('reviews-dock-show-more-context', {package: 'github'});
  }

  lessContext = () => {
    this.setState(prev => ({contextLines: Math.max(prev.contextLines - 1, 1)}));
    addEvent('reviews-dock-show-less-context', {package: 'github'});
  }

  openIssueish = async (owner, repo, number) => {
    const host = this.props.endpoint.getHost();

    const homeRepository = await this.props.localRepository.hasGitHubRemote(host, owner, repo)
      ? this.props.localRepository
      : (await this.props.workdirContextPool.getMatchingContext(host, owner, repo)).getRepository();

    const uri = IssueishDetailItem.buildURI({
      host, owner, repo, number, workdir: homeRepository.getWorkingDirectoryPath(),
    });
    return this.props.workspace.open(uri, {pending: true, searchAllPanes: true});
  }

  showSummaries = () => new Promise(resolve => this.setState({summarySectionOpen: true}, resolve));

  hideSummaries = () => new Promise(resolve => this.setState({summarySectionOpen: false}, resolve));

  showComments = () => new Promise(resolve => this.setState({commentSectionOpen: true}, resolve));

  hideComments = () => new Promise(resolve => this.setState({commentSectionOpen: false}, resolve));

  showThreadID = commentID => new Promise(resolve => this.setState(state => {
    state.threadIDsOpen.add(commentID);
    return {};
  }, resolve));

  hideThreadID = commentID => new Promise(resolve => this.setState(state => {
    state.threadIDsOpen.delete(commentID);
    return {};
  }, resolve));

  highlightThread = threadID => {
    this.setState(state => {
      state.highlightedThreadIDs.add(threadID);
      return {};
    }, () => {
      setTimeout(() => this.setState(state => {
        state.highlightedThreadIDs.delete(threadID);
        if (state.scrollToThreadID === threadID) {
          return {scrollToThreadID: null};
        }
        return {};
      }), FLASH_DELAY);
    });
  }

  resolveThread = async thread => {
    if (thread.viewerCanResolve) {
      // optimistically hide the thread to avoid jankiness;
      // if the operation fails, the onError callback will revert it.
      this.hideThreadID(thread.id);
      try {
        await resolveReviewThreadMutation(this.props.relay.environment, {
          threadID: thread.id,
          viewerID: this.props.viewer.id,
          viewerLogin: this.props.viewer.login,
        });
        this.highlightThread(thread.id);
        addEvent('resolve-comment-thread', {package: 'github'});
      } catch (err) {
        this.showThreadID(thread.id);
        this.props.reportMutationErrors('Unable to resolve the comment thread', err);
      }
    }
  }

  unresolveThread = async thread => {
    if (thread.viewerCanUnresolve) {
      try {
        await unresolveReviewThreadMutation(this.props.relay.environment, {
          threadID: thread.id,
          viewerID: this.props.viewer.id,
          viewerLogin: this.props.viewer.login,
        });
        this.highlightThread(thread.id);
        addEvent('unresolve-comment-thread', {package: 'github'});
      } catch (err) {
        this.props.reportMutationErrors('Unable to unresolve the comment thread', err);
      }
    }
  }

  addSingleComment = async (commentBody, threadID, replyToID, path, position, callbacks = {}) => {
    let pendingReviewID = null;
    try {
      this.setState({postingToThreadID: threadID});

      const reviewResult = await addReviewMutation(this.props.relay.environment, {
        pullRequestID: this.props.pullRequest.id,
        viewerID: this.props.viewer.id,
      });
      const reviewID = reviewResult.addPullRequestReview.reviewEdge.node.id;
      pendingReviewID = reviewID;

      const commentPromise = addReviewCommentMutation(this.props.relay.environment, {
        body: commentBody,
        inReplyTo: replyToID,
        reviewID,
        threadID,
        viewerID: this.props.viewer.id,
        path,
        position,
      });
      if (callbacks.didSubmitComment) {
        callbacks.didSubmitComment();
      }
      await commentPromise;
      pendingReviewID = null;

      await submitReviewMutation(this.props.relay.environment, {
        event: 'COMMENT',
        reviewID,
      });
      addEvent('add-single-comment', {package: 'github'});
    } catch (error) {
      if (callbacks.didFailComment) {
        callbacks.didFailComment();
      }

      if (pendingReviewID !== null) {
        try {
          await deleteReviewMutation(this.props.relay.environment, {
            reviewID: pendingReviewID,
            pullRequestID: this.props.pullRequest.id,
          });
        } catch (e) {
          /* istanbul ignore else */
          if (error.errors && e.errors) {
            error.errors.push(...e.errors);
          } else {
            // eslint-disable-next-line no-console
            console.warn('Unable to delete pending review', e);
          }
        }
      }

      this.props.reportMutationErrors('Unable to submit your comment', error);
    } finally {
      this.setState({postingToThreadID: null});
    }
  }

  updateComment = async (commentId, commentBody, callback) => {
    try {
      await updatePrReviewCommentMutation(this.props.relay.environment, {
        commentId,
        commentBody,
      });
      callback();
    } catch (error) {
      this.props.reportMutationErrors('Unable to update comment', error);
    }
  }

  updateSummary = async (reviewId, reviewBody, callback) => {
    try {
      await updatePrReviewSummaryMutation(this.props.relay.environment, {
        reviewId,
        reviewBody,
      });
      callback();
    } catch (error) {
      this.props.reportMutationErrors('Unable to update review summary', error);
    }
  }
}

export default createFragmentContainer(BareReviewsController, {
  viewer: graphql`
    fragment reviewsController_viewer on User {
      id
      login
      avatarUrl
    }
  `,
  repository: graphql`
    fragment reviewsController_repository on Repository {
      ...prCheckoutController_repository
    }
  `,
  pullRequest: graphql`
    fragment reviewsController_pullRequest on PullRequest {
      id
      ...prCheckoutController_pullRequest
    }
  `,
});
<commit_msg>add some metrics tings :sparkles:<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import {createFragmentContainer, graphql} from 'react-relay';

import {RemoteSetPropType, BranchSetPropType, EndpointPropType, WorkdirContextPoolPropType} from '../prop-types';
import ReviewsView from '../views/reviews-view';
import PullRequestCheckoutController from '../controllers/pr-checkout-controller';
import addReviewMutation from '../mutations/add-pr-review';
import addReviewCommentMutation from '../mutations/add-pr-review-comment';
import submitReviewMutation from '../mutations/submit-pr-review';
import deleteReviewMutation from '../mutations/delete-pr-review';
import resolveReviewThreadMutation from '../mutations/resolve-review-thread';
import unresolveReviewThreadMutation from '../mutations/unresolve-review-thread';
import updatePrReviewCommentMutation from '../mutations/update-pr-review-comment';
import updatePrReviewSummaryMutation from '../mutations/update-pr-review-summary';
import IssueishDetailItem from '../items/issueish-detail-item';
import {addEvent} from '../reporter-proxy';

// Milliseconds to update highlightedThreadIDs
const FLASH_DELAY = 1500;

export class BareReviewsController extends React.Component {
  static propTypes = {
    // Relay results
    relay: PropTypes.shape({
      environment: PropTypes.object.isRequired,
    }).isRequired,
    viewer: PropTypes.shape({
      id: PropTypes.string.isRequired,
    }).isRequired,
    repository: PropTypes.object.isRequired,
    pullRequest: PropTypes.shape({
      id: PropTypes.string.isRequired,
    }).isRequired,
    summaries: PropTypes.array.isRequired,
    commentThreads: PropTypes.arrayOf(PropTypes.shape({
      thread: PropTypes.object.isRequired,
      comments: PropTypes.arrayOf(PropTypes.object).isRequired,
    })),
    refetch: PropTypes.func.isRequired,

    // Package models
    workdirContextPool: WorkdirContextPoolPropType.isRequired,
    localRepository: PropTypes.object.isRequired,
    isAbsent: PropTypes.bool.isRequired,
    isLoading: PropTypes.bool.isRequired,
    isPresent: PropTypes.bool.isRequired,
    isMerging: PropTypes.bool.isRequired,
    isRebasing: PropTypes.bool.isRequired,
    branches: BranchSetPropType.isRequired,
    remotes: RemoteSetPropType.isRequired,
    multiFilePatch: PropTypes.object.isRequired,
    initThreadID: PropTypes.string,

    // Connection properties
    endpoint: EndpointPropType.isRequired,

    // URL parameters
    owner: PropTypes.string.isRequired,
    repo: PropTypes.string.isRequired,
    number: PropTypes.number.isRequired,
    workdir: PropTypes.string.isRequired,

    // Atom environment
    workspace: PropTypes.object.isRequired,
    config: PropTypes.object.isRequired,
    commands: PropTypes.object.isRequired,
    tooltips: PropTypes.object.isRequired,
    confirm: PropTypes.object.isRequired,

    // Action methods
    reportMutationErrors: PropTypes.func.isRequired,
  }

  constructor(props) {
    super(props);

    this.state = {
      contextLines: 4,
      postingToThreadID: null,
      scrollToThreadID: this.props.initThreadID,
      summarySectionOpen: true,
      commentSectionOpen: true,
      threadIDsOpen: new Set(
        this.props.initThreadID ? [this.props.initThreadID] : [],
      ),
      highlightedThreadIDs: new Set(),
    };
  }

  componentDidMount() {
    const {scrollToThreadID} = this.state;
    if (scrollToThreadID) {
      this.highlightThread(scrollToThreadID);
    }
  }

  componentDidUpdate(prevProps) {
    const {initThreadID} = this.props;
    if (initThreadID && initThreadID !== prevProps.initThreadID) {
      this.setState(prev => {
        prev.threadIDsOpen.add(initThreadID);
        this.highlightThread(initThreadID);
        return {commentSectionOpen: true, scrollToThreadID: initThreadID};
      });
    }
  }

  render() {
    return (
      <PullRequestCheckoutController
        repository={this.props.repository}
        pullRequest={this.props.pullRequest}

        localRepository={this.props.localRepository}
        isAbsent={this.props.isAbsent}
        isLoading={this.props.isLoading}
        isPresent={this.props.isPresent}
        isMerging={this.props.isMerging}
        isRebasing={this.props.isRebasing}
        branches={this.props.branches}
        remotes={this.props.remotes}>

        {checkoutOp => (
          <ReviewsView
            checkoutOp={checkoutOp}
            contextLines={this.state.contextLines}
            postingToThreadID={this.state.postingToThreadID}
            summarySectionOpen={this.state.summarySectionOpen}
            commentSectionOpen={this.state.commentSectionOpen}
            threadIDsOpen={this.state.threadIDsOpen}
            highlightedThreadIDs={this.state.highlightedThreadIDs}
            scrollToThreadID={this.state.scrollToThreadID}

            moreContext={this.moreContext}
            lessContext={this.lessContext}
            openFile={this.openFile}
            openDiff={this.openDiff}
            openPR={this.openPR}
            openIssueish={this.openIssueish}
            showSummaries={this.showSummaries}
            hideSummaries={this.hideSummaries}
            showComments={this.showComments}
            hideComments={this.hideComments}
            showThreadID={this.showThreadID}
            hideThreadID={this.hideThreadID}
            resolveThread={this.resolveThread}
            unresolveThread={this.unresolveThread}
            addSingleComment={this.addSingleComment}
            updateComment={this.updateComment}
            updateSummary={this.updateSummary}
            {...this.props}
          />
        )}

      </PullRequestCheckoutController>
    );
  }

  openFile = async (filePath, lineNumber) => {
    await this.props.workspace.open(
      filePath, {
        initialLine: lineNumber - 1,
        initialColumn: 0,
        pending: true,
      });
    addEvent('reviews-dock-open-file', {package: 'github'});
  }

  openDiff = async (filePath, lineNumber) => {
    const item = await this.getPRDetailItem();
    item.openFilesTab({
      changedFilePath: filePath,
      changedFilePosition: lineNumber,
    });
    addEvent('reviews-dock-open-diff', {package: 'github', component: this.constructor.name});
  }

  openPR = async () => {
    await this.getPRDetailItem();
    addEvent('reviews-dock-open-pr', {package: 'github', component: this.constructor.name});
  }

  getPRDetailItem = () => {
    return this.props.workspace.open(
      IssueishDetailItem.buildURI({
        host: this.props.endpoint.getHost(),
        owner: this.props.owner,
        repo: this.props.repo,
        number: this.props.number,
        workdir: this.props.workdir,
      }), {
        pending: true,
        searchAllPanes: true,
      },
    );
  }

  moreContext = () => {
    this.setState(prev => ({contextLines: prev.contextLines + 1}));
    addEvent('reviews-dock-show-more-context', {package: 'github'});
  }

  lessContext = () => {
    this.setState(prev => ({contextLines: Math.max(prev.contextLines - 1, 1)}));
    addEvent('reviews-dock-show-less-context', {package: 'github'});
  }

  openIssueish = async (owner, repo, number) => {
    const host = this.props.endpoint.getHost();

    const homeRepository = await this.props.localRepository.hasGitHubRemote(host, owner, repo)
      ? this.props.localRepository
      : (await this.props.workdirContextPool.getMatchingContext(host, owner, repo)).getRepository();

    const uri = IssueishDetailItem.buildURI({
      host, owner, repo, number, workdir: homeRepository.getWorkingDirectoryPath(),
    });
    return this.props.workspace.open(uri, {pending: true, searchAllPanes: true});
  }

  showSummaries = () => new Promise(resolve => this.setState({summarySectionOpen: true}, resolve));

  hideSummaries = () => new Promise(resolve => this.setState({summarySectionOpen: false}, resolve));

  showComments = () => new Promise(resolve => this.setState({commentSectionOpen: true}, resolve));

  hideComments = () => new Promise(resolve => this.setState({commentSectionOpen: false}, resolve));

  showThreadID = commentID => new Promise(resolve => this.setState(state => {
    state.threadIDsOpen.add(commentID);
    return {};
  }, resolve));

  hideThreadID = commentID => new Promise(resolve => this.setState(state => {
    state.threadIDsOpen.delete(commentID);
    return {};
  }, resolve));

  highlightThread = threadID => {
    this.setState(state => {
      state.highlightedThreadIDs.add(threadID);
      return {};
    }, () => {
      setTimeout(() => this.setState(state => {
        state.highlightedThreadIDs.delete(threadID);
        if (state.scrollToThreadID === threadID) {
          return {scrollToThreadID: null};
        }
        return {};
      }), FLASH_DELAY);
    });
  }

  resolveThread = async thread => {
    if (thread.viewerCanResolve) {
      // optimistically hide the thread to avoid jankiness;
      // if the operation fails, the onError callback will revert it.
      this.hideThreadID(thread.id);
      try {
        await resolveReviewThreadMutation(this.props.relay.environment, {
          threadID: thread.id,
          viewerID: this.props.viewer.id,
          viewerLogin: this.props.viewer.login,
        });
        this.highlightThread(thread.id);
        addEvent('resolve-comment-thread', {package: 'github'});
      } catch (err) {
        this.showThreadID(thread.id);
        this.props.reportMutationErrors('Unable to resolve the comment thread', err);
      }
    }
  }

  unresolveThread = async thread => {
    if (thread.viewerCanUnresolve) {
      try {
        await unresolveReviewThreadMutation(this.props.relay.environment, {
          threadID: thread.id,
          viewerID: this.props.viewer.id,
          viewerLogin: this.props.viewer.login,
        });
        this.highlightThread(thread.id);
        addEvent('unresolve-comment-thread', {package: 'github'});
      } catch (err) {
        this.props.reportMutationErrors('Unable to unresolve the comment thread', err);
      }
    }
  }

  addSingleComment = async (commentBody, threadID, replyToID, path, position, callbacks = {}) => {
    let pendingReviewID = null;
    try {
      this.setState({postingToThreadID: threadID});

      const reviewResult = await addReviewMutation(this.props.relay.environment, {
        pullRequestID: this.props.pullRequest.id,
        viewerID: this.props.viewer.id,
      });
      const reviewID = reviewResult.addPullRequestReview.reviewEdge.node.id;
      pendingReviewID = reviewID;

      const commentPromise = addReviewCommentMutation(this.props.relay.environment, {
        body: commentBody,
        inReplyTo: replyToID,
        reviewID,
        threadID,
        viewerID: this.props.viewer.id,
        path,
        position,
      });
      if (callbacks.didSubmitComment) {
        callbacks.didSubmitComment();
      }
      await commentPromise;
      pendingReviewID = null;

      await submitReviewMutation(this.props.relay.environment, {
        event: 'COMMENT',
        reviewID,
      });
      addEvent('add-single-comment', {package: 'github'});
    } catch (error) {
      if (callbacks.didFailComment) {
        callbacks.didFailComment();
      }

      if (pendingReviewID !== null) {
        try {
          await deleteReviewMutation(this.props.relay.environment, {
            reviewID: pendingReviewID,
            pullRequestID: this.props.pullRequest.id,
          });
        } catch (e) {
          /* istanbul ignore else */
          if (error.errors && e.errors) {
            error.errors.push(...e.errors);
          } else {
            // eslint-disable-next-line no-console
            console.warn('Unable to delete pending review', e);
          }
        }
      }

      this.props.reportMutationErrors('Unable to submit your comment', error);
    } finally {
      this.setState({postingToThreadID: null});
    }
  }

  updateComment = async (commentId, commentBody, callback) => {
    try {
      await updatePrReviewCommentMutation(this.props.relay.environment, {
        commentId,
        commentBody,
      });
      addEvent('update-review-comment', {package: 'github'});
      callback();
    } catch (error) {
      this.props.reportMutationErrors('Unable to update comment', error);
    }
  }

  updateSummary = async (reviewId, reviewBody, callback) => {
    try {
      await updatePrReviewSummaryMutation(this.props.relay.environment, {
        reviewId,
        reviewBody,
      });
      addEvent('update-review-summary', {package: 'github'});
      callback();
    } catch (error) {
      this.props.reportMutationErrors('Unable to update review summary', error);
    }
  }
}

export default createFragmentContainer(BareReviewsController, {
  viewer: graphql`
    fragment reviewsController_viewer on User {
      id
      login
      avatarUrl
    }
  `,
  repository: graphql`
    fragment reviewsController_repository on Repository {
      ...prCheckoutController_repository
    }
  `,
  pullRequest: graphql`
    fragment reviewsController_pullRequest on PullRequest {
      id
      ...prCheckoutController_pullRequest
    }
  `,
});
<|endoftext|>


<commit_before>$(function() {
    drawFigures();
    initWindowResizing();
});

var prevWidth; //Figure container width before resizing

function initWindowResizing() {
    prevWidth = $('.cimg').width();

    var resizeId;
    $(window).resize(function() {
        clearTimeout(resizeId);
        resizeId = setTimeout(windowResized, 500);
    });
}

function windowResized() {
    var w = $('.cimg').width();
    if(w != prevWidth) {
        resizeFigures();
        prevWidth = w;
    }
}

function resizeFigures() {
    $('svg').each(function() {
        Snap(this).clear();
    });

    drawFigures();
}

var numcol  = 7; //Number of columns in this calendar
var gutter  = 10; //Spacing between months in pixels
var space   = 2; //Spacing between cells in pixels

var showDateText = false;

/**
 * Draw a figure for all counters.
 */
function drawFigures() {
    var now = new Date();
    //console.log(now);
    //console.log(now.getFullYear());
    $('svg').each(function() {
        drawFigure(this, now.getFullYear(), now.getMonth());
    });
}

/**
 * Draw a figure, which contains multiple calendar.
 */
function drawFigure(svg, year, month) {
    var width = Math.min($('.cimg').width() - 50, 900); //Width of the figure
    var snap = Snap(svg);

    //snap.rect(50, 50, 50, 50);
    var g1, g2;

    if(month === 0) {
        g1 = drawMonthCalendar(snap, 0, width, year - 1, 11); //December of last year
    }
    else {
        g1 = drawMonthCalendar(snap, 0, width, year, month - 1);
    }

    var g2 = drawMonthCalendar(snap, 1, width, year, month);
    var monthWidth = +g1.attr('width');
    var monthHeight = +g1.attr('height');
    var tx = (monthWidth) + gutter;
    g2.transform('t' + tx);

    snap.attr({width: 2 * monthWidth + gutter, height: monthHeight});
}

/**
 * Draw a calendar.
 * @param snap      Snap object
 * @param i         calendar index: the first calendar is 0, next is 1.
 * @param cwidth    figure (canvas) total width.
 * @param year      year, as in 2014
 * @param month     month: 0 = Jan, 1 = Feb, ... , 11 = Dec
 */
function drawMonthCalendar(snap, i, cwidth, year, month) {
    var numdays = numberOfDays(year, month + 1); //Number of days in this month;
    var startOn = (new Date(year, month, 1)).getDay(); //Day of the first of this month; 0 = Sunday, 1 = Monday, etc
    var numrow  = Math.ceil((numdays + startOn) / numcol); //Number of rows in this calendar
    var width   = (((cwidth - gutter) / 2) - ((numcol - 1) * space)) / numcol; //width of cell
    var calId   = snap.attr('id'); //Id of this svg calendar
    var now     = new Date();
    //console.log(hist);

    /*console.log('year: ' + year);
    console.log('month: ' + month);
    console.log('numdays: ' + numdays);
    console.log('startOn: ' + startOn);
    console.log('numcol: ' + numcol);
    console.log('numrow: ' + numrow);
    console.log('gutter: ' + gutter);
    console.log('space: ' + space);
    console.log('width: ' + width);*/

    var group = snap.group();
    group.attr({width: width * numcol + space * numcol, height: width * numrow + space * numrow});

    for(row = 0; row < numrow; row++) {
        for(col = 0; col < numcol; col++) {
            var x = col * width + col * space;
            var y = row * width + row * space;
            var s = row * numcol + col; //Cell sequence number, starting from 0;
            var date = s - startOn + 1; //Date number, e.g. 15
            //console.log(s);
            //console.log(startOn);
            var c = '#d6e685';

            if(s < startOn || s >= numdays + startOn)
                c = '#f2f2f2';
            else {
                c = getColor(calId, new Date(year, month, date));
            }

            //var c = s < startOn || s > numdays + startOn ? '#eeeeee' : '#d6e685';
            var rect = snap.rect(x, y, width, width).attr({fill:c});
            if(year == now.getFullYear() && month == now.getMonth() && date == now.getDate())
                rect.attr({strokeWidth:1, stroke:'#aaa'});
            group.add(rect);

            if(showDateText) {
                if(date > 0 && date <= numdays) {
                    var fontSize = width / 2;
                    var numchar = date < 10 ? 1 : 2;
                    var textX = x + (width - fontSize) / numchar;
                    var textY = y + (width - fontSize + (width / 6));
                    var textColor = '#aaa';
                    var text = snap.text(textX, textY, date).
                        attr({'font-size': fontSize + 'px', 'fill': textColor, 'opacity':0.8});
                    group.add(text);
                }
            }
        }
    }

    return group;
}

var colorYes = '#d6e685';
var colorNo  = '#e3e3e3';
var colorStart = '#bee685';
//var colorEnd = '#e6c785';

function getColor(calId, date) {
    //If this date is today or in the future, set this cell as no color.
    if(dateGreaterOrEqual(date, new Date()))
        return colorNo;

    var hist = data[calId]; //History data for this counter

    for(var h = 0; h < hist.length; h++) {
        var start = hist[h].start;
        var end = hist[h].end == null ? null : hist[h].end;

        if((dateGreaterOrEqual(date, start) && dateLess(date, end)) || (dateGreaterOrEqual(date, start) && (end == null))) {
            if(dateEqual(date, start))
                return colorStart;
            //else if(dateEqual(date, end))
            //    return '#e6c785';
            else
                return colorYes;
        }
    }

    return colorNo;
}

function dateEqual(date1, date2) {
    if(date1 == null || date2 == null)
        return false;

    return date1.getFullYear() == date2.getFullYear() && date1.getMonth() == date2.getMonth() && date1.getDate() == date2.getDate();
}

/**
 * date1 is greater than (comes after) date2.
 */
function dateGreater(date1, date2) {
    if(date1 == null || date2 == null)
        return false;

    if(date1.getFullYear() > date2.getFullYear())
        return true;
    if(date1.getFullYear() < date2.getFullYear())
        return false;
    if(date1.getMonth() > date2.getMonth())
        return true;
    if(date1.getMonth() < date2.getMonth())
        return false;
    if(date1.getDate() > date2.getDate())
        return true;
    return false;
}

/**
 * date1 comes before date2.
 */
function dateLess(date1, date2) {
    return dateGreater(date2, date1);
}

function dateGreaterOrEqual(date1, date2) {
    return dateGreater(date1, date2) || dateEqual(date1, date2);
}

function dateLessOrEqual(date1, date2) {
    return dateLess(date1, date2) || dateEqual(date1, date2);
}

/**
 * Make date string YYYY-mm-dd
 */
function makeDateStr(year, month, date) {
    if(month < 10) month = '0' + month;
    if(date  < 10) date  = '0' + date;
    return year + '-' + month + '-' + date;
}

function numberOfDays(year, month) {
    var d = new Date(year, month, 0);
    return +d.getDate();
}<commit_msg>Calendar date popup on mouse over.<commit_after>$(function() {
    drawFigures();
    initWindowResizing();
});

var prevWidth; //Figure container width before resizing

function initWindowResizing() {
    prevWidth = $('.cimg').width();

    var resizeId;
    $(window).resize(function() {
        clearTimeout(resizeId);
        resizeId = setTimeout(windowResized, 500);
    });
}

function windowResized() {
    var w = $('.cimg').width();
    if(w != prevWidth) {
        resizeFigures();
        prevWidth = w;
    }
}

function resizeFigures() {
    $('svg').each(function() {
        Snap(this).clear();
    });

    drawFigures();
}

var numcol  = 7; //Number of columns in this calendar
var gutter  = 10; //Spacing between months in pixels
var space   = 2; //Spacing between cells in pixels

var showDateText = false;

var monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];

/**
 * Draw a figure for all counters.
 */
function drawFigures() {
    var now = new Date();
    //console.log(now);
    //console.log(now.getFullYear());
    $('svg').each(function() {
        drawFigure(this, now.getFullYear(), now.getMonth());
    });

    $('rect').tooltip({container:'body'});
}

/**
 * Draw a figure, which contains multiple calendar.
 */
function drawFigure(svg, year, month) {
    var width = Math.min($('.cimg').width() - 50, 900); //Width of the figure
    var snap = Snap(svg);

    //snap.rect(50, 50, 50, 50);
    var g1, g2;

    if(month === 0) {
        g1 = drawMonthCalendar(snap, 0, width, year - 1, 11); //December of last year
    }
    else {
        g1 = drawMonthCalendar(snap, 0, width, year, month - 1);
    }

    var g2 = drawMonthCalendar(snap, 1, width, year, month);
    var monthWidth = +g1.attr('width');
    var monthHeight = +g1.attr('height');
    var tx = (monthWidth) + gutter;
    g2.transform('t' + tx);

    snap.attr({width: 2 * monthWidth + gutter, height: monthHeight});
}

/**
 * Draw a calendar.
 * @param snap      Snap object
 * @param i         calendar index: the first calendar is 0, next is 1.
 * @param cwidth    figure (canvas) total width.
 * @param year      year, as in 2014
 * @param month     month: 0 = Jan, 1 = Feb, ... , 11 = Dec
 */
function drawMonthCalendar(snap, i, cwidth, year, month) {
    var numdays = numberOfDays(year, month + 1); //Number of days in this month;
    var startOn = (new Date(year, month, 1)).getDay(); //Day of the first of this month; 0 = Sunday, 1 = Monday, etc
    var numrow  = Math.ceil((numdays + startOn) / numcol); //Number of rows in this calendar
    var width   = (((cwidth - gutter) / 2) - ((numcol - 1) * space)) / numcol; //width of cell
    var calId   = snap.attr('id'); //Id of this svg calendar
    var now     = new Date();
    //console.log(hist);

    /*console.log('year: ' + year);
    console.log('month: ' + month);
    console.log('numdays: ' + numdays);
    console.log('startOn: ' + startOn);
    console.log('numcol: ' + numcol);
    console.log('numrow: ' + numrow);
    console.log('gutter: ' + gutter);
    console.log('space: ' + space);
    console.log('width: ' + width);*/

    var group = snap.group();
    group.attr({width: width * numcol + space * numcol, height: width * numrow + space * numrow});

    for(row = 0; row < numrow; row++) {
        for(col = 0; col < numcol; col++) {
            var x = col * width + col * space;
            var y = row * width + row * space;
            var s = row * numcol + col; //Cell sequence number, starting from 0;
            var date = s - startOn + 1; //Date number, e.g. 15
            //console.log(s);
            //console.log(startOn);
            var c = '#d6e685';

            if(s < startOn || s >= numdays + startOn)
                c = '#f2f2f2';
            else {
                c = getColor(calId, new Date(year, month, date));
            }

            //var c = s < startOn || s > numdays + startOn ? '#eeeeee' : '#d6e685';
            var rectId = 'rect' + s;
            var rect = snap.rect(x, y, width, width).attr({id:rectId, fill:c});
            if(s >= startOn && s < startOn + numdays)
                rect.attr({'data-toggle':'tooltip', title:makeFullDateStr(year, month, date)});

            if(year == now.getFullYear() && month == now.getMonth() && date == now.getDate())
                rect.attr({strokeWidth:1, stroke:'#aaa'});
            group.add(rect);

            if(showDateText) {
                if(date > 0 && date <= numdays) {
                    var fontSize = width / 2;
                    var numchar = date < 10 ? 1 : 2;
                    var textX = x + (width - fontSize) / numchar;
                    var textY = y + (width - fontSize + (width / 6));
                    var textColor = '#aaa';
                    var text = snap.text(textX, textY, date).
                        attr({'font-size': fontSize + 'px', 'fill': textColor, 'opacity':0.8});
                    group.add(text);
                }
            }
        }
    }

    return group;
}

var colorYes = '#d6e685';
var colorNo  = '#e3e3e3';
var colorStart = '#bee685';
//var colorEnd = '#e6c785';

function getColor(calId, date) {
    //If this date is today or in the future, set this cell as no color.
    if(dateGreaterOrEqual(date, new Date()))
        return colorNo;

    var hist = data[calId]; //History data for this counter

    for(var h = 0; h < hist.length; h++) {
        var start = hist[h].start;
        var end = hist[h].end == null ? null : hist[h].end;

        if((dateGreaterOrEqual(date, start) && dateLess(date, end)) || (dateGreaterOrEqual(date, start) && (end == null))) {
            if(dateEqual(date, start))
                return colorStart;
            //else if(dateEqual(date, end))
            //    return '#e6c785';
            else
                return colorYes;
        }
    }

    return colorNo;
}

function dateEqual(date1, date2) {
    if(date1 == null || date2 == null)
        return false;

    return date1.getFullYear() == date2.getFullYear() && date1.getMonth() == date2.getMonth() && date1.getDate() == date2.getDate();
}

/**
 * date1 is greater than (comes after) date2.
 */
function dateGreater(date1, date2) {
    if(date1 == null || date2 == null)
        return false;

    if(date1.getFullYear() > date2.getFullYear())
        return true;
    if(date1.getFullYear() < date2.getFullYear())
        return false;
    if(date1.getMonth() > date2.getMonth())
        return true;
    if(date1.getMonth() < date2.getMonth())
        return false;
    if(date1.getDate() > date2.getDate())
        return true;
    return false;
}

/**
 * date1 comes before date2.
 */
function dateLess(date1, date2) {
    return dateGreater(date2, date1);
}

function dateGreaterOrEqual(date1, date2) {
    return dateGreater(date1, date2) || dateEqual(date1, date2);
}

function dateLessOrEqual(date1, date2) {
    return dateLess(date1, date2) || dateEqual(date1, date2);
}

/**
 * Make date string YYYY-mm-dd
 */
function makeDateStr(year, month, date) {
    if(month < 10) month = '0' + month;
    if(date  < 10) date  = '0' + date;
    return year + '-' + month + '-' + date;
}

/**
 * Example: March 22, 2015
 */
function makeFullDateStr(year, month, date) {
    return monthNames[month] + ' ' + date + ', ' + year;
}

function numberOfDays(year, month) {
    var d = new Date(year, month, 0);
    return +d.getDate();
}<|endoftext|>


<commit_before>// ==UserScript==
// @version 1.12.0
// ==/UserScript==
<commit_msg>Update for Humble Bundle<commit_after>// ==UserScript==
// @version 1.13.0
// ==/UserScript==
<|endoftext|>


<commit_before>import request from 'axios'
import { auth, handleError } from './constants'
import { URL } from 'constants/URL'

const API_URL = `${URL}/notification`
const appVersion = '0.0.92'

export const checkVersion = () => dispatch =>
  request
    .get(`${API_URL}/version?version=${appVersion}`)
    .then(response =>
      dispatch({
        type: 'CHECK_VERSION',
        data: response.data
      })
    )
    .catch(error => {
      console.error(error.response || error)
      handleError(error, dispatch)
    })

export const clearNotifications = () => ({
  type: 'CLEAR_NOTIFICATIONS'
})

export const fetchNotifications = () => async dispatch => {
  try {
    if (auth().headers.authorization === null) {
      const { data } = await request.get(`${API_URL}/chatSubject`)
      return dispatch({
        type: 'FETCH_NOTIFICATIONS',
        data: {
          notifications: [],
          currentChatSubject: data
        }
      })
    }
    const { data } = await request.get(API_URL, auth())
    return dispatch({
      type: 'FETCH_NOTIFICATIONS',
      data: data
    })
  } catch (error) {
    console.error(error.response || error)
    handleError(error, dispatch)
  }
}

export const notifyChatSubjectChange = subject => ({
  type: 'NOTIFY_CHAT_SUBJECT_CHANGE',
  subject
})
<commit_msg>version up<commit_after>import request from 'axios'
import { auth, handleError } from './constants'
import { URL } from 'constants/URL'

const API_URL = `${URL}/notification`
const appVersion = '0.0.93'

export const checkVersion = () => dispatch =>
  request
    .get(`${API_URL}/version?version=${appVersion}`)
    .then(response =>
      dispatch({
        type: 'CHECK_VERSION',
        data: response.data
      })
    )
    .catch(error => {
      console.error(error.response || error)
      handleError(error, dispatch)
    })

export const clearNotifications = () => ({
  type: 'CLEAR_NOTIFICATIONS'
})

export const fetchNotifications = () => async dispatch => {
  try {
    if (auth().headers.authorization === null) {
      const { data } = await request.get(`${API_URL}/chatSubject`)
      return dispatch({
        type: 'FETCH_NOTIFICATIONS',
        data: {
          notifications: [],
          currentChatSubject: data
        }
      })
    }
    const { data } = await request.get(API_URL, auth())
    return dispatch({
      type: 'FETCH_NOTIFICATIONS',
      data: data
    })
  } catch (error) {
    console.error(error.response || error)
    handleError(error, dispatch)
  }
}

export const notifyChatSubjectChange = subject => ({
  type: 'NOTIFY_CHAT_SUBJECT_CHANGE',
  subject
})
<|endoftext|>


<commit_before>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var sys = require('sys');
var fs = require('fs');

var sprintf = require('extern/sprintf').sprintf;

var crypto = require('crypto');
var ps = require('util/pubsub');
var config = require('util/config');
var clutch = require('extern/clutch');
var http = require('util/http');

/* List of enabled application */
var APPS = ['bundles', 'services', 'facts', 'health', 'instances'];

/* Default http services root path */
var SERVICES_HTTP_ROOT = 'services/http/';

/* List of available API versions */
var AVAILABLE_API_VERSION = [ '1.0' ];

function index(req, res) {
    res.writeHead(200, {'Content-Type': 'text-plain'});
    APPS.forEach(function(app) {
      res.write(app + '\n');
    });
    res.end();
}

exports._serverOnly = function(services_http_root, apps) {
  var r = ['GET /$', index];
  var urls = [];
  var service_urls, clutch_args, routes;

  services_http_root = services_http_root || SERVICES_HTTP_ROOT;
  apps = apps || APPS;

  APPS.forEach(function(app) {
    service_urls = require(sprintf('%s%s', services_http_root, app)).urls;

    for (var api_version in service_urls) {
      if (service_urls.hasOwnProperty(api_version)) {
        clutch_args = service_urls[api_version];
        routes = clutch.route(clutch_args);

        urls.push([sprintf('* /%s/%s', api_version, app), routes]);
      }
    }
  });

  urls.push(r);

  routes = clutch.route404(urls);

  // Note: This calls util/http.server
  var server = http.server(routes);

  return server;
};

exports.route = function(routes) {
  var i = 0, clutch_routes = {};
  var route, method, path, func;
  var split, arg_len, api_version;
  var routes_len = routes.length;

  for (i = 0; i < routes_len; i++) {
    route = routes[i];
    arg_len = route.length;

    split = route[0].split(' ');
    method = split[0];
    path = split[1];

    if (arg_len !== 3) {
      throw new Error('Function takes 3 argument - path, api version, callback');
    }

    api_version = route[1];
    func = route[2];

    if (!clutch_routes.hasOwnProperty(api_version)) {
      clutch_routes[api_version] = [];
    }

    clutch_routes[api_version].push([ sprintf('%s %s', method, path), func ]);
  }

  return clutch_routes;
};

exports.load = function() {
  var server, ip;
  var conf = config.get();

  ps.ensure(ps.AGENT_STATE_START, function() {
    server = exports._serverOnly();
    ip = conf.ip || '0.0.0.0';
    server.listen(conf.port, ip);
  });

  ps.on(ps.AGENT_STATE_STOP, function() {
    if (server) {
      server.close();
      server = null;
    }
  });
};
<commit_msg>Always show current version when no version number is provider. Maybe we should send an http redirect?<commit_after>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var sys = require('sys');
var fs = require('fs');

var sprintf = require('extern/sprintf').sprintf;

var crypto = require('crypto');
var ps = require('util/pubsub');
var config = require('util/config');
var clutch = require('extern/clutch');
var http = require('util/http');

/* List of enabled application */
var APPS = ['bundles', 'services', 'facts', 'health', 'instances'];

/* Default http services root path */
var SERVICES_HTTP_ROOT = 'services/http/';

/* List of available API versions */
var AVAILABLE_API_VERSION = [ '1.0' ];

/* Currently active API version */
var CURRENT_API_VERSION = '1.0';

function index(req, res) {
    res.writeHead(200, {'Content-Type': 'text-plain'});
    APPS.forEach(function(app) {
      res.write(app + '\n');
    });
    res.end();
}

exports._serverOnly = function(services_http_root, apps, current_api_version) {
  var r = ['GET /$', index];
  var urls = [];
  var service_urls, clutch_args, routes;

  services_http_root = services_http_root || SERVICES_HTTP_ROOT;
  apps = apps || APPS;
  current_api_version = current_api_version || CURRENT_API_VERSION;

  apps.forEach(function(app) {
    // Create "symlinks" for latest version
    service_urls = require(sprintf('%s%s', services_http_root, app)).urls;

    for (var api_version in service_urls) {
      if (service_urls.hasOwnProperty(api_version)) {
        clutch_args = service_urls[api_version];
        routes = clutch.route(clutch_args);

        if (api_version === current_api_version) {
          urls.push([sprintf('* /%s', app), routes]);
        }

        urls.push([sprintf('* /%s/%s', api_version, app), routes]);
      }
    }
  });

  urls.push(r);

  routes = clutch.route404(urls);

  // Note: This calls util/http.server
  var server = http.server(routes);

  return server;
};

exports.route = function(routes) {
  var i = 0, clutch_routes = {};
  var route, method, path, func;
  var split, arg_len, api_version;
  var routes_len = routes.length;

  for (i = 0; i < routes_len; i++) {
    route = routes[i];
    arg_len = route.length;

    split = route[0].split(' ');
    method = split[0];
    path = split[1];

    if (arg_len !== 3) {
      throw new Error('Function takes 3 argument - path, api version, callback');
    }

    api_version = route[1];
    func = route[2];

    if (!clutch_routes.hasOwnProperty(api_version)) {
      clutch_routes[api_version] = [];
    }

    clutch_routes[api_version].push([ sprintf('%s %s', method, path), func ]);
  }

  return clutch_routes;
};

exports.load = function() {
  var server, ip;
  var conf = config.get();

  ps.ensure(ps.AGENT_STATE_START, function() {
    server = exports._serverOnly();
    ip = conf.ip || '0.0.0.0';
    server.listen(conf.port, ip);
  });

  ps.on(ps.AGENT_STATE_STOP, function() {
    if (server) {
      server.close();
      server = null;
    }
  });
};
<|endoftext|>


<commit_before>
const assign = Object.assign;

class TransactionDispatcher {

    _cloneObject(object) {
        return assign({}, object);
    }

    _cloneArray(array) {
        return array.slice(0);
    }

    _createTransaction(action) {
        return null;
    }

    _updateTransaction(transition, payload) {
        for (let propsKey in payload) {
            switch (propsKey) {
                case 'ready':;
                    transaction.setReady(payload[propsKey]);
                    break;
                case 'processing':;
                    transaction.setProcessing(payload[propsKey]);
                    break;
                case 'succeeded':;
                    transaction.setSucceeded(payload[propsKey]);
                    break;
                case 'failed':;
                    transaction.setFailed(payload[propsKey]);
                    break;
                case 'errors':;
                    transaction.setErrors(this._cloneArray(payload[propsKey]));
                    break;
            }
        }
    }

    dispatch(transactionMap, action) {
        const actionTypeFrags = action.split('_');
        if (actionTypeFrags[0] === 'UPDATE') {
            const transaction = transactionMap.find(action.id);
            if (transaction) {
                this._updateTransaction(transaction, action.payload);
            }
        }
        else if (actionTypeFrags[0] === 'SET' || actionTypeFrags[0] === 'ADD') {
            const newTransactAction = this._createTransaction(action);
            if (action.payload) {
                this._updateTransaction(newTransactAction, action.payload);
            }
            transactionMap.set(action.id, newTransactAction);
        }
    }
}

export default TransactionDispatcher;<commit_msg>fixed case statements<commit_after>
const assign = Object.assign;

class TransactionDispatcher {

    _cloneObject(object) {
        return assign({}, object);
    }

    _cloneArray(array) {
        return array.slice(0);
    }

    _createTransaction(action) {
        return null;
    }

    _updateTransaction(transition, payload) {
        for (let propsKey in payload) {
            switch (propsKey) {
                case 'ready':
                    transaction.setReady(payload[propsKey]);
                    break;
                case 'processing':
                    transaction.setProcessing(payload[propsKey]);
                    break;
                case 'succeeded':
                    transaction.setSucceeded(payload[propsKey]);
                    break;
                case 'failed':
                    transaction.setFailed(payload[propsKey]);
                    break;
                case 'errors':
                    transaction.setErrors(this._cloneArray(payload[propsKey]));
                    break;
            }
        }
    }

    dispatch(transactionMap, action) {
        const actionTypeFrags = action.split('_');
        if (actionTypeFrags[0] === 'UPDATE') {
            const transaction = transactionMap.find(action.id);
            if (transaction) {
                this._updateTransaction(transaction, action.payload);
            }
        }
        else if (actionTypeFrags[0] === 'SET' || actionTypeFrags[0] === 'ADD') {
            const newTransactAction = this._createTransaction(action);
            if (action.payload) {
                this._updateTransaction(newTransactAction, action.payload);
            }
            transactionMap.set(action.id, newTransactAction);
        }
    }
}

export default TransactionDispatcher;<|endoftext|>


<commit_before>(function () {
  'use strict';

  var React = require('react');
  var Licon = require('../../../../src/js/index.js');

  var SingleIcon = React.createClass({
    incrementIndex: function () {
      this.setState({
        iconIndex: (this.state.iconIndex += 1) % this.props.icons.length
      });
    },

    selectRandom: function () {
      var randomIconIndex = Math.floor((Math.random() * this.props.icons.length));

      while(this.props.icons.length > 1 && randomIconIndex === this.state.iconIndex) {
        randomIconIndex = Math.floor((Math.random() * this.props.icons.length));
      }

      this.setState({
        iconIndex: randomIconIndex
      });
    },

    componentDidMount: function () {
      setInterval(this.selectRandom, 2000);
    },

    getInitialState: function () {
      return {
        iconIndex: 0
      };
    },

    render: function () {
      return (
        <Licon icon={this.props.icons[this.state.iconIndex]} border rounded />
      );
    }
  });

  module.exports = SingleIcon;
})();
<commit_msg>Circular random icon<commit_after>(function () {
  'use strict';

  var React = require('react');
  var Licon = require('../../../../src/js/index.js');

  var SingleIcon = React.createClass({
    incrementIndex: function () {
      this.setState({
        iconIndex: (this.state.iconIndex += 1) % this.props.icons.length
      });
    },

    selectRandom: function () {
      var randomIconIndex = Math.floor((Math.random() * this.props.icons.length));

      while(this.props.icons.length > 1 && randomIconIndex === this.state.iconIndex) {
        randomIconIndex = Math.floor((Math.random() * this.props.icons.length));
      }

      this.setState({
        iconIndex: randomIconIndex
      });
    },

    componentDidMount: function () {
      setInterval(this.selectRandom, 2000);
    },

    getInitialState: function () {
      return {
        iconIndex: 0
      };
    },

    render: function () {
      return (
        <Licon icon={this.props.icons[this.state.iconIndex]} border circle />
      );
    }
  });

  module.exports = SingleIcon;
})();
<|endoftext|>


<commit_before>var Utils     = require("../../utils")
  , DataTypes = require("../../data-types")
  , util      = require("util")

module.exports = (function() {
  var QueryGenerator = {
    createTableQuery: function(tableName, attributes, options) {
      options = Utils._.extend({
        engine: 'InnoDB',
        charset: null
      }, options || {})

      var query   = "CREATE TABLE IF NOT EXISTS <%= table %> (<%= attributes%>) ENGINE=<%= engine %> <%= charset %>"
        , primaryKeys = []
        , attrStr = []

      for (var attr in attributes) {
        if (attributes.hasOwnProperty(attr)) {
          var dataType = attributes[attr]

          if (Utils._.includes(dataType, 'PRIMARY KEY')) {
            primaryKeys.push(attr)
            attrStr.push(Utils.addTicks(attr) + " " + dataType.replace(/PRIMARY KEY/, ''))
          } else {
            attrStr.push(Utils.addTicks(attr) + " " + dataType)
          }
        }
      }

      var values = {
        table: Utils.addTicks(tableName),
        attributes: attrStr.join(", "),
        engine: options.engine,
        charset: (options.charset ? "DEFAULT CHARSET=" + options.charset : "")
      }
      , pkString = primaryKeys.map(function(pk) { return Utils.addTicks(pk) }).join(", ")

      if(pkString.length > 0) {
        values.attributes += ", PRIMARY KEY (" + pkString + ")"
      }

      return Utils._.template(query)(values).trim() + ";"
    },

    dropTableQuery: function(tableName, options) {
      options = options || {}

      var query = "DROP TABLE IF EXISTS <%= table %>;"

      return Utils._.template(query)({table: Utils.addTicks(tableName)})
    },

    renameTableQuery: function(before, after) {
      var query = "RENAME TABLE `<%= before %>` TO `<%= after %>`;"
      return Utils._.template(query)({ before: before, after: after })
    },

    showTablesQuery: function() {
      return 'SHOW TABLES;'
    },

    addColumnQuery: function(tableName, attributes) {
      var query      = "ALTER TABLE `<%= tableName %>` ADD <%= attributes %>;"
        , attrString = []

      for (var attrName in attributes) {
        var definition = attributes[attrName]

        attrString.push(Utils._.template('`<%= attrName %>` <%= definition %>')({
          attrName: attrName,
          definition: definition
        }))
      }

      return Utils._.template(query)({ tableName: tableName, attributes: attrString.join(', ') })
    },

    removeColumnQuery: function(tableName, attributeName) {
      var query = "ALTER TABLE `<%= tableName %>` DROP `<%= attributeName %>`;"
      return Utils._.template(query)({ tableName: tableName, attributeName: attributeName })
    },

    changeColumnQuery: function(tableName, attributes) {
      var query      = "ALTER TABLE `<%= tableName %>` CHANGE <%= attributes %>;"
      var attrString = []

      for (attrName in attributes) {
        var definition = attributes[attrName]

        attrString.push(Utils._.template('`<%= attrName %>` `<%= attrName %>` <%= definition %>')({
          attrName: attrName,
          definition: definition
        }))
      }

      return Utils._.template(query)({ tableName: tableName, attributes: attrString.join(', ') })
    },

    renameColumnQuery: function(tableName, attrBefore, attributes) {
      var query      = "ALTER TABLE `<%= tableName %>` CHANGE <%= attributes %>;"
      var attrString = []

      for (var attrName in attributes) {
        var definition = attributes[attrName]

        attrString.push(Utils._.template('`<%= before %>` `<%= after %>` <%= definition %>')({
          before: attrBefore,
          after: attrName,
          definition: definition
        }))
      }

      return Utils._.template(query)({ tableName: tableName, attributes: attrString.join(', ') })
    },

    selectQuery: function(tableName, options) {
      var query = "SELECT <%= attributes %> FROM <%= table %>"

      options = options || {}
      options.table = Array.isArray(tableName) ? tableName.map(function(tbl){ return Utils.addTicks(tbl) }).join(", ") : Utils.addTicks(tableName)
      options.attributes = options.attributes && options.attributes.map(function(attr){
        if(Array.isArray(attr) && attr.length == 2) {
          return [attr[0], Utils.addTicks(attr[1])].join(' as ')
        } else {
          return attr.indexOf(Utils.TICK_CHAR) < 0 ? Utils.addTicks(attr) : attr
        }
      }).join(", ")
      options.attributes = options.attributes || '*'

      if (options.include) {
        var tableNames    = [options.table]
          , optAttributes = [options.table + '.*']

        for (var daoName in options.include) {
          if (options.include.hasOwnProperty(daoName)) {
            var dao        = options.include[daoName]
              , _tableName = Utils.addTicks(dao.tableName)

            tableNames.push(_tableName)
            optAttributes = optAttributes.concat(
              Utils._.keys(dao.attributes).map(function(attr) {
                var identifer = [_tableName, Utils.addTicks(attr)]
                return identifer.join('.') + ' AS ' + Utils.addTicks(identifer.join('.'))
              })
            )
          }
        }

        options.table      = tableNames.join(', ')
        options.attributes = optAttributes.join(', ')
      }

      if(options.where) {
        options.where = this.getWhereConditions(options.where, tableName)
        query += " WHERE <%= where %>"
      }

      if(options.order) {
        query += " ORDER BY <%= order %>"
      }

      if(options.group) {
        options.group = Utils.addTicks(options.group)
        query += " GROUP BY <%= group %>"
      }

      if(options.limit && !(options.include && (options.limit === 1))) {
        if(options.offset) {
          query += " LIMIT <%= offset %>, <%= limit %>"
        } else {
          query += " LIMIT <%= limit %>"
        }
      }

      query += ";"

      return Utils._.template(query)(options)
    },

    insertQuery: function(tableName, attrValueHash) {
      attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull)

      var query = "INSERT INTO <%= table %> (<%= attributes %>) VALUES (<%= values %>);"

      var replacements  = {
        table: Utils.addTicks(tableName),
        attributes: Utils._.keys(attrValueHash).map(function(attr){return Utils.addTicks(attr)}).join(","),
        values: Utils._.values(attrValueHash).map(function(value){
          return Utils.escape((value instanceof Date) ? Utils.toSqlDate(value) : value)
        }).join(",")
      }

      return Utils._.template(query)(replacements)
    },

    updateQuery: function(tableName, attrValueHash, where) {
      attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull)

      var query  = "UPDATE <%= table %> SET <%= values %> WHERE <%= where %>"
        , values = []

      for (var key in attrValueHash) {
        var value  = attrValueHash[key]
          , _value = (value instanceof Date) ? Utils.toSqlDate(value) : value

        values.push(Utils.addTicks(key) + "=" + Utils.escape(_value))
      }

      var replacements = {
        table: Utils.addTicks(tableName),
        values: values.join(","),
        where: QueryGenerator.getWhereConditions(where)
      }

      return Utils._.template(query)(replacements)
    },

    deleteQuery: function(tableName, where, options) {
      options = options || {}
      options.limit = options.limit || 1

      var query = "DELETE FROM <%= table %> WHERE <%= where %> LIMIT <%= limit %>"
      var replacements = {
        table: Utils.addTicks(tableName),
        where: QueryGenerator.getWhereConditions(where),
        limit: Utils.escape(options.limit)
      }

      return Utils._.template(query)(replacements)
    },

    addIndexQuery: function(tableName, attributes, options) {
      var transformedAttributes = attributes.map(function(attribute) {
        if(typeof attribute == 'string')
          return attribute
        else {
          var result = ""

          if(!attribute.attribute)
            throw new Error('The following index attribute has no attribute: ' + util.inspect(attribute))

          result += attribute.attribute

          if(attribute.length)
            result += '(' + attribute.length + ')'

          if(attribute.order)
            result += ' ' + attribute.order

          return result
        }
      })

      var onlyAttributeNames = attributes.map(function(attribute) {
        return (typeof attribute == 'string') ? attribute : attribute.attribute
      })

      options = Utils._.extend({
        indicesType: null,
        indexName: Utils._.underscored(tableName + '_' + onlyAttributeNames.join('_')),
        parser: null
      }, options || {})

      return Utils._.compact([
        "CREATE", options.indicesType, "INDEX", options.indexName,
        (options.indexType ? ('USING ' + options.indexType) : undefined),
        "ON", tableName, '(' + transformedAttributes.join(', ') + ')',
        (options.parser ? "WITH PARSER " + options.parser : undefined)
      ]).join(' ')
    },

    showIndexQuery: function(tableName, options) {
      var sql = "SHOW INDEX FROM <%= tableName %><%= options %>"
      return Utils._.template(sql)({
        tableName: tableName,
        options: (options || {}).database ? ' FROM ' + options.database : ''
      })
    },

    removeIndexQuery: function(tableName, indexNameOrAttributes) {
      var sql       = "DROP INDEX <%= indexName %> ON <%= tableName %>"
        , indexName = indexNameOrAttributes

      if(typeof indexName != 'string')
        indexName = Utils._.underscored(tableName + '_' + indexNameOrAttributes.join('_'))

      return Utils._.template(sql)({ tableName: tableName, indexName: indexName })
    },

    getWhereConditions: function(smth, tableName) {
      var result = null

      if(Utils.isHash(smth)) {
        smth   = Utils.prependTableNameToHash(tableName, smth)
        result = this.hashToWhereConditions(smth)
      } else if (typeof smth === 'number') {
        smth   = Utils.prependTableNameToHash(tableName, { id: smth })
        result = this.hashToWhereConditions(smth)
      } else if (typeof smth === "string") {
        result = smth
      } else if (Array.isArray(smth)) {
        result = Utils.format(smth)
      }

      return result
    },

    hashToWhereConditions: function(hash) {
      var result = []

      for (var key in hash) {
        var value = hash[key]

         //handle qualified key names
        var _key   = key.split('.').map(function(col){return Utils.addTicks(col)}).join(".")
          , _value = null

        if (Array.isArray(value)) {
          // is value an array?

          _value = "(" + value.map(function(subValue) {
            return Utils.escape(subValue);
          }).join(',') + ")"

          result.push([_key, _value].join(" IN "))
        } else if ((value) && (typeof value == 'object')) {
          // is value an object?

          //using as sentinel for join column => value
          _value = value.join.split('.').map(function(col){ return Utils.addTicks(col) }).join(".")
          result.push([_key, _value].join("="))
        } else {
          _value = Utils.escape(value)
          result.push((_value == 'NULL') ? _key + " IS NULL" : [_key, _value].join("="))
        }
      }

      return result.join(" AND ")
    },

    attributesToSQL: function(attributes) {
      var result = {}

      for (var name in attributes) {
        var dataType = attributes[name]

        if(Utils.isHash(dataType)) {
          var template     = "<%= type %>"
            , replacements = { type: dataType.type }

          if(dataType.hasOwnProperty('allowNull') && (!dataType.allowNull)) {
            template += " NOT NULL"
          }

          if(dataType.autoIncrement) {
            template +=" auto_increment"
          }

          if((dataType.defaultValue != undefined) && (dataType.defaultValue != DataTypes.NOW)) {
            template += " DEFAULT <%= defaultValue %>"
            replacements.defaultValue = Utils.escape(dataType.defaultValue)
          }

          if(dataType.unique) {
            template += " UNIQUE"
          }

          if(dataType.primaryKey) {
            template += " PRIMARY KEY"
          }

          result[name] = Utils._.template(template)(replacements)
        } else {
          result[name] = dataType
        }
      }

      return result
    },

    findAutoIncrementField: function(factory) {
      var fields = []

      for (var name in factory.attributes) {
        if (factory.attributes.hasOwnProperty(name)) {
          var definition = factory.attributes[name]

          if (definition && (definition.indexOf('auto_increment') > -1)) {
            fields.push(name)
          }
        }
      }

      return fields
    }
  }

  return Utils._.extend(Utils._.clone(require("../query-generator")), QueryGenerator)
})()
<commit_msg>formatting<commit_after>var Utils     = require("../../utils")
  , DataTypes = require("../../data-types")
  , util      = require("util")

module.exports = (function() {
  var QueryGenerator = {
    createTableQuery: function(tableName, attributes, options) {
      options = Utils._.extend({
        engine: 'InnoDB',
        charset: null
      }, options || {})

      var query   = "CREATE TABLE IF NOT EXISTS <%= table %> (<%= attributes%>) ENGINE=<%= engine %> <%= charset %>"
        , primaryKeys = []
        , attrStr = []

      for (var attr in attributes) {
        if (attributes.hasOwnProperty(attr)) {
          var dataType = attributes[attr]

          if (Utils._.includes(dataType, 'PRIMARY KEY')) {
            primaryKeys.push(attr)
            attrStr.push(Utils.addTicks(attr) + " " + dataType.replace(/PRIMARY KEY/, ''))
          } else {
            attrStr.push(Utils.addTicks(attr) + " " + dataType)
          }
        }
      }

      var values = {
        table: Utils.addTicks(tableName),
        attributes: attrStr.join(", "),
        engine: options.engine,
        charset: (options.charset ? "DEFAULT CHARSET=" + options.charset : "")
      }
      , pkString = primaryKeys.map(function(pk) { return Utils.addTicks(pk) }).join(", ")

      if(pkString.length > 0) {
        values.attributes += ", PRIMARY KEY (" + pkString + ")"
      }

      return Utils._.template(query)(values).trim() + ";"
    },

    dropTableQuery: function(tableName, options) {
      options = options || {}

      var query = "DROP TABLE IF EXISTS <%= table %>;"

      return Utils._.template(query)({table: Utils.addTicks(tableName)})
    },

    renameTableQuery: function(before, after) {
      var query = "RENAME TABLE `<%= before %>` TO `<%= after %>`;"
      return Utils._.template(query)({ before: before, after: after })
    },

    showTablesQuery: function() {
      return 'SHOW TABLES;'
    },

    addColumnQuery: function(tableName, attributes) {
      var query      = "ALTER TABLE `<%= tableName %>` ADD <%= attributes %>;"
        , attrString = []

      for (var attrName in attributes) {
        var definition = attributes[attrName]

        attrString.push(Utils._.template('`<%= attrName %>` <%= definition %>')({
          attrName: attrName,
          definition: definition
        }))
      }

      return Utils._.template(query)({ tableName: tableName, attributes: attrString.join(', ') })
    },

    removeColumnQuery: function(tableName, attributeName) {
      var query = "ALTER TABLE `<%= tableName %>` DROP `<%= attributeName %>`;"
      return Utils._.template(query)({ tableName: tableName, attributeName: attributeName })
    },

    changeColumnQuery: function(tableName, attributes) {
      var query      = "ALTER TABLE `<%= tableName %>` CHANGE <%= attributes %>;"
      var attrString = []

      for (attrName in attributes) {
        var definition = attributes[attrName]

        attrString.push(Utils._.template('`<%= attrName %>` `<%= attrName %>` <%= definition %>')({
          attrName: attrName,
          definition: definition
        }))
      }

      return Utils._.template(query)({ tableName: tableName, attributes: attrString.join(', ') })
    },

    renameColumnQuery: function(tableName, attrBefore, attributes) {
      var query      = "ALTER TABLE `<%= tableName %>` CHANGE <%= attributes %>;"
      var attrString = []

      for (var attrName in attributes) {
        var definition = attributes[attrName]

        attrString.push(Utils._.template('`<%= before %>` `<%= after %>` <%= definition %>')({
          before: attrBefore,
          after: attrName,
          definition: definition
        }))
      }

      return Utils._.template(query)({ tableName: tableName, attributes: attrString.join(', ') })
    },

    selectQuery: function(tableName, options) {
      var query = "SELECT <%= attributes %> FROM <%= table %>"

      options = options || {}
      options.table = Array.isArray(tableName) ? tableName.map(function(tbl){ return Utils.addTicks(tbl) }).join(", ") : Utils.addTicks(tableName)
      options.attributes = options.attributes && options.attributes.map(function(attr){
        if(Array.isArray(attr) && attr.length == 2) {
          return [attr[0], Utils.addTicks(attr[1])].join(' as ')
        } else {
          return attr.indexOf(Utils.TICK_CHAR) < 0 ? Utils.addTicks(attr) : attr
        }
      }).join(", ")
      options.attributes = options.attributes || '*'

      if (options.include) {
        var tableNames    = [options.table]
          , optAttributes = [options.table + '.*']

        for (var daoName in options.include) {
          if (options.include.hasOwnProperty(daoName)) {
            var dao        = options.include[daoName]
              , _tableName = Utils.addTicks(dao.tableName)

            tableNames.push(_tableName)
            optAttributes = optAttributes.concat(
              Utils._.keys(dao.attributes).map(function(attr) {
                var identifer = [_tableName, Utils.addTicks(attr)]
                return identifer.join('.') + ' AS ' + Utils.addTicks(identifer.join('.'))
              })
            )
          }
        }

        options.table      = tableNames.join(', ')
        options.attributes = optAttributes.join(', ')
      }

      if(options.where) {
        options.where = this.getWhereConditions(options.where, tableName)
        query += " WHERE <%= where %>"
      }

      if(options.order) {
        query += " ORDER BY <%= order %>"
      }

      if(options.group) {
        options.group = Utils.addTicks(options.group)
        query += " GROUP BY <%= group %>"
      }

      if(options.limit && !(options.include && (options.limit === 1))) {
        if(options.offset) {
          query += " LIMIT <%= offset %>, <%= limit %>"
        } else {
          query += " LIMIT <%= limit %>"
        }
      }

      query += ";"

      return Utils._.template(query)(options)
    },

    insertQuery: function(tableName, attrValueHash) {
      attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull)

      var query = "INSERT INTO <%= table %> (<%= attributes %>) VALUES (<%= values %>);"

      var replacements  = {
        table: Utils.addTicks(tableName),
        attributes: Utils._.keys(attrValueHash).map(function(attr){return Utils.addTicks(attr)}).join(","),
        values: Utils._.values(attrValueHash).map(function(value){
          return Utils.escape((value instanceof Date) ? Utils.toSqlDate(value) : value)
        }).join(",")
      }

      return Utils._.template(query)(replacements)
    },

    updateQuery: function(tableName, attrValueHash, where) {
      attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull)

      var query  = "UPDATE <%= table %> SET <%= values %> WHERE <%= where %>"
        , values = []

      for (var key in attrValueHash) {
        var value  = attrValueHash[key]
          , _value = (value instanceof Date) ? Utils.toSqlDate(value) : value

        values.push(Utils.addTicks(key) + "=" + Utils.escape(_value))
      }

      var replacements = {
        table: Utils.addTicks(tableName),
        values: values.join(","),
        where: QueryGenerator.getWhereConditions(where)
      }

      return Utils._.template(query)(replacements)
    },

    deleteQuery: function(tableName, where, options) {
      options = options || {}
      options.limit = options.limit || 1

      var query = "DELETE FROM <%= table %> WHERE <%= where %> LIMIT <%= limit %>"
      var replacements = {
        table: Utils.addTicks(tableName),
        where: QueryGenerator.getWhereConditions(where),
        limit: Utils.escape(options.limit)
      }

      return Utils._.template(query)(replacements)
    },

    addIndexQuery: function(tableName, attributes, options) {
      var transformedAttributes = attributes.map(function(attribute) {
        if(typeof attribute == 'string')
          return attribute
        else {
          var result = ""

          if(!attribute.attribute)
            throw new Error('The following index attribute has no attribute: ' + util.inspect(attribute))

          result += attribute.attribute

          if(attribute.length)
            result += '(' + attribute.length + ')'

          if(attribute.order)
            result += ' ' + attribute.order

          return result
        }
      })

      var onlyAttributeNames = attributes.map(function(attribute) {
        return (typeof attribute == 'string') ? attribute : attribute.attribute
      })

      options = Utils._.extend({
        indicesType: null,
        indexName: Utils._.underscored(tableName + '_' + onlyAttributeNames.join('_')),
        parser: null
      }, options || {})

      return Utils._.compact([
        "CREATE", options.indicesType, "INDEX", options.indexName,
        (options.indexType ? ('USING ' + options.indexType) : undefined),
        "ON", tableName, '(' + transformedAttributes.join(', ') + ')',
        (options.parser ? "WITH PARSER " + options.parser : undefined)
      ]).join(' ')
    },

    showIndexQuery: function(tableName, options) {
      var sql = "SHOW INDEX FROM <%= tableName %><%= options %>"
      return Utils._.template(sql)({
        tableName: tableName,
        options: (options || {}).database ? ' FROM ' + options.database : ''
      })
    },

    removeIndexQuery: function(tableName, indexNameOrAttributes) {
      var sql       = "DROP INDEX <%= indexName %> ON <%= tableName %>"
        , indexName = indexNameOrAttributes

      if(typeof indexName != 'string')
        indexName = Utils._.underscored(tableName + '_' + indexNameOrAttributes.join('_'))

      return Utils._.template(sql)({ tableName: tableName, indexName: indexName })
    },

    getWhereConditions: function(smth, tableName) {
      var result = null

      if(Utils.isHash(smth)) {
        smth   = Utils.prependTableNameToHash(tableName, smth)
        result = this.hashToWhereConditions(smth)
      } else if (typeof smth === 'number') {
        smth   = Utils.prependTableNameToHash(tableName, { id: smth })
        result = this.hashToWhereConditions(smth)
      } else if (typeof smth === "string") {
        result = smth
      } else if (Array.isArray(smth)) {
        result = Utils.format(smth)
      }

      return result
    },

    hashToWhereConditions: function(hash) {
      var result = []

      for (var key in hash) {
        var value = hash[key]

         //handle qualified key names
        var _key   = key.split('.').map(function(col){return Utils.addTicks(col)}).join(".")
          , _value = null

        if (Array.isArray(value)) {
          // is value an array?

          _value = "(" + value.map(function(subValue) {
            return Utils.escape(subValue);
          }).join(',') + ")"

          result.push([_key, _value].join(" IN "))
        } else if ((value) && (typeof value == 'object')) {
          // is value an object?

          //using as sentinel for join column => value
          _value = value.join.split('.').map(function(col){ return Utils.addTicks(col) }).join(".")
          result.push([_key, _value].join("="))
        } else {
          _value = Utils.escape(value)
          result.push((_value == 'NULL') ? _key + " IS NULL" : [_key, _value].join("="))
        }
      }

      return result.join(" AND ")
    },

    attributesToSQL: function(attributes) {
      var result = {}

      for (var name in attributes) {
        var dataType = attributes[name]

        if(Utils.isHash(dataType)) {
          var template     = "<%= type %>"
            , replacements = { type: dataType.type }

          if(dataType.hasOwnProperty('allowNull') && (!dataType.allowNull)) {
            template += " NOT NULL"
          }

          if(dataType.autoIncrement) {
            template += " auto_increment"
          }

          if((dataType.defaultValue != undefined) && (dataType.defaultValue != DataTypes.NOW)) {
            template += " DEFAULT <%= defaultValue %>"
            replacements.defaultValue = Utils.escape(dataType.defaultValue)
          }

          if(dataType.unique) {
            template += " UNIQUE"
          }

          if(dataType.primaryKey) {
            template += " PRIMARY KEY"
          }

          result[name] = Utils._.template(template)(replacements)
        } else {
          result[name] = dataType
        }
      }

      return result
    },

    findAutoIncrementField: function(factory) {
      var fields = []

      for (var name in factory.attributes) {
        if (factory.attributes.hasOwnProperty(name)) {
          var definition = factory.attributes[name]

          if (definition && (definition.indexOf('auto_increment') > -1)) {
            fields.push(name)
          }
        }
      }

      return fields
    }
  }

  return Utils._.extend(Utils._.clone(require("../query-generator")), QueryGenerator)
})()
<|endoftext|>


<commit_before>// Essentially, this is a fstream.DirReader class, but with a
// bit of special logic to read the specified sort of ignore files,
// and a filter that prevents it from picking up anything excluded
// by those files.

var Minimatch = require("minimatch").Minimatch
, fstream = require("fstream")
, DirReader = fstream.DirReader
, inherits = require("inherits")
, path = require("path")

module.exports = IgnoreReader

inherits(IgnoreReader, DirReader)

function IgnoreReader (props) {
  if (!(this instanceof IgnoreReader)) {
    return new IgnoreReader(props)
  }

  // must be a Directory type
  if (typeof props === "string") {
    props = { path: props }
  }

  props.type = "Directory"
  props.Directory = true

  if (!props.ignoreFiles) props.ignoreFiles = [".ignore"]
  this.ignoreFiles = props.ignoreFiles

  this.ignoreRules = null

  // get the set of ancestors that have ignore rules.
  // we unshift so that they'll be in the right order
  // to be iterated over from 0->length later.
  this.ancestorIgnores = []
  for (var p = this.parent; p; p = p.parent) {
    if (p.ignoreRules) this.ancestorIgnores.unshift(p)
  }
  // then, push this one in, so that it's the highest precedence
  this.ancestorIgnores.push(this)

  if (props.filter) this._filter = props.filter
  props.filter = this.filter.bind(this)

  // ensure that .ignore files always show up at the top of the list
  // that way, they can be read before proceeding to handle other
  // entries in that same folder
  if (props.sort) {
    this._sort = props.sort === "alpha" ? alphasort : props.sort
  }
  props.sort = this.sort.bind(this)

  this.on("entry", function (e) {
    // if this is an ignore file, then process it for rules
    var isIg = this.ignoreFiles.indexOf(e.basename) !== -1
    if (!isIg) return

    this.emit("ignoreFile", e)

    // call e.abort() in the above event to prevent its inclusion
    if (!e._aborted)
      this.addIgnoreFile(e)
  })

  DirReader.call(this, props)
}

IgnoreReader.prototype.getChildProps = function (stat) {
  var props = DirReader.prototype.getChildProps.call(this, stat)
  props.ignoreFiles = this.ignoreFiles

  // Directories have to be read as IgnoreReaders
  // otherwise fstream.Reader will create a DirReader instead.
  if (stat.isDirectory()) {
    props.type = this.constructor
  }
  return props
}

IgnoreReader.prototype.addIgnoreFile = function (e) {
  // buffer the output.
  // these files won't be very big.
  var buf = new Buffer(e.size)
  , i = 0

  e.on("data", ondata)
  function ondata (c) {
    c.copy(buf, i)
    i += c.length
  }

  var onend = function onend () {
    // perhaps aborted.  do nothing.
    if (i === 0 || e._aborted) return
    var rules = this.readRules(buf, e)
    this.addIgnoreRules(rules, e)
  }.bind(this)
  e.on("end", onend)

  e.on("abort", function () {
    e.removeListener("data", ondata)
    e.removeListener("end", onend)
  })
}

IgnoreReader.prototype.readRules = function (buf, entry) {
  return buf.toString().split(/\r?\n/)
}

IgnoreReader.prototype.addIgnoreRules = function (set, e) {
  // filter out anything obvious
  set = set.filter(function (s) {
    s = s.trim()
    return s && !s.match(/^#/)
  })

  // no rules to add!
  if (!set.length) return

  // now get a minimatch object for each one of these.
  // Note that we need to allow dot files by default, and
  // not switch the meaning of their exclusion, so they're
  var mm = set.map(function (s) {
    var m = new Minimatch(s, { matchBase: true, dot: true, flipNegate: true })
    m.ignoreFile = e.basename
    return m
  })

  if (!this.ignoreRules) this.ignoreRules = []
  this.ignoreRules.push.apply(this.ignoreRules, mm)
}

IgnoreReader.prototype.filter = function (entry) {
  this.applyIgnores(entry)
  if (entry.excluded) return false
  return this._filter ? this._filter.apply(entry, arguments) : true

}

// sets an "excluded" flag on the entry if it's excluded.
IgnoreReader.prototype.applyIgnores = function (entry) {
  // walk back up the family tree.
  // At each level, test the entry against all the rules
  // at that level, as if it was rooted there.
  // For example, when testing a/b/c, we'll test against a's rules
  // as /b/c and then against b's rules as /c.  This is because
  // a .ignore file at a/.ignore would igore the a/b/c file with
  // a rule of `/b/c`, but not with a rule of `/c`.
  //
  // Negated Rules
  // Since we're *ignoring* things here, negating means that a file
  // is re-included, if it would have been excluded by a previous
  // rule.  So, negated rules are only relevant if the file
  // has been excluded.
  //
  // Similarly, if a file has been excluded, then there's no point
  // trying it against rules that have already been applied
  //
  // We're using the "flipnegate" flag here, which tells minimatch
  // to set the "negate" for our information, but still report
  // whether the core pattern was a hit or a miss.

  if (this.parent) this.parent.applyIgnores(entry)
  if (!this.ignoreRules) return

  var test = entry.path.substr(this.path.length)
  // console.error("rules", this.ignoreRules.map(function (rule) {
  //   return (rule.negate ? "!" : "") + rule.pattern
  // }))

  this.ignoreRules.forEach(function (rule) {
    // negation means inclusion
    if (rule.negate && !entry.excluded ||
        !rule.negate && entry.excluded) return

    var match = rule.match(test) || rule.match(test.substr(1))
    if (match) {
      entry.excluded = !rule.negate
    }
  })
}

IgnoreReader.prototype.sort = function (a, b) {
  var aig = this.ignoreFiles.indexOf(a) !== -1
  , big = this.ignoreFiles.indexOf(b) !== -1
  if (aig && !big) return -1
  if (big && !aig) return 1
  return this._sort(a, b)
}

IgnoreReader.prototype._sort = function (a, b) {
  return 0
}

function alphasort (a, b) {
  return a === b ? 0
       : a.toLowerCase() > b.toLowerCase() ? 1
       : a.toLowerCase() < b.toLowerCase() ? -1
       : a > b ? 1
       : -1
}
<commit_msg>savepoint before significant refactor<commit_after>// Essentially, this is a fstream.DirReader class, but with a
// bit of special logic to read the specified sort of ignore files,
// and a filter that prevents it from picking up anything excluded
// by those files.

var Minimatch = require("minimatch").Minimatch
, fstream = require("fstream")
, DirReader = fstream.DirReader
, inherits = require("inherits")
, path = require("path")

module.exports = IgnoreReader

inherits(IgnoreReader, DirReader)

function IgnoreReader (props) {
  if (!(this instanceof IgnoreReader)) {
    return new IgnoreReader(props)
  }

  // must be a Directory type
  if (typeof props === "string") {
    props = { path: props }
  }

  props.type = "Directory"
  props.Directory = true

  if (!props.ignoreFiles) props.ignoreFiles = [".ignore"]
  this.ignoreFiles = props.ignoreFiles

  this.ignoreRules = null

  // XXX
  // Existing filters are not handled properly.
  // this results in files being missed if they're re-included
  // if (props.filter &&
  //     (!this.parent || props.filter !== this.parent.filter)) {
  //   this._filter = props.filter
  // }

  props.filter = this.filter = this.filter.bind(this)

  // ensure that .ignore files always show up at the top of the list
  // that way, they can be read before proceeding to handle other
  // entries in that same folder
  if (props.sort) {
    this._sort = props.sort === "alpha" ? alphasort : props.sort
  }
  props.sort = this.sort.bind(this)

  // XXX This needs to be detected much earlier, in the
  // addEntries method.
  this.on("entry", function (e) {
    // if this is an ignore file, then process it for rules
    var isIg = this.ignoreFiles.indexOf(e.basename) !== -1
    if (!isIg) return

    this.emit("ignoreFile", e)

    // call e.abort() in the above event to prevent its inclusion
    if (!e._aborted)
      this.addIgnoreFile(e)
  })

  DirReader.call(this, props)
}

IgnoreReader.prototype.getChildProps = function (stat) {
  var props = DirReader.prototype.getChildProps.call(this, stat)
  props.ignoreFiles = this.ignoreFiles

  // Directories have to be read as IgnoreReaders
  // otherwise fstream.Reader will create a DirReader instead.
  if (stat.isDirectory()) {
    props.type = this.constructor
  }
  return props
}

IgnoreReader.prototype.addIgnoreFile = function (e) {
  // buffer the output.
  // these files won't be very big.
  var buf = new Buffer(e.size)
  , i = 0

  e.on("data", ondata)
  function ondata (c) {
    c.copy(buf, i)
    i += c.length
  }

  var onend = function onend () {
    console.error("end", e.path, e._aborted)
    // perhaps aborted.  do nothing.
    if (i === 0 || e._aborted) return
    var rules = this.readRules(buf, e)
    this.addIgnoreRules(rules, e)
  }.bind(this)
  e.on("end", onend)

  e.on("abort", function () {
    e.removeListener("data", ondata)
    e.removeListener("end", onend)
  })
}

IgnoreReader.prototype.readRules = function (buf, entry) {
  return buf.toString().split(/\r?\n/)
}

IgnoreReader.prototype.addIgnoreRules = function (set, e) {
  // filter out anything obvious
  set = set.filter(function (s) {
    s = s.trim()
    return s && !s.match(/^#/)
  })

  // no rules to add!
  if (!set.length) return

  console.error("addIgnoreRules", e.path, set)

  // now get a minimatch object for each one of these.
  // Note that we need to allow dot files by default, and
  // not switch the meaning of their exclusion, so they're
  var mm = set.map(function (s) {
    var m = new Minimatch(s, { matchBase: true, dot: true, flipNegate: true })
    m.ignoreFile = e.basename
    return m
  })

  if (!this.ignoreRules) this.ignoreRules = []
  this.ignoreRules.push.apply(this.ignoreRules, mm)
}

IgnoreReader.prototype.filter = function (entry) {

  var d = entry.basename === ".cba" ? function () {
    var p = this.path.substr(this.root.path.length)
    var args = [p, entry.path.substr(this.path.length)].concat([].slice.call(arguments))
    console.error.apply(console, args)
  }.bind(this) : function () {}

  d("FILTER: apply ignores")
  this.applyIgnores(entry)
  // if (!entry.excluded && this._filter) {
  //   d("Has a _filter")
  //   entry.excluded = !this._filter.apply(entry, arguments)
  //   d("applied _filter, excluded=", entry.excluded)
  // }

  // if it's an ignore file, we may not be in a mood to
  // include it, but its rules still have an effect, even
  // if it's been excluded.
  if (entry.excluded &&
      -1 !== this.ignoreFiles.indexOf(entry.basename)) {
    this.pause()
    this.disown(entry)

    this.emit("ignoreFile", entry)
    if (!entry._aborted)
      this.addIgnoreFile(entry)

    entry.on("close", function () {
      console.error("resuming", this.path, this.ignoreRules.map(function (m) {
        return (m.negate ? "!" : "") + m.pattern
      }))
      this.resume()
    }.bind(this))
    entry.on("data", function (c) {
      console.error("disowned data >" + c)
    })

    console.error("resuming entry")
    entry.resume()
  }

  return !entry.excluded
}

// sets an "excluded" flag on the entry if it's excluded.
IgnoreReader.prototype.applyIgnores = function (entry) {

  var d = entry.basename === ".cba" ? function () {
    var p = this.path.substr(this.root.path.length)
    var args = [p, entry.path.substr(this.path.length)].concat([].slice.call(arguments))
    console.error.apply(console, args)
  }.bind(this) : function () {}

  // walk back up the family tree.
  // At each level, test the entry against all the rules
  // at that level, as if it was rooted there.
  // For example, when testing a/b/c, we'll test against a's rules
  // as /b/c and then against b's rules as /c.  This is because
  // a .ignore file at a/.ignore would igore the a/b/c file with
  // a rule of `/b/c`, but not with a rule of `/c`.
  //
  // Negated Rules
  // Since we're *ignoring* things here, negating means that a file
  // is re-included, if it would have been excluded by a previous
  // rule.  So, negated rules are only relevant if the file
  // has been excluded.
  //
  // Similarly, if a file has been excluded, then there's no point
  // trying it against rules that have already been applied
  //
  // We're using the "flipnegate" flag here, which tells minimatch
  // to set the "negate" for our information, but still report
  // whether the core pattern was a hit or a miss.

  d("START")
  if (this.parent) this.parent.applyIgnores(entry)
  d("asked parents")
  if (!this.ignoreRules) {
    d("  no rules")
    return
  }

  var test = entry.path.substr(this.path.length)
  d("TEST", test, this.ignoreRules.map(function (rule) {
    return (rule.negate ? "!" : "") + rule.pattern
  }))

  // d("rules", this.ignoreRules.map(function (rule) {
  //   return (rule.negate ? "!" : "") + rule.pattern
  // }))

  // d("apply ignores "+ test)

  this.ignoreRules.forEach(function (rule) {
    // negation means inclusion
    if (rule.negate && !entry.excluded ||
        !rule.negate && entry.excluded) {
      d("  unnecessary", rule.pattern)
      return
    }

    // first, match against /foo/bar
    var match = rule.match(test)

    if (!match) {
      // try with the leading / trimmed off the test
      // eg: foo/bar instead of /foo/bar
      match = rule.match(test.substr(1))
    }

    d("  filematch", match, rule.pattern)

    // if the entry is a directory, then it will match
    // with a trailing slash. eg: /foo/bar/ or foo/bar/
    if (!match && entry.type === "Directory") {
      match = rule.match(test + "/")
      if (!match) {
        match = rule.match(test.substr(1) + "/")
      }

      // When including a file with a negated rule, it's
      // relevant if a directory partially matches, since
      // it may then match a file within it.
      // Eg, if you ignore /a, but !/a/b/c
      if (!match && rule.negate) {
        match = rule.match(test, true) ||
                rule.match(test.substr(1), true) ||
                rule.match(test + "/", true) ||
                rule.match(test.substr(1) + "/", true)
      }
      d("  dirmatch ", match, rule.pattern)
    }

    if (match) {
      entry.excluded = !rule.negate
      d("  MATCH! excluded =", entry.excluded, rule.pattern)
      //d("HIT", rule.negate, this.path, rule.pattern, entry.path.substr(this.path.length), this.ignoreRules.map(function (r) { return r.pattern }))
    }
  }, this)
  d("FINISH", entry.excluded)
}

IgnoreReader.prototype.sort = function (a, b) {
  var aig = this.ignoreFiles.indexOf(a) !== -1
  , big = this.ignoreFiles.indexOf(b) !== -1
  if (aig && !big) return -1
  if (big && !aig) return 1
  return this._sort(a, b)
}

IgnoreReader.prototype._sort = function (a, b) {
  return 0
}

function alphasort (a, b) {
  return a === b ? 0
       : a.toLowerCase() > b.toLowerCase() ? 1
       : a.toLowerCase() < b.toLowerCase() ? -1
       : a > b ? 1
       : -1
}
<|endoftext|>