<commit_before>// see http://eslint.org/docs/rules/#stylistic-issues

module.exports = {
	// Enforce linebreaks after opening and before closing array brackets
	'array-bracket-newline': 'off',
	// Enforce spacing inside array brackets
	'array-bracket-spacing': 'off',
	// Enforce line breaks after each array element
	'array-element-newline': 'off',
	// Disallow or enforce spaces inside of single line blocks
	'block-spacing': ['warn', 'always'],
	// Enforce one true brace style
	'brace-style': ['warn', '1tbs', {
		allowSingleLine: true,
	}],
	// Require camel case names
	camelcase: ['warn', {
		properties: 'always',
	}],
	// Enforce or disallow capitalization of the first letter of a comment
	'capitalized-comments': 'off',
	// Disallow or enforce trailing commas
	'comma-dangle': ['error', 'always-multiline'],
	// Enforce spacing before and after comma
	'comma-spacing': ['warn', {
		before: false,
		after: true,
	}],
	// Enforce one true comma style
	'comma-style': ['warn', 'last'],
	// Require or disallow padding inside computed properties
	'computed-property-spacing': 'off',
	// Enforces consistent naming when capturing the current execution context
	'consistent-this': ['warn', 'self'],
	// Enforce newline at the end of file, with no multiple empty lines
	'eol-last': 'warn',
	// Require or disallow spacing between function identifiers and their invocations
	'func-call-spacing': 'off',
	// Require function names to match the name of the variable or property to which they are assigned
	'func-name-matching': 'off',
	// Don't require function expressions to have a name
	'func-names': 'off',
	// Enforces use of function declarations or expressions
	'func-style': ['warn', 'declaration'],
	// Enforce consistent line breaks inside function parentheses
	'function-paren-newline': 'off',
	// Blacklist certain identifiers to prevent them being used
	'id-blacklist': 'off',
	// This option enforces minimum and maximum identifier lengths (variable names, property names etc.)
	'id-length': ['warn', {
		min: 2,
		properties: 'always',
		exceptions: ['x', 'y', 'i', 'j', 't', '_', '$'],
	}],
	// Require identifiers to match the provided regular expression
	'id-match': 'off',
	// This option sets a specific tab width for your code
	indent: ['error', 'tab', {
		SwitchCase: 1,
	}],
	// Specify whether double or single quotes should be used in JSX attributes
	'jsx-quotes': ['warn', 'prefer-double'],
	// Enforces spacing between keys and values in object literal properties
	'key-spacing': ['warn', {
		beforeColon: false,
		afterColon: true,
	}],
	// Enforce spacing before and after keywords
	'keyword-spacing': ['warn', {
		before: true,
		after: true,
		overrides: {},
	}],
	// Disallow mixed "LF" and "CRLF" as linebreaks
	'linebreak-style': 'off',
	// Enforce position of line comments
	'line-comment-position': 'off',
	// Enforces empty lines around comments
	'lines-around-comment': ['warn', {
		beforeBlockComment: true,
	}],
	// Require or disallow an empty line between class members
	'lines-between-class-members': 'off',
	// Specify the maximum depth that blocks can be nested
	'max-depth': 'off',
	// Specify the maximum line length
	'max-len': 'off',
	// Enforce a maximum number of lines per file
	'max-lines': 'off',
	// Specify the maximum depth callbacks can be nested
	'max-nested-callbacks': 'off',
	// Specify the maximum number of parameters in function definitions
	'max-params': 'off',
	// Specify the maximum number of statements allowed in function blocks
	'max-statements': 'off',
	// Specify the maximum number of statements allowed per line
	'max-statements-per-line': ['warn', {
		max: 2,
	}],
	// Enforce a particular style for multiline comments
	'multiline-comment-style': 'off',
	// Enforce newlines between operands of ternary expressions
	'multiline-ternary': 'off',
	// Require a capital letter for constructors
	'new-cap': 'off',
	// Disallow the omission of parentheses when invoking a constructor with no arguments
	'new-parens': 'warn',
	// Enforce newline after each call when chaining the calls
	'newline-per-chained-call': ['warn', {
		ignoreChainWithDepth: 3,
	}],
	// Disallow use of the Array constructor
	'no-array-constructor': 'error',
	// Disallow bitwise operators
	'no-bitwise': 'off',
	// Disallow use of the continue statement
	'no-continue': 'off',
	// Disallow comments inline after code
	'no-inline-comments': 'off',
	// Disallow if as the only statement in an else block
	'no-lonely-if': 'off',
	// Disallow mixed binary operators
	'no-mixed-operators': 'off',
	// Disallow mixed spaces and tabs for indentation
	'no-mixed-spaces-and-tabs': 'warn',
	// Disallow use of chained assignment expressions
	'no-multi-assign': 'off',
	// Disallow multiple empty lines
	'no-multiple-empty-lines': 'warn',
	// Disallow negated conditions
	'no-negated-condition': 'off',
	// Disallow nested ternary expressions
	'no-nested-ternary': 'warn',
	// Disallow use of the Object constructor
	'no-new-object': 'warn',
	// Ddisallow the unary operators ++ and --
	'no-plusplus:': 'off',
	// Disallow specified syntax
	'no-restricted-syntax': 'off',
	// Disallow tabs in file
	'no-tabs': 'off',
	// Disallow the use of ternary operators
	'no-ternary': 'off',
	// Disallow trailing whitespace at the end of lines
	'no-trailing-spaces': 'error',
	// Allow dangling underscores in identifiers
	'no-underscore-dangle': 'off',
	// Disallow the use of Boolean literals in conditional expressions
	'no-unneeded-ternary': 'warn',
	// Disallow whitespace before properties
	'no-whitespace-before-property': 'error',
	// Enforce the location of single-line statements
	'nonblock-statement-body-position': 'off',
	// Enforce consistent line breaks inside braces
	'object-curly-newline': 'off',
	// Require or disallow padding inside curly braces
	'object-curly-spacing': 'off',
	// Enforce placing object properties on separate lines
	'object-property-newline': 'off',
	// Allow or disallow one variable declaration per function
	'one-var': 'off',
	// Require or disallow an newline around variable declarations
	'one-var-declaration-per-line': ['warn', 'initializations'],
	// Require assignment operator shorthand where possible or prohibit it entirely
	'operator-assignment': ['warn', 'always'],
	// Enforce operators to be placed before or after line breaks
	'operator-linebreak': ['warn', 'after', {
		overrides: {
			'?': 'before',
			':': 'before',
		},
	}],
	// Enforce padding within blocks
	'padded-blocks': 'off',
	// Require or disallow padding lines between statements
	'padding-line-between-statements': 'off',
	// Require quotes around object literal property names
	'quote-props': ['warn', 'as-needed'],
	// Specify whether backticks, double or single quotes should be used
	quotes: ['error', 'single', 'avoid-escape'],
	// Require JSDoc comments
	'require-jsdoc': 'off',
	// Require or disallow use of semicolons instead of ASI
	semi: ['error', 'always'],
	// Enforce spacing before and after semicolons
	'semi-spacing': ['error', {
		before: false,
		after: true,
	}],
	// Enforce location of semicolons
	'semi-style': 'off',
	// Require object keys to be sorted
	'sort-keys': 'off',
	// Sort variables within the same declaration block
	'sort-vars': 'off',
	// Require or disallow space before blocks
	'space-before-blocks': ['warn', 'always'],
	// Require or disallow space before function opening parenthesis
	'space-before-function-paren': ['warn', 'never'],
	// Require or disallow spaces inside parentheses
	'space-in-parens': 'off',
	// Require spaces around operators
	'space-infix-ops': 'warn',
	// Require or disallow spaces before/after unary operators (words on by default, nonwords)
	'space-unary-ops': ['warn', {
		words: true,
		nonwords: false,
		overrides: {
			'!': true,
		},
	}],
	// Require or disallow a space immediately following the // or /* in a comment
	'spaced-comment': ['warn', 'always'],
	// Enforce spacing around colons of switch statements
	'switch-colon-spacing': 'off',
	// Require or disallow spacing between template tags and their literals
	'template-tag-spacing': 'off',
	// Require or disallow Unicode byte order mark (BOM)
	'unicode-bom': 'off',
	// Require regex literals to be wrapped in parentheses
	'wrap-regex': 'off',
};
<commit_msg>feat: add new `implicit-arrow-linebreak` rule introduced in ESLint `4.12.0`<commit_after>// see http://eslint.org/docs/rules/#stylistic-issues

module.exports = {
	// Enforce linebreaks after opening and before closing array brackets
	'array-bracket-newline': 'off',
	// Enforce spacing inside array brackets
	'array-bracket-spacing': 'off',
	// Enforce line breaks after each array element
	'array-element-newline': 'off',
	// Disallow or enforce spaces inside of single line blocks
	'block-spacing': ['warn', 'always'],
	// Enforce one true brace style
	'brace-style': ['warn', '1tbs', {
		allowSingleLine: true,
	}],
	// Require camel case names
	camelcase: ['warn', {
		properties: 'always',
	}],
	// Enforce or disallow capitalization of the first letter of a comment
	'capitalized-comments': 'off',
	// Disallow or enforce trailing commas
	'comma-dangle': ['error', 'always-multiline'],
	// Enforce spacing before and after comma
	'comma-spacing': ['warn', {
		before: false,
		after: true,
	}],
	// Enforce one true comma style
	'comma-style': ['warn', 'last'],
	// Require or disallow padding inside computed properties
	'computed-property-spacing': 'off',
	// Enforces consistent naming when capturing the current execution context
	'consistent-this': ['warn', 'self'],
	// Enforce newline at the end of file, with no multiple empty lines
	'eol-last': 'warn',
	// Require or disallow spacing between function identifiers and their invocations
	'func-call-spacing': 'off',
	// Require function names to match the name of the variable or property to which they are assigned
	'func-name-matching': 'off',
	// Don't require function expressions to have a name
	'func-names': 'off',
	// Enforces use of function declarations or expressions
	'func-style': ['warn', 'declaration'],
	// Enforce consistent line breaks inside function parentheses
	'function-paren-newline': 'off',
	// Blacklist certain identifiers to prevent them being used
	'id-blacklist': 'off',
	// This option enforces minimum and maximum identifier lengths (variable names, property names etc.)
	'id-length': ['warn', {
		min: 2,
		properties: 'always',
		exceptions: ['x', 'y', 'i', 'j', 't', '_', '$'],
	}],
	// Require identifiers to match the provided regular expression
	'id-match': 'off',
	// Enforce the location of arrow function bodies
	'implicit-arrow-linebreak': 'off',
	// This option sets a specific tab width for your code
	indent: ['error', 'tab', {
		SwitchCase: 1,
	}],
	// Specify whether double or single quotes should be used in JSX attributes
	'jsx-quotes': ['warn', 'prefer-double'],
	// Enforces spacing between keys and values in object literal properties
	'key-spacing': ['warn', {
		beforeColon: false,
		afterColon: true,
	}],
	// Enforce spacing before and after keywords
	'keyword-spacing': ['warn', {
		before: true,
		after: true,
		overrides: {},
	}],
	// Disallow mixed "LF" and "CRLF" as linebreaks
	'linebreak-style': 'off',
	// Enforce position of line comments
	'line-comment-position': 'off',
	// Enforces empty lines around comments
	'lines-around-comment': ['warn', {
		beforeBlockComment: true,
	}],
	// Require or disallow an empty line between class members
	'lines-between-class-members': 'off',
	// Specify the maximum depth that blocks can be nested
	'max-depth': 'off',
	// Specify the maximum line length
	'max-len': 'off',
	// Enforce a maximum number of lines per file
	'max-lines': 'off',
	// Specify the maximum depth callbacks can be nested
	'max-nested-callbacks': 'off',
	// Specify the maximum number of parameters in function definitions
	'max-params': 'off',
	// Specify the maximum number of statements allowed in function blocks
	'max-statements': 'off',
	// Specify the maximum number of statements allowed per line
	'max-statements-per-line': ['warn', {
		max: 2,
	}],
	// Enforce a particular style for multiline comments
	'multiline-comment-style': 'off',
	// Enforce newlines between operands of ternary expressions
	'multiline-ternary': 'off',
	// Require a capital letter for constructors
	'new-cap': 'off',
	// Disallow the omission of parentheses when invoking a constructor with no arguments
	'new-parens': 'warn',
	// Enforce newline after each call when chaining the calls
	'newline-per-chained-call': ['warn', {
		ignoreChainWithDepth: 3,
	}],
	// Disallow use of the Array constructor
	'no-array-constructor': 'error',
	// Disallow bitwise operators
	'no-bitwise': 'off',
	// Disallow use of the continue statement
	'no-continue': 'off',
	// Disallow comments inline after code
	'no-inline-comments': 'off',
	// Disallow if as the only statement in an else block
	'no-lonely-if': 'off',
	// Disallow mixed binary operators
	'no-mixed-operators': 'off',
	// Disallow mixed spaces and tabs for indentation
	'no-mixed-spaces-and-tabs': 'warn',
	// Disallow use of chained assignment expressions
	'no-multi-assign': 'off',
	// Disallow multiple empty lines
	'no-multiple-empty-lines': 'warn',
	// Disallow negated conditions
	'no-negated-condition': 'off',
	// Disallow nested ternary expressions
	'no-nested-ternary': 'warn',
	// Disallow use of the Object constructor
	'no-new-object': 'warn',
	// Ddisallow the unary operators ++ and --
	'no-plusplus:': 'off',
	// Disallow specified syntax
	'no-restricted-syntax': 'off',
	// Disallow tabs in file
	'no-tabs': 'off',
	// Disallow the use of ternary operators
	'no-ternary': 'off',
	// Disallow trailing whitespace at the end of lines
	'no-trailing-spaces': 'error',
	// Allow dangling underscores in identifiers
	'no-underscore-dangle': 'off',
	// Disallow the use of Boolean literals in conditional expressions
	'no-unneeded-ternary': 'warn',
	// Disallow whitespace before properties
	'no-whitespace-before-property': 'error',
	// Enforce the location of single-line statements
	'nonblock-statement-body-position': 'off',
	// Enforce consistent line breaks inside braces
	'object-curly-newline': 'off',
	// Require or disallow padding inside curly braces
	'object-curly-spacing': 'off',
	// Enforce placing object properties on separate lines
	'object-property-newline': 'off',
	// Allow or disallow one variable declaration per function
	'one-var': 'off',
	// Require or disallow an newline around variable declarations
	'one-var-declaration-per-line': ['warn', 'initializations'],
	// Require assignment operator shorthand where possible or prohibit it entirely
	'operator-assignment': ['warn', 'always'],
	// Enforce operators to be placed before or after line breaks
	'operator-linebreak': ['warn', 'after', {
		overrides: {
			'?': 'before',
			':': 'before',
		},
	}],
	// Enforce padding within blocks
	'padded-blocks': 'off',
	// Require or disallow padding lines between statements
	'padding-line-between-statements': 'off',
	// Require quotes around object literal property names
	'quote-props': ['warn', 'as-needed'],
	// Specify whether backticks, double or single quotes should be used
	quotes: ['error', 'single', 'avoid-escape'],
	// Require JSDoc comments
	'require-jsdoc': 'off',
	// Require or disallow use of semicolons instead of ASI
	semi: ['error', 'always'],
	// Enforce spacing before and after semicolons
	'semi-spacing': ['error', {
		before: false,
		after: true,
	}],
	// Enforce location of semicolons
	'semi-style': 'off',
	// Require object keys to be sorted
	'sort-keys': 'off',
	// Sort variables within the same declaration block
	'sort-vars': 'off',
	// Require or disallow space before blocks
	'space-before-blocks': ['warn', 'always'],
	// Require or disallow space before function opening parenthesis
	'space-before-function-paren': ['warn', 'never'],
	// Require or disallow spaces inside parentheses
	'space-in-parens': 'off',
	// Require spaces around operators
	'space-infix-ops': 'warn',
	// Require or disallow spaces before/after unary operators (words on by default, nonwords)
	'space-unary-ops': ['warn', {
		words: true,
		nonwords: false,
		overrides: {
			'!': true,
		},
	}],
	// Require or disallow a space immediately following the // or /* in a comment
	'spaced-comment': ['warn', 'always'],
	// Enforce spacing around colons of switch statements
	'switch-colon-spacing': 'off',
	// Require or disallow spacing between template tags and their literals
	'template-tag-spacing': 'off',
	// Require or disallow Unicode byte order mark (BOM)
	'unicode-bom': 'off',
	// Require regex literals to be wrapped in parentheses
	'wrap-regex': 'off',
};
<|endoftext|>


<commit_before>import path from 'path';

import React from 'react';
import PropTypes from 'prop-types';

import GitTabView from '../views/git-tab-view';
import UserStore from '../models/user-store';
import {CommitPropType, BranchPropType, FilePatchItemPropType, MergeConflictItemPropType} from '../prop-types';
import {autobind} from '../helpers';

export default class GitTabController extends React.Component {
  static focus = {
    ...GitTabView.focus,
  };

  static propTypes = {
    repository: PropTypes.object.isRequired,

    lastCommit: CommitPropType.isRequired,
    recentCommits: PropTypes.arrayOf(CommitPropType).isRequired,
    isMerging: PropTypes.bool.isRequired,
    isRebasing: PropTypes.bool.isRequired,
    hasUndoHistory: PropTypes.bool.isRequired,
    currentBranch: BranchPropType.isRequired,
    unstagedChanges: PropTypes.arrayOf(FilePatchItemPropType).isRequired,
    stagedChanges: PropTypes.arrayOf(FilePatchItemPropType).isRequired,
    mergeConflicts: PropTypes.arrayOf(MergeConflictItemPropType).isRequired,
    workingDirectoryPath: PropTypes.string.isRequired,
    mergeMessage: PropTypes.string,
    fetchInProgress: PropTypes.bool.isRequired,

    workspace: PropTypes.object.isRequired,
    commandRegistry: PropTypes.object.isRequired,
    grammars: PropTypes.object.isRequired,
    resolutionProgress: PropTypes.object.isRequired,
    notificationManager: PropTypes.object.isRequired,
    config: PropTypes.object.isRequired,
    project: PropTypes.object.isRequired,
    tooltips: PropTypes.object.isRequired,

    confirm: PropTypes.func.isRequired,
    ensureGitTab: PropTypes.func.isRequired,
    refreshResolutionProgress: PropTypes.func.isRequired,
    undoLastDiscard: PropTypes.func.isRequired,
    discardWorkDirChangesForPaths: PropTypes.func.isRequired,
    openFiles: PropTypes.func.isRequired,
    initializeRepo: PropTypes.func.isRequired,
  };

  constructor(props, context) {
    super(props, context);
    autobind(
      this,
      'unstageFilePatch', 'attemptStageAllOperation', 'attemptFileStageOperation', 'unstageFiles', 'prepareToCommit',
      'commit', 'updateSelectedCoAuthors', 'undoLastCommit', 'abortMerge', 'resolveAsOurs', 'resolveAsTheirs',
      'checkout', 'rememberLastFocus', 'quietlySelectItem',
    );

    this.stagingOperationInProgress = false;
    this.lastFocus = GitTabView.focus.STAGING;

    this.refView = null;

    this.state = {
      mentionableUsers: [],
      selectedCoAuthors: [],
    };

    this.userStore = new UserStore({
      repository: this.props.repository,
      onDidUpdate: users => {
        this.setState({mentionableUsers: users});
      },
    });
  }

  render() {
    return (
      <GitTabView
        ref={c => { this.refView = c; }}

        isLoading={this.props.fetchInProgress}
        repository={this.props.repository}

        lastCommit={this.props.lastCommit}
        recentCommits={this.props.recentCommits}
        isMerging={this.props.isMerging}
        isRebasing={this.props.isRebasing}
        hasUndoHistory={this.props.hasUndoHistory}
        currentBranch={this.props.currentBranch}
        unstagedChanges={this.props.unstagedChanges}
        stagedChanges={this.props.stagedChanges}
        mergeConflicts={this.props.mergeConflicts}
        workingDirectoryPath={this.props.workingDirectoryPath}
        mergeMessage={this.props.mergeMessage}
        mentionableUsers={this.state.mentionableUsers}
        selectedCoAuthors={this.state.selectedCoAuthors}
        updateSelectedCoAuthors={this.updateSelectedCoAuthors}

        resolutionProgress={this.props.resolutionProgress}
        workspace={this.props.workspace}
        commandRegistry={this.props.commandRegistry}
        grammars={this.props.grammars}
        tooltips={this.props.tooltips}
        notificationManager={this.props.notificationManager}
        project={this.props.project}
        confirm={this.props.confirm}
        config={this.props.config}

        initializeRepo={this.props.initializeRepo}
        openFiles={this.props.openFiles}
        discardWorkDirChangesForPaths={this.props.discardWorkDirChangesForPaths}
        undoLastDiscard={this.props.undoLastDiscard}

        stageFilePatch={this.stageFilePatch}
        unstageFilePatch={this.unstageFilePatch}
        attemptFileStageOperation={this.attemptFileStageOperation}
        attemptStageAllOperation={this.attemptStageAllOperation}
        prepareToCommit={this.prepareToCommit}
        commit={this.commit}
        undoLastCommit={this.undoLastCommit}
        push={this.push}
        pull={this.pull}
        fetch={this.fetch}
        checkout={this.checkout}
        abortMerge={this.abortMerge}
        resolveAsOurs={this.resolveAsOurs}
        resolveAsTheirs={this.resolveAsTheirs}
      />
    );
  }

  componentDidMount() {
    this.refreshResolutionProgress(false, false);
    this.refView.refRoot.addEventListener('focusin', this.rememberLastFocus);
  }

  componentDidUpdate(prevProps) {
    if (prevProps.repository !== this.props.repository) {
      this.userStore = new UserStore({
        repository: this.props.repository,
        onDidUpdate: users => {
          this.setState({mentionableUsers: users});
        },
      });
    }

    this.refreshResolutionProgress(false, false);
  }

  componentWillUnmount() {
    this.refView.refRoot.removeEventListener('focusin', this.rememberLastFocus);
  }

  /*
   * Begin (but don't await) an async conflict-counting task for each merge conflict path that has no conflict
   * marker count yet. Omit any path that's already open in a TextEditor or that has already been counted.
   *
   * includeOpen - update marker counts for files that are currently open in TextEditors
   * includeCounted - update marker counts for files that have been counted before
   */
  refreshResolutionProgress(includeOpen, includeCounted) {
    if (this.props.fetchInProgress) {
      return;
    }

    const openPaths = new Set(
      this.props.workspace.getTextEditors().map(editor => editor.getPath()),
    );

    for (let i = 0; i < this.props.mergeConflicts.length; i++) {
      const conflictPath = path.join(
        this.props.workingDirectoryPath,
        this.props.mergeConflicts[i].filePath,
      );

      if (!includeOpen && openPaths.has(conflictPath)) {
        continue;
      }

      if (!includeCounted && this.props.resolutionProgress.getRemaining(conflictPath) !== undefined) {
        continue;
      }

      this.props.refreshResolutionProgress(conflictPath);
    }
  }

  unstageFilePatch(filePatch) {
    return this.props.repository.applyPatchToIndex(filePatch.getUnstagePatch());
  }

  attemptStageAllOperation(stageStatus) {
    return this.attemptFileStageOperation(['.'], stageStatus);
  }

  attemptFileStageOperation(filePaths, stageStatus) {
    if (this.stagingOperationInProgress) {
      return {
        stageOperationPromise: Promise.resolve(),
        selectionUpdatePromise: Promise.resolve(),
      };
    }

    this.stagingOperationInProgress = true;

    const fileListUpdatePromise = this.refView.refStagingView.getNextListUpdatePromise();
    let stageOperationPromise;
    if (stageStatus === 'staged') {
      stageOperationPromise = this.unstageFiles(filePaths);
    } else {
      stageOperationPromise = this.stageFiles(filePaths);
    }
    const selectionUpdatePromise = fileListUpdatePromise.then(() => {
      this.stagingOperationInProgress = false;
    });

    return {stageOperationPromise, selectionUpdatePromise};
  }

  async stageFiles(filePaths) {
    const pathsToStage = new Set(filePaths);

    const mergeMarkers = await Promise.all(
      filePaths.map(async filePath => {
        return {
          filePath,
          hasMarkers: await this.props.repository.pathHasMergeMarkers(filePath),
        };
      }),
    );

    for (const {filePath, hasMarkers} of mergeMarkers) {
      if (hasMarkers) {
        const choice = this.props.confirm({
          message: 'File contains merge markers: ',
          detailedMessage: `Do you still want to stage this file?\n${filePath}`,
          buttons: ['Stage', 'Cancel'],
        });
        if (choice !== 0) { pathsToStage.delete(filePath); }
      }
    }

    return this.props.repository.stageFiles(Array.from(pathsToStage));
  }

  unstageFiles(filePaths) {
    return this.props.repository.unstageFiles(filePaths);
  }

  async prepareToCommit() {
    return !await this.props.ensureGitTab();
  }

  commit(message, options) {
    return this.props.repository.commit(message, options);
  }

  updateSelectedCoAuthors(selectedCoAuthors, newAuthor) {
    if (newAuthor) {
      this.userStore.addUsers({[newAuthor.email]: newAuthor.name});
      selectedCoAuthors = selectedCoAuthors.concat([newAuthor]);
    }
    this.setState({selectedCoAuthors});
  }

  async undoLastCommit() {
    const repo = this.props.repository;
    const lastCommit = await repo.getLastCommit();
    if (lastCommit.isUnbornRef()) { return null; }
    repo.setCommitMessage(lastCommit.getFullMessage());
    this.updateSelectedCoAuthors(lastCommit.getCoAuthors());
    return repo.undoLastCommit();
  }

  async abortMerge() {
    const choice = this.props.confirm({
      message: 'Abort merge',
      detailedMessage: 'Are you sure?',
      buttons: ['Abort', 'Cancel'],
    });
    if (choice !== 0) { return; }

    try {
      await this.props.repository.abortMerge();
    } catch (e) {
      if (e.code === 'EDIRTYSTAGED') {
        this.props.notificationManager.addError(
          `Cannot abort because ${e.path} is both dirty and staged.`,
          {dismissable: true},
        );
      } else {
        throw e;
      }
    }
  }

  async resolveAsOurs(paths) {
    if (this.props.fetchInProgress) {
      return;
    }

    const side = this.props.isRebasing ? 'theirs' : 'ours';
    await this.props.repository.checkoutSide(side, paths);
    this.refreshResolutionProgress(false, true);
  }

  async resolveAsTheirs(paths) {
    if (this.props.fetchInProgress) {
      return;
    }

    const side = this.props.isRebasing ? 'ours' : 'theirs';
    await this.props.repository.checkoutSide(side, paths);
    this.refreshResolutionProgress(false, true);
  }

  checkout(branchName, options) {
    return this.props.repository.checkout(branchName, options);
  }

  rememberLastFocus(event) {
    this.lastFocus = this.refView.rememberFocus(event) || GitTabView.focus.STAGING;
  }

  restoreFocus() {
    this.refView.setFocus(this.lastFocus);
  }

  hasFocus() {
    return this.refView.refRoot.contains(document.activeElement);
  }

  wasActivated(isStillActive) {
    process.nextTick(() => {
      isStillActive() && this.restoreFocus();
    });
  }

  focusAndSelectStagingItem(filePath, stagingStatus) {
    return this.refView.focusAndSelectStagingItem(filePath, stagingStatus);
  }

  quietlySelectItem(filePath, stagingStatus) {
    return this.refView.quietlySelectItem(filePath, stagingStatus);
  }
}
<commit_msg>The UserStore observes its Repository<commit_after>import path from 'path';

import React from 'react';
import PropTypes from 'prop-types';

import GitTabView from '../views/git-tab-view';
import UserStore from '../models/user-store';
import {CommitPropType, BranchPropType, FilePatchItemPropType, MergeConflictItemPropType} from '../prop-types';
import {autobind} from '../helpers';

export default class GitTabController extends React.Component {
  static focus = {
    ...GitTabView.focus,
  };

  static propTypes = {
    repository: PropTypes.object.isRequired,

    lastCommit: CommitPropType.isRequired,
    recentCommits: PropTypes.arrayOf(CommitPropType).isRequired,
    isMerging: PropTypes.bool.isRequired,
    isRebasing: PropTypes.bool.isRequired,
    hasUndoHistory: PropTypes.bool.isRequired,
    currentBranch: BranchPropType.isRequired,
    unstagedChanges: PropTypes.arrayOf(FilePatchItemPropType).isRequired,
    stagedChanges: PropTypes.arrayOf(FilePatchItemPropType).isRequired,
    mergeConflicts: PropTypes.arrayOf(MergeConflictItemPropType).isRequired,
    workingDirectoryPath: PropTypes.string.isRequired,
    mergeMessage: PropTypes.string,
    fetchInProgress: PropTypes.bool.isRequired,

    workspace: PropTypes.object.isRequired,
    commandRegistry: PropTypes.object.isRequired,
    grammars: PropTypes.object.isRequired,
    resolutionProgress: PropTypes.object.isRequired,
    notificationManager: PropTypes.object.isRequired,
    config: PropTypes.object.isRequired,
    project: PropTypes.object.isRequired,
    tooltips: PropTypes.object.isRequired,

    confirm: PropTypes.func.isRequired,
    ensureGitTab: PropTypes.func.isRequired,
    refreshResolutionProgress: PropTypes.func.isRequired,
    undoLastDiscard: PropTypes.func.isRequired,
    discardWorkDirChangesForPaths: PropTypes.func.isRequired,
    openFiles: PropTypes.func.isRequired,
    initializeRepo: PropTypes.func.isRequired,
  };

  constructor(props, context) {
    super(props, context);
    autobind(
      this,
      'unstageFilePatch', 'attemptStageAllOperation', 'attemptFileStageOperation', 'unstageFiles', 'prepareToCommit',
      'commit', 'updateSelectedCoAuthors', 'undoLastCommit', 'abortMerge', 'resolveAsOurs', 'resolveAsTheirs',
      'checkout', 'rememberLastFocus', 'quietlySelectItem',
    );

    this.stagingOperationInProgress = false;
    this.lastFocus = GitTabView.focus.STAGING;

    this.refView = null;

    this.state = {
      mentionableUsers: [],
      selectedCoAuthors: [],
    };

    this.userStore = new UserStore({repository: this.props.repository});
  }

  render() {
    return (
      <GitTabView
        ref={c => { this.refView = c; }}

        isLoading={this.props.fetchInProgress}
        repository={this.props.repository}

        lastCommit={this.props.lastCommit}
        recentCommits={this.props.recentCommits}
        isMerging={this.props.isMerging}
        isRebasing={this.props.isRebasing}
        hasUndoHistory={this.props.hasUndoHistory}
        currentBranch={this.props.currentBranch}
        unstagedChanges={this.props.unstagedChanges}
        stagedChanges={this.props.stagedChanges}
        mergeConflicts={this.props.mergeConflicts}
        workingDirectoryPath={this.props.workingDirectoryPath}
        mergeMessage={this.props.mergeMessage}
        mentionableUsers={this.state.mentionableUsers}
        selectedCoAuthors={this.state.selectedCoAuthors}
        updateSelectedCoAuthors={this.updateSelectedCoAuthors}

        resolutionProgress={this.props.resolutionProgress}
        workspace={this.props.workspace}
        commandRegistry={this.props.commandRegistry}
        grammars={this.props.grammars}
        tooltips={this.props.tooltips}
        notificationManager={this.props.notificationManager}
        project={this.props.project}
        confirm={this.props.confirm}
        config={this.props.config}

        initializeRepo={this.props.initializeRepo}
        openFiles={this.props.openFiles}
        discardWorkDirChangesForPaths={this.props.discardWorkDirChangesForPaths}
        undoLastDiscard={this.props.undoLastDiscard}

        stageFilePatch={this.stageFilePatch}
        unstageFilePatch={this.unstageFilePatch}
        attemptFileStageOperation={this.attemptFileStageOperation}
        attemptStageAllOperation={this.attemptStageAllOperation}
        prepareToCommit={this.prepareToCommit}
        commit={this.commit}
        undoLastCommit={this.undoLastCommit}
        push={this.push}
        pull={this.pull}
        fetch={this.fetch}
        checkout={this.checkout}
        abortMerge={this.abortMerge}
        resolveAsOurs={this.resolveAsOurs}
        resolveAsTheirs={this.resolveAsTheirs}
      />
    );
  }

  componentDidMount() {
    this.refreshResolutionProgress(false, false);
    this.refView.refRoot.addEventListener('focusin', this.rememberLastFocus);
  }

  componentDidUpdate() {
    this.userStore.setRepository(this.props.repository);
    this.refreshResolutionProgress(false, false);
  }

  componentWillUnmount() {
    this.refView.refRoot.removeEventListener('focusin', this.rememberLastFocus);
  }

  /*
   * Begin (but don't await) an async conflict-counting task for each merge conflict path that has no conflict
   * marker count yet. Omit any path that's already open in a TextEditor or that has already been counted.
   *
   * includeOpen - update marker counts for files that are currently open in TextEditors
   * includeCounted - update marker counts for files that have been counted before
   */
  refreshResolutionProgress(includeOpen, includeCounted) {
    if (this.props.fetchInProgress) {
      return;
    }

    const openPaths = new Set(
      this.props.workspace.getTextEditors().map(editor => editor.getPath()),
    );

    for (let i = 0; i < this.props.mergeConflicts.length; i++) {
      const conflictPath = path.join(
        this.props.workingDirectoryPath,
        this.props.mergeConflicts[i].filePath,
      );

      if (!includeOpen && openPaths.has(conflictPath)) {
        continue;
      }

      if (!includeCounted && this.props.resolutionProgress.getRemaining(conflictPath) !== undefined) {
        continue;
      }

      this.props.refreshResolutionProgress(conflictPath);
    }
  }

  unstageFilePatch(filePatch) {
    return this.props.repository.applyPatchToIndex(filePatch.getUnstagePatch());
  }

  attemptStageAllOperation(stageStatus) {
    return this.attemptFileStageOperation(['.'], stageStatus);
  }

  attemptFileStageOperation(filePaths, stageStatus) {
    if (this.stagingOperationInProgress) {
      return {
        stageOperationPromise: Promise.resolve(),
        selectionUpdatePromise: Promise.resolve(),
      };
    }

    this.stagingOperationInProgress = true;

    const fileListUpdatePromise = this.refView.refStagingView.getNextListUpdatePromise();
    let stageOperationPromise;
    if (stageStatus === 'staged') {
      stageOperationPromise = this.unstageFiles(filePaths);
    } else {
      stageOperationPromise = this.stageFiles(filePaths);
    }
    const selectionUpdatePromise = fileListUpdatePromise.then(() => {
      this.stagingOperationInProgress = false;
    });

    return {stageOperationPromise, selectionUpdatePromise};
  }

  async stageFiles(filePaths) {
    const pathsToStage = new Set(filePaths);

    const mergeMarkers = await Promise.all(
      filePaths.map(async filePath => {
        return {
          filePath,
          hasMarkers: await this.props.repository.pathHasMergeMarkers(filePath),
        };
      }),
    );

    for (const {filePath, hasMarkers} of mergeMarkers) {
      if (hasMarkers) {
        const choice = this.props.confirm({
          message: 'File contains merge markers: ',
          detailedMessage: `Do you still want to stage this file?\n${filePath}`,
          buttons: ['Stage', 'Cancel'],
        });
        if (choice !== 0) { pathsToStage.delete(filePath); }
      }
    }

    return this.props.repository.stageFiles(Array.from(pathsToStage));
  }

  unstageFiles(filePaths) {
    return this.props.repository.unstageFiles(filePaths);
  }

  async prepareToCommit() {
    return !await this.props.ensureGitTab();
  }

  commit(message, options) {
    return this.props.repository.commit(message, options);
  }

  updateSelectedCoAuthors(selectedCoAuthors, newAuthor) {
    if (newAuthor) {
      this.userStore.addUsers({[newAuthor.email]: newAuthor.name});
      selectedCoAuthors = selectedCoAuthors.concat([newAuthor]);
    }
    this.setState({selectedCoAuthors});
  }

  async undoLastCommit() {
    const repo = this.props.repository;
    const lastCommit = await repo.getLastCommit();
    if (lastCommit.isUnbornRef()) { return null; }
    repo.setCommitMessage(lastCommit.getFullMessage());
    this.updateSelectedCoAuthors(lastCommit.getCoAuthors());
    return repo.undoLastCommit();
  }

  async abortMerge() {
    const choice = this.props.confirm({
      message: 'Abort merge',
      detailedMessage: 'Are you sure?',
      buttons: ['Abort', 'Cancel'],
    });
    if (choice !== 0) { return; }

    try {
      await this.props.repository.abortMerge();
    } catch (e) {
      if (e.code === 'EDIRTYSTAGED') {
        this.props.notificationManager.addError(
          `Cannot abort because ${e.path} is both dirty and staged.`,
          {dismissable: true},
        );
      } else {
        throw e;
      }
    }
  }

  async resolveAsOurs(paths) {
    if (this.props.fetchInProgress) {
      return;
    }

    const side = this.props.isRebasing ? 'theirs' : 'ours';
    await this.props.repository.checkoutSide(side, paths);
    this.refreshResolutionProgress(false, true);
  }

  async resolveAsTheirs(paths) {
    if (this.props.fetchInProgress) {
      return;
    }

    const side = this.props.isRebasing ? 'ours' : 'theirs';
    await this.props.repository.checkoutSide(side, paths);
    this.refreshResolutionProgress(false, true);
  }

  checkout(branchName, options) {
    return this.props.repository.checkout(branchName, options);
  }

  rememberLastFocus(event) {
    this.lastFocus = this.refView.rememberFocus(event) || GitTabView.focus.STAGING;
  }

  restoreFocus() {
    this.refView.setFocus(this.lastFocus);
  }

  hasFocus() {
    return this.refView.refRoot.contains(document.activeElement);
  }

  wasActivated(isStillActive) {
    process.nextTick(() => {
      isStillActive() && this.restoreFocus();
    });
  }

  focusAndSelectStagingItem(filePath, stagingStatus) {
    return this.refView.focusAndSelectStagingItem(filePath, stagingStatus);
  }

  quietlySelectItem(filePath, stagingStatus) {
    return this.refView.quietlySelectItem(filePath, stagingStatus);
  }
}
<|endoftext|>


<commit_before>/**
 * Copyright reelyActive 2014-2015
 * We believe in an open Internet of Things
 */

var util = require('util');
var events = require('events');
var reelib = require('reelib');

var DEFAULT_MIXING_DELAY_MILLISECONDS = 25;
var DEFAULT_MIN_MIXING_DELAY_MILLISECONDS = 5;

/**
 * TemporalMixingQueue Class
 * Groups, based on time, objects which share a common string.
 * @param {Object} options The options as a JSON object.
 * @constructor
 * @extends {events.EventEmitter}
 */
function TemporalMixingQueue(options) {
  var self = this;
  self.delayms = options.mixingDelayMilliseconds || DEFAULT_DELAY;
  self.minSleepMilliseconds = options.minMixingDelayMilliseconds ||
                              DEFAULT_MIN_MIXING_DELAY_MILLISECONDS;
  self.emitters = [];
  self.signatures = {};

  self.handleTimeoutEvents();

  events.EventEmitter.call(self);
}
util.inherits(TemporalMixingQueue, events.EventEmitter);

/**
 * Handle all expired timeouts.  This function sets itself to run again when
 * the next timeout is due to expire, or after the minimum sleep milliseconds,
 * whichever is greater.
 */
TemporalMixingQueue.prototype.handleTimeoutEvents = function() {
  var self = this;
  var nextTimeout = reelib.time.getFuture(self.delayms);

  // Iterate through all signatures in the queue
  for(var signature in self.signatures) {
    var signatureEvent = self.signatures[signature];

    // Timeout expired, emit the packet array
    if(reelib.time.isInPast(signatureEvent.timeout - 1)) {
      emitPacketArray(self, signature, false);
    }

    // Find the next earliest timeout
    else if(reelib.time.isEarlier(signatureEvent.timeout, nextTimeout)) {
      nextTimeout = signatureEvent.timeout;
    }
  }

  var timeoutMilliseconds = Math.max(reelib.time.getCurrentOffset(nextTimeout),
                                     self.minSleepMilliseconds);
  setTimeout(self.handleTimeoutEvents.bind(self), timeoutMilliseconds);
};

/**
 * Update the queue based on the given packet.
 * @param {TemporalMixingQueue} instance The given TMQ instance.
 * @param {Packet} packet The DecodedRadioSignal packet.
 */
function handleDecodedRadioSignalPacket(instance, packet)
{
  var signature = packet.identifier.value;
  var signatureEvent = instance.signatures[signature];
  var isSignaturePresent = ((typeof signatureEvent !== 'undefined') &&
                            signatureEvent);

  // The given signature is already present in the queue
  if(isSignaturePresent) {

    var originPacket = getSignatureOriginPacket(instance, signature,
                                                packet.origin);
    var isOriginPresent = (originPacket !== null);

    // The given origin is already present for this signature
    if(isOriginPresent) {

      var isUnacceptableDuplicate = false; // TODO: the logic for this
                                           //       in external function

      // Duplicate origin/offset is detected and unacceptable
      if(isUnacceptableDuplicate) {
        emitPacketArray(instance, signature, true);
        createSignatureEvent(instance, signature);
        addSignaturePacket(instance, signature, packet);
      }

      // Merge the origins
      else {
        mergePackets(instance, originPacket, packet);
      }
    }

    // The given origin needs to be added for this signature
    else {
      addSignaturePacket(instance, signature, packet);
    }

  }

  // The given signature needs to be created in the queue
  else {
    createSignatureEvent(instance, signature);
    addSignaturePacket(instance, signature, packet);
  }

}

/**
 * Create a new signature with the given timeout and empty packets array.
 * @param {TemporalMixingQueue} instance The given TMQ instance.
 * @param {String} signature The signature.
 */
function createSignatureEvent(instance, signature) {
  var timeout = reelib.time.getFuture(instance.delayms);
  instance.signatures[signature] = { timeout: timeout, packets: [] };
}

/**
 * Add the given packet to the given signature.
 * @param {TemporalMixingQueue} instance The given TMQ instance.
 * @param {String} signature The signature.
 * @param {DecodedRadioSignal} packet The packet to add
 */
function addSignaturePacket(instance, signature, packet) {
  instance.signatures[signature].packets.push(packet);
}

/**
 * Merge the two given packets, averaging RSSI values from common reelOffsets.
 * @param {TemporalMixingQueue} instance The given TMQ instance.
 * @param {DecodedRadioSignal} targetPacket The packet to update.
 * @param {DecodedRadioSignal} sourcePacket The packet from which to source.
 */
function mergePackets(instance, targetPacket, sourcePacket) {
  var sourceDecodings = sourcePacket.radioDecodings;
  var targetDecodings = targetPacket.radioDecodings;

  // Iterate through all source offsets
  for(var cSourceOffset = 0; cSourceOffset < sourceDecodings.length;
      cSourceOffset++) {
    var sourceDecoding = sourceDecodings[cSourceOffset];
    var sourceOffset = sourceDecoding.reelOffset;
    var isMerged = false;

    // Look for a match in the target offsets
    for(var cTargetOffset = 0; cTargetOffset < targetDecodings.length;
        cTargetOffset++) {
      var targetDecoding = targetDecodings[cTargetOffset];
      var targetOffset = targetDecoding.reelOffset;
      if(sourceOffset === targetOffset) {
        isMerged = true;
        mergeDecodings(targetDecoding, sourceDecoding);
      }
    }

    // No match found, push new offset to target
    if(!isMerged) {
      targetDecodings.push(sourceDecoding);
    }
  }
}

/**
 * Merge the two given packets, averaging RSSI values from common reelOffsets.
 * @param {Object} targetDecoding The decoding to update.
 * @param {Object} sourceDecoding The decoding from which to source.
 */
function mergeDecodings(targetDecoding, sourceDecoding) {
  var rssiSum = 0;

  if(targetDecoding.rssiArray) {
    targetDecoding.rssiArray.push(sourceDecoding.rssi);
  }
  else {
    targetDecoding.rssiArray = [ targetDecoding.rssi, sourceDecoding.rssi ];
  }

  for(var cRssi = 0; cRssi < targetDecoding.rssiArray.length; cRssi++) {
    rssiSum += targetDecoding.rssiArray[cRssi];
  }

  targetDecoding.rssi = Math.round(rssiSum / targetDecoding.rssiArray.length);
}

/**
 * Get the packet with the same origin as that given, for the given signature.
 * @param {TemporalMixingQueue} instance The given TMQ instance.
 * @param {String} signature The signature.
 * @param {String} origin The origin to search for.
 * @return {DecodedRadioSignal} packet if found, null otherwise.
 */
function getSignatureOriginPacket(instance, signature, origin) {
  var packets = instance.signatures[signature].packets;

  for(var cPacket = 0; cPacket < packets.length; cPacket++) {
    var packet = instance.signatures[signature].packets[cPacket];
    if(origin === packet.origin) {
      return packet;
    }
  }

  return null;
}

/**
 * Emit the packet array for the given signature.
 * @param {TemporalMixingQueue} instance The given TMQ instance.
 * @param {String} signature The signature.
 * @param {boolean} keepSignature Should the signature be kept in memory?
 */
function emitPacketArray(instance, signature, keepSignature) {
  var signaturePackets = instance.signatures[signature].packets;

  instance.emit('decodedRadioSignalPacketArray', signaturePackets);
  signaturePackets = [];

  if(!keepSignature) {
    delete instance.signatures[signature];
  }
}

/**
 * Bind the temporal mixing queue to an event emitter.
 * @param {ListenerService} emitter ListenerService.
 */
TemporalMixingQueue.prototype.bind = function(emitter) {
  var self = this;
  self.emitters.push(emitter);
  emitter.on('decodedRadioSignalPacket', function(packet) {
    handleDecodedRadioSignalPacket(self, packet);
  });
};

module.exports = TemporalMixingQueue;
<commit_msg>Fiexed bug with incorrect DEFAULT_DELAY reference<commit_after>/**
 * Copyright reelyActive 2014-2015
 * We believe in an open Internet of Things
 */

var util = require('util');
var events = require('events');
var reelib = require('reelib');

var DEFAULT_MIXING_DELAY_MILLISECONDS = 25;
var DEFAULT_MIN_MIXING_DELAY_MILLISECONDS = 5;

/**
 * TemporalMixingQueue Class
 * Groups, based on time, objects which share a common string.
 * @param {Object} options The options as a JSON object.
 * @constructor
 * @extends {events.EventEmitter}
 */
function TemporalMixingQueue(options) {
  var self = this;
  self.delayms = options.mixingDelayMilliseconds ||
                 DEFAULT_MIXING_DELAY_MILLISECONDS;
  self.minSleepMilliseconds = options.minMixingDelayMilliseconds ||
                              DEFAULT_MIN_MIXING_DELAY_MILLISECONDS;
  self.emitters = [];
  self.signatures = {};

  self.handleTimeoutEvents();

  events.EventEmitter.call(self);
}
util.inherits(TemporalMixingQueue, events.EventEmitter);

/**
 * Handle all expired timeouts.  This function sets itself to run again when
 * the next timeout is due to expire, or after the minimum sleep milliseconds,
 * whichever is greater.
 */
TemporalMixingQueue.prototype.handleTimeoutEvents = function() {
  var self = this;
  var nextTimeout = reelib.time.getFuture(self.delayms);

  // Iterate through all signatures in the queue
  for(var signature in self.signatures) {
    var signatureEvent = self.signatures[signature];

    // Timeout expired, emit the packet array
    if(reelib.time.isInPast(signatureEvent.timeout - 1)) {
      emitPacketArray(self, signature, false);
    }

    // Find the next earliest timeout
    else if(reelib.time.isEarlier(signatureEvent.timeout, nextTimeout)) {
      nextTimeout = signatureEvent.timeout;
    }
  }

  var timeoutMilliseconds = Math.max(reelib.time.getCurrentOffset(nextTimeout),
                                     self.minSleepMilliseconds);
  setTimeout(self.handleTimeoutEvents.bind(self), timeoutMilliseconds);
};

/**
 * Update the queue based on the given packet.
 * @param {TemporalMixingQueue} instance The given TMQ instance.
 * @param {Packet} packet The DecodedRadioSignal packet.
 */
function handleDecodedRadioSignalPacket(instance, packet)
{
  var signature = packet.identifier.value;
  var signatureEvent = instance.signatures[signature];
  var isSignaturePresent = ((typeof signatureEvent !== 'undefined') &&
                            signatureEvent);

  // The given signature is already present in the queue
  if(isSignaturePresent) {

    var originPacket = getSignatureOriginPacket(instance, signature,
                                                packet.origin);
    var isOriginPresent = (originPacket !== null);

    // The given origin is already present for this signature
    if(isOriginPresent) {

      var isUnacceptableDuplicate = false; // TODO: the logic for this
                                           //       in external function

      // Duplicate origin/offset is detected and unacceptable
      if(isUnacceptableDuplicate) {
        emitPacketArray(instance, signature, true);
        createSignatureEvent(instance, signature);
        addSignaturePacket(instance, signature, packet);
      }

      // Merge the origins
      else {
        mergePackets(instance, originPacket, packet);
      }
    }

    // The given origin needs to be added for this signature
    else {
      addSignaturePacket(instance, signature, packet);
    }

  }

  // The given signature needs to be created in the queue
  else {
    createSignatureEvent(instance, signature);
    addSignaturePacket(instance, signature, packet);
  }

}

/**
 * Create a new signature with the given timeout and empty packets array.
 * @param {TemporalMixingQueue} instance The given TMQ instance.
 * @param {String} signature The signature.
 */
function createSignatureEvent(instance, signature) {
  var timeout = reelib.time.getFuture(instance.delayms);
  instance.signatures[signature] = { timeout: timeout, packets: [] };
}

/**
 * Add the given packet to the given signature.
 * @param {TemporalMixingQueue} instance The given TMQ instance.
 * @param {String} signature The signature.
 * @param {DecodedRadioSignal} packet The packet to add
 */
function addSignaturePacket(instance, signature, packet) {
  instance.signatures[signature].packets.push(packet);
}

/**
 * Merge the two given packets, averaging RSSI values from common reelOffsets.
 * @param {TemporalMixingQueue} instance The given TMQ instance.
 * @param {DecodedRadioSignal} targetPacket The packet to update.
 * @param {DecodedRadioSignal} sourcePacket The packet from which to source.
 */
function mergePackets(instance, targetPacket, sourcePacket) {
  var sourceDecodings = sourcePacket.radioDecodings;
  var targetDecodings = targetPacket.radioDecodings;

  // Iterate through all source offsets
  for(var cSourceOffset = 0; cSourceOffset < sourceDecodings.length;
      cSourceOffset++) {
    var sourceDecoding = sourceDecodings[cSourceOffset];
    var sourceOffset = sourceDecoding.reelOffset;
    var isMerged = false;

    // Look for a match in the target offsets
    for(var cTargetOffset = 0; cTargetOffset < targetDecodings.length;
        cTargetOffset++) {
      var targetDecoding = targetDecodings[cTargetOffset];
      var targetOffset = targetDecoding.reelOffset;
      if(sourceOffset === targetOffset) {
        isMerged = true;
        mergeDecodings(targetDecoding, sourceDecoding);
      }
    }

    // No match found, push new offset to target
    if(!isMerged) {
      targetDecodings.push(sourceDecoding);
    }
  }
}

/**
 * Merge the two given packets, averaging RSSI values from common reelOffsets.
 * @param {Object} targetDecoding The decoding to update.
 * @param {Object} sourceDecoding The decoding from which to source.
 */
function mergeDecodings(targetDecoding, sourceDecoding) {
  var rssiSum = 0;

  if(targetDecoding.rssiArray) {
    targetDecoding.rssiArray.push(sourceDecoding.rssi);
  }
  else {
    targetDecoding.rssiArray = [ targetDecoding.rssi, sourceDecoding.rssi ];
  }

  for(var cRssi = 0; cRssi < targetDecoding.rssiArray.length; cRssi++) {
    rssiSum += targetDecoding.rssiArray[cRssi];
  }

  targetDecoding.rssi = Math.round(rssiSum / targetDecoding.rssiArray.length);
}

/**
 * Get the packet with the same origin as that given, for the given signature.
 * @param {TemporalMixingQueue} instance The given TMQ instance.
 * @param {String} signature The signature.
 * @param {String} origin The origin to search for.
 * @return {DecodedRadioSignal} packet if found, null otherwise.
 */
function getSignatureOriginPacket(instance, signature, origin) {
  var packets = instance.signatures[signature].packets;

  for(var cPacket = 0; cPacket < packets.length; cPacket++) {
    var packet = instance.signatures[signature].packets[cPacket];
    if(origin === packet.origin) {
      return packet;
    }
  }

  return null;
}

/**
 * Emit the packet array for the given signature.
 * @param {TemporalMixingQueue} instance The given TMQ instance.
 * @param {String} signature The signature.
 * @param {boolean} keepSignature Should the signature be kept in memory?
 */
function emitPacketArray(instance, signature, keepSignature) {
  var signaturePackets = instance.signatures[signature].packets;

  instance.emit('decodedRadioSignalPacketArray', signaturePackets);
  signaturePackets = [];

  if(!keepSignature) {
    delete instance.signatures[signature];
  }
}

/**
 * Bind the temporal mixing queue to an event emitter.
 * @param {ListenerService} emitter ListenerService.
 */
TemporalMixingQueue.prototype.bind = function(emitter) {
  var self = this;
  self.emitters.push(emitter);
  emitter.on('decodedRadioSignalPacket', function(packet) {
    handleDecodedRadioSignalPacket(self, packet);
  });
};

module.exports = TemporalMixingQueue;
<|endoftext|>


<commit_before>import { Picker } from 'meteor/meteorhacks:picker';
import { Posts } from '../../lib/collections/posts'
import { Comments } from '../../lib/collections/comments'
import Users from 'meteor/vulcan:users';

// Some legacy routes have an optional subreddit prefix, which is either
// omitted, is /r/all, /r/discussion, or /r/lesswrong. The is followed by
// /lw/postid possibly followed by a slug, comment ID, filter settings, or other
// things, some of which is supported and some of which isn't.
//
// If a route has this optional prefix, use `subredditPrefixRoute` to represent
// that part. It contains two optional parameters, constrained to be `r` and
// a subreddit name, respectively (the subreddits being lesswrong, discussion,
// and all). Since old-LW made all post IDs non-overlapping, we just ignore
// which subreddit was specified.
//
// (In old LW, the set of possible subreddits may also have included user
// account names, for things in users' draft folders. We don't support getting
// old drafts via legacy routes; I'm not sure whether we support getting them
// through other UI).
const subredditPrefixRoute = "/:section(r)?/:subreddit(all|discussion|lesswrong)?";

function findPostByLegacyId(legacyId) {
  const parsedId = parseInt(legacyId, 36);
  return Posts.findOne({"legacyId": parsedId.toString()});
}

function findCommentByLegacyId(legacyId) {
  const parsedId = parseInt(legacyId, 36);
  return Comments.findOne({"legacyId": parsedId.toString()});
}

function makeRedirect(res, destination) {
  res.writeHead(301, {"Location": destination});
  res.end();
}

function findPostByLegacyAFId(legacyId) {
  return Posts.findOne({"agentFoundationsId": legacyId})
}

function findCommentByLegacyAFId(legacyId) {
  return Comments.findOne({"agentFoundationsId": legacyId})
}

//Route for redirecting LessWrong legacy posts
// addRoute({ name: 'lessWrongLegacy', path: 'lw/:id/:slug/:commentId', componentName: 'LegacyPostRedirect'});

// Route for old post links
Picker.route(subredditPrefixRoute+'/lw/:id/:slug?', (params, req, res, next) => {
  if(params.id){

    try {
      const post = findPostByLegacyId(params.id);
      if (post) {
        return makeRedirect(res, Posts.getPageUrl(post));
      } else {
        // don't redirect if we can't find a post for that link
        //eslint-disable-next-line no-console
        console.log('// Missing legacy post', params);
        res.statusCode = 404
        res.end(`No legacy post found with: id=${params.id} slug=${params.slug}`);
      }
    } catch (error) {
      //eslint-disable-next-line no-console
      console.error('// Legacy Post error', error, params)
      res.statusCode = 404
      res.end(`No legacy post found with: id=${params.id} slug=${params.slug}`);
    }
  } else {
    res.statusCode = 404
    res.end("Please provide a URL");
  }
});

// Route for old comment links
Picker.route(subredditPrefixRoute+'/lw/:id/:slug/:commentId', (params, req, res, next) => {
  if(params.id){

    try {
      const post = findPostByLegacyId(params.id);
      const comment = findCommentByLegacyId(params.commentId);
      if (post && comment) {
        return makeRedirect(res, Comments.getPageUrl(comment));
      } else if (post) {
        return makeRedirect(res, Posts.getPageUrl(post));
      } else {
        // don't redirect if we can't find a post for that link
        res.statusCode = 404
        res.end(`No legacy post found with: id=${params.id} slug=${params.slug}`);
      }
    } catch (error) {
      //eslint-disable-next-line no-console
      console.log('// Legacy comment error', error, params)
      res.statusCode = 404
      res.end(`No legacy post found with: id=${params.id} slug=${params.slug}`);
    }
  } else {
    res.statusCode = 404
    res.end(`No legacy post found with: id=${params.id} slug=${params.slug}`);
  }
});

// Route for old user links
Picker.route('/user/:slug/:category?/:filter?', (params, req, res, next) => {
  res.statusCode = 404
  if(params.slug){
    try {
      const user = Users.findOne({$or: [{slug: params.slug}, {username: params.slug}]});
      if (user) {
        return makeRedirect(res, Users.getProfileUrl(user));
      } else {
        //eslint-disable-next-line no-console
        console.log('// Missing legacy user', params);
        res.statusCode = 404
        res.end(`No legacy user found with: ${params.slug}`);
      }
    } catch (error) {
      //eslint-disable-next-line no-console
      console.log('// Legacy User error', error, params);
      res.statusCode = 404
      res.end(`No legacy user found with: ${params.slug}`);
    }
  } else {
    res.statusCode = 404
    res.end(`No legacy user found with: ${params.slug}`);
  }
});

// Route for old comment links

Picker.route('/posts/:_id/:slug/:commentId', (params, req, res, next) => {
  if(params.commentId){
    try {
      const comment = Comments.findOne({_id: params.commentId});
      if (comment) {
        return makeRedirect(res, Comments.getPageUrl(comment));
      } else {
        // don't redirect if we can't find a post for that link
        //eslint-disable-next-line no-console
        console.log('// Missing legacy comment', params);
        res.statusCode = 404
        res.end(`No comment found with: ${params.commentId}`);
      }
    } catch (error) {
      //eslint-disable-next-line no-console
      console.error('// Legacy Comment error', error, params)
      res.statusCode = 404
      res.end(`No comment found with: ${params.commentId}`);
    }
  } else {
    res.statusCode = 404
    res.end("Please provide a URL");
  }
});

// Route for old images

Picker.route('/static/imported/:year/:month/:day/:imageName', (params, req, res, next) => {
  if(params.imageName){
    try {
      return makeRedirect(res,
        `https://raw.githubusercontent.com/tricycle/lesswrong/master/r2/r2/public/static/imported/${params.year}/${params.month}/${params.day}/${params.imageName}`);
    } catch (error) {
      //eslint-disable-next-line no-console
      console.error('// Legacy Comment error', error, params)
      res.statusCode = 404;
      res.end("Invalid image url")
    }
  } else {
    res.statusCode = 404;
    res.end("Please provide a URL")
  }
});

// Legacy RSS Routes

// Route for old comment rss feeds
Picker.route(subredditPrefixRoute+'/lw/:id/:slug/:commentId/.rss', (params, req, res, next) => {
  if(params.id){
    try {
      const post = findPostByLegacyId(params.id);
      const comment = findCommentByLegacyId(params.commentId);
      if (post && comment) {
        return makeRedirect(res, Comments.getRSSUrl(comment));
      } else if (post) {
        return makeRedirect(res, Posts.getPageUrl(post));
      } else {
        // don't redirect if we can't find a post for that link
        res.statusCode = 404
        res.end(`No legacy post found with: id=${params.id} slug=${params.slug}`);
      }
    } catch (error) {
      //eslint-disable-next-line no-console
      console.log('// Legacy comment error', error, params)
      res.statusCode = 404
      res.end(`No legacy post found with: id=${params.id} slug=${params.slug}`);
    }
  } else {
    res.statusCode = 404
    res.end(`No legacy post found with: id=${params.id} slug=${params.slug}`);
  }
});

// Route for old general RSS (all posts)
Picker.route('/.rss', (params, req, res, next) => {
  return makeRedirect(res, "/feed.xml");
});

// Route for old general RSS (all comments)
Picker.route('comments/.rss', (params, req, res, next) => {
  return makeRedirect(res, '/feed.xml?type=comments');
});

Picker.route('/rss/comments.xml', (params, req, res, next) => {
  return makeRedirect(res, '/feed.xml?type=comments');
});

// Route for old general RSS (all posts)
Picker.route('/:section?/:subreddit?/:new?/.rss', (params, req, res, next) => {
  return makeRedirect(res, '/feed.xml');
});

// Route for old promoted RSS (promoted posts)
Picker.route('/promoted/.rss', (params, req, res, next) => {
  return makeRedirect(res, '/feed.xml?view=curated-rss');
});

// Route for old agent-foundations post and commentlinks
Picker.route('/item', (params, req, res, next) => {
  if(params.query.id){
    const id = parseInt(params.query.id)
    try {
      const post = findPostByLegacyAFId(id);

      if (post) {
        return makeRedirect(res, Posts.getPageUrl(post));
      } else {
        const comment = findCommentByLegacyAFId(id);
        if (comment) {
          return makeRedirect(res, Comments.getPageUrl(comment))
        } else {
          // don't redirect if we can't find a post for that link
          //eslint-disable-next-line no-console
          console.log('// Missing legacy af item', params);
          res.statusCode = 404
          res.end(`No af legacy item found with: id=${params.query.id}`);
        }

      }
    } catch (error) {
      //eslint-disable-next-line no-console
      console.error('// Legacy item error', error, params)
      res.statusCode = 404
      res.end(`No legacy item found with: params=${params}`);
    }
  } else {
    res.statusCode = 404
    res.end("Please provide a URL");
  }
});
<commit_msg>add setting for flexible legacy redirects<commit_after>import { getSetting } from 'meteor/vulcan:core'
import { Picker } from 'meteor/meteorhacks:picker'
import { Posts } from '../../lib/collections/posts'
import { Comments } from '../../lib/collections/comments'
import Users from 'meteor/vulcan:users';

// Some legacy routes have an optional subreddit prefix, which is either
// omitted, is /r/all, /r/discussion, or /r/lesswrong. The is followed by
// /lw/postid possibly followed by a slug, comment ID, filter settings, or other
// things, some of which is supported and some of which isn't.
//
// If a route has this optional prefix, use `subredditPrefixRoute` to represent
// that part. It contains two optional parameters, constrained to be `r` and
// a subreddit name, respectively (the subreddits being lesswrong, discussion,
// and all). Since old-LW made all post IDs non-overlapping, we just ignore
// which subreddit was specified.
//
// (In old LW, the set of possible subreddits may also have included user
// account names, for things in users' draft folders. We don't support getting
// old drafts via legacy routes; I'm not sure whether we support getting them
// through other UI).
const subredditPrefixRoute = "/:section(r)?/:subreddit(all|discussion|lesswrong)?";

// Because the EA Forum was identical except for the change from /lw/ to /ea/
const legacyRouteAcronym = getSetting('legacyRouteAcronym', 'lw')

function findPostByLegacyId(legacyId) {
  const parsedId = parseInt(legacyId, 36);
  return Posts.findOne({"legacyId": parsedId.toString()});
}

function findCommentByLegacyId(legacyId) {
  const parsedId = parseInt(legacyId, 36);
  return Comments.findOne({"legacyId": parsedId.toString()});
}

function makeRedirect(res, destination) {
  res.writeHead(301, {"Location": destination});
  res.end();
}

function findPostByLegacyAFId(legacyId) {
  return Posts.findOne({"agentFoundationsId": legacyId})
}

function findCommentByLegacyAFId(legacyId) {
  return Comments.findOne({"agentFoundationsId": legacyId})
}

//Route for redirecting LessWrong legacy posts
// addRoute({ name: 'lessWrongLegacy', path: 'lw/:id/:slug/:commentId', componentName: 'LegacyPostRedirect'});

// Route for old post links
Picker.route(subredditPrefixRoute+`/${legacyRouteAcronym}/:id/:slug?`, (params, req, res, next) => {
  if(params.id){

    try {
      const post = findPostByLegacyId(params.id);
      if (post) {
        return makeRedirect(res, Posts.getPageUrl(post));
      } else {
        // don't redirect if we can't find a post for that link
        //eslint-disable-next-line no-console
        console.log('// Missing legacy post', params);
        res.statusCode = 404
        res.end(`No legacy post found with: id=${params.id} slug=${params.slug}`);
      }
    } catch (error) {
      //eslint-disable-next-line no-console
      console.error('// Legacy Post error', error, params)
      res.statusCode = 404
      res.end(`No legacy post found with: id=${params.id} slug=${params.slug}`);
    }
  } else {
    res.statusCode = 404
    res.end("Please provide a URL");
  }
});

// Route for old comment links
Picker.route(subredditPrefixRoute+`/${legacyRouteAcronym}/:id/:slug/:commentId`, (params, req, res, next) => {
  if(params.id){

    try {
      const post = findPostByLegacyId(params.id);
      const comment = findCommentByLegacyId(params.commentId);
      if (post && comment) {
        return makeRedirect(res, Comments.getPageUrl(comment));
      } else if (post) {
        return makeRedirect(res, Posts.getPageUrl(post));
      } else {
        // don't redirect if we can't find a post for that link
        res.statusCode = 404
        res.end(`No legacy post found with: id=${params.id} slug=${params.slug}`);
      }
    } catch (error) {
      //eslint-disable-next-line no-console
      console.log('// Legacy comment error', error, params)
      res.statusCode = 404
      res.end(`No legacy post found with: id=${params.id} slug=${params.slug}`);
    }
  } else {
    res.statusCode = 404
    res.end(`No legacy post found with: id=${params.id} slug=${params.slug}`);
  }
});

// Route for old user links
Picker.route('/user/:slug/:category?/:filter?', (params, req, res, next) => {
  res.statusCode = 404
  if(params.slug){
    try {
      const user = Users.findOne({$or: [{slug: params.slug}, {username: params.slug}]});
      if (user) {
        return makeRedirect(res, Users.getProfileUrl(user));
      } else {
        //eslint-disable-next-line no-console
        console.log('// Missing legacy user', params);
        res.statusCode = 404
        res.end(`No legacy user found with: ${params.slug}`);
      }
    } catch (error) {
      //eslint-disable-next-line no-console
      console.log('// Legacy User error', error, params);
      res.statusCode = 404
      res.end(`No legacy user found with: ${params.slug}`);
    }
  } else {
    res.statusCode = 404
    res.end(`No legacy user found with: ${params.slug}`);
  }
});

// Route for old comment links

Picker.route('/posts/:_id/:slug/:commentId', (params, req, res, next) => {
  if(params.commentId){
    try {
      const comment = Comments.findOne({_id: params.commentId});
      if (comment) {
        return makeRedirect(res, Comments.getPageUrl(comment));
      } else {
        // don't redirect if we can't find a post for that link
        //eslint-disable-next-line no-console
        console.log('// Missing legacy comment', params);
        res.statusCode = 404
        res.end(`No comment found with: ${params.commentId}`);
      }
    } catch (error) {
      //eslint-disable-next-line no-console
      console.error('// Legacy Comment error', error, params)
      res.statusCode = 404
      res.end(`No comment found with: ${params.commentId}`);
    }
  } else {
    res.statusCode = 404
    res.end("Please provide a URL");
  }
});

// Route for old images

Picker.route('/static/imported/:year/:month/:day/:imageName', (params, req, res, next) => {
  if(params.imageName){
    try {
      return makeRedirect(res,
        `https://raw.githubusercontent.com/tricycle/lesswrong/master/r2/r2/public/static/imported/${params.year}/${params.month}/${params.day}/${params.imageName}`);
    } catch (error) {
      //eslint-disable-next-line no-console
      console.error('// Legacy Comment error', error, params)
      res.statusCode = 404;
      res.end("Invalid image url")
    }
  } else {
    res.statusCode = 404;
    res.end("Please provide a URL")
  }
});

// Legacy RSS Routes

// Route for old comment rss feeds
Picker.route(subredditPrefixRoute+`/${legacyRouteAcronym}/:id/:slug/:commentId/.rss`, (params, req, res, next) => {
  if(params.id){
    try {
      const post = findPostByLegacyId(params.id);
      const comment = findCommentByLegacyId(params.commentId);
      if (post && comment) {
        return makeRedirect(res, Comments.getRSSUrl(comment));
      } else if (post) {
        return makeRedirect(res, Posts.getPageUrl(post));
      } else {
        // don't redirect if we can't find a post for that link
        res.statusCode = 404
        res.end(`No legacy post found with: id=${params.id} slug=${params.slug}`);
      }
    } catch (error) {
      //eslint-disable-next-line no-console
      console.log('// Legacy comment error', error, params)
      res.statusCode = 404
      res.end(`No legacy post found with: id=${params.id} slug=${params.slug}`);
    }
  } else {
    res.statusCode = 404
    res.end(`No legacy post found with: id=${params.id} slug=${params.slug}`);
  }
});

// Route for old general RSS (all posts)
Picker.route('/.rss', (params, req, res, next) => {
  return makeRedirect(res, "/feed.xml");
});

// Route for old general RSS (all comments)
Picker.route('comments/.rss', (params, req, res, next) => {
  return makeRedirect(res, '/feed.xml?type=comments');
});

Picker.route('/rss/comments.xml', (params, req, res, next) => {
  return makeRedirect(res, '/feed.xml?type=comments');
});

// Route for old general RSS (all posts)
Picker.route('/:section?/:subreddit?/:new?/.rss', (params, req, res, next) => {
  return makeRedirect(res, '/feed.xml');
});

// Route for old promoted RSS (promoted posts)
Picker.route('/promoted/.rss', (params, req, res, next) => {
  return makeRedirect(res, '/feed.xml?view=curated-rss');
});

// Route for old agent-foundations post and commentlinks
Picker.route('/item', (params, req, res, next) => {
  if(params.query.id){
    const id = parseInt(params.query.id)
    try {
      const post = findPostByLegacyAFId(id);

      if (post) {
        return makeRedirect(res, Posts.getPageUrl(post));
      } else {
        const comment = findCommentByLegacyAFId(id);
        if (comment) {
          return makeRedirect(res, Comments.getPageUrl(comment))
        } else {
          // don't redirect if we can't find a post for that link
          //eslint-disable-next-line no-console
          console.log('// Missing legacy af item', params);
          res.statusCode = 404
          res.end(`No af legacy item found with: id=${params.query.id}`);
        }

      }
    } catch (error) {
      //eslint-disable-next-line no-console
      console.error('// Legacy item error', error, params)
      res.statusCode = 404
      res.end(`No legacy item found with: params=${params}`);
    }
  } else {
    res.statusCode = 404
    res.end("Please provide a URL");
  }
});
<|endoftext|>


<commit_before>/*
 *  GameoverScene.js
 *  2014/06/23
 *  @auther minimo
 *  This Program is MIT license.
 *
 */

tm.define("shotgun.GameoverScene", {
    superClass: tm.app.Scene,

    parentScene: null,
    mode: 0,
    dispExtend: false,

    //ラベル用フォントパラメータ
    headerParam: {fontFamily:"CasinoRegular", align: "center", baseline:"middle", outlineWidth:2 },
    labelParam: {fontFamily:"Yasashisa", align: "center", baseline:"middle", outlineWidth:2 },
    scoreParam: {fontFamily:"Yasashisa", align: "left", baseline:"middle", outlineWidth:2 },
    extendParam: {fontFamily:"Yasashisa", align: "center", baseline:"middle", outlineWidth:2, fillStyle: "red" },

    init: function(parentScene) {
        this.superInit();
        this.background = "rgba(0, 0, 0, 0.0)";

        this.parentScene = parentScene;
        this.mode = parentScene.mode;

        //スコア情報取得
        var m = appMain.returnJoker? this.mode+10: this.mode;
        var lastScore = appMain.lastScore[m];
        var highScore = appMain.highScore[m];
        var newRecord = parentScene.newRecord;

        //バックグラウンド
        this.bg = tm.display.RectangleShape({width: SC_W, height: SC_H, fillStyle: appMain.bgColor, strokeStyle: appMain.bgColor})
            .addChildTo(this)
            .setPosition(SC_W*0.5, SC_H*0.5);

        var that = this;
        var width = SC_W, height = 80;

        //メインとリザルトを分けてレイヤーを作成
        this.mainLayer = tm.app.Object2D().addChildTo(this);
        this.resultLayer = tm.app.Object2D().addChildTo(this);

        this.top = tm.display.OutlineLabel("RESULT", 60)
            .addChildTo(this)
            .setParam(this.headerParam)
            .setPosition(SC_W*0.5, SC_H*0.05);

        //スコア表示
        this.score = tm.display.OutlineLabel("SCORE "+lastScore, 50)
            .addChildTo(this)
            .setParam(this.labelParam)
            .setPosition(SC_W*0.5, SC_H*0.12);

        this.score = tm.display.OutlineLabel("YOUR BEST SCORE IS "+highScore, 35)
            .addChildTo(this)
            .setParam(this.labelParam)
            .setPosition(SC_W*0.5, SC_H*0.17);
        if (newRecord) {
            var nr = tm.display.OutlineLabel("NewRecord!!", 20)
                .addChildTo(this)
                .setParam(this.labelParam)
                .setFillStyle("Red")
                .setFillStyleOutline("rgb(255,200,200)")
                .setPosition(SC_W*0.82, SC_H*0.20);
        }

        //役一覧
        for (var i = 0; i < 12; i++) {
            tm.display.OutlineLabel(appMain.handList[i].name+":"+this.parentScene.handCount[appMain.handList[i].point], 35)
                .addChildTo(this.resultLayer)
                .setParam(this.scoreParam)
                .setPosition(SC_W*0.2, SC_H*0.22+(i*42));
        }

        //ボタン用パラメータ
        var param = {flat: appMain.buttonFlat, fontSize:50};

        //全画面広告ボタン
        this.Ad = shotgun.Button(width*0.5, height, "Ad", param)
            .addChildTo(this)
            .setPosition(SC_W*0.25, SC_H*0.71)
            .addEventListener("pushed", function() {
                if(ENABLE_PHONEGAP && AdMob) {
                    AdMob.prepareInterstitial({
                        adId:admobid.interstitial,
                        autoShow:true
                    });
                }
                if (that.mode != GAMEMODE_HARD) appMain.bonusLife = 1;
            });

        //GAMECENTER
        shotgun.Button(width*0.5, height, "RANKING", param)
            .addChildTo(this)
            .setPosition(SC_W*0.75, SC_H*0.71)
            .addEventListener("pushed", function() {
                var mode = that.parentScene.mode;
                var lb = "Normal";
                if (mode == GAMEMODE_HARD) lb = "Hard";
                if (appMain.returnJoker) lb += "_ReturnJoker";
                showLeadersBoard(lb);
            });

        //リトライボタン
        this.retry = shotgun.Button(width, height, "TRY AGAIN", param)
            .addChildTo(this)
            .setPosition(SC_W*0.5, SC_H*0.78)
            .addEventListener("pushed", function() {
                var mode = that.parentScene.mode;
                that.parentScene = null;
                that.mask.tweener.clear().fadeIn(300).call(function(){appMain.replaceScene(shotgun.MainScene(mode));});
            });

        //戻るボタン
        this.back = shotgun.Button(width, height, "RETURN TO TITLE", param)
            .addChildTo(this)
            .setPosition(SC_W*0.5, SC_H*0.85)
            .addEventListener("pushed", function() {
                that.parentScene = null;
                that.mask.tweener.clear().fadeIn(300).call(function(){appMain.replaceScene(shotgun.TitleScene());});
            });

        //目隠し
        this.mask = tm.display.RectangleShape({width: SC_W, height: SC_H, fillStyle: "rgba(0, 0, 0, 1.0)", strokeStyle: "rgba(0, 0, 0, 1.0)"})
            .addChildTo(this)
            .setPosition(SC_W*0.5, SC_H*0.5);
        this.mask.tweener.clear().fadeOut(200);

        //GameCenter登録
        registScore(this.mode, appMain.returnJoker, lastScore);
    },

    update: function() {
        if (!this.dispExtend && appMain.bonusLife != 0) {
            var that = this;
            var c = tm.display.Sprite("card", CARD_W, CARD_H)
                .addChildTo(this.retry)
                .setPosition(190, 0)
                .setFrameIndex(13*3)
                .tweener.clear()
                .fadeOut(1)
                .wait(1000)
                .call(function(){
                    that.Ad.remove();
                })
                .wait(1000)
                .fadeIn(1)
                .scale(0.4, 1000, "easeOutBounce")
                .call(function(){
                    tm.display.OutlineLabel("+", 70)
                        .addChildTo(that.retry)
                        .setParam(that.extendParam)
                        .setPosition(150, 0);
                });
            this.dispExtend = true;
        }
    },

    //タッチorクリック開始処理
    ontouchstart: function(e) {
    },

    //タッチorクリック移動処理
    ontouchmove: function(e) {
    },

    //タッチorクリック終了処理
    ontouchend: function(e) {
    },

});
<commit_msg>GameCenterへのスコア送信変更<commit_after>/*
 *  GameoverScene.js
 *  2014/06/23
 *  @auther minimo
 *  This Program is MIT license.
 *
 */

tm.define("shotgun.GameoverScene", {
    superClass: tm.app.Scene,

    parentScene: null,
    mode: 0,
    dispExtend: false,

    //ラベル用フォントパラメータ
    headerParam: {fontFamily:"CasinoRegular", align: "center", baseline:"middle", outlineWidth:2 },
    labelParam: {fontFamily:"Yasashisa", align: "center", baseline:"middle", outlineWidth:2 },
    scoreParam: {fontFamily:"Yasashisa", align: "left", baseline:"middle", outlineWidth:2 },
    extendParam: {fontFamily:"Yasashisa", align: "center", baseline:"middle", outlineWidth:2, fillStyle: "red" },

    init: function(parentScene) {
        this.superInit();
        this.background = "rgba(0, 0, 0, 0.0)";

        this.parentScene = parentScene;
        this.mode = parentScene.mode;

        //スコア情報取得
        var m = appMain.returnJoker? this.mode+10: this.mode;
        var lastScore = appMain.lastScore[m];
        var highScore = appMain.highScore[m];
        var newRecord = parentScene.newRecord;

        //バックグラウンド
        this.bg = tm.display.RectangleShape({width: SC_W, height: SC_H, fillStyle: appMain.bgColor, strokeStyle: appMain.bgColor})
            .addChildTo(this)
            .setPosition(SC_W*0.5, SC_H*0.5);

        var that = this;
        var width = SC_W, height = 80;

        //メインとリザルトを分けてレイヤーを作成
        this.mainLayer = tm.app.Object2D().addChildTo(this);
        this.resultLayer = tm.app.Object2D().addChildTo(this);

        this.top = tm.display.OutlineLabel("RESULT", 60)
            .addChildTo(this)
            .setParam(this.headerParam)
            .setPosition(SC_W*0.5, SC_H*0.05);

        //スコア表示
        this.score = tm.display.OutlineLabel("SCORE "+lastScore, 50)
            .addChildTo(this)
            .setParam(this.labelParam)
            .setPosition(SC_W*0.5, SC_H*0.12);

        this.score = tm.display.OutlineLabel("YOUR BEST SCORE IS "+highScore, 35)
            .addChildTo(this)
            .setParam(this.labelParam)
            .setPosition(SC_W*0.5, SC_H*0.17);
        if (newRecord) {
            var nr = tm.display.OutlineLabel("NewRecord!!", 20)
                .addChildTo(this)
                .setParam(this.labelParam)
                .setFillStyle("Red")
                .setFillStyleOutline("rgb(255,200,200)")
                .setPosition(SC_W*0.82, SC_H*0.20);

            //最高得点更新時のみGameCenter登録
            registScore(this.mode, appMain.returnJoker, lastScore);
        }

        //役一覧
        for (var i = 0; i < 12; i++) {
            tm.display.OutlineLabel(appMain.handList[i].name+":"+this.parentScene.handCount[appMain.handList[i].point], 35)
                .addChildTo(this.resultLayer)
                .setParam(this.scoreParam)
                .setPosition(SC_W*0.2, SC_H*0.22+(i*42));
        }

        //ボタン用パラメータ
        var param = {flat: appMain.buttonFlat, fontSize:50};

        //全画面広告ボタン
        this.Ad = shotgun.Button(width*0.5, height, "Ad", param)
            .addChildTo(this)
            .setPosition(SC_W*0.25, SC_H*0.71)
            .addEventListener("pushed", function() {
                if(ENABLE_PHONEGAP && AdMob) {
                    AdMob.prepareInterstitial({
                        adId:admobid.interstitial,
                        autoShow:true
                    });
                }
                if (that.mode != GAMEMODE_HARD) appMain.bonusLife = 1;
            });

        //GAMECENTER
        shotgun.Button(width*0.5, height, "RANKING", param)
            .addChildTo(this)
            .setPosition(SC_W*0.75, SC_H*0.71)
            .addEventListener("pushed", function() {
                var mode = that.parentScene.mode;
                var lb = "Normal";
                if (mode == GAMEMODE_HARD) lb = "Hard";
                if (appMain.returnJoker) lb += "_ReturnJoker";
                showLeadersBoard(lb);
            });

        //リトライボタン
        this.retry = shotgun.Button(width, height, "TRY AGAIN", param)
            .addChildTo(this)
            .setPosition(SC_W*0.5, SC_H*0.78)
            .addEventListener("pushed", function() {
                var mode = that.parentScene.mode;
                that.parentScene = null;
                that.mask.tweener.clear().fadeIn(300).call(function(){appMain.replaceScene(shotgun.MainScene(mode));});
            });

        //戻るボタン
        this.back = shotgun.Button(width, height, "RETURN TO TITLE", param)
            .addChildTo(this)
            .setPosition(SC_W*0.5, SC_H*0.85)
            .addEventListener("pushed", function() {
                that.parentScene = null;
                that.mask.tweener.clear().fadeIn(300).call(function(){appMain.replaceScene(shotgun.TitleScene());});
            });

        //目隠し
        this.mask = tm.display.RectangleShape({width: SC_W, height: SC_H, fillStyle: "rgba(0, 0, 0, 1.0)", strokeStyle: "rgba(0, 0, 0, 1.0)"})
            .addChildTo(this)
            .setPosition(SC_W*0.5, SC_H*0.5);
        this.mask.tweener.clear().fadeOut(200);
    },

    update: function() {
        if (!this.dispExtend && appMain.bonusLife != 0) {
            var that = this;
            var c = tm.display.Sprite("card", CARD_W, CARD_H)
                .addChildTo(this.retry)
                .setPosition(190, 0)
                .setFrameIndex(13*3)
                .tweener.clear()
                .fadeOut(1)
                .wait(1000)
                .call(function(){
                    that.Ad.remove();
                })
                .wait(1000)
                .fadeIn(1)
                .scale(0.4, 1000, "easeOutBounce")
                .call(function(){
                    tm.display.OutlineLabel("+", 70)
                        .addChildTo(that.retry)
                        .setParam(that.extendParam)
                        .setPosition(150, 0);
                });
            this.dispExtend = true;
        }
    },

    //タッチorクリック開始処理
    ontouchstart: function(e) {
    },

    //タッチorクリック移動処理
    ontouchmove: function(e) {
    },

    //タッチorクリック終了処理
    ontouchend: function(e) {
    },

});
<|endoftext|>


<commit_before>'use strict';

var Component = require('substance/ui/Component');
var TextProperty = require('substance/ui/TextPropertyComponent');
var Paragraph = require('substance/packages/paragraph/ParagraphComponent');

function CaptionComponent() {
  Component.apply(this, arguments);
}

CaptionComponent.Prototype = function() {

  this.render = function($$) {
    var doc = this.props.node.getDocument();
    var el = $$('div')
      .addClass('sc-caption')
      .attr('data-id', this.props.node.id);

    el.append($$(TextProperty, {
      path: [ this.props.node.id, 'title']
    }));

    // Render caption content (0..n paragraphs)

    var contentEl = $$('div').addClass('se-content');
    this.props.node.contentNodes.forEach(function(paragraphId) {
      var node = doc.get(paragraphId);
      contentEl.append(
        $$(Paragraph, {
          doc: doc,
          node: node
        })
      );
    }.bind(this));

    return el;
  };
};

Component.extend(CaptionComponent);

module.exports = CaptionComponent;<commit_msg>Render CaptionComponent's content.<commit_after>'use strict';

var Component = require('substance/ui/Component');
var TextProperty = require('substance/ui/TextPropertyComponent');
var Paragraph = require('substance/packages/paragraph/ParagraphComponent');

function CaptionComponent() {
  Component.apply(this, arguments);
}

CaptionComponent.Prototype = function() {

  this.render = function($$) {
    var doc = this.props.node.getDocument();
    var el = $$('div')
      .addClass('sc-caption')
      .attr('data-id', this.props.node.id);

    el.append($$(TextProperty, {
      path: [ this.props.node.id, 'title']
    }));

    // Render caption content (0..n paragraphs)

    var contentEl = $$('div').addClass('se-content');
    this.props.node.contentNodes.forEach(function(paragraphId) {
      var node = doc.get(paragraphId);
      contentEl.append(
        $$(Paragraph, {
          doc: doc,
          node: node
        })
      );
    }.bind(this));
    el.append(contentEl);

    return el;
  };
};

Component.extend(CaptionComponent);

module.exports = CaptionComponent;<|endoftext|>


<commit_before>define([
    'backbone',
    'computedProperty',
    'proxyProperty',
    'underscore'], function (Backbone, ComputedProperty, ProxyProperty, _) {

    return Backbone.Model.extend({
        unsettableProperties: [],

        set: function(key, val, options) {
            var self = this,
                attrs = {},
                stack = [],
                delayInitial = [],
                callSelf = false;

            this.computedCallbacks = this.computedCallbacks || {};
            if (key == null) {
                return this;
            } else if (typeof key == 'object') {
                attrs = key;
                options = val;

                _.each(key, function (attrValue, attrKey) {
                    if (attrValue instanceof ComputedProperty) {
                        if (!attrValue.skipInitialComputation) {
                            self.bindComputed(attrKey, attrValue);
                            callSelf = true;
                        } else {
                            delayInitial.push(function() {
                                self.bindComputed(attrKey, attrValue);
                            })
                        }
                        delete attrs[attrKey];
                    } else if (attrValue instanceof ProxyProperty) {
                        self.bindProxy(attrKey, attrValue);
                        delete attrs[attrKey];
                    } else {
                        if (self.computedCallbacks[attrKey]) {
                            stack.push(self.computedCallbacks[attrKey]);
                        }
                    }
                });
            } else {
                attrs[key] = val;
                if (val instanceof ComputedProperty) {
                    this.bindComputed(key, val);
                    return;
                } else if (val instanceof ProxyProperty) {
                    this.bindProxy(key, val);
                    return;
                } else {
                    if (this.computedCallbacks[key]) {
                        stack.push(this.computedCallbacks[key]);
                    }
                }
            }

            if (callSelf) {
                this.set.apply(this, [attrs, options]);
            } else {
                Backbone.Model.prototype.set.apply(this, [attrs, options]);
                _.forEach(stack, function(callbackArray) {
                    _.forEach(callbackArray, function(callback) {
                        callback.call(self);
                    });
                });
            }
            if (delayInitial) {
                _.forEach(delayInitial, function(cb) {
                    cb();
                });
            }
        },
        bindComputed: function (key, computed) {
            var self = this,
                callback;

            callback = function () {
                this.set(key, computed.callback.apply(this, this.getListenableValues(computed.listenables)));
            };

            _.forEach(computed.listenables, function(listenTo) {
                self.computedCallbacks[listenTo] = self.computedCallbacks[listenTo] || [];
                self.computedCallbacks[listenTo].push(callback);
                if (!computed.skipInitialComputation) {
                    callback.call(self);
                }
            });
        },
        bindProxy: function (key, proxy) {
            var self = this,
                model = proxy.model,
                modelAttribute = proxy.propertyNameOnModel;

            console.log(proxy);
            this.set(key, model.get(modelAttribute));

            model.on('change:' + modelAttribute, function() {
                self.set(key, model.get(modelAttribute));
            });

            this.on('change:' + key, function() {
                model.set(modelAttribute, self.get(key));
            });

        },
        getListenableValues: function (listenables) {
            var args = [],
                self = this;

            _.each(listenables, function (listenablePropertyKey) {
                args.push(self.get(listenablePropertyKey));
            });

            return args;
        }
    });
});

<commit_msg>removing console.log<commit_after>define([
    'backbone',
    'computedProperty',
    'proxyProperty',
    'underscore'], function (Backbone, ComputedProperty, ProxyProperty, _) {

    return Backbone.Model.extend({
        unsettableProperties: [],

        set: function(key, val, options) {
            var self = this,
                attrs = {},
                stack = [],
                delayInitial = [],
                callSelf = false;

            this.computedCallbacks = this.computedCallbacks || {};
            if (key == null) {
                return this;
            } else if (typeof key == 'object') {
                attrs = key;
                options = val;

                _.each(key, function (attrValue, attrKey) {
                    if (attrValue instanceof ComputedProperty) {
                        if (!attrValue.skipInitialComputation) {
                            self.bindComputed(attrKey, attrValue);
                            callSelf = true;
                        } else {
                            delayInitial.push(function() {
                                self.bindComputed(attrKey, attrValue);
                            })
                        }
                        delete attrs[attrKey];
                    } else if (attrValue instanceof ProxyProperty) {
                        self.bindProxy(attrKey, attrValue);
                        delete attrs[attrKey];
                    } else {
                        if (self.computedCallbacks[attrKey]) {
                            stack.push(self.computedCallbacks[attrKey]);
                        }
                    }
                });
            } else {
                attrs[key] = val;
                if (val instanceof ComputedProperty) {
                    this.bindComputed(key, val);
                    return;
                } else if (val instanceof ProxyProperty) {
                    this.bindProxy(key, val);
                    return;
                } else {
                    if (this.computedCallbacks[key]) {
                        stack.push(this.computedCallbacks[key]);
                    }
                }
            }

            if (callSelf) {
                this.set.apply(this, [attrs, options]);
            } else {
                Backbone.Model.prototype.set.apply(this, [attrs, options]);
                _.forEach(stack, function(callbackArray) {
                    _.forEach(callbackArray, function(callback) {
                        callback.call(self);
                    });
                });
            }
            if (delayInitial) {
                _.forEach(delayInitial, function(cb) {
                    cb();
                });
            }
        },
        bindComputed: function (key, computed) {
            var self = this,
                callback;

            callback = function () {
                this.set(key, computed.callback.apply(this, this.getListenableValues(computed.listenables)));
            };

            _.forEach(computed.listenables, function(listenTo) {
                self.computedCallbacks[listenTo] = self.computedCallbacks[listenTo] || [];
                self.computedCallbacks[listenTo].push(callback);
                if (!computed.skipInitialComputation) {
                    callback.call(self);
                }
            });
        },
        bindProxy: function (key, proxy) {
            var self = this,
                model = proxy.model,
                modelAttribute = proxy.propertyNameOnModel;

            this.set(key, model.get(modelAttribute));

            model.on('change:' + modelAttribute, function() {
                self.set(key, model.get(modelAttribute));
            });

            this.on('change:' + key, function() {
                model.set(modelAttribute, self.get(key));
            });

        },
        getListenableValues: function (listenables) {
            var args = [],
                self = this;

            _.each(listenables, function (listenablePropertyKey) {
                args.push(self.get(listenablePropertyKey));
            });

            return args;
        }
    });
});

<|endoftext|>