<commit_before>#! /usr/bin/env node

/**
 * This module handles the `shrink` command line interface.
 *
 * @module bin/commands/shrink
 * @author Nathan Buchar
 * @see module:lib/shrink
 */

'use strict';

var chalk = require('chalk');
var copyPaste = require('copy-paste');

var shrink = require('../../lib/shrink');

module.exports = function (yargs) {
  var argv = yargs
    .reset()
    .usage('Usage: gitio shrink <long url> [-c code] [-f]')
    .demand(2)
    .options({
      c: {
        alias: 'code',
        description: 'A custom code for the short link, e.g. http://git.io/mycode',
        demand: false,
        type: 'string'
      },
      f: {
        alias: 'force',
        description: 'Try to shorten link even if the custom code has been used previously.',
        demand: false,
        type: 'boolean',
        default: false
      }
    })
    .alias('h', 'help')
    .help('h')
    .wrap(74)
    .epilogue('See http://git.io/vZ9RJ for more information.')
    .argv;

  // Perform the shrink given that there are not CLI errors.
  shrink({
    url: argv._[1],
    code: argv.code,
    force: argv.force
  }).then(function (result) {
    copyPaste.copy(result, function () {
      console.log('\n%s %s', chalk.green(result), '(copied to clipboard)');
    });
  }).catch(function (err) {
    console.error(chalk.red('\n%s'), err);
  });
};
<commit_msg>Improved shrink success colors<commit_after>#! /usr/bin/env node

/**
 * This module handles the `shrink` command line interface.
 *
 * @module bin/commands/shrink
 * @author Nathan Buchar
 * @see module:lib/shrink
 */

'use strict';

var chalk = require('chalk');
var copyPaste = require('copy-paste');

var shrink = require('../../lib/shrink');

module.exports = function (yargs) {
  var argv = yargs
    .reset()
    .usage('Usage: gitio shrink <long url> [-c code] [-f]')
    .demand(2)
    .options({
      c: {
        alias: 'code',
        description: 'A custom code for the short link, e.g. http://git.io/mycode',
        demand: false,
        type: 'string'
      },
      f: {
        alias: 'force',
        description: 'Try to shorten link even if the custom code has been used previously.',
        demand: false,
        type: 'boolean',
        default: false
      }
    })
    .alias('h', 'help')
    .help('h')
    .wrap(74)
    .epilogue('See http://git.io/vZ9RJ for more information.')
    .argv;

  // Perform the shrink given that there are not CLI errors.
  shrink({
    url: argv._[1],
    code: argv.code,
    force: argv.force
  }).then(function (result) {
    copyPaste.copy(result, function () {
      console.log('\n%s %s', result, chalk.dim('(copied to clipboard)'));
    });
  }).catch(function (err) {
    console.error(chalk.red('\n%s'), err);
  });
};
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { connect } from 'react-redux';
import { StyleSheet, RefreshControl, Share } from 'react-native';
import { ListItem } from 'react-native-elements';
import ActionSheet from 'react-native-actionsheet';

import {
  ViewContainer,
  LoadingRepositoryProfile,
  RepositoryProfile,
  MembersList,
  SectionList,
  ParallaxScroll,
  LoadingUserListItem,
  UserListItem,
  IssueListItem,
  LoadingMembersList,
  LoadingModal,
} from 'components';
import { translate } from 'utils';
import { colors, fonts } from 'config';
import {
  getRepositoryInfo,
  getContributors,
  getIssues,
  changeStarStatusRepo,
  forkRepo,
  subscribeToRepo,
  unSubscribeToRepo,
} from '../repository.action';

const mapStateToProps = state => ({
  username: state.auth.user.login,
  language: state.auth.language,
  repository: state.repository.repository,
  contributors: state.repository.contributors,
  issues: state.repository.issues,
  starred: state.repository.starred,
  forked: state.repository.forked,
  subscribed: state.repository.subscribed,
  isPendingRepository: state.repository.isPendingRepository,
  isPendingContributors: state.repository.isPendingContributors,
  isPendingIssues: state.repository.isPendingIssues,
  isPendingCheckStarred: state.repository.isPendingCheckStarred,
  isPendingFork: state.repository.isPendingFork,
});

const mapDispatchToProps = dispatch => ({
  getRepositoryInfoByDispatch: url => dispatch(getRepositoryInfo(url)),
  getContributorsByDispatch: url => dispatch(getContributors(url)),
  getIssuesByDispatch: url => dispatch(getIssues(url)),
  changeStarStatusRepoByDispatch: (owner, repo, starred) =>
    dispatch(changeStarStatusRepo(owner, repo, starred)),
  forkRepoByDispatch: (owner, repo) => dispatch(forkRepo(owner, repo)),
  subscribeToRepo: (owner, repo) => dispatch(subscribeToRepo(owner, repo)),
  unSubscribeToRepo: (owner, repo) => dispatch(unSubscribeToRepo(owner, repo)),
});

const styles = StyleSheet.create({
  listTitle: {
    color: colors.black,
    ...fonts.fontPrimary,
  },
});

class Repository extends Component {
  props: {
    // selectRepositoryByDispatch: Function,
    getRepositoryInfoByDispatch: Function,
    // getIssuesByDispatch: Function,
    changeStarStatusRepoByDispatch: Function,
    forkRepoByDispatch: Function,
    // repositoryName: string,
    repository: Object,
    contributors: Array,
    issues: Array,
    starred: boolean,
    // forked: boolean,
    isPendingRepository: boolean,
    isPendingContributors: boolean,
    isPendingIssues: boolean,
    isPendingCheckStarred: boolean,
    isPendingFork: boolean,
    // isPendingCheckForked: boolean,
    navigation: Object,
    username: string,
    language: string,
    subscribed: boolean,
    subscribeToRepo: Function,
    unSubscribeToRepo: Function,
  };

  state: {
    refreshing: boolean,
  };

  constructor(props) {
    super(props);
    this.state = {
      refreshing: false,
    };
  }

  componentDidMount() {
    const {
      repository: repo,
      repositoryUrl: repoUrl,
    } = this.props.navigation.state.params;

    this.props.getRepositoryInfoByDispatch(repo ? repo.url : repoUrl);
  }

  showMenuActionSheet = () => {
    this.ActionSheet.show();
  };

  handlePress = index => {
    const {
      starred,
      subscribed,
      repository,
      changeStarStatusRepoByDispatch,
      forkRepoByDispatch,
      navigation,
      username,
    } = this.props;

    const showFork = repository.owner.login !== username;

    if (index === 0) {
      changeStarStatusRepoByDispatch(
        repository.owner.login,
        repository.name,
        starred
      );
    } else if (index === 1 && showFork) {
      forkRepoByDispatch(repository.owner.login, repository.name).then(json => {
        navigation.navigate('Repository', { repository: json });
      });
    } else if ((index === 2 && showFork) || (index === 1 && !showFork)) {
      this.shareRepository(repository);
    } else if (index === 3) {
      const subscribeMethod = !subscribed
        ? this.props.subscribeToRepo
        : this.props.unSubscribeToRepo;

      subscribeMethod(repository.owner.login, repository.name);
    }
  };

  fetchRepoInfo = () => {
    const {
      repository: repo,
      repositoryUrl: repoUrl,
    } = this.props.navigation.state.params;

    this.setState({ refreshing: true });
    this.props
      .getRepositoryInfoByDispatch(repo ? repo.url : repoUrl)
      .then(() => {
        this.setState({ refreshing: false });
      });
  };

  shareRepository = repository => {
    const { language } = this.props;
    const title = translate('repository.main.shareRepositoryTitle', language, {
      repoName: repository.name,
    });

    Share.share(
      {
        title,
        message: translate('repository.main.shareRepositoryMessage', language, {
          repoName: repository.name,
          repoUrl: repository.html_url,
        }),
        url: undefined,
      },
      {
        dialogTitle: title,
        excludedActivityTypes: [],
      }
    );
  };

  render() {
    const {
      repository,
      contributors,
      issues,
      starred,
      language,
      isPendingRepository,
      isPendingContributors,
      isPendingIssues,
      isPendingCheckStarred,
      isPendingFork,
      navigation,
      username,
      subscribed,
    } = this.props;
    const { refreshing } = this.state;

    const initalRepository = navigation.state.params.repository;
    const pulls = issues.filter(issue => issue.hasOwnProperty('pull_request')); // eslint-disable-line no-prototype-builtins
    const pureIssues = issues.filter(issue => {
      // eslint-disable-next-line no-prototype-builtins
      return !issue.hasOwnProperty('pull_request');
    });

    const openPulls = pulls.filter(pull => pull.state === 'open');
    const openIssues = pureIssues.filter(issue => issue.state === 'open');
    const showFork =
      repository && repository.owner && repository.owner.login !== username;

    const repositoryActions = [
      starred
        ? translate('repository.main.unstarAction', language)
        : translate('repository.main.starAction', language),
      subscribed
        ? translate('repository.main.unwatchAction', language)
        : translate('repository.main.watchAction', language),
      translate('repository.main.shareAction', language),
    ];

    if (showFork) {
      repositoryActions.splice(
        1,
        0,
        translate('repository.main.forkAction', language)
      );
    }

    const loader = isPendingFork ? <LoadingModal /> : null;

    return (
      <ViewContainer>
        {loader}

        <ParallaxScroll
          renderContent={() => {
            if (isPendingRepository && !initalRepository) {
              return <LoadingRepositoryProfile language={language} />;
            }

            return (
              <RepositoryProfile
                repository={isPendingRepository ? initalRepository : repository}
                starred={
                  isPendingRepository || isPendingCheckStarred ? false : starred
                }
                loading={isPendingRepository}
                navigation={navigation}
                language={language}
              />
            );
          }}
          refreshControl={
            <RefreshControl
              refreshing={refreshing}
              onRefresh={this.fetchRepoInfo}
            />
          }
          stickyTitle={repository.name}
          showMenu={!isPendingRepository && !isPendingCheckStarred}
          menuAction={this.showMenuActionSheet}
          navigation={navigation}
          navigateBack
        >
          {initalRepository &&
            !initalRepository.owner &&
            isPendingRepository &&
            <SectionList
              title={translate('repository.main.ownerTitle', language)}
            >
              <LoadingUserListItem />
            </SectionList>}

          {!(initalRepository && initalRepository.owner) &&
            (repository && repository.owner) &&
            !isPendingRepository &&
            <SectionList
              title={translate('repository.main.ownerTitle', language)}
            >
              <UserListItem user={repository.owner} navigation={navigation} />
            </SectionList>}

          {initalRepository &&
            initalRepository.owner &&
            <SectionList
              title={translate('repository.main.ownerTitle', language)}
            >
              <UserListItem
                user={initalRepository.owner}
                navigation={navigation}
              />
            </SectionList>}

          {(isPendingRepository || isPendingContributors) &&
            <LoadingMembersList
              title={translate('repository.main.contributorsTitle', language)}
            />}

          {!isPendingContributors &&
            <MembersList
              title={translate('repository.main.contributorsTitle', language)}
              members={contributors}
              noMembersMessage={translate(
                'repository.main.noContributorsMessage',
                language
              )}
              navigation={navigation}
            />}

          <SectionList
            title={translate('repository.main.sourceTitle', language)}
          >
            <ListItem
              title={translate('repository.main.readMe', language)}
              leftIcon={{
                name: 'book',
                color: colors.grey,
                type: 'octicon',
              }}
              titleStyle={styles.listTitle}
              onPress={() =>
                navigation.navigate('ReadMe', {
                  repository,
                })}
              underlayColor={colors.greyLight}
            />
            <ListItem
              title={translate('repository.main.viewSource', language)}
              titleStyle={styles.listTitle}
              leftIcon={{
                name: 'code',
                color: colors.grey,
                type: 'octicon',
              }}
              onPress={() =>
                navigation.navigate('RepositoryCodeList', {
                  title: translate('repository.codeList.title', language),
                  topLevel: true,
                })}
              underlayColor={colors.greyLight}
            />
          </SectionList>

          <SectionList
            loading={isPendingIssues}
            title={translate('repository.main.issuesTitle', language)}
            noItems={openIssues.length === 0}
            noItemsMessage={
              pureIssues.length === 0
                ? translate('repository.main.noIssuesMessage', language)
                : translate('repository.main.noOpenIssuesMessage', language)
            }
            showButton
            buttonTitle={
              pureIssues.length > 0
                ? translate('repository.main.viewAllButton', language)
                : translate('repository.main.newIssueButton', language)
            }
            buttonAction={() => {
              if (pureIssues.length > 0) {
                navigation.navigate('IssueList', {
                  title: translate('repository.issueList.title', language),
                  type: 'issue',
                  issues: pureIssues,
                });
              } else {
                navigation.navigate('NewIssue', {
                  title: translate('issue.newIssue.title', language),
                });
              }
            }}
          >
            {openIssues
              .slice(0, 3)
              .map(item =>
                <IssueListItem
                  key={item.id}
                  type="issue"
                  issue={item}
                  navigation={navigation}
                  language={language}
                />
              )}
          </SectionList>

          <SectionList
            loading={isPendingIssues}
            title={translate('repository.main.pullRequestTitle', language)}
            noItems={openPulls.length === 0}
            noItemsMessage={
              pulls.length === 0
                ? translate('repository.main.noPullRequestsMessage', language)
                : translate(
                    'repository.main.noOpenPullRequestsMessage',
                    language
                  )
            }
            showButton={pulls.length > 0}
            buttonTitle={translate('repository.main.viewAllButton', language)}
            buttonAction={() =>
              navigation.navigate('PullList', {
                title: translate('repository.pullList.title', language),
                type: 'pull',
                issues: pulls,
              })}
          >
            {openPulls
              .slice(0, 3)
              .map(item =>
                <IssueListItem
                  key={item.id}
                  type="pull"
                  issue={item}
                  navigation={navigation}
                  language={language}
                />
              )}
          </SectionList>
        </ParallaxScroll>

        <ActionSheet
          ref={o => {
            this.ActionSheet = o;
          }}
          title={translate('repository.main.repoActions', language)}
          options={[...repositoryActions, translate('common.cancel', language)]}
          cancelButtonIndex={repositoryActions.length}
          onPress={this.handlePress}
        />
      </ViewContainer>
    );
  }
}

export const RepositoryScreen = connect(mapStateToProps, mapDispatchToProps)(
  Repository
);
<commit_msg>fix(repository): swap watch and share actions (#250)<commit_after>import React, { Component } from 'react';
import { connect } from 'react-redux';
import { StyleSheet, RefreshControl, Share } from 'react-native';
import { ListItem } from 'react-native-elements';
import ActionSheet from 'react-native-actionsheet';

import {
  ViewContainer,
  LoadingRepositoryProfile,
  RepositoryProfile,
  MembersList,
  SectionList,
  ParallaxScroll,
  LoadingUserListItem,
  UserListItem,
  IssueListItem,
  LoadingMembersList,
  LoadingModal,
} from 'components';
import { translate } from 'utils';
import { colors, fonts } from 'config';
import {
  getRepositoryInfo,
  getContributors,
  getIssues,
  changeStarStatusRepo,
  forkRepo,
  subscribeToRepo,
  unSubscribeToRepo,
} from '../repository.action';

const mapStateToProps = state => ({
  username: state.auth.user.login,
  language: state.auth.language,
  repository: state.repository.repository,
  contributors: state.repository.contributors,
  issues: state.repository.issues,
  starred: state.repository.starred,
  forked: state.repository.forked,
  subscribed: state.repository.subscribed,
  isPendingRepository: state.repository.isPendingRepository,
  isPendingContributors: state.repository.isPendingContributors,
  isPendingIssues: state.repository.isPendingIssues,
  isPendingCheckStarred: state.repository.isPendingCheckStarred,
  isPendingFork: state.repository.isPendingFork,
});

const mapDispatchToProps = dispatch => ({
  getRepositoryInfoByDispatch: url => dispatch(getRepositoryInfo(url)),
  getContributorsByDispatch: url => dispatch(getContributors(url)),
  getIssuesByDispatch: url => dispatch(getIssues(url)),
  changeStarStatusRepoByDispatch: (owner, repo, starred) =>
    dispatch(changeStarStatusRepo(owner, repo, starred)),
  forkRepoByDispatch: (owner, repo) => dispatch(forkRepo(owner, repo)),
  subscribeToRepo: (owner, repo) => dispatch(subscribeToRepo(owner, repo)),
  unSubscribeToRepo: (owner, repo) => dispatch(unSubscribeToRepo(owner, repo)),
});

const styles = StyleSheet.create({
  listTitle: {
    color: colors.black,
    ...fonts.fontPrimary,
  },
});

class Repository extends Component {
  props: {
    // selectRepositoryByDispatch: Function,
    getRepositoryInfoByDispatch: Function,
    // getIssuesByDispatch: Function,
    changeStarStatusRepoByDispatch: Function,
    forkRepoByDispatch: Function,
    // repositoryName: string,
    repository: Object,
    contributors: Array,
    issues: Array,
    starred: boolean,
    // forked: boolean,
    isPendingRepository: boolean,
    isPendingContributors: boolean,
    isPendingIssues: boolean,
    isPendingCheckStarred: boolean,
    isPendingFork: boolean,
    // isPendingCheckForked: boolean,
    navigation: Object,
    username: string,
    language: string,
    subscribed: boolean,
    subscribeToRepo: Function,
    unSubscribeToRepo: Function,
  };

  state: {
    refreshing: boolean,
  };

  constructor(props) {
    super(props);
    this.state = {
      refreshing: false,
    };
  }

  componentDidMount() {
    const {
      repository: repo,
      repositoryUrl: repoUrl,
    } = this.props.navigation.state.params;

    this.props.getRepositoryInfoByDispatch(repo ? repo.url : repoUrl);
  }

  showMenuActionSheet = () => {
    this.ActionSheet.show();
  };

  handlePress = index => {
    const {
      starred,
      subscribed,
      repository,
      changeStarStatusRepoByDispatch,
      forkRepoByDispatch,
      navigation,
      username,
    } = this.props;

    const showFork = repository.owner.login !== username;

    if (index === 0) {
      changeStarStatusRepoByDispatch(
        repository.owner.login,
        repository.name,
        starred
      );
    } else if (index === 1 && showFork) {
      forkRepoByDispatch(repository.owner.login, repository.name).then(json => {
        navigation.navigate('Repository', { repository: json });
      });
    } else if ((index === 2 && showFork) || (index === 1 && !showFork)) {
      const subscribeMethod = !subscribed
        ? this.props.subscribeToRepo
        : this.props.unSubscribeToRepo;

      subscribeMethod(repository.owner.login, repository.name);
    } else if ((index === 3 && showFork) || (index === 2 && !showFork)) {
      this.shareRepository(repository);
    }
  };

  fetchRepoInfo = () => {
    const {
      repository: repo,
      repositoryUrl: repoUrl,
    } = this.props.navigation.state.params;

    this.setState({ refreshing: true });
    this.props
      .getRepositoryInfoByDispatch(repo ? repo.url : repoUrl)
      .then(() => {
        this.setState({ refreshing: false });
      });
  };

  shareRepository = repository => {
    const { language } = this.props;
    const title = translate('repository.main.shareRepositoryTitle', language, {
      repoName: repository.name,
    });

    Share.share(
      {
        title,
        message: translate('repository.main.shareRepositoryMessage', language, {
          repoName: repository.name,
          repoUrl: repository.html_url,
        }),
        url: undefined,
      },
      {
        dialogTitle: title,
        excludedActivityTypes: [],
      }
    );
  };

  render() {
    const {
      repository,
      contributors,
      issues,
      starred,
      language,
      isPendingRepository,
      isPendingContributors,
      isPendingIssues,
      isPendingCheckStarred,
      isPendingFork,
      navigation,
      username,
      subscribed,
    } = this.props;
    const { refreshing } = this.state;

    const initalRepository = navigation.state.params.repository;
    const pulls = issues.filter(issue => issue.hasOwnProperty('pull_request')); // eslint-disable-line no-prototype-builtins
    const pureIssues = issues.filter(issue => {
      // eslint-disable-next-line no-prototype-builtins
      return !issue.hasOwnProperty('pull_request');
    });

    const openPulls = pulls.filter(pull => pull.state === 'open');
    const openIssues = pureIssues.filter(issue => issue.state === 'open');
    const showFork =
      repository && repository.owner && repository.owner.login !== username;

    const repositoryActions = [
      starred
        ? translate('repository.main.unstarAction', language)
        : translate('repository.main.starAction', language),
      subscribed
        ? translate('repository.main.unwatchAction', language)
        : translate('repository.main.watchAction', language),
      translate('repository.main.shareAction', language),
    ];

    if (showFork) {
      repositoryActions.splice(
        1,
        0,
        translate('repository.main.forkAction', language)
      );
    }

    const loader = isPendingFork ? <LoadingModal /> : null;

    return (
      <ViewContainer>
        {loader}

        <ParallaxScroll
          renderContent={() => {
            if (isPendingRepository && !initalRepository) {
              return <LoadingRepositoryProfile language={language} />;
            }

            return (
              <RepositoryProfile
                repository={isPendingRepository ? initalRepository : repository}
                starred={
                  isPendingRepository || isPendingCheckStarred ? false : starred
                }
                loading={isPendingRepository}
                navigation={navigation}
                language={language}
              />
            );
          }}
          refreshControl={
            <RefreshControl
              refreshing={refreshing}
              onRefresh={this.fetchRepoInfo}
            />
          }
          stickyTitle={repository.name}
          showMenu={!isPendingRepository && !isPendingCheckStarred}
          menuAction={this.showMenuActionSheet}
          navigation={navigation}
          navigateBack
        >
          {initalRepository &&
            !initalRepository.owner &&
            isPendingRepository &&
            <SectionList
              title={translate('repository.main.ownerTitle', language)}
            >
              <LoadingUserListItem />
            </SectionList>}

          {!(initalRepository && initalRepository.owner) &&
            (repository && repository.owner) &&
            !isPendingRepository &&
            <SectionList
              title={translate('repository.main.ownerTitle', language)}
            >
              <UserListItem user={repository.owner} navigation={navigation} />
            </SectionList>}

          {initalRepository &&
            initalRepository.owner &&
            <SectionList
              title={translate('repository.main.ownerTitle', language)}
            >
              <UserListItem
                user={initalRepository.owner}
                navigation={navigation}
              />
            </SectionList>}

          {(isPendingRepository || isPendingContributors) &&
            <LoadingMembersList
              title={translate('repository.main.contributorsTitle', language)}
            />}

          {!isPendingContributors &&
            <MembersList
              title={translate('repository.main.contributorsTitle', language)}
              members={contributors}
              noMembersMessage={translate(
                'repository.main.noContributorsMessage',
                language
              )}
              navigation={navigation}
            />}

          <SectionList
            title={translate('repository.main.sourceTitle', language)}
          >
            <ListItem
              title={translate('repository.main.readMe', language)}
              leftIcon={{
                name: 'book',
                color: colors.grey,
                type: 'octicon',
              }}
              titleStyle={styles.listTitle}
              onPress={() =>
                navigation.navigate('ReadMe', {
                  repository,
                })}
              underlayColor={colors.greyLight}
            />
            <ListItem
              title={translate('repository.main.viewSource', language)}
              titleStyle={styles.listTitle}
              leftIcon={{
                name: 'code',
                color: colors.grey,
                type: 'octicon',
              }}
              onPress={() =>
                navigation.navigate('RepositoryCodeList', {
                  title: translate('repository.codeList.title', language),
                  topLevel: true,
                })}
              underlayColor={colors.greyLight}
            />
          </SectionList>

          <SectionList
            loading={isPendingIssues}
            title={translate('repository.main.issuesTitle', language)}
            noItems={openIssues.length === 0}
            noItemsMessage={
              pureIssues.length === 0
                ? translate('repository.main.noIssuesMessage', language)
                : translate('repository.main.noOpenIssuesMessage', language)
            }
            showButton
            buttonTitle={
              pureIssues.length > 0
                ? translate('repository.main.viewAllButton', language)
                : translate('repository.main.newIssueButton', language)
            }
            buttonAction={() => {
              if (pureIssues.length > 0) {
                navigation.navigate('IssueList', {
                  title: translate('repository.issueList.title', language),
                  type: 'issue',
                  issues: pureIssues,
                });
              } else {
                navigation.navigate('NewIssue', {
                  title: translate('issue.newIssue.title', language),
                });
              }
            }}
          >
            {openIssues
              .slice(0, 3)
              .map(item =>
                <IssueListItem
                  key={item.id}
                  type="issue"
                  issue={item}
                  navigation={navigation}
                  language={language}
                />
              )}
          </SectionList>

          <SectionList
            loading={isPendingIssues}
            title={translate('repository.main.pullRequestTitle', language)}
            noItems={openPulls.length === 0}
            noItemsMessage={
              pulls.length === 0
                ? translate('repository.main.noPullRequestsMessage', language)
                : translate(
                    'repository.main.noOpenPullRequestsMessage',
                    language
                  )
            }
            showButton={pulls.length > 0}
            buttonTitle={translate('repository.main.viewAllButton', language)}
            buttonAction={() =>
              navigation.navigate('PullList', {
                title: translate('repository.pullList.title', language),
                type: 'pull',
                issues: pulls,
              })}
          >
            {openPulls
              .slice(0, 3)
              .map(item =>
                <IssueListItem
                  key={item.id}
                  type="pull"
                  issue={item}
                  navigation={navigation}
                  language={language}
                />
              )}
          </SectionList>
        </ParallaxScroll>

        <ActionSheet
          ref={o => {
            this.ActionSheet = o;
          }}
          title={translate('repository.main.repoActions', language)}
          options={[...repositoryActions, translate('common.cancel', language)]}
          cancelButtonIndex={repositoryActions.length}
          onPress={this.handlePress}
        />
      </ViewContainer>
    );
  }
}

export const RepositoryScreen = connect(mapStateToProps, mapDispatchToProps)(
  Repository
);
<|endoftext|>


<commit_before>'use strict';

const Promise = require('promise');
const facebookAnalyticsClient = require('../../clients/facebook/FacebookAnalyticsClient');
const cassandraConnector = require('../../clients/cassandra/CassandraConnector');
const withRunTime = require('../shared').withRunTime;
const trackEvent = require('../../clients/appinsights/AppInsightsClient').trackEvent;

function cassandraRowToSite(row) {
  // Please note that the following properties in the SiteProperties are NOT in Cassandra's sitessetings:
  // storageConnectionString, featuresConnectionString, mapzenApiKey, fbToken.
  return {
    name: row.sitename,
    properties: {
      targetBbox: row.geofence,
      defaultZoomLevel: row.defaultzoom,
      logo: row.logo,
      title: row.title,
      defaultLocation: row.geofence,
      supportedLanguages: row.languages
    }
  };
}

/**
 * @param {{siteId: string}} args
 * @returns {Promise.<{runTime: string, sites: Array<{name: string, properties: {targetBbox: number[], defaultZoomLevel: number, logo: string, title: string, defaultLocation: number[], storageConnectionString: string, featuresConnectionString: string, mapzenApiKey: string, fbToken: string, supportedLanguages: string[]}}>}>}
 */
function sites(args, res) { // eslint-disable-line no-unused-vars
  return new Promise((resolve, reject) => {
    const siteId = args.siteId;
    if (!siteId) {
      return reject('No site id to fetch specified');
    }

    const siteById = 'SELECT * FROM fortis.sitesettings WHERE id = ?';
    cassandraConnector.executeQuery(siteById, [siteId])
    .then(rows => {
      if (rows.length < 1) return reject(`Could not find site with id ${siteId}`);
      if (rows.length > 1) return reject(`Got more than one site (got ${rows.length}) with id '${siteId}'`);

      const site = cassandraRowToSite(rows[0]);
      resolve({sites: [site]});
    })
    .catch(reject);
  });
}

function cassandraRowToTwitterAccount(row) {
  return {
    accountName: row.params.accountName,
    consumerKey: row.params.consumerKey,
    consumerSecret: row.params.consumerSecret,
    token: row.params.token,
    tokenSecret: row.params.tokenSecret
  };
}

/**
 * @param {{siteId: string}} args
 * @returns {Promise.<{runTime: string, accounts: Array<{accountName: string, consumerKey: string, consumerSecret: string, token: string, tokenSecret: string}>}>}
 */
function twitterAccounts(args, res) { // eslint-disable-line no-unused-vars
  return new Promise((resolve, reject) => {
    const sourcesByConnector = 'SELECT params FROM fortis.streams WHERE connector = ? ALLOW FILTERING';
    cassandraConnector.executeQuery(sourcesByConnector, ['twitter'])
    .then(rows => {
      const accounts = rows.map(cassandraRowToTwitterAccount);
      resolve({accounts: accounts});
    })
    .catch(reject)
    ;
  });
}

function cassandraRowToTrustedTwitterAccount(row) {
  return {
    RowKey: `${row.connector},${row.sourceid},${row.sourcetype}`,
    acctUrl: row.sourceid
  };
}

/**
 * @param {{siteId: string}} args
 * @returns {Promise.<{runTime: string, accounts: Array<{RowKey: string, acctUrl: string}>}>}
 */
function trustedTwitterAccounts(args, res) { // eslint-disable-line no-unused-vars
  return new Promise((resolve, reject) => {
    const sourcesByConnector = 'SELECT connector, sourceid, sourcetype  FROM fortis.trustedsources WHERE connector = ? ALLOW FILTERING';
    cassandraConnector.executeQuery(sourcesByConnector, ['twitter'])
    .then(rows => {
      const accounts = rows.map(cassandraRowToTrustedTwitterAccount);
      resolve({accounts: accounts});
    })
    .catch(reject)
    ;
  });
}

function cassandraRowToFacebookPage(row) {
  return {
    RowKey: `${row.connector},${row.sourceid},${row.sourcetype}`,
    pageUrl: row.sourceid
  };
}

/**
 * @param {{siteId: string}} args
 * @returns {Promise.<{runTime: string, pages: Array<{RowKey: string, pageUrl: string}>}>}
 */
function facebookPages(args, res) { // eslint-disable-line no-unused-vars
  return new Promise((resolve, reject) => {
    const sourcesByConnector = 'SELECT connector, sourceid, sourcetype FROM fortis.trustedsources WHERE connector = ? ALLOW FILTERING';
    cassandraConnector.executeQuery(sourcesByConnector, ['facebook'])
    .then(rows => {
      const pages = rows.map(cassandraRowToFacebookPage);
      resolve({pages: pages});
    })
    .catch(reject)
    ;
  });
}

/**
 * @param {{siteId: string, days: number}} args
 * @returns {Promise.<{analytics: Array<{Name: string, Count: number, LastUpdated: string}>}>}
 */
function facebookAnalytics(args, res) { // eslint-disable-line no-unused-vars
  return new Promise((resolve, reject) => {
    const pageIds = ['aljazeera', 'microsoftvan']; // todo: fetch pages for args.siteId from sitesettings

    Promise.all(pageIds.map(pageId => ({Name: pageId, LastUpdated: facebookAnalyticsClient.fetchPageLastUpdatedAt(pageId), Count: -1})))
    .then(analytics => resolve({analytics}))
    .catch(err => reject(err));
  });
}

function cassandraRowToTermFilter(row) {
  return {
    filteredTerms: row.conjunctivefilter,
    lang: null,
    RowKey: row.id
  };
}

/**
 * @param {{siteId: string}} args
 * @returns {Promise.<{runTime: string, filters: Array<{filteredTerms: string[], lang: string, RowKey: string}>}>}
 */
function termBlacklist(args, res) { // eslint-disable-line no-unused-vars
  return new Promise((resolve, reject) => {
    const blacklistQuery = 'SELECT id, conjunctivefilter FROM fortis.blacklist';
    cassandraConnector.executeQuery(blacklistQuery, [])
    .then(rows => {
      const filters = rows.map(cassandraRowToTermFilter);
      resolve({ filters: filters });
    })
    .catch(reject)
    ;
  });
}

module.exports = {
  sites: trackEvent(withRunTime(sites), 'sites'),
  twitterAccounts: trackEvent(withRunTime(twitterAccounts), 'twitterAccounts'),
  trustedTwitterAccounts: trackEvent(withRunTime(trustedTwitterAccounts), 'trustedTwitterAccounts'),
  facebookPages: trackEvent(withRunTime(facebookPages), 'facebookPages'),
  facebookAnalytics: trackEvent(facebookAnalytics, 'facebookAnalytics'),
  termBlacklist: trackEvent(withRunTime(termBlacklist), 'termBlacklist')
};
<commit_msg>Fetch facebook pages for analytics from db<commit_after>'use strict';

const Promise = require('promise');
const facebookAnalyticsClient = require('../../clients/facebook/FacebookAnalyticsClient');
const cassandraConnector = require('../../clients/cassandra/CassandraConnector');
const withRunTime = require('../shared').withRunTime;
const trackEvent = require('../../clients/appinsights/AppInsightsClient').trackEvent;

function cassandraRowToSite(row) {
  // Please note that the following properties in the SiteProperties are NOT in Cassandra's sitessetings:
  // storageConnectionString, featuresConnectionString, mapzenApiKey, fbToken.
  return {
    name: row.sitename,
    properties: {
      targetBbox: row.geofence,
      defaultZoomLevel: row.defaultzoom,
      logo: row.logo,
      title: row.title,
      defaultLocation: row.geofence,
      supportedLanguages: row.languages
    }
  };
}

/**
 * @param {{siteId: string}} args
 * @returns {Promise.<{runTime: string, sites: Array<{name: string, properties: {targetBbox: number[], defaultZoomLevel: number, logo: string, title: string, defaultLocation: number[], storageConnectionString: string, featuresConnectionString: string, mapzenApiKey: string, fbToken: string, supportedLanguages: string[]}}>}>}
 */
function sites(args, res) { // eslint-disable-line no-unused-vars
  return new Promise((resolve, reject) => {
    const siteId = args.siteId;
    if (!siteId) {
      return reject('No site id to fetch specified');
    }

    const siteById = 'SELECT * FROM fortis.sitesettings WHERE id = ?';
    cassandraConnector.executeQuery(siteById, [siteId])
    .then(rows => {
      if (rows.length < 1) return reject(`Could not find site with id ${siteId}`);
      if (rows.length > 1) return reject(`Got more than one site (got ${rows.length}) with id '${siteId}'`);

      const site = cassandraRowToSite(rows[0]);
      resolve({sites: [site]});
    })
    .catch(reject);
  });
}

function cassandraRowToTwitterAccount(row) {
  return {
    accountName: row.params.accountName,
    consumerKey: row.params.consumerKey,
    consumerSecret: row.params.consumerSecret,
    token: row.params.token,
    tokenSecret: row.params.tokenSecret
  };
}

/**
 * @param {{siteId: string}} args
 * @returns {Promise.<{runTime: string, accounts: Array<{accountName: string, consumerKey: string, consumerSecret: string, token: string, tokenSecret: string}>}>}
 */
function twitterAccounts(args, res) { // eslint-disable-line no-unused-vars
  return new Promise((resolve, reject) => {
    const sourcesByConnector = 'SELECT params FROM fortis.streams WHERE connector = ? ALLOW FILTERING';
    cassandraConnector.executeQuery(sourcesByConnector, ['twitter'])
    .then(rows => {
      const accounts = rows.map(cassandraRowToTwitterAccount);
      resolve({accounts: accounts});
    })
    .catch(reject)
    ;
  });
}

function cassandraRowToTrustedTwitterAccount(row) {
  return {
    RowKey: `${row.connector},${row.sourceid},${row.sourcetype}`,
    acctUrl: row.sourceid
  };
}

/**
 * @param {{siteId: string}} args
 * @returns {Promise.<{runTime: string, accounts: Array<{RowKey: string, acctUrl: string}>}>}
 */
function trustedTwitterAccounts(args, res) { // eslint-disable-line no-unused-vars
  return new Promise((resolve, reject) => {
    const sourcesByConnector = 'SELECT connector, sourceid, sourcetype  FROM fortis.trustedsources WHERE connector = ? ALLOW FILTERING';
    cassandraConnector.executeQuery(sourcesByConnector, ['twitter'])
    .then(rows => {
      const accounts = rows.map(cassandraRowToTrustedTwitterAccount);
      resolve({accounts: accounts});
    })
    .catch(reject)
    ;
  });
}

function cassandraRowToFacebookPage(row) {
  return {
    RowKey: `${row.connector},${row.sourceid},${row.sourcetype}`,
    pageUrl: row.sourceid
  };
}

/**
 * @param {{siteId: string}} args
 * @returns {Promise.<{runTime: string, pages: Array<{RowKey: string, pageUrl: string}>}>}
 */
function facebookPages(args, res) { // eslint-disable-line no-unused-vars
  return new Promise((resolve, reject) => {
    const sourcesByConnector = 'SELECT connector, sourceid, sourcetype FROM fortis.trustedsources WHERE connector = ? ALLOW FILTERING';
    cassandraConnector.executeQuery(sourcesByConnector, ['facebook'])
    .then(rows => {
      const pages = rows.map(cassandraRowToFacebookPage);
      resolve({pages: pages});
    })
    .catch(reject)
    ;
  });
}

function facebookPageToId(page) {
  const match = page && page.pageUrl && page.pageUrl.match(/facebook.com\/([^/]+)/);
  return match && match.length >= 1 && match[1];
}

/**
 * @param {{siteId: string, days: number}} args
 * @returns {Promise.<{analytics: Array<{Name: string, Count: number, LastUpdated: string}>}>}
 */
function facebookAnalytics(args, res) { // eslint-disable-line no-unused-vars
  return new Promise((resolve, reject) => {
    facebookPages({siteId: args.siteId})
    .then(response => {
      const pageIds = response.pages.map(facebookPageToId).filter(pageId => !!pageId);
      Promise.all(pageIds.map(pageId => ({Name: pageId, LastUpdated: facebookAnalyticsClient.fetchPageLastUpdatedAt(pageId), Count: -1})))
      .then(analytics => resolve({analytics}))
      .catch(reject);
    });
  });
}

function cassandraRowToTermFilter(row) {
  return {
    filteredTerms: row.conjunctivefilter,
    lang: null,
    RowKey: row.id
  };
}

/**
 * @param {{siteId: string}} args
 * @returns {Promise.<{runTime: string, filters: Array<{filteredTerms: string[], lang: string, RowKey: string}>}>}
 */
function termBlacklist(args, res) { // eslint-disable-line no-unused-vars
  return new Promise((resolve, reject) => {
    const blacklistQuery = 'SELECT id, conjunctivefilter FROM fortis.blacklist';
    cassandraConnector.executeQuery(blacklistQuery, [])
    .then(rows => {
      const filters = rows.map(cassandraRowToTermFilter);
      resolve({ filters: filters });
    })
    .catch(reject)
    ;
  });
}

module.exports = {
  sites: trackEvent(withRunTime(sites), 'sites'),
  twitterAccounts: trackEvent(withRunTime(twitterAccounts), 'twitterAccounts'),
  trustedTwitterAccounts: trackEvent(withRunTime(trustedTwitterAccounts), 'trustedTwitterAccounts'),
  facebookPages: trackEvent(withRunTime(facebookPages), 'facebookPages'),
  facebookAnalytics: trackEvent(facebookAnalytics, 'facebookAnalytics'),
  termBlacklist: trackEvent(withRunTime(termBlacklist), 'termBlacklist')
};
<|endoftext|>


<commit_before>#!/usr/bin/env node

/*
  Determine Basal

  Released under MIT license. See the accompanying LICENSE.txt file for
  full terms and conditions

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
*/

function getLastGlucose(data) {

    var now = data[0];
    var last = data[1];
    var avg;
    //TODO: calculate average using system_time instead of assuming 1 data point every 5m
    if (typeof data[3] !== 'undefined' && data[3].glucose > 30) {
        avg = ( now.glucose - data[3].glucose) / 3;
    } else if (typeof data[2] !== 'undefined' && data[2].glucose > 30) {
        avg = ( now.glucose - data[2].glucose) / 2;
    } else if (typeof data[1] !== 'undefined' && data[1].glucose > 30) {
        avg = now.glucose - data[1].glucose;
    } else { avg = 0; }
    var o = {
        delta: now.glucose - last.glucose
        , glucose: now.glucose
        , avgdelta: avg
    };

    return o;

}

function setTempBasal(rate, duration) {

    maxSafeBasal = Math.min(profile_data.max_basal, 3 * profile_data.max_daily_basal, 4 * profile_data.current_basal);

    if (rate < 0) { rate = 0; } // if >30m @ 0 required, zero temp will be extended to 30m instead
    else if (rate > maxSafeBasal) { rate = maxSafeBasal; }

    // rather than canceling temps, if Offline mode is set, always set the current basal as a 30m temp
    // so we can see on the pump that openaps is working
    if (duration == 0 && offline_input == 'Offline') {
        rate = profile_data.current_basal;
        duration  = 30;
    }

    requestedTemp.duration = duration;
    requestedTemp.rate = Math.round((Math.round(rate / 0.05) * 0.05)*100)/100;
};

if (!module.parent) {
    var iob_input = process.argv.slice(2, 3).pop()
    var temps_input = process.argv.slice(3, 4).pop()
    var glucose_input = process.argv.slice(4, 5).pop()
    var profile_input = process.argv.slice(5, 6).pop()
    var offline_input = process.argv.slice(6, 7).pop()

    if (!iob_input || !temps_input || !glucose_input || !profile_input) {
        console.error('usage: ', process.argv.slice(0, 2), '<iob.json> <current-temps.json> <glucose.json> <profile.json> [Offline]');
        process.exit(1);
    }

    var cwd = process.cwd()
    var glucose_data = require(cwd + '/' + glucose_input);
    var temps_data = require(cwd + '/' + temps_input);
    var iob_data = require(cwd + '/' + iob_input);
    var profile_data = require(cwd + '/' + profile_input);

    if (typeof profile_data === 'undefined' || typeof profile_data.current_basal === 'undefined') {
        console.error('Error: could not get current basal rate');
        process.exit(1);
    }

    var max_iob = profile_data.max_iob; // maximum amount of non-bolus IOB OpenAPS will ever deliver

    // if target_bg is set, great. otherwise, if min and max are set, then set target to their average
    var target_bg;
    if (typeof profile_data.target_bg !== 'undefined') {
        target_bg = profile_data.target_bg;
    } else {
        if (typeof profile_data.max_bg !== 'undefined' && typeof profile_data.max_bg !== 'undefined') {
            target_bg = (profile_data.min_bg + profile_data.max_bg) / 2;
        } else {
            console.error('Error: could not determine target_bg');
            process.exit(1);
        }
    }

    var glucose_status = getLastGlucose(glucose_data);
    var bg = glucose_status.glucose;
    var tick;
    if (glucose_status.delta >= 0) { tick = "+" + glucose_status.delta; }
    else { tick = glucose_status.delta; }
    console.error("IOB: " + iob_data.iob.toFixed(2) + ", Bolus IOB: " + iob_data.bolusiob.toFixed(2));
    var bgi = -iob_data.activity * profile_data.sens * 5;
    console.error("Avg. Delta: " + glucose_status.avgdelta.toFixed(1) + ", BGI: " + bgi.toFixed(1));
    // project deviation over next 15 minutes
    var deviation = Math.round( 15 / 5 * ( glucose_status.avgdelta - bgi ) );
    console.error("15m deviation: " + deviation.toFixed(0));
    var bolusContrib = iob_data.bolusiob * profile_data.sens;
    var naive_eventualBG = Math.round( bg - (iob_data.iob * profile_data.sens) );
    var eventualBG = naive_eventualBG + deviation;
    var naive_snoozeBG = Math.round( naive_eventualBG + bolusContrib );
    var snoozeBG = naive_snoozeBG + deviation;
    console.error("BG: " + bg + tick + " -> " + eventualBG + "-" + snoozeBG + " (Unadjusted: " + naive_eventualBG + "-" + naive_snoozeBG + ")");
    if (typeof eventualBG === 'undefined') { console.error('Error: could not calculate eventualBG'); }
    var requestedTemp = {
        'temp': 'absolute'
        , 'bg': bg
        , 'tick': tick
        , 'eventualBG': eventualBG
        , 'snoozeBG': snoozeBG
    };

    //if old reading from Dexcom do nothing

    var systemTime = new Date();
    var bgTime;
    if (glucose_data[0].display_time) {
        bgTime = new Date(glucose_data[0].display_time.replace('T', ' '));
    } else if (glucose_data[0].dateString) {
        bgTime = new Date(glucose_data[0].dateString);
    } else { console.error("Could not determine last BG time"); }
    var minAgo = (systemTime - bgTime) / 60 / 1000
    var threshold = profile_data.min_bg - 30;
    var reason="";

    if (minAgo < 10 && minAgo > -5) { // Dexcom data is recent, but not far in the future

        if (bg > 10) {  //Dexcom is in ??? mode or calibrating, do nothing. Asked @benwest for raw data in iter_glucose

            if (bg < threshold) { // low glucose suspend mode: BG is < ~80
                reason = "BG " + bg + "<" + threshold;
                console.error(reason);
                if (glucose_status.delta > 0) { // if BG is rising
                    if (temps_data.rate > profile_data.current_basal) { // if a high-temp is running
                        setTempBasal(0, 0); // cancel high temp
                    } else if (temps_data.duration && eventualBG > profile_data.max_bg) { // if low-temped and predicted to go high from negative IOB
                        setTempBasal(0, 0); // cancel low temp
                    } else {
                        reason = bg + "<" + threshold + "; no high-temp to cancel";
                        console.error(reason);
                    }
                }
                else { // BG is not yet rising
                    setTempBasal(0, 30);
                }

            } else {

                // if BG is rising but eventual BG is below min, or BG is falling but eventual BG is above min
                if ((glucose_status.delta > 0 && eventualBG < profile_data.min_bg) || (glucose_status.delta < 0 && eventualBG >= profile_data.min_bg)) {
                    if (temps_data.duration > 0) { // if there is currently any temp basal running
                        // if it's a low-temp and eventualBG < profile_data.max_bg, let it run a bit longer
                        if (temps_data.rate <= profile_data.current_basal && eventualBG < profile_data.max_bg) {
                            reason = "BG" + tick + " but " + eventualBG + "<" + profile_data.max_bg;
                            console.error(reason);
                        } else {
                            reason = glucose_status.delta + " and " + eventualBG;
                            setTempBasal(0, 0); // cancel temp
                        }
                    } else {
                        reason = tick + "; no temp to cancel";
                        console.error(reason);
                    }

                } else if (eventualBG < profile_data.min_bg) { // if eventual BG is below target:
                    // if this is just due to boluses, we can snooze until the bolus IOB decays (at double speed)
                    if (snoozeBG > profile_data.min_bg) { // if adding back in the bolus contribution BG would be above min
                        // if BG is falling and high-temped, or rising and low-temped, cancel
                        if (glucose_status.delta < 0 && temps_data.rate > profile_data.current_basal) {
                            reason = tick + " and " + temps_data.rate + ">" + profile_data.current_basal;
                            setTempBasal(0, 0); // cancel temp
                        } else if (glucose_status.delta > 0 && temps_data.rate < profile_data.current_basal) {
                            reason = tick + " and " + temps_data.rate + "<" + profile_data.current_basal;
                            setTempBasal(0, 0); // cancel temp
                        } else {
                            reason = "bolus snooze: eventual BG range " + eventualBG + "-" + snoozeBG;
                            console.error(reason);
                        }
                    } else {
                        // calculate 30m low-temp required to get projected BG up to target
                        // negative insulin required to get up to min:
                        //var insulinReq = Math.max(0, (target_bg - eventualBG) / profile_data.sens);
                        // use snoozeBG instead of eventualBG to more gradually ramp in any counteraction of the user's boluses
                        var insulinReq = Math.min(0, (snoozeBG - target_bg) / profile_data.sens);
                        // rate required to deliver insulinReq less insulin over 30m:
                        var rate = profile_data.current_basal + (2 * insulinReq);
                        rate = Math.round( rate * 1000 ) / 1000;
                        // if required temp < existing temp basal
                        if (typeof temps_data.rate !== 'undefined' && (temps_data.duration > 0 && rate > temps_data.rate - 0.1)) {
                            reason = temps_data.rate + "<~" + rate;
                            console.error(reason);
                        } else {
                            reason = "Eventual BG " + eventualBG + "<" + profile_data.min_bg;
                            //console.error(reason);
                            setTempBasal(rate, 30);
                        }
                    }

                } else if (eventualBG > profile_data.max_bg) { // if eventual BG is above target:
                    // if iob is over max, just cancel any temps
                    var basal_iob = iob_data.iob - iob_data.bolusiob;
                    if (basal_iob > max_iob) {
                        reason = basal_iob + ">" + max_iob;
                        setTempBasal(0, 0);
                    }
                    // calculate 30m high-temp required to get projected BG down to target
                    // additional insulin required to get down to max bg:
                    var insulinReq = (eventualBG - target_bg) / profile_data.sens;
                    // if that would put us over max_iob, then reduce accordingly
                    insulinReq = Math.min(insulinReq, max_iob-basal_iob);

                    // rate required to deliver insulinReq more insulin over 30m:
                    var rate = profile_data.current_basal + (2 * insulinReq);
                    rate = Math.round( rate * 1000 ) / 1000;
                    maxSafeBasal = Math.min(profile_data.max_basal, 3 * profile_data.max_daily_basal, 4 * profile_data.current_basal);
                    if (rate > maxSafeBasal) {
                        rate = maxSafeBasal;
                        //console.error(maxSafeBasal);
                    }
                    var insulinScheduled = temps_data.duration * (temps_data.rate - profile_data.current_basal) / 60;
                    if (insulinScheduled > insulinReq + 0.3) { // if current temp would deliver >0.3U more than the required insulin, lower the rate
                        reason = temps_data.duration + "@" + temps_data.rate + " > " + insulinReq + "U";
                        setTempBasal(rate, 30);
                    }
                    else if (typeof temps_data.rate !== 'undefined' && (temps_data.duration > 0 && rate < temps_data.rate + 0.1)) { // if required temp < existing temp basal
                        reason = temps_data.rate + ">~" + rate;
                        console.error(reason);
                    } else { // required temp > existing temp basal
                        reason = temps_data.rate + "<" + rate;
                        setTempBasal(rate, 30);
                    }

                } else {
                    reason = eventualBG + " is in range. No temp required.";
                    if (temps_data.duration > 0) { // if there is currently any temp basal running
                        setTempBasal(0, 0); // cancel temp
                    } else {
                        console.error(reason);
                    }
                }
            }

            if (offline_input == 'Offline') {
                // if no temp is running or required, set the current basal as a temp, so you can see on the pump that the loop is working
                if ((!temps_data.duration || (temps_data.rate == profile_data.current_basal)) && !requestedTemp.duration) {
                    reason = reason + "; setting current basal of " + profile_data.current_basal + " as temp";
                    setTempBasal(profile_data.current_basal, 30);
                }
            }
        }  else {
            reason = "CGM is calibrating or in ??? state";
            console.error(reason);
        }
    } else {
        reason = "BG data is too old, or clock set incorrectly";
        console.error(reason);
    }

requestedTemp.reason = reason;
console.log(JSON.stringify(requestedTemp));
}
<commit_msg>more descriptive reasons<commit_after>#!/usr/bin/env node

/*
  Determine Basal

  Released under MIT license. See the accompanying LICENSE.txt file for
  full terms and conditions

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
*/

function getLastGlucose(data) {

    var now = data[0];
    var last = data[1];
    var avg;
    //TODO: calculate average using system_time instead of assuming 1 data point every 5m
    if (typeof data[3] !== 'undefined' && data[3].glucose > 30) {
        avg = ( now.glucose - data[3].glucose) / 3;
    } else if (typeof data[2] !== 'undefined' && data[2].glucose > 30) {
        avg = ( now.glucose - data[2].glucose) / 2;
    } else if (typeof data[1] !== 'undefined' && data[1].glucose > 30) {
        avg = now.glucose - data[1].glucose;
    } else { avg = 0; }
    var o = {
        delta: now.glucose - last.glucose
        , glucose: now.glucose
        , avgdelta: avg
    };

    return o;

}

function setTempBasal(rate, duration) {

    maxSafeBasal = Math.min(profile_data.max_basal, 3 * profile_data.max_daily_basal, 4 * profile_data.current_basal);

    if (rate < 0) { rate = 0; } // if >30m @ 0 required, zero temp will be extended to 30m instead
    else if (rate > maxSafeBasal) { rate = maxSafeBasal; }

    // rather than canceling temps, if Offline mode is set, always set the current basal as a 30m temp
    // so we can see on the pump that openaps is working
    if (duration == 0 && offline_input == 'Offline') {
        rate = profile_data.current_basal;
        duration  = 30;
    }

    requestedTemp.duration = duration;
    requestedTemp.rate = Math.round((Math.round(rate / 0.05) * 0.05)*100)/100;
};

if (!module.parent) {
    var iob_input = process.argv.slice(2, 3).pop()
    var temps_input = process.argv.slice(3, 4).pop()
    var glucose_input = process.argv.slice(4, 5).pop()
    var profile_input = process.argv.slice(5, 6).pop()
    var offline_input = process.argv.slice(6, 7).pop()

    if (!iob_input || !temps_input || !glucose_input || !profile_input) {
        console.error('usage: ', process.argv.slice(0, 2), '<iob.json> <current-temps.json> <glucose.json> <profile.json> [Offline]');
        process.exit(1);
    }

    var cwd = process.cwd()
    var glucose_data = require(cwd + '/' + glucose_input);
    var temps_data = require(cwd + '/' + temps_input);
    var iob_data = require(cwd + '/' + iob_input);
    var profile_data = require(cwd + '/' + profile_input);

    if (typeof profile_data === 'undefined' || typeof profile_data.current_basal === 'undefined') {
        console.error('Error: could not get current basal rate');
        process.exit(1);
    }

    var max_iob = profile_data.max_iob; // maximum amount of non-bolus IOB OpenAPS will ever deliver

    // if target_bg is set, great. otherwise, if min and max are set, then set target to their average
    var target_bg;
    if (typeof profile_data.target_bg !== 'undefined') {
        target_bg = profile_data.target_bg;
    } else {
        if (typeof profile_data.max_bg !== 'undefined' && typeof profile_data.max_bg !== 'undefined') {
            target_bg = (profile_data.min_bg + profile_data.max_bg) / 2;
        } else {
            console.error('Error: could not determine target_bg');
            process.exit(1);
        }
    }

    var glucose_status = getLastGlucose(glucose_data);
    var bg = glucose_status.glucose;
    var tick;
    if (glucose_status.delta >= 0) { tick = "+" + glucose_status.delta; }
    else { tick = glucose_status.delta; }
    console.error("IOB: " + iob_data.iob.toFixed(2) + ", Bolus IOB: " + iob_data.bolusiob.toFixed(2));
    var bgi = -iob_data.activity * profile_data.sens * 5;
    console.error("Avg. Delta: " + glucose_status.avgdelta.toFixed(1) + ", BGI: " + bgi.toFixed(1));
    // project deviation over next 15 minutes
    var deviation = Math.round( 15 / 5 * ( glucose_status.avgdelta - bgi ) );
    console.error("15m deviation: " + deviation.toFixed(0));
    var bolusContrib = iob_data.bolusiob * profile_data.sens;
    var naive_eventualBG = Math.round( bg - (iob_data.iob * profile_data.sens) );
    var eventualBG = naive_eventualBG + deviation;
    var naive_snoozeBG = Math.round( naive_eventualBG + bolusContrib );
    var snoozeBG = naive_snoozeBG + deviation;
    console.error("BG: " + bg + tick + " -> " + eventualBG + "-" + snoozeBG + " (Unadjusted: " + naive_eventualBG + "-" + naive_snoozeBG + ")");
    if (typeof eventualBG === 'undefined') { console.error('Error: could not calculate eventualBG'); }
    var requestedTemp = {
        'temp': 'absolute'
        , 'bg': bg
        , 'tick': tick
        , 'eventualBG': eventualBG
        , 'snoozeBG': snoozeBG
    };

    //if old reading from Dexcom do nothing

    var systemTime = new Date();
    var bgTime;
    if (glucose_data[0].display_time) {
        bgTime = new Date(glucose_data[0].display_time.replace('T', ' '));
    } else if (glucose_data[0].dateString) {
        bgTime = new Date(glucose_data[0].dateString);
    } else { console.error("Could not determine last BG time"); }
    var minAgo = (systemTime - bgTime) / 60 / 1000
    var threshold = profile_data.min_bg - 30;
    var reason="";

    if (minAgo < 10 && minAgo > -5) { // Dexcom data is recent, but not far in the future

        if (bg > 10) {  //Dexcom is in ??? mode or calibrating, do nothing. Asked @benwest for raw data in iter_glucose

            if (bg < threshold) { // low glucose suspend mode: BG is < ~80
                reason = "BG " + bg + "<" + threshold;
                console.error(reason);
                if (glucose_status.delta > 0) { // if BG is rising
                    if (temps_data.rate > profile_data.current_basal) { // if a high-temp is running
                        setTempBasal(0, 0); // cancel high temp
                    } else if (temps_data.duration && eventualBG > profile_data.max_bg) { // if low-temped and predicted to go high from negative IOB
                        setTempBasal(0, 0); // cancel low temp
                    } else {
                        reason = bg + "<" + threshold + "; no high-temp to cancel";
                        console.error(reason);
                    }
                }
                else { // BG is not yet rising
                    setTempBasal(0, 30);
                }

            } else {

                // if BG is rising but eventual BG is below min, or BG is falling but eventual BG is above min
                if ((glucose_status.delta > 0 && eventualBG < profile_data.min_bg) || (glucose_status.delta < 0 && eventualBG >= profile_data.min_bg)) {
                    if (temps_data.duration > 0) { // if there is currently any temp basal running
                        // if it's a low-temp and eventualBG < profile_data.max_bg, let it run a bit longer
                        if (temps_data.rate <= profile_data.current_basal && eventualBG < profile_data.max_bg) {
                            reason = "BG" + tick + " but eventualBG " + eventualBG + "<" + profile_data.max_bg;
                            console.error(reason);
                        } else {
                            reason = tick + " and eventualBG " + eventualBG;
                            setTempBasal(0, 0); // cancel temp
                        }
                    } else {
                        reason = tick + "; no temp to cancel";
                        console.error(reason);
                    }

                } else if (eventualBG < profile_data.min_bg) { // if eventual BG is below target:
                    // if this is just due to boluses, we can snooze until the bolus IOB decays (at double speed)
                    if (snoozeBG > profile_data.min_bg) { // if adding back in the bolus contribution BG would be above min
                        // if BG is falling and high-temped, or rising and low-temped, cancel
                        if (glucose_status.delta < 0 && temps_data.rate > profile_data.current_basal) {
                            reason = tick + " and temp " + temps_data.rate + "> basal " + profile_data.current_basal;
                            setTempBasal(0, 0); // cancel temp
                        } else if (glucose_status.delta > 0 && temps_data.rate < profile_data.current_basal) {
                            reason = tick + " and temp " + temps_data.rate + "< basal " + profile_data.current_basal;
                            setTempBasal(0, 0); // cancel temp
                        } else {
                            reason = "bolus snooze: eventual BG range " + eventualBG + "-" + snoozeBG;
                            console.error(reason);
                        }
                    } else {
                        // calculate 30m low-temp required to get projected BG up to target
                        // negative insulin required to get up to min:
                        //var insulinReq = Math.max(0, (target_bg - eventualBG) / profile_data.sens);
                        // use snoozeBG instead of eventualBG to more gradually ramp in any counteraction of the user's boluses
                        var insulinReq = Math.min(0, (snoozeBG - target_bg) / profile_data.sens);
                        // rate required to deliver insulinReq less insulin over 30m:
                        var rate = profile_data.current_basal + (2 * insulinReq);
                        rate = Math.round( rate * 1000 ) / 1000;
                        // if required temp < existing temp basal
                        if (typeof temps_data.rate !== 'undefined' && (temps_data.duration > 0 && rate > temps_data.rate - 0.1)) {
                            reason = "temp " + temps_data.rate + "<~ req " + rate + "U/hr";
                            console.error(reason);
                        } else {
                            reason = "Eventual BG " + eventualBG + "<" + profile_data.min_bg;
                            //console.error(reason);
                            setTempBasal(rate, 30);
                        }
                    }

                } else if (eventualBG > profile_data.max_bg) { // if eventual BG is above target:
                    // if iob is over max, just cancel any temps
                    var basal_iob = iob_data.iob - iob_data.bolusiob;
                    if (basal_iob > max_iob) {
                        reason = "IOB " + basal_iob + ">" + max_iob;
                        setTempBasal(0, 0);
                    }
                    // calculate 30m high-temp required to get projected BG down to target
                    // additional insulin required to get down to max bg:
                    var insulinReq = (eventualBG - target_bg) / profile_data.sens;
                    // if that would put us over max_iob, then reduce accordingly
                    insulinReq = Math.min(insulinReq, max_iob-basal_iob);

                    // rate required to deliver insulinReq more insulin over 30m:
                    var rate = profile_data.current_basal + (2 * insulinReq);
                    rate = Math.round( rate * 1000 ) / 1000;
                    maxSafeBasal = Math.min(profile_data.max_basal, 3 * profile_data.max_daily_basal, 4 * profile_data.current_basal);
                    if (rate > maxSafeBasal) {
                        rate = maxSafeBasal;
                        //console.error(maxSafeBasal);
                    }
                    var insulinScheduled = temps_data.duration * (temps_data.rate - profile_data.current_basal) / 60;
                    if (insulinScheduled > insulinReq + 0.3) { // if current temp would deliver >0.3U more than the required insulin, lower the rate
                        reason = temps_data.duration + "@" + temps_data.rate + " > req " + insulinReq + "U";
                        setTempBasal(rate, 30);
                    }
                    else if (typeof temps_data.rate !== 'undefined' && (temps_data.duration > 0 && rate < temps_data.rate + 0.1)) { // if required temp < existing temp basal
                        reason = "temp " + temps_data.rate + ">~ req " + rate + "U/hr";
                        console.error(reason);
                    } else { // required temp > existing temp basal
                        reason = "temp " + temps_data.rate + "<" + rate + "U/hr";
                        setTempBasal(rate, 30);
                    }

                } else {
                    reason = eventualBG + " is in range. No temp required.";
                    if (temps_data.duration > 0) { // if there is currently any temp basal running
                        setTempBasal(0, 0); // cancel temp
                    } else {
                        console.error(reason);
                    }
                }
            }

            if (offline_input == 'Offline') {
                // if no temp is running or required, set the current basal as a temp, so you can see on the pump that the loop is working
                if ((!temps_data.duration || (temps_data.rate == profile_data.current_basal)) && !requestedTemp.duration) {
                    reason = reason + "; setting current basal of " + profile_data.current_basal + " as temp";
                    setTempBasal(profile_data.current_basal, 30);
                }
            }
        }  else {
            reason = "CGM is calibrating or in ??? state";
            console.error(reason);
        }
    } else {
        reason = "BG data is too old, or clock set incorrectly";
        console.error(reason);
    }

requestedTemp.reason = reason;
console.log(JSON.stringify(requestedTemp));
}
<|endoftext|>


<commit_before>module("selector");

test("element", function() {
	expect(9);
	ok( $("*").size() >= 30, "Select all" );
	t( "Element Selector", "div", ["main","foo"] );
	t( "Element Selector", "body", ["body"] );
	t( "Element Selector", "html", ["html"] );
	t( "Parent Element", "div div", ["foo"] );
	ok( $("param", "#object1").length == 2, "Object/param as context" );

	ok( $("#length").length, '<input name="length"> cannot be found under IE, see #945' );
	ok( $("#lengthtest input").length, '<input name="length"> cannot be found under IE, see #945' );

	t( "Element Selector with underscore", "foo_bar", ["foobar"] );
});

test("broken", function() {
	expect(7);
	t( "Broken Selector", "[", [] );
	t( "Broken Selector", "(", [] );
	t( "Broken Selector", "{", [] );
	t( "Broken Selector", "<", [] );
	t( "Broken Selector", "()", [] );
	t( "Broken Selector", "<>", [] );
	t( "Broken Selector", "{}", [] );
});

test("id", function() {
	expect(23);
	t( "ID Selector", "#body", ["body"] );
	t( "ID Selector w/ Element", "body#body", ["body"] );
	t( "ID Selector w/ Element", "ul#first", [] );
	t( "ID selector with existing ID descendant", "#firstp #simon1", ["simon1"] );
	t( "ID selector with non-existant descendant", "#firstp #foobar", [] );
	t( "ID selector using UTF8", "#台北Táiběi", ["台北Táiběi"] );
	t( "Multiple ID selectors using UTF8", "#台北Táiběi, #台北", ["台北Táiběi","台北"] );
	t( "Descendant ID selector using UTF8", "div #台北", ["台北"] );
	t( "Child ID selector using UTF8", "form > #台北", ["台北"] );

	t( "Escaped ID", "#foo\\:bar", ["foo:bar"] );
	t( "Escaped ID", "#test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );
	t( "Descendant escaped ID", "div #foo\\:bar", ["foo:bar"] );
	t( "Descendant escaped ID", "div #test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );
	t( "Child escaped ID", "form > #foo\\:bar", ["foo:bar"] );
	t( "Child escaped ID", "form > #test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );

	t( "ID Selector, child ID present", "#form > #radio1", ["radio1"] );  // bug #267
	t( "ID Selector, not an ancestor ID", "#form  #first", [] );
	t( "ID Selector, not a child ID", "#form > #option1a", [] );

	t( "All Children of ID", "#foo/*", ["sndp", "en", "sap"] );
	t( "All Children of ID with no children", "#firstUL/*", [] );

	$('tName1 AtName2 A
tName1 Div
').appendTo('#main');
	ok( $("#tName1")[0].id == 'tName1', "ID selector with same value for a name attribute" );
	ok( $("#tName2").length == 0, "ID selector non-existing but name attribute on an A tag" );

	t( "ID selector with non-existant ancestor", "#asdfasdf #foobar", [] ); // bug #986
});

test("class", function() {
	expect(16);
	t( "Class Selector", ".blog", ["mark","simon"] );
	t( "Class Selector", ".blog.link", ["simon"] );
	t( "Class Selector w/ Element", "a.blog", ["mark","simon"] );
	t( "Parent Class Selector", "p .blog", ["mark","simon"] );

	t( "Class selector using UTF8", ".台北Táiběi", ["utf8class1"] );
	t( "Class selector using UTF8", ".台北", ["utf8class1","utf8class2"] );
	t( "Class selector using UTF8", ".台北Táiběi.台北", ["utf8class1"] );
	t( "Class selector using UTF8", ".台北Táiběi, .台北", ["utf8class1","utf8class2"] );
	t( "Descendant class selector using UTF8", "div .台北Táiběi", ["utf8class1"] );
	t( "Child class selector using UTF8", "form > .台北Táiběi", ["utf8class1"] );

	t( "Escaped Class", ".foo\\:bar", ["foo:bar"] );
	t( "Escaped Class", ".test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );
	t( "Descendant scaped Class", "div .foo\\:bar", ["foo:bar"] );
	t( "Descendant scaped Class", "div .test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );
	t( "Child escaped Class", "form > .foo\\:bar", ["foo:bar"] );
	t( "Child escaped Class", "form > .test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );
});

test("multiple", function() {
	expect(4);
	t( "Comma Support", "a.blog, div", ["mark","simon","main","foo"] );
	t( "Comma Support", "a.blog , div", ["mark","simon","main","foo"] );
	t( "Comma Support", "a.blog ,div", ["mark","simon","main","foo"] );
	t( "Comma Support", "a.blog,div", ["mark","simon","main","foo"] );
});

test("child and adjacent", function() {
	expect(18);
	t( "Child", "p > a", ["simon1","google","groups","mark","yahoo","simon"] );
	t( "Child", "p> a", ["simon1","google","groups","mark","yahoo","simon"] );
	t( "Child", "p >a", ["simon1","google","groups","mark","yahoo","simon"] );
	t( "Child", "p>a", ["simon1","google","groups","mark","yahoo","simon"] );
	t( "Child w/ Class", "p > a.blog", ["mark","simon"] );
	t( "All Children", "code > *", ["anchor1","anchor2"] );
	t( "All Grandchildren", "p > * > *", ["anchor1","anchor2"] );
	t( "Adjacent", "a + a", ["groups"] );
	t( "Adjacent", "a +a", ["groups"] );
	t( "Adjacent", "a+ a", ["groups"] );
	t( "Adjacent", "a+a", ["groups"] );
	t( "Adjacent", "p + p", ["ap","en","sap"] );
	t( "Comma, Child, and Adjacent", "a + a, code > a", ["groups","anchor1","anchor2"] );

	t( "First Child", "p:first-child", ["firstp","sndp"] );
	t( "Nth Child", "p:nth-child(1)", ["firstp","sndp"] );

	t( "Last Child", "p:last-child", ["sap"] );

	t( "Nth-child", "#main form > *:nth-child(2)", ["text2"] );
	t( "Nth-child", "#main form > :nth-child(2)", ["text2"] );
});

test("attributes", function() {
	expect(20);
	t( "Attribute Exists", "a[@title]", ["google"] );
	t( "Attribute Exists", "*[@title]", ["google"] );
	t( "Attribute Exists", "[@title]", ["google"] );

	t( "Attribute Equals", "a[@rel='bookmark']", ["simon1"] );
	t( "Attribute Equals", 'a[@rel="bookmark"]', ["simon1"] );
	t( "Attribute Equals", "a[@rel=bookmark]", ["simon1"] );
	t( "Multiple Attribute Equals", "input[@type='hidden'],input[@type='radio']", ["hidden1","radio1","radio2"] );
	t( "Multiple Attribute Equals", "input[@type=\"hidden\"],input[@type='radio']", ["hidden1","radio1","radio2"] );
	t( "Multiple Attribute Equals", "input[@type=hidden],input[@type=radio]", ["hidden1","radio1","radio2"] );

	t( "Attribute selector using UTF8", "span[@lang=中文]", ["台北"] );

	t( "Attribute Begins With", "a[@href ^= 'http://www']", ["google","yahoo"] );
	t( "Attribute Ends With", "a[@href $= 'org/']", ["mark"] );
	t( "Attribute Contains", "a[@href *= 'google']", ["google","groups"] );

	t("Select options via [@selected]", "#select1 option[@selected]", ["option1a"] );
	t("Select options via [@selected]", "#select2 option[@selected]", ["option2d"] );
	t("Select options via [@selected]", "#select3 option[@selected]", ["option3b", "option3c"] );

	t( "Grouped Form Elements", "input[@name='foo[bar]']", ["hidden2"] );

	t( ":not() Existing attribute", "select:not([@multiple])", ["select1", "select2"]);
	t( ":not() Equals attribute", "select:not([@name=select1])", ["select2", "select3"]);
	t( ":not() Equals quoted attribute", "select:not([@name='select1'])", ["select2", "select3"]);
});

test("pseudo (:) selectors", function() {
	expect(30);
	t( "First Child", "p:first-child", ["firstp","sndp"] );
	t( "Last Child", "p:last-child", ["sap"] );
	t( "Only Child", "a:only-child", ["simon1","anchor1","yahoo","anchor2"] );
	t( "Empty", "ul:empty", ["firstUL"] );
	t( "Enabled UI Element", "input:enabled", ["text1","radio1","radio2","check1","check2","hidden1","hidden2","name","length"] );
	t( "Disabled UI Element", "input:disabled", ["text2"] );
	t( "Checked UI Element", "input:checked", ["radio2","check1"] );
	t( "Selected Option Element", "option:selected", ["option1a","option2d","option3b","option3c"] );
	t( "Text Contains", "a:contains('Google')", ["google","groups"] );
	t( "Text Contains", "a:contains('Google Groups')", ["groups"] );
	t( "Element Preceded By", "p ~ div", ["foo"] );
	t( "Not", "a.blog:not(.link)", ["mark"] );

	t( "nth Element", "p:nth(1)", ["ap"] );
	t( "First Element", "p:first", ["firstp"] );
	t( "Last Element", "p:last", ["first"] );
	t( "Even Elements", "p:even", ["firstp","sndp","sap"] );
	t( "Odd Elements", "p:odd", ["ap","en","first"] );
	t( "Position Equals", "p:eq(1)", ["ap"] );
	t( "Position Greater Than", "p:gt(0)", ["ap","sndp","en","sap","first"] );
	t( "Position Less Than", "p:lt(3)", ["firstp","ap","sndp"] );
	t( "Is A Parent", "p:parent", ["firstp","ap","sndp","en","sap","first"] );
	t( "Is Visible", "input:visible", ["text1","text2","radio1","radio2","check1","check2","name","length"] );
	t( "Is Hidden", "input:hidden", ["hidden1","hidden2"] );

	t( "Form element :input", ":input", ["text1", "text2", "radio1", "radio2", "check1", "check2", "hidden1", "hidden2", "name", "button", "area1", "select1", "select2", "select3", "length"] );
	t( "Form element :radio", ":radio", ["radio1", "radio2"] );
	t( "Form element :checkbox", ":checkbox", ["check1", "check2"] );
	t( "Form element :text", ":text", ["text1", "text2", "hidden2", "name", "length"] );
	t( "Form element :radio:checked", ":radio:checked", ["radio2"] );
	t( "Form element :checkbox:checked", ":checkbox:checked", ["check1"] );
	t( "Form element :checkbox:checked, :radio:checked", ":checkbox:checked, :radio:checked", ["check1", "radio2"] );
});

test("basic xpath", function() {
	expect(17);
	ok( jQuery.find("//*").length >= 30, "All Elements (//*)" );
	t( "All Div Elements", "//div", ["main","foo"] );
	t( "Absolute Path", "/html/body", ["body"] );
	t( "Absolute Path w/ *", "/* /body", ["body"] );
	t( "Long Absolute Path", "/html/body/dl/div/div/p", ["sndp","en","sap"] );
	t( "Absolute and Relative Paths", "/html//div", ["main","foo"] );
	t( "All Children, Explicit", "//code/*", ["anchor1","anchor2"] );
	t( "All Children, Implicit", "//code/", ["anchor1","anchor2"] );
	t( "Attribute Exists", "//a[@title]", ["google"] );
	t( "Attribute Equals", "//a[@rel='bookmark']", ["simon1"] );
	t( "Attribute RegExp", "//a[@rel=~/BooKmaRk/i]", ["simon1"] );
	t( "Attribute Inverse RegExp", "//a[@id!~/mon/]", ["google","groups","anchor1","mark","yahoo","anchor2"] );
	t( "Parent Axis", "//p/..", ["main","foo"] );
	t( "Sibling Axis", "//p/../", ["firstp","ap","foo","first","firstUL","empty","form","floatTest","iframe","lengthtest","sndp","en","sap"] );
	t( "Sibling Axis", "//p/../*", ["firstp","ap","foo","first","firstUL","empty","form","floatTest","iframe","lengthtest","sndp","en","sap"] );
	t( "Has Children", "//p[a]", ["firstp","ap","en","sap"] );

	$("#foo").each(function() {
		isSet( $("/p", this).get(), q("sndp", "en", "sap"), "Check XPath context" );
	});
});
<commit_msg>TDD. Broken test case, need to fix xpath parser...<commit_after>module("selector");

test("element", function() {
	expect(9);
	ok( $("*").size() >= 30, "Select all" );
	t( "Element Selector", "div", ["main","foo"] );
	t( "Element Selector", "body", ["body"] );
	t( "Element Selector", "html", ["html"] );
	t( "Parent Element", "div div", ["foo"] );
	ok( $("param", "#object1").length == 2, "Object/param as context" );

	ok( $("#length").length, '<input name="length"> cannot be found under IE, see #945' );
	ok( $("#lengthtest input").length, '<input name="length"> cannot be found under IE, see #945' );

	t( "Element Selector with underscore", "foo_bar", ["foobar"] );
});

test("broken", function() {
	expect(7);
	t( "Broken Selector", "[", [] );
	t( "Broken Selector", "(", [] );
	t( "Broken Selector", "{", [] );
	t( "Broken Selector", "<", [] );
	t( "Broken Selector", "()", [] );
	t( "Broken Selector", "<>", [] );
	t( "Broken Selector", "{}", [] );
});

test("id", function() {
	expect(23);
	t( "ID Selector", "#body", ["body"] );
	t( "ID Selector w/ Element", "body#body", ["body"] );
	t( "ID Selector w/ Element", "ul#first", [] );
	t( "ID selector with existing ID descendant", "#firstp #simon1", ["simon1"] );
	t( "ID selector with non-existant descendant", "#firstp #foobar", [] );
	t( "ID selector using UTF8", "#台北Táiběi", ["台北Táiběi"] );
	t( "Multiple ID selectors using UTF8", "#台北Táiběi, #台北", ["台北Táiběi","台北"] );
	t( "Descendant ID selector using UTF8", "div #台北", ["台北"] );
	t( "Child ID selector using UTF8", "form > #台北", ["台北"] );

	t( "Escaped ID", "#foo\\:bar", ["foo:bar"] );
	t( "Escaped ID", "#test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );
	t( "Descendant escaped ID", "div #foo\\:bar", ["foo:bar"] );
	t( "Descendant escaped ID", "div #test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );
	t( "Child escaped ID", "form > #foo\\:bar", ["foo:bar"] );
	t( "Child escaped ID", "form > #test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );

	t( "ID Selector, child ID present", "#form > #radio1", ["radio1"] );  // bug #267
	t( "ID Selector, not an ancestor ID", "#form  #first", [] );
	t( "ID Selector, not a child ID", "#form > #option1a", [] );

	t( "All Children of ID", "#foo/*", ["sndp", "en", "sap"] );
	t( "All Children of ID with no children", "#firstUL/*", [] );

	$('tName1 AtName2 A
tName1 Div
').appendTo('#main');
	ok( $("#tName1")[0].id == 'tName1', "ID selector with same value for a name attribute" );
	ok( $("#tName2").length == 0, "ID selector non-existing but name attribute on an A tag" );

	t( "ID selector with non-existant ancestor", "#asdfasdf #foobar", [] ); // bug #986
});

test("class", function() {
	expect(16);
	t( "Class Selector", ".blog", ["mark","simon"] );
	t( "Class Selector", ".blog.link", ["simon"] );
	t( "Class Selector w/ Element", "a.blog", ["mark","simon"] );
	t( "Parent Class Selector", "p .blog", ["mark","simon"] );

	t( "Class selector using UTF8", ".台北Táiběi", ["utf8class1"] );
	t( "Class selector using UTF8", ".台北", ["utf8class1","utf8class2"] );
	t( "Class selector using UTF8", ".台北Táiběi.台北", ["utf8class1"] );
	t( "Class selector using UTF8", ".台北Táiběi, .台北", ["utf8class1","utf8class2"] );
	t( "Descendant class selector using UTF8", "div .台北Táiběi", ["utf8class1"] );
	t( "Child class selector using UTF8", "form > .台北Táiběi", ["utf8class1"] );

	t( "Escaped Class", ".foo\\:bar", ["foo:bar"] );
	t( "Escaped Class", ".test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );
	t( "Descendant scaped Class", "div .foo\\:bar", ["foo:bar"] );
	t( "Descendant scaped Class", "div .test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );
	t( "Child escaped Class", "form > .foo\\:bar", ["foo:bar"] );
	t( "Child escaped Class", "form > .test\\.foo\\[5\\]bar", ["test.foo[5]bar"] );
});

test("multiple", function() {
	expect(4);
	t( "Comma Support", "a.blog, div", ["mark","simon","main","foo"] );
	t( "Comma Support", "a.blog , div", ["mark","simon","main","foo"] );
	t( "Comma Support", "a.blog ,div", ["mark","simon","main","foo"] );
	t( "Comma Support", "a.blog,div", ["mark","simon","main","foo"] );
});

test("child and adjacent", function() {
	expect(18);
	t( "Child", "p > a", ["simon1","google","groups","mark","yahoo","simon"] );
	t( "Child", "p> a", ["simon1","google","groups","mark","yahoo","simon"] );
	t( "Child", "p >a", ["simon1","google","groups","mark","yahoo","simon"] );
	t( "Child", "p>a", ["simon1","google","groups","mark","yahoo","simon"] );
	t( "Child w/ Class", "p > a.blog", ["mark","simon"] );
	t( "All Children", "code > *", ["anchor1","anchor2"] );
	t( "All Grandchildren", "p > * > *", ["anchor1","anchor2"] );
	t( "Adjacent", "a + a", ["groups"] );
	t( "Adjacent", "a +a", ["groups"] );
	t( "Adjacent", "a+ a", ["groups"] );
	t( "Adjacent", "a+a", ["groups"] );
	t( "Adjacent", "p + p", ["ap","en","sap"] );
	t( "Comma, Child, and Adjacent", "a + a, code > a", ["groups","anchor1","anchor2"] );

	t( "First Child", "p:first-child", ["firstp","sndp"] );
	t( "Nth Child", "p:nth-child(1)", ["firstp","sndp"] );

	t( "Last Child", "p:last-child", ["sap"] );

	t( "Nth-child", "#main form > *:nth-child(2)", ["text2"] );
	t( "Nth-child", "#main form > :nth-child(2)", ["text2"] );
});

test("attributes", function() {
	expect(20);
	t( "Attribute Exists", "a[@title]", ["google"] );
	t( "Attribute Exists", "*[@title]", ["google"] );
	t( "Attribute Exists", "[@title]", ["google"] );

	t( "Attribute Equals", "a[@rel='bookmark']", ["simon1"] );
	t( "Attribute Equals", 'a[@rel="bookmark"]', ["simon1"] );
	t( "Attribute Equals", "a[@rel=bookmark]", ["simon1"] );
	t( "Multiple Attribute Equals", "input[@type='hidden'],input[@type='radio']", ["hidden1","radio1","radio2"] );
	t( "Multiple Attribute Equals", "input[@type=\"hidden\"],input[@type='radio']", ["hidden1","radio1","radio2"] );
	t( "Multiple Attribute Equals", "input[@type=hidden],input[@type=radio]", ["hidden1","radio1","radio2"] );

	t( "Attribute selector using UTF8", "span[@lang=中文]", ["台北"] );

	t( "Attribute Begins With", "a[@href ^= 'http://www']", ["google","yahoo"] );
	t( "Attribute Ends With", "a[@href $= 'org/']", ["mark"] );
	t( "Attribute Contains", "a[@href *= 'google']", ["google","groups"] );

	t("Select options via [@selected]", "#select1 option[@selected]", ["option1a"] );
	t("Select options via [@selected]", "#select2 option[@selected]", ["option2d"] );
	t("Select options via [@selected]", "#select3 option[@selected]", ["option3b", "option3c"] );

	t( "Grouped Form Elements", "input[@name='foo[bar]']", ["hidden2"] );

	t( ":not() Existing attribute", "select:not([@multiple])", ["select1", "select2"]);
	t( ":not() Equals attribute", "select:not([@name=select1])", ["select2", "select3"]);
	t( ":not() Equals quoted attribute", "select:not([@name='select1'])", ["select2", "select3"]);
});

test("pseudo (:) selectors", function() {
	expect(30);
	t( "First Child", "p:first-child", ["firstp","sndp"] );
	t( "Last Child", "p:last-child", ["sap"] );
	t( "Only Child", "a:only-child", ["simon1","anchor1","yahoo","anchor2"] );
	t( "Empty", "ul:empty", ["firstUL"] );
	t( "Enabled UI Element", "input:enabled", ["text1","radio1","radio2","check1","check2","hidden1","hidden2","name","length"] );
	t( "Disabled UI Element", "input:disabled", ["text2"] );
	t( "Checked UI Element", "input:checked", ["radio2","check1"] );
	t( "Selected Option Element", "option:selected", ["option1a","option2d","option3b","option3c"] );
	t( "Text Contains", "a:contains('Google')", ["google","groups"] );
	t( "Text Contains", "a:contains('Google Groups')", ["groups"] );
	t( "Element Preceded By", "p ~ div", ["foo"] );
	t( "Not", "a.blog:not(.link)", ["mark"] );

	t( "nth Element", "p:nth(1)", ["ap"] );
	t( "First Element", "p:first", ["firstp"] );
	t( "Last Element", "p:last", ["first"] );
	t( "Even Elements", "p:even", ["firstp","sndp","sap"] );
	t( "Odd Elements", "p:odd", ["ap","en","first"] );
	t( "Position Equals", "p:eq(1)", ["ap"] );
	t( "Position Greater Than", "p:gt(0)", ["ap","sndp","en","sap","first"] );
	t( "Position Less Than", "p:lt(3)", ["firstp","ap","sndp"] );
	t( "Is A Parent", "p:parent", ["firstp","ap","sndp","en","sap","first"] );
	t( "Is Visible", "input:visible", ["text1","text2","radio1","radio2","check1","check2","name","length"] );
	t( "Is Hidden", "input:hidden", ["hidden1","hidden2"] );

	t( "Form element :input", ":input", ["text1", "text2", "radio1", "radio2", "check1", "check2", "hidden1", "hidden2", "name", "button", "area1", "select1", "select2", "select3", "length"] );
	t( "Form element :radio", ":radio", ["radio1", "radio2"] );
	t( "Form element :checkbox", ":checkbox", ["check1", "check2"] );
	t( "Form element :text", ":text", ["text1", "text2", "hidden2", "name", "length"] );
	t( "Form element :radio:checked", ":radio:checked", ["radio2"] );
	t( "Form element :checkbox:checked", ":checkbox:checked", ["check1"] );
	t( "Form element :checkbox:checked, :radio:checked", ":checkbox:checked, :radio:checked", ["check1", "radio2"] );
});

test("basic xpath", function() {
	expect(18);
	ok( jQuery.find("//*").length >= 30, "All Elements (//*)" );
	t( "All Div Elements", "//div", ["main","foo"] );
	t( "Absolute Path", "/html/body", ["body"] );
	t( "Absolute Path w/ *", "/* /body", ["body"] );
	t( "Long Absolute Path", "/html/body/dl/div/div/p", ["sndp","en","sap"] );
	t( "Absolute and Relative Paths", "/html//div", ["main","foo"] );
	t( "All Children, Explicit", "//code/*", ["anchor1","anchor2"] );
	t( "All Children, Implicit", "//code/", ["anchor1","anchor2"] );
	t( "Attribute Exists", "//a[@title]", ["google"] );
	t( "Attribute Equals", "//a[@rel='bookmark']", ["simon1"] );
	t( "Attribute RegExp", "//a[@rel=~/BooKmaRk/i]", ["simon1"] );
	t( "Attribute RegExp w/enclosed braces", "//a[@rel=~/B[okm]+aRk/i]", ["simon1"] );
	t( "Attribute Inverse RegExp", "//a[@id!~/mon/]", ["google","groups","anchor1","mark","yahoo","anchor2"] );
	t( "Parent Axis", "//p/..", ["main","foo"] );
	t( "Sibling Axis", "//p/../", ["firstp","ap","foo","first","firstUL","empty","form","floatTest","iframe","lengthtest","sndp","en","sap"] );
	t( "Sibling Axis", "//p/../*", ["firstp","ap","foo","first","firstUL","empty","form","floatTest","iframe","lengthtest","sndp","en","sap"] );
	t( "Has Children", "//p[a]", ["firstp","ap","en","sap"] );

	$("#foo").each(function() {
		isSet( $("/p", this).get(), q("sndp", "en", "sap"), "Check XPath context" );
	});
});
<|endoftext|>


<commit_before>import React from 'react';
import {connect} from 'react-redux';
import get from 'lodash/get';
import setStateByPath from './setStateByPath';
import replaceStateByPath from './replaceStateByPath';

/**
 * Connect provided component to `path` part of the redux state
 * @param path
 * @returns {Function}
 */
export default function connectSlicedState(path) {
  return function (WrappedComponent) {
    return connect(
      state => state,
      dispatch => ({dispatch}),
      (state, {dispatch}, props) => {
        const slicedState = get(state, path);
        return {
          ...props,
          state: slicedState,
          setState: newState => dispatch(setStateByPath(path, newState)),
          replaceState: newState => dispatch(replaceStateByPath(path, newState)),
        };
      }
    )(WrappedComponent);
  };
}
<commit_msg>rename setState, replaceState methods (cherry picked from commit 30836f7)<commit_after>import React from 'react';
import {connect} from 'react-redux';
import get from 'lodash/get';
import setStateByPath from './setStateByPath';
import replaceStateByPath from './replaceStateByPath';

/**
 * Connect provided component to `path` part of the redux state
 * @param path
 * @returns {Function}
 */
export default function connectSlicedState(path, setStateName = 'setState', replaceStateName = 'replaceState') {
  return function (WrappedComponent) {
    return connect(
      state => state,
      dispatch => ({dispatch}),
      (state, {dispatch}, props) => {
        const slicedState = get(state, path);
        return {
          ...props,
          state: slicedState,
          [setStateName]: newState => dispatch(setStateByPath(path, newState)),
          [replaceStateName]: newState => dispatch(replaceStateByPath(path, newState)),
        };
      }
    )(WrappedComponent);
  };
}
<|endoftext|>