<commit_before>import PropTypes from 'prop-types';
import React from 'react';
import {
  View,
  StyleSheet,
  TouchableHighlight,
  TouchableOpacity,
  Platform,
  Switch,
  Image,
  TextInput,
} from 'react-native';
import Avatar from '../avatar/Avatar';
import Badge from '../badge/badge';
import Icon from '../icons/Icon';
import Text from '../text/Text';
import colors from '../config/colors';
import fonts from '../config/fonts';
import normalize from '../helpers/normalizeText';
import ViewPropTypes from '../config/ViewPropTypes';

const ListItem = props => {
  const {
    onPress,
    title,
    leftIcon,
    rightIcon,
    leftIconOnPress,
    leftIconOnLongPress,
    leftIconUnderlayColor,
    leftIconContainerStyle,
    avatarStyle,
    avatarContainerStyle,
    avatarOverlayContainerStyle,
    underlayColor,
    subtitle,
    subtitleStyle,
    containerStyle,
    wrapperStyle,
    titleNumberOfLines,
    titleStyle,
    titleContainerStyle,
    hideChevron,
    chevronColor,
    roundAvatar,
    component,
    fontFamily,
    rightTitle,
    rightTitleContainerStyle,
    rightTitleStyle,
    rightTitleNumberOfLines,
    subtitleContainerStyle,
    subtitleNumberOfLines,
    badge,
    label,
    onLongPress,
    switchButton,
    onSwitch,
    switchDisabled,
    switchOnTintColor,
    switchThumbTintColor,
    switchTintColor,
    switched,
    textInput,
    textInputAutoCapitalize,
    textInputAutoCorrect,
    textInputAutoFocus,
    textInputEditable,
    textInputKeyboardType,
    textInputMaxLength,
    textInputMultiline,
    textInputOnChangeText,
    textInputOnFocus,
    textInputOnBlur,
    textInputSelectTextOnFocus,
    textInputReturnKeyType,
    textInputValue,
    textInputSecure,
    textInputStyle,
    textInputContainerStyle,
    textInputPlaceholder,
    onPressRightIcon,
    disabled,
    disabledStyle,
    ...attributes
  } = props;

  let { avatar } = props;

  let Component = onPress || onLongPress ? TouchableHighlight : View;
  let LeftIconWrapper =
    leftIconOnPress || leftIconOnLongPress ? TouchableHighlight : View;
  if (component) {
    Component = component;
  }
  if (typeof avatar === 'string') {
    avatar = { uri: avatar };
  }
  return (
    <Component
      {...attributes}
      onLongPress={onLongPress}
      onPress={onPress}
      disabled={disabled}
      underlayColor={underlayColor}
      style={[
        styles.container,
        containerStyle && containerStyle,
        disabled && styles.disabled,
        disabled && disabledStyle && disabledStyle,
      ]}
    >
      <View style={[styles.wrapper, wrapperStyle && wrapperStyle]}>
        {React.isValidElement(leftIcon)
          ? leftIcon
          : leftIcon &&
            leftIcon.name && (
              <LeftIconWrapper
                onLongPress={leftIconOnLongPress}
                onPress={leftIconOnPress}
                disabled={disabled}
                underlayColor={leftIconUnderlayColor}
                style={[
                  styles.iconStyle,
                  leftIconContainerStyle && leftIconContainerStyle,
                ]}
              >
                <View>
                  <Icon
                    type={leftIcon.type}
                    iconStyle={[styles.icon, leftIcon.style && leftIcon.style]}
                    name={leftIcon.name}
                    color={leftIcon.color || colors.grey4}
                    size={leftIcon.size || 24}
                  />
                </View>
              </LeftIconWrapper>
            )}
        {avatar && React.isValidElement(avatar)
          ? avatar
          : avatar &&
            !React.isValidElement(avatar) && (
              <Avatar
                avatarStyle={avatarStyle && avatarStyle}
                containerStyle={avatarContainerStyle && avatarContainerStyle}
                overlayContainerStyle={
                  avatarOverlayContainerStyle && avatarOverlayContainerStyle
                }
                rounded={roundAvatar}
                source={avatar}
              />
            )}
        <View style={styles.titleSubtitleContainer}>
          <View style={titleContainerStyle}>
            {title !== null &&
            (typeof title === 'string' || typeof title === 'number') ? (
              <Text
                numberOfLines={titleNumberOfLines}
                style={[
                  styles.title,
                  !leftIcon && { marginLeft: 10 },
                  titleStyle && titleStyle,
                  fontFamily && { fontFamily },
                ]}
              >
                {title}
              </Text>
            ) : (
              <View>{title}</View>
            )}
          </View>
          <View style={subtitleContainerStyle}>
            {subtitle !== null &&
            (typeof subtitle === 'string' || typeof subtitle === 'number') ? (
              <Text
                numberOfLines={subtitleNumberOfLines}
                style={[
                  styles.subtitle,
                  !leftIcon && { marginLeft: 10 },
                  subtitleStyle && subtitleStyle,
                  fontFamily && { fontFamily },
                ]}
              >
                {subtitle}
              </Text>
            ) : (
              <View>{subtitle}</View>
            )}
          </View>
        </View>
        {!!rightTitle &&
          rightTitle !== '' &&
          !textInput && (
            <View
              style={[styles.rightTitleContainer, rightTitleContainerStyle]}
            >
              <Text
                numberOfLines={rightTitleNumberOfLines}
                style={[styles.rightTitleStyle, rightTitleStyle]}
              >
                {rightTitle}
              </Text>
            </View>
          )}
        {textInput && (
          <View
            style={[
              styles.rightTitleContainer,
              styles.textInputContainerStyle,
              textInputContainerStyle,
            ]}
          >
            <TextInput
              style={[styles.textInputStyle, textInputStyle]}
              underlineColorAndroid={'transparent'}
              defaultValue={rightTitle}
              value={textInputValue}
              placeholder={textInputPlaceholder}
              autoCapitalize={textInputAutoCapitalize}
              autoCorrect={textInputAutoCorrect}
              autoFocus={textInputAutoFocus}
              editable={disabled ? false : textInputEditable}
              keyboardType={textInputKeyboardType}
              maxLength={textInputMaxLength}
              multiline={textInputMultiline}
              onChangeText={textInputOnChangeText}
              onFocus={textInputOnFocus}
              onBlur={textInputOnBlur}
              secureTextEntry={textInputSecure}
              selectTextOnFocus={textInputSelectTextOnFocus}
              returnKeyType={textInputReturnKeyType}
            />
          </View>
        )}
        {badge && !rightTitle && <Badge {...badge} />}
        {!hideChevron &&
          (React.isValidElement(rightIcon) ? (
            rightIcon
          ) : (
            <TouchableOpacity
              onPress={onPressRightIcon}
              disabled={disabled ? disabled : !onPressRightIcon}
              style={styles.chevronContainer}
            >
              <Icon
                type={rightIcon.type}
                iconStyle={rightIcon.style}
                size={28}
                name={rightIcon.name || 'chevron-right'}
                color={rightIcon.color || chevronColor}
              />
            </TouchableOpacity>
          ))}
        {switchButton &&
          hideChevron && (
            <View style={styles.switchContainer}>
              <Switch
                onValueChange={onSwitch}
                disabled={disabled ? disabled : switchDisabled}
                onTintColor={switchOnTintColor}
                thumbTintColor={switchThumbTintColor}
                tintColor={switchTintColor}
                value={switched}
              />
            </View>
          )}
        {label && label}
      </View>
    </Component>
  );
};

ListItem.defaultProps = {
  underlayColor: 'white',
  leftIconUnderlayColor: 'white',
  chevronColor: colors.grey4,
  rightIcon: { name: 'chevron-right' },
  hideChevron: false,
  roundAvatar: false,
  switchButton: false,
  textInputEditable: true,
  titleNumberOfLines: 1,
  subtitleNumberOfLines: 1,
  rightTitleNumberOfLines: 1,
  disabled: false,
};

ListItem.propTypes = {
  title: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
    PropTypes.object,
  ]),
  avatar: PropTypes.any,
  icon: PropTypes.any,
  onPress: PropTypes.func,
  rightIcon: PropTypes.oneOfType([PropTypes.element, PropTypes.object]),
  underlayColor: PropTypes.string,
  subtitle: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
    PropTypes.object,
  ]),
  subtitleStyle: PropTypes.any,
  subtitleNumberOfLines: PropTypes.number,
  containerStyle: PropTypes.any,
  wrapperStyle: PropTypes.any,
  titleStyle: PropTypes.any,
  titleContainerStyle: PropTypes.any,
  titleNumberOfLines: PropTypes.number,
  hideChevron: PropTypes.bool,
  chevronColor: PropTypes.string,
  roundAvatar: PropTypes.bool,
  badge: PropTypes.any,
  switchButton: PropTypes.bool,
  onSwitch: PropTypes.func,
  switchDisabled: PropTypes.bool,
  switchOnTintColor: PropTypes.string,
  switchThumbTintColor: PropTypes.string,
  switchTintColor: PropTypes.string,
  switched: PropTypes.bool,
  textInput: PropTypes.bool,
  textInputAutoCapitalize: PropTypes.oneOf([
    'none',
    'sentences',
    'words',
    'characters',
  ]),
  textInputAutoCorrect: PropTypes.bool,
  textInputAutoFocus: PropTypes.bool,
  textInputEditable: PropTypes.bool,
  textInputKeyboardType: PropTypes.oneOf([
    'default',
    'email-address',
    'numeric',
    'phone-pad',
    'ascii-capable',
    'numbers-and-punctuation',
    'url',
    'number-pad',
    'name-phone-pad',
    'decimal-pad',
    'twitter',
    'web-search',
  ]),
  textInputMaxLength: PropTypes.number,
  textInputMultiline: PropTypes.bool,
  textInputOnChangeText: PropTypes.func,
  textInputOnFocus: PropTypes.func,
  textInputOnBlur: PropTypes.func,
  textInputSelectTextOnFocus: PropTypes.bool,
  textInputReturnKeyType: PropTypes.string,
  textInputValue: PropTypes.string,
  textInputSecure: PropTypes.bool,
  textInputStyle: PropTypes.any,
  textInputContainerStyle: PropTypes.any,
  textInputPlaceholder: PropTypes.string,
  component: PropTypes.any,
  fontFamily: PropTypes.string,
  rightTitle: PropTypes.string,
  rightTitleContainerStyle: ViewPropTypes.style,
  rightTitleStyle: Text.propTypes.style,
  rightTitleNumberOfLines: PropTypes.number,
  subtitleContainerStyle: ViewPropTypes.style,
  label: PropTypes.any,
  onLongPress: PropTypes.func,
  leftIcon: PropTypes.oneOfType([PropTypes.element, PropTypes.object]),
  leftIconOnPress: PropTypes.func,
  leftIconOnLongPress: PropTypes.func,
  leftIconUnderlayColor: PropTypes.string,
  leftIconContainerStyle: ViewPropTypes.style,
  avatarStyle: Image.propTypes.style,
  avatarContainerStyle: ViewPropTypes.style,
  avatarOverlayContainerStyle: ViewPropTypes.style,
  onPressRightIcon: PropTypes.func,
  disabled: PropTypes.bool,
  disabledStyle: ViewPropTypes.style,
};

const styles = StyleSheet.create({
  container: {
    paddingTop: 10,
    paddingRight: 10,
    paddingBottom: 10,
    borderBottomColor: colors.greyOutline,
    borderBottomWidth: 1,
    backgroundColor: 'transparent',
  },
  wrapper: {
    flexDirection: 'row',
    marginLeft: 10,
    alignItems: 'center',
  },
  iconStyle: {
    justifyContent: 'center',
    alignItems: 'center',
  },
  icon: {
    marginRight: 8,
  },
  title: {
    fontSize: normalize(14),
    color: colors.grey1,
  },
  subtitle: {
    color: colors.grey3,
    fontSize: normalize(12),
    marginTop: 1,
    ...Platform.select({
      ios: {
        fontWeight: '600',
      },
      android: {
        ...fonts.android.bold,
      },
    }),
  },
  titleSubtitleContainer: {
    justifyContent: 'center',
    flex: 1,
  },
  chevronContainer: {
    alignItems: 'flex-end',
    justifyContent: 'center',
  },
  switchContainer: {
    alignItems: 'flex-end',
    justifyContent: 'center',
    marginRight: 5,
  },
  rightTitleContainer: {
    flex: 1,
    alignItems: 'flex-end',
    justifyContent: 'center',
  },
  rightTitleStyle: {
    marginRight: 5,
    color: colors.grey4,
  },
  textInputContainerStyle: {
    alignItems: null,
  },
  textInputStyle: {
    height: 20,
    flex: 1,
    textAlign: 'right',
  },
  disabled: {
    opacity: 0.5,
  },
});

export default ListItem;
<commit_msg>added listItem right icon size so that it takes rightIcon size, or 28 (#852)<commit_after>import PropTypes from 'prop-types';
import React from 'react';
import {
  View,
  StyleSheet,
  TouchableHighlight,
  TouchableOpacity,
  Platform,
  Switch,
  Image,
  TextInput,
} from 'react-native';
import Avatar from '../avatar/Avatar';
import Badge from '../badge/badge';
import Icon from '../icons/Icon';
import Text from '../text/Text';
import colors from '../config/colors';
import fonts from '../config/fonts';
import normalize from '../helpers/normalizeText';
import ViewPropTypes from '../config/ViewPropTypes';

const ListItem = props => {
  const {
    onPress,
    title,
    leftIcon,
    rightIcon,
    leftIconOnPress,
    leftIconOnLongPress,
    leftIconUnderlayColor,
    leftIconContainerStyle,
    avatarStyle,
    avatarContainerStyle,
    avatarOverlayContainerStyle,
    underlayColor,
    subtitle,
    subtitleStyle,
    containerStyle,
    wrapperStyle,
    titleNumberOfLines,
    titleStyle,
    titleContainerStyle,
    hideChevron,
    chevronColor,
    roundAvatar,
    component,
    fontFamily,
    rightTitle,
    rightTitleContainerStyle,
    rightTitleStyle,
    rightTitleNumberOfLines,
    subtitleContainerStyle,
    subtitleNumberOfLines,
    badge,
    label,
    onLongPress,
    switchButton,
    onSwitch,
    switchDisabled,
    switchOnTintColor,
    switchThumbTintColor,
    switchTintColor,
    switched,
    textInput,
    textInputAutoCapitalize,
    textInputAutoCorrect,
    textInputAutoFocus,
    textInputEditable,
    textInputKeyboardType,
    textInputMaxLength,
    textInputMultiline,
    textInputOnChangeText,
    textInputOnFocus,
    textInputOnBlur,
    textInputSelectTextOnFocus,
    textInputReturnKeyType,
    textInputValue,
    textInputSecure,
    textInputStyle,
    textInputContainerStyle,
    textInputPlaceholder,
    onPressRightIcon,
    disabled,
    disabledStyle,
    ...attributes
  } = props;

  let { avatar } = props;

  let Component = onPress || onLongPress ? TouchableHighlight : View;
  let LeftIconWrapper =
    leftIconOnPress || leftIconOnLongPress ? TouchableHighlight : View;
  if (component) {
    Component = component;
  }
  if (typeof avatar === 'string') {
    avatar = { uri: avatar };
  }
  return (
    <Component
      {...attributes}
      onLongPress={onLongPress}
      onPress={onPress}
      disabled={disabled}
      underlayColor={underlayColor}
      style={[
        styles.container,
        containerStyle && containerStyle,
        disabled && styles.disabled,
        disabled && disabledStyle && disabledStyle,
      ]}
    >
      <View style={[styles.wrapper, wrapperStyle && wrapperStyle]}>
        {React.isValidElement(leftIcon)
          ? leftIcon
          : leftIcon &&
            leftIcon.name && (
              <LeftIconWrapper
                onLongPress={leftIconOnLongPress}
                onPress={leftIconOnPress}
                disabled={disabled}
                underlayColor={leftIconUnderlayColor}
                style={[
                  styles.iconStyle,
                  leftIconContainerStyle && leftIconContainerStyle,
                ]}
              >
                <View>
                  <Icon
                    type={leftIcon.type}
                    iconStyle={[styles.icon, leftIcon.style && leftIcon.style]}
                    name={leftIcon.name}
                    color={leftIcon.color || colors.grey4}
                    size={leftIcon.size || 24}
                  />
                </View>
              </LeftIconWrapper>
            )}
        {avatar && React.isValidElement(avatar)
          ? avatar
          : avatar &&
            !React.isValidElement(avatar) && (
              <Avatar
                avatarStyle={avatarStyle && avatarStyle}
                containerStyle={avatarContainerStyle && avatarContainerStyle}
                overlayContainerStyle={
                  avatarOverlayContainerStyle && avatarOverlayContainerStyle
                }
                rounded={roundAvatar}
                source={avatar}
              />
            )}
        <View style={styles.titleSubtitleContainer}>
          <View style={titleContainerStyle}>
            {title !== null &&
            (typeof title === 'string' || typeof title === 'number') ? (
              <Text
                numberOfLines={titleNumberOfLines}
                style={[
                  styles.title,
                  !leftIcon && { marginLeft: 10 },
                  titleStyle && titleStyle,
                  fontFamily && { fontFamily },
                ]}
              >
                {title}
              </Text>
            ) : (
              <View>{title}</View>
            )}
          </View>
          <View style={subtitleContainerStyle}>
            {subtitle !== null &&
            (typeof subtitle === 'string' || typeof subtitle === 'number') ? (
              <Text
                numberOfLines={subtitleNumberOfLines}
                style={[
                  styles.subtitle,
                  !leftIcon && { marginLeft: 10 },
                  subtitleStyle && subtitleStyle,
                  fontFamily && { fontFamily },
                ]}
              >
                {subtitle}
              </Text>
            ) : (
              <View>{subtitle}</View>
            )}
          </View>
        </View>
        {!!rightTitle &&
          rightTitle !== '' &&
          !textInput && (
            <View
              style={[styles.rightTitleContainer, rightTitleContainerStyle]}
            >
              <Text
                numberOfLines={rightTitleNumberOfLines}
                style={[styles.rightTitleStyle, rightTitleStyle]}
              >
                {rightTitle}
              </Text>
            </View>
          )}
        {textInput && (
          <View
            style={[
              styles.rightTitleContainer,
              styles.textInputContainerStyle,
              textInputContainerStyle,
            ]}
          >
            <TextInput
              style={[styles.textInputStyle, textInputStyle]}
              underlineColorAndroid={'transparent'}
              defaultValue={rightTitle}
              value={textInputValue}
              placeholder={textInputPlaceholder}
              autoCapitalize={textInputAutoCapitalize}
              autoCorrect={textInputAutoCorrect}
              autoFocus={textInputAutoFocus}
              editable={disabled ? false : textInputEditable}
              keyboardType={textInputKeyboardType}
              maxLength={textInputMaxLength}
              multiline={textInputMultiline}
              onChangeText={textInputOnChangeText}
              onFocus={textInputOnFocus}
              onBlur={textInputOnBlur}
              secureTextEntry={textInputSecure}
              selectTextOnFocus={textInputSelectTextOnFocus}
              returnKeyType={textInputReturnKeyType}
            />
          </View>
        )}
        {badge && !rightTitle && <Badge {...badge} />}
        {!hideChevron &&
          (React.isValidElement(rightIcon) ? (
            rightIcon
          ) : (
            <TouchableOpacity
              onPress={onPressRightIcon}
              disabled={disabled ? disabled : !onPressRightIcon}
              style={styles.chevronContainer}
            >
              <Icon
                type={rightIcon.type}
                iconStyle={rightIcon.style}
                size={rightIcon.size || 28}
                name={rightIcon.name || 'chevron-right'}
                color={rightIcon.color || chevronColor}
              />
            </TouchableOpacity>
          ))}
        {switchButton &&
          hideChevron && (
            <View style={styles.switchContainer}>
              <Switch
                onValueChange={onSwitch}
                disabled={disabled ? disabled : switchDisabled}
                onTintColor={switchOnTintColor}
                thumbTintColor={switchThumbTintColor}
                tintColor={switchTintColor}
                value={switched}
              />
            </View>
          )}
        {label && label}
      </View>
    </Component>
  );
};

ListItem.defaultProps = {
  underlayColor: 'white',
  leftIconUnderlayColor: 'white',
  chevronColor: colors.grey4,
  rightIcon: { name: 'chevron-right' },
  hideChevron: false,
  roundAvatar: false,
  switchButton: false,
  textInputEditable: true,
  titleNumberOfLines: 1,
  subtitleNumberOfLines: 1,
  rightTitleNumberOfLines: 1,
  disabled: false,
};

ListItem.propTypes = {
  title: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
    PropTypes.object,
  ]),
  avatar: PropTypes.any,
  icon: PropTypes.any,
  onPress: PropTypes.func,
  rightIcon: PropTypes.oneOfType([PropTypes.element, PropTypes.object]),
  underlayColor: PropTypes.string,
  subtitle: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
    PropTypes.object,
  ]),
  subtitleStyle: PropTypes.any,
  subtitleNumberOfLines: PropTypes.number,
  containerStyle: PropTypes.any,
  wrapperStyle: PropTypes.any,
  titleStyle: PropTypes.any,
  titleContainerStyle: PropTypes.any,
  titleNumberOfLines: PropTypes.number,
  hideChevron: PropTypes.bool,
  chevronColor: PropTypes.string,
  roundAvatar: PropTypes.bool,
  badge: PropTypes.any,
  switchButton: PropTypes.bool,
  onSwitch: PropTypes.func,
  switchDisabled: PropTypes.bool,
  switchOnTintColor: PropTypes.string,
  switchThumbTintColor: PropTypes.string,
  switchTintColor: PropTypes.string,
  switched: PropTypes.bool,
  textInput: PropTypes.bool,
  textInputAutoCapitalize: PropTypes.oneOf([
    'none',
    'sentences',
    'words',
    'characters',
  ]),
  textInputAutoCorrect: PropTypes.bool,
  textInputAutoFocus: PropTypes.bool,
  textInputEditable: PropTypes.bool,
  textInputKeyboardType: PropTypes.oneOf([
    'default',
    'email-address',
    'numeric',
    'phone-pad',
    'ascii-capable',
    'numbers-and-punctuation',
    'url',
    'number-pad',
    'name-phone-pad',
    'decimal-pad',
    'twitter',
    'web-search',
  ]),
  textInputMaxLength: PropTypes.number,
  textInputMultiline: PropTypes.bool,
  textInputOnChangeText: PropTypes.func,
  textInputOnFocus: PropTypes.func,
  textInputOnBlur: PropTypes.func,
  textInputSelectTextOnFocus: PropTypes.bool,
  textInputReturnKeyType: PropTypes.string,
  textInputValue: PropTypes.string,
  textInputSecure: PropTypes.bool,
  textInputStyle: PropTypes.any,
  textInputContainerStyle: PropTypes.any,
  textInputPlaceholder: PropTypes.string,
  component: PropTypes.any,
  fontFamily: PropTypes.string,
  rightTitle: PropTypes.string,
  rightTitleContainerStyle: ViewPropTypes.style,
  rightTitleStyle: Text.propTypes.style,
  rightTitleNumberOfLines: PropTypes.number,
  subtitleContainerStyle: ViewPropTypes.style,
  label: PropTypes.any,
  onLongPress: PropTypes.func,
  leftIcon: PropTypes.oneOfType([PropTypes.element, PropTypes.object]),
  leftIconOnPress: PropTypes.func,
  leftIconOnLongPress: PropTypes.func,
  leftIconUnderlayColor: PropTypes.string,
  leftIconContainerStyle: ViewPropTypes.style,
  avatarStyle: Image.propTypes.style,
  avatarContainerStyle: ViewPropTypes.style,
  avatarOverlayContainerStyle: ViewPropTypes.style,
  onPressRightIcon: PropTypes.func,
  disabled: PropTypes.bool,
  disabledStyle: ViewPropTypes.style,
};

const styles = StyleSheet.create({
  container: {
    paddingTop: 10,
    paddingRight: 10,
    paddingBottom: 10,
    borderBottomColor: colors.greyOutline,
    borderBottomWidth: 1,
    backgroundColor: 'transparent',
  },
  wrapper: {
    flexDirection: 'row',
    marginLeft: 10,
    alignItems: 'center',
  },
  iconStyle: {
    justifyContent: 'center',
    alignItems: 'center',
  },
  icon: {
    marginRight: 8,
  },
  title: {
    fontSize: normalize(14),
    color: colors.grey1,
  },
  subtitle: {
    color: colors.grey3,
    fontSize: normalize(12),
    marginTop: 1,
    ...Platform.select({
      ios: {
        fontWeight: '600',
      },
      android: {
        ...fonts.android.bold,
      },
    }),
  },
  titleSubtitleContainer: {
    justifyContent: 'center',
    flex: 1,
  },
  chevronContainer: {
    alignItems: 'flex-end',
    justifyContent: 'center',
  },
  switchContainer: {
    alignItems: 'flex-end',
    justifyContent: 'center',
    marginRight: 5,
  },
  rightTitleContainer: {
    flex: 1,
    alignItems: 'flex-end',
    justifyContent: 'center',
  },
  rightTitleStyle: {
    marginRight: 5,
    color: colors.grey4,
  },
  textInputContainerStyle: {
    alignItems: null,
  },
  textInputStyle: {
    height: 20,
    flex: 1,
    textAlign: 'right',
  },
  disabled: {
    opacity: 0.5,
  },
});

export default ListItem;
<|endoftext|>


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

const Git = require('nodegit');
const helpers = require('./helpers');

const PANTHEON_KEY_PRIVATE = process.env.PANTHEON_KEY_PRIVATE;
const PANTHEON_REMOTE_NAME = 'pantheon';
const PANTHEON_REMOTE_BRANCH = 'master';
const PANTHEON_REMOTE = `${PANTHEON_REMOTE_NAME}/${PANTHEON_REMOTE_BRANCH}`

const GITLAB_KEY_PRIVATE = process.env.GITLAB_KEY_PRIVATE;
const GITLAB_REMOTE_NAME = 'gitlab';
const GITLAB_REMOTE_BRANCH = 'master';
const GITLAB_REMOTE = `${GITLAB_REMOTE_NAME}/${GITLAB_REMOTE_BRANCH}`

const PANTHEON_LOCAL = `pantheon-master-`+Date.now();
const LOCAL_BRANCH = 'master';
const SIGNATURE_NAME = 'Chisel Bot';
const SIGNATURE_EMAIL = 'jakub.bogucki+chisel-bot@xfive.co';
const MESSAGE_BUILD_PREFIX = '[chisel-build]';
const IS_SPECIFIC_COMMAND = Boolean(process.argv[2]);

let repository = null;

async function main() {
  const repo = await getRepository();
  await repo.checkoutBranch(LOCAL_BRANCH, {
    checkoutStrategy: Git.Checkout.STRATEGY.FORCE,
  });
  await fetchAll(repo);
  await repo.createBranch(PANTHEON_LOCAL, await repository.getBranchCommit(PANTHEON_REMOTE), true);

  try {
    if(IS_SPECIFIC_COMMAND) {
      const command = process.argv[2];
      if(command == 'standard') {
        await updateRemoteBasedOnLocal();
      } else if(command == 'pushback') {
        await updateLocalBasedOnRemote();
      } else {
        throw new Error(`Command ${command} not recognized`);
      }
    } else {
      if(process.env.CHISEL_PUSHBACK) {
        await updateLocalBasedOnRemote();
      }
      await updateRemoteBasedOnLocal();
    }
  } finally {
    await repo.checkoutBranch(LOCAL_BRANCH, {
      checkoutStrategy: Git.Checkout.STRATEGY.FORCE,
    });
    await Git.Reset.reset(repo, await repo.getHeadCommit(), Git.Reset.TYPE.HARD);
    await Git.Branch.delete(await repo.getBranch(PANTHEON_LOCAL));
  }
}

async function getRepository() {
  if(repository == null) {
    repository = await Git.Repository.open('.');
  }
  return repository;
}

async function removeBuildsFromPantheon(repo, commit, stopId) {
  let firstNonBuildCommit = null;
  while(commit) {
    const message = commit.message();
    if(!message.startsWith(MESSAGE_BUILD_PREFIX)) {
      console.log(`Pantheon first non build commit: ${commit.id()}`);
      firstNonBuildCommit = commit;
      break;
    }

    if(stopId.equal(commit.id())) {
      throw new Error('Reached stop commit');
    }

    const parents = await commit.getParents();
    if(parents.length > 1) {
      throw new Error('When removing build commits encountered commit with more than one parent');
    }
    commit = parents[0];
  }

  if(firstNonBuildCommit) {
    await repo.createBranch(PANTHEON_LOCAL, firstNonBuildCommit, true);
  }
}

async function pushToPantheon(repo) {
  const remote = await repo.getRemote(PANTHEON_REMOTE_NAME);
  return remote.push([
    `+refs/heads/${PANTHEON_LOCAL}:refs/heads/${PANTHEON_REMOTE_BRANCH}` // Plus at the beginning means force
  ], {
    callbacks: {
      credentials: (url, user) => helpers.getCredentials(url, user, PANTHEON_KEY_PRIVATE),
    }
  });
}

async function pushToGitLab(repo) {
  const remote = await repo.getRemote(GITLAB_REMOTE_NAME);
  return remote.push([
    `refs/heads/${LOCAL_BRANCH}:refs/heads/${GITLAB_REMOTE_BRANCH}`,
  ], {
    callbacks: {
      credentials: (url, user) => helpers.getCredentials(url, user, GITLAB_KEY_PRIVATE),
    }
  });
}

async function fetchAll(repo) {
  await repo.fetch(GITLAB_REMOTE_NAME, {
    callbacks: {
      credentials: (url, user) => helpers.getCredentials(url, user, GITLAB_KEY_PRIVATE),
    }
  });
  await repo.fetch(PANTHEON_REMOTE_NAME, {
    callbacks: {
      credentials: (url, user) => helpers.getCredentials(url, user, PANTHEON_KEY_PRIVATE),
    }
  });
}

async function updateRemoteBasedOnLocal() {
  const repo = await getRepository();

  const headCommit = await repo.getHeadCommit();
  let branchCommit = await repo.getBranchCommit(PANTHEON_LOCAL);

  console.log(`Our branch (${LOCAL_BRANCH}) is currenrly at commit: ${headCommit.id()}`);
  console.log(`Pantheon branch (${PANTHEON_REMOTE}) is currently at commit: ${branchCommit.id()}`);

  // Git.Merge.base throws when no base found
  const base = await Git.Merge.base(repo, headCommit.id(), branchCommit.id());

  console.log(`Our and Pantheon's branches join at commit ${base}`);

  await removeBuildsFromPantheon(repo, branchCommit, base);
  branchCommit = await repo.getBranchCommit(PANTHEON_LOCAL);
  if(!base.equal(branchCommit.id())) {
    throw new Error('Patheon cleaning was not successful');
  }

  // Reset pantheon to master (it is really fast forward merge :D)
  await repo.createBranch(PANTHEON_LOCAL, headCommit, true);
  await repo.checkoutBranch(PANTHEON_LOCAL);

  // TODO: do real build
  require('fs').writeFileSync('./iambuild', Date.now().toString());

  const repoIndex = await repo.refreshIndex();
  await repoIndex.addAll(['iambuild'], Git.Index.ADD_OPTION.ADD_FORCE);
  await repoIndex.write();
  const treeOid = await repoIndex.writeTree();
  const author = Git.Signature.now(SIGNATURE_NAME, SIGNATURE_EMAIL);
  const newCommitId = await repo.createCommit(
    'HEAD',
    author,
    author,
    `${MESSAGE_BUILD_PREFIX} Builded!`,
    treeOid,
    [headCommit],
  );
  console.log(`Builded project commited in ${newCommitId}`)
  await pushToPantheon(repo);
}

async function findCommitsBetween(repo, start, end) {
  const endId = end.id();
  const commits = [];
  let check = start;
  while(check) {
    if(check.id().equal(endId)) {
      break;
    }
    const parentsIds = check.parents();
    const parents = [];
    for(const parentId of parentsIds) {
      parents.push(await Git.Commit.lookup(repo, parentId));
    }
    // console.log(check.sha() + ' -> ' + parents.map(p => p.sha()).join(' '));
    commits.push({
      commit: check,
      parents,
    });

    check = parents[0];
  }
  return commits;
}

async function updateLocalBasedOnRemote() {
  const repo = await getRepository();

  const headCommit = await repo.getHeadCommit();
  let branchCommit = await repo.getBranchCommit(PANTHEON_LOCAL);

  console.log(`Our branch (${LOCAL_BRANCH}) is currenrly at commit: ${headCommit.id()}`);
  console.log(`Pantheon branch (${PANTHEON_REMOTE}) is currently at commit: ${branchCommit.id()}`);

  // Git.Merge.base throws when no base found
  const base = await Git.Merge.base(repo, headCommit.id(), branchCommit.id());

  console.log(`Our and Pantheon's branches join at commit ${base}`);

  if(!base.equal(headCommit.id())) {
    throw new Error('Pantheons branch must be entirely on top of ours, it is not');
  }

  const commitsToAdd = await findCommitsBetween(repo, branchCommit, headCommit);
  commitsToAdd.reverse();

  for(const { commit, parents } of commitsToAdd) {
    if(parents.length == 1) {
      // Single commit - cherry pick
      const message = commit.message();
      if(message.startsWith(MESSAGE_BUILD_PREFIX)) {
        // Skip commit that is build
        continue;
      }
      // console.log('Picking: '+parents[0].sha());
      const head = await repo.getHeadCommit();
      await Git.Cherrypick.cherrypick(repo, commit, {});
      const index = await repo.refreshIndex();
      if(index.hasConflicts()) {
        throw new Error(`Conflicts when cherrypicking ${commit.id()}`);
      }
      const treeOid = await index.writeTreeTo(repo);
      await repo.createCommit(
        'HEAD',
        commit.author(),
        Git.Signature.now(SIGNATURE_NAME, SIGNATURE_EMAIL),
        commit.message()+'\n[ci skip]',
        treeOid,
        [head],
      );
    } else if(parents.length == 2) {
      // Merge commit
      const head = await repo.getHeadCommit();
      console.log(`merging ${parents[1].id()} with ${head.id()}`);
      const index = await Git.Merge.commits(repo, head, parents[1]);
      if(index.hasConflicts()) {
        throw new Error(`Conflicts when merging ${parents[1].id()} with ${head.id()}`);
      }
      const treeOid = await index.writeTreeTo(repo);
      await repo.createCommit(
        'HEAD',
        commit.author(),
        Git.Signature.now(SIGNATURE_NAME, SIGNATURE_EMAIL),
        commit.message()+'\n[ci skip]',
        treeOid,
        [head, parents[1]],
      );
      await Git.Reset.reset(repo, await repo.getHeadCommit(), Git.Reset.TYPE.HARD);
    } else {
      throw new Error('Merge commits of more than two things are not supported');
    }
  }
  await repo.createBranch(PANTHEON_LOCAL, await repo.getHeadCommit(), true);
  await pushToPantheon(repo);
  await pushToGitLab(repo);
}

main().
  catch(e => console.log(e));
<commit_msg>Rename gitlab into base<commit_after>#!/usr/bin/env node

const Git = require('nodegit');
const helpers = require('./helpers');

const PANTHEON_KEY_PRIVATE = process.env.PANTHEON_KEY_PRIVATE;
const PANTHEON_REMOTE_NAME = 'pantheon';
const PANTHEON_REMOTE_BRANCH = 'master';
const PANTHEON_REMOTE = `${PANTHEON_REMOTE_NAME}/${PANTHEON_REMOTE_BRANCH}`

const BASE_KEY_PRIVATE = process.env.BASE_KEY_PRIVATE;
const BASE_REMOTE_NAME = 'base';
const BASE_REMOTE_BRANCH = 'master';
const BASE_REMOTE = `${BASE_REMOTE_NAME}/${BASE_REMOTE_BRANCH}`

const PANTHEON_LOCAL = `pantheon-master-`+Date.now();
const LOCAL_BRANCH = 'master';
const SIGNATURE_NAME = 'Chisel Bot';
const SIGNATURE_EMAIL = 'jakub.bogucki+chisel-bot@xfive.co';
const MESSAGE_BUILD_PREFIX = '[chisel-build]';
const IS_SPECIFIC_COMMAND = Boolean(process.argv[2]);

let repository = null;

async function main() {
  const repo = await getRepository();
  await repo.checkoutBranch(LOCAL_BRANCH, {
    checkoutStrategy: Git.Checkout.STRATEGY.FORCE,
  });
  await fetchAll(repo);
  await repo.createBranch(PANTHEON_LOCAL, await repository.getBranchCommit(PANTHEON_REMOTE), true);

  try {
    if(IS_SPECIFIC_COMMAND) {
      const command = process.argv[2];
      if(command == 'standard') {
        await updateRemoteBasedOnLocal();
      } else if(command == 'pushback') {
        await updateLocalBasedOnRemote();
      } else {
        throw new Error(`Command ${command} not recognized`);
      }
    } else {
      if(process.env.CHISEL_PUSHBACK) {
        await updateLocalBasedOnRemote();
      }
      await updateRemoteBasedOnLocal();
    }
  } finally {
    await repo.checkoutBranch(LOCAL_BRANCH, {
      checkoutStrategy: Git.Checkout.STRATEGY.FORCE,
    });
    await Git.Reset.reset(repo, await repo.getHeadCommit(), Git.Reset.TYPE.HARD);
    await Git.Branch.delete(await repo.getBranch(PANTHEON_LOCAL));
  }
}

async function getRepository() {
  if(repository == null) {
    repository = await Git.Repository.open('.');
  }
  return repository;
}

async function removeBuildsFromPantheon(repo, commit, stopId) {
  let firstNonBuildCommit = null;
  while(commit) {
    const message = commit.message();
    if(!message.startsWith(MESSAGE_BUILD_PREFIX)) {
      console.log(`Pantheon first non build commit: ${commit.id()}`);
      firstNonBuildCommit = commit;
      break;
    }

    if(stopId.equal(commit.id())) {
      throw new Error('Reached stop commit');
    }

    const parents = await commit.getParents();
    if(parents.length > 1) {
      throw new Error('When removing build commits encountered commit with more than one parent');
    }
    commit = parents[0];
  }

  if(firstNonBuildCommit) {
    await repo.createBranch(PANTHEON_LOCAL, firstNonBuildCommit, true);
  }
}

async function pushToPantheon(repo) {
  const remote = await repo.getRemote(PANTHEON_REMOTE_NAME);
  return remote.push([
    `+refs/heads/${PANTHEON_LOCAL}:refs/heads/${PANTHEON_REMOTE_BRANCH}` // Plus at the beginning means force
  ], {
    callbacks: {
      credentials: (url, user) => helpers.getCredentials(url, user, PANTHEON_KEY_PRIVATE),
    }
  });
}

async function pushToBase(repo) {
  const remote = await repo.getRemote(BASE_REMOTE_NAME);
  return remote.push([
    `refs/heads/${LOCAL_BRANCH}:refs/heads/${BASE_REMOTE_BRANCH}`,
  ], {
    callbacks: {
      credentials: (url, user) => helpers.getCredentials(url, user, BASE_KEY_PRIVATE),
    }
  });
}

async function fetchAll(repo) {
  await repo.fetch(BASE_REMOTE_NAME, {
    callbacks: {
      credentials: (url, user) => helpers.getCredentials(url, user, BASE_KEY_PRIVATE),
    }
  });
  await repo.fetch(PANTHEON_REMOTE_NAME, {
    callbacks: {
      credentials: (url, user) => helpers.getCredentials(url, user, PANTHEON_KEY_PRIVATE),
    }
  });
}

async function updateRemoteBasedOnLocal() {
  const repo = await getRepository();

  const headCommit = await repo.getHeadCommit();
  let branchCommit = await repo.getBranchCommit(PANTHEON_LOCAL);

  console.log(`Our branch (${LOCAL_BRANCH}) is currenrly at commit: ${headCommit.id()}`);
  console.log(`Pantheon branch (${PANTHEON_REMOTE}) is currently at commit: ${branchCommit.id()}`);

  // Git.Merge.base throws when no base found
  const base = await Git.Merge.base(repo, headCommit.id(), branchCommit.id());

  console.log(`Our and Pantheon's branches join at commit ${base}`);

  await removeBuildsFromPantheon(repo, branchCommit, base);
  branchCommit = await repo.getBranchCommit(PANTHEON_LOCAL);
  if(!base.equal(branchCommit.id())) {
    throw new Error('Patheon cleaning was not successful');
  }

  // Reset pantheon to master (it is really fast forward merge :D)
  await repo.createBranch(PANTHEON_LOCAL, headCommit, true);
  await repo.checkoutBranch(PANTHEON_LOCAL);

  // TODO: do real build
  require('fs').writeFileSync('./iambuild', Date.now().toString());

  const repoIndex = await repo.refreshIndex();
  await repoIndex.addAll(['iambuild'], Git.Index.ADD_OPTION.ADD_FORCE);
  await repoIndex.write();
  const treeOid = await repoIndex.writeTree();
  const author = Git.Signature.now(SIGNATURE_NAME, SIGNATURE_EMAIL);
  const newCommitId = await repo.createCommit(
    'HEAD',
    author,
    author,
    `${MESSAGE_BUILD_PREFIX} Builded!`,
    treeOid,
    [headCommit],
  );
  console.log(`Builded project commited in ${newCommitId}`)
  await pushToPantheon(repo);
}

async function findCommitsBetween(repo, start, end) {
  const endId = end.id();
  const commits = [];
  let check = start;
  while(check) {
    if(check.id().equal(endId)) {
      break;
    }
    const parentsIds = check.parents();
    const parents = [];
    for(const parentId of parentsIds) {
      parents.push(await Git.Commit.lookup(repo, parentId));
    }
    // console.log(check.sha() + ' -> ' + parents.map(p => p.sha()).join(' '));
    commits.push({
      commit: check,
      parents,
    });

    check = parents[0];
  }
  return commits;
}

async function updateLocalBasedOnRemote() {
  const repo = await getRepository();

  const headCommit = await repo.getHeadCommit();
  let branchCommit = await repo.getBranchCommit(PANTHEON_LOCAL);

  console.log(`Our branch (${LOCAL_BRANCH}) is currenrly at commit: ${headCommit.id()}`);
  console.log(`Pantheon branch (${PANTHEON_REMOTE}) is currently at commit: ${branchCommit.id()}`);

  // Git.Merge.base throws when no base found
  const base = await Git.Merge.base(repo, headCommit.id(), branchCommit.id());

  console.log(`Our and Pantheon's branches join at commit ${base}`);

  if(!base.equal(headCommit.id())) {
    throw new Error('Pantheons branch must be entirely on top of ours, it is not');
  }

  const commitsToAdd = await findCommitsBetween(repo, branchCommit, headCommit);
  commitsToAdd.reverse();

  for(const { commit, parents } of commitsToAdd) {
    if(parents.length == 1) {
      // Single commit - cherry pick
      const message = commit.message();
      if(message.startsWith(MESSAGE_BUILD_PREFIX)) {
        // Skip commit that is build
        continue;
      }
      // console.log('Picking: '+parents[0].sha());
      const head = await repo.getHeadCommit();
      await Git.Cherrypick.cherrypick(repo, commit, {});
      const index = await repo.refreshIndex();
      if(index.hasConflicts()) {
        throw new Error(`Conflicts when cherrypicking ${commit.id()}`);
      }
      const treeOid = await index.writeTreeTo(repo);
      await repo.createCommit(
        'HEAD',
        commit.author(),
        Git.Signature.now(SIGNATURE_NAME, SIGNATURE_EMAIL),
        commit.message()+'\n[ci skip]',
        treeOid,
        [head],
      );
    } else if(parents.length == 2) {
      // Merge commit
      const head = await repo.getHeadCommit();
      console.log(`merging ${parents[1].id()} with ${head.id()}`);
      const index = await Git.Merge.commits(repo, head, parents[1]);
      if(index.hasConflicts()) {
        throw new Error(`Conflicts when merging ${parents[1].id()} with ${head.id()}`);
      }
      const treeOid = await index.writeTreeTo(repo);
      await repo.createCommit(
        'HEAD',
        commit.author(),
        Git.Signature.now(SIGNATURE_NAME, SIGNATURE_EMAIL),
        commit.message()+'\n[ci skip]',
        treeOid,
        [head, parents[1]],
      );
      await Git.Reset.reset(repo, await repo.getHeadCommit(), Git.Reset.TYPE.HARD);
    } else {
      throw new Error('Merge commits of more than two things are not supported');
    }
  }
  await repo.createBranch(PANTHEON_LOCAL, await repo.getHeadCommit(), true);
  await pushToPantheon(repo);
  await pushToBase(repo);
}

main().
  catch(e => console.log(e));
<|endoftext|>


<commit_before>import './GCode.css';
import React, { Component } from 'react';
import {
  Button,
  ControlLabel,
  FormControl,
  FormGroup,
  ListGroupItem,
  Modal,
} from 'react-bootstrap'
import { connect } from 'react-redux'
import {
  getVertices,
} from '../inputs/Computer.js';

import {
  Vertex,
} from '../Geometry.js'
import Victor from 'victor';

// GCode Actions
export const setGCodeFilename = ( text ) => {
  return {
    type: 'SET_GCODE_FILENAME',
    value: text,
  };
}

export const setGCodePre = ( text ) => {
  localStorage.setItem('gcode_pre', text)
  return {
    type: 'SET_GCODE_PRE',
    value: text,
  };
}

export const setGCodePost = ( text ) => {
  localStorage.setItem('gcode_post', text)
  return {
    type: 'SET_GCODE_POST',
    value: text,
  };
}

export const toggleReverse = ( ) => {
  return {
    type: 'TOGGLE_REVERSE',
  };
}

export const setShowGCode = ( on ) => {
  return {
    type: 'SET_SHOW_GCODE',
    value: on,
  };
}

// Helper function to take a string and make the user download a text file with that text as the
// content.
//
// I don't really understand this, but I took it from here, and it seems to work:
// https://stackoverflow.com/a/18197511
//
function download(filename, text) {
  var pom = document.createElement('a');
  pom.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
  pom.setAttribute('download', filename);

  if (document.createEvent) {
    var event = document.createEvent('MouseEvents');
    event.initEvent('click', true, true);
    pom.dispatchEvent(event);
  }
  else {
    pom.click();
  }
}

function gcode(vertex) {
  var command = 'G01' +
    ' X' + vertex.x.toFixed(3) +
    ' Y' + vertex.y.toFixed(3)
  if (vertex.speed > 0.0) {
    command += ' F' + vertex.f
  }
  return command + '\n'
}

function thetarho(vertex) {
  return "" + vertex.x.toFixed(5) + " " + vertex.y.toFixed(5) + "\n";
}

const getComments = (state) => {

  let comments = [];
  comments.push("Created by Sandify");
  comments.push("");
  comments.push("  https://sandify.org");
  comments.push("");
  comments.push("  Sandify Version: " + state.app.sandifyVersion);
  comments.push("");
  comments.push("  Machine Type: " + (state.machine.rectangular ? "Rectangular" : "Polar"));
  if (state.machine.rectangular) {
    comments.push("    MinX: " + state.machine.min_x + " MaxX: " + state.machine.max_x + " MinY: " + state.machine.min_y + " MaxY: " + state.machine.max_y);
  } else {
    comments.push("    Max Radius: " + state.machine.max_radius);
    comments.push("    Force Endpoints: " + state.machine.polarEndpoints);
  }

  switch (state.app.input) {
    case 0: // shapes
      comments.push("  Content Type: Shapes");
      comments.push("    Starting Size: " + state.shapes.startingSize);
      comments.push("    Offset: X: " + state.transform.xformOffsetX + " Y: " + state.transform.xformOffsetY);
      switch (state.shapes.currentShape) {
        case "Polygon":
          comments.push("    Selected Shape: Polygon");
          comments.push("      Polygon Sides: " + state.shapes.polygonSides);
          break;
        case "Star":
          comments.push("    Selected Shape: Star");
          comments.push("      Star Points: " + state.shapes.starPoints);
          comments.push("      Star Ratio: " + state.shapes.starRatio);
          break;
        case "Circle":
          comments.push("    Selected Shape: Circle");
          comments.push("      Circle Lobes: " + state.shapes.circleLobes);
          break;
        case "Text":
          comments.push("    Selected Shape: Text");
          comments.push("      Input Text: " + state.shapes.inputText);
          break;
        case "Vicious1":
          comments.push("    Selected Shape: Vicious1");
          break;
        default:
          comments.push("    Selected Shape: None");
          break;
      }

      comments.push("    Number of Loops: " + state.transform.numLoops);
      comments.push("    Spin: " + state.transform.spinEnabled);
      if (state.transform.spinEnabled) {
        comments.push("      Spin Value: " + state.transform.spinValue);
        comments.push("      Spin Switchbacks: " + state.transform.spinSwitchbacks);
      }
      comments.push("    Grow: " + state.transform.growEnabled);
      if (state.transform.growEnabled) {
        comments.push("      Grow Value: " + state.transform.growValue);
      }
      comments.push("    Track: " + state.transform.trackEnabled);
      if (state.transform.trackEnabled) {
        comments.push("      Track Count: " + state.transform.trackValue);
        comments.push("      Track Size: " + state.transform.trackLength);
        comments.push("      Track Grow: " + state.transform.trackGrowEnabled);
        if (state.transform.trackGrowEnabled) {
          comments.push("          Track Grow Value: " + state.transform.trackGrow);
        }
      }
      break;
    case 2: // wiper
      comments.push("  Content Type: Wiper");
      comments.push("    Wiper Angle: " + state.wiper.angleDeg);
      comments.push("    Wiper Size: "  + state.wiper.size);
      break;
    case 3: // thetarho
      comments.push("  Content Type: ThetaRho");
      comments.push("    Input File: " + state.file.name);
      comments.push("    Zoom: "  + state.file.zoom);
      comments.push("    Aspect Ratio: " + state.file.aspectRatio);
      break;
    default: // Dunno
      comments.push("  Content Type: Unknown");
      break;
  }
  comments.push("  Path Reversed: " + state.app.reverse);
  comments.push("");

  return comments;
};

const gcodeProps = (state, ownProps) => {
  return {
    reverse: state.app.reverse,
    show: state.app.showGCode,
    vertices: getVertices(state),

    settings: getComments(state),
    xOffset: (state.machine.min_x + state.machine.max_x) / 2.0,
    yOffset: (state.machine.min_y + state.machine.max_y) / 2.0,
    max_radius: state.machine.max_radius,

    filename: state.gcode.filename,
    pre: state.gcode.pre,
    post: state.gcode.post,
  }
}

const gcodeDispatch = (dispatch, ownProps) => {
  return {
    open: () => {
      dispatch(setShowGCode(true));
    },
    close: () => {
      dispatch(setShowGCode(false));
    },
    toggleReverse: () => {
      dispatch(toggleReverse());
    },
    setFilename: (event) => {
      dispatch(setGCodeFilename(event.target.value));
    },
    setPre: (event) => {
      dispatch(setGCodePre(event.target.value));
    },
    setPost: (event) => {
      dispatch(setGCodePost(event.target.value));
    },
  }
}

// A class that will encapsulate all the gcode generation. This is currently just a button that
// converts vertices and a speed into a list of positions. There is a lot more than could exists
// here.
class GCodeGenerator extends Component {

  generateGCode() {
    var content = "; " + this.props.settings.join("\n; ");
    content += "\n";
    content += "; filename: '" + this.props.filename + "'\n\n";
    content += "; BEGIN PRE\n";
    content += this.props.pre;
    content += "; END PRE\n";

    console.log("offset x: " + this.props.xOffset + " y: " + this.props.yOffset);
    var centeredVertices = this.props.vertices.map( (vertex) => {
      return {
        ...vertex,
        x: vertex.x + this.props.xOffset,
        y: vertex.y + this.props.yOffset,
      }
    });

    var lines = centeredVertices.map(gcode);

    content += lines.join('');

    content += '\n';
    content += "; BEGIN POST\n";
    content += this.props.post;
    content += "; END POST\n";
    var filename = this.props.filename;
    if (!filename.includes(".")) {
      filename += ".gcode";
    }
    download(filename, content)
    this.props.close();
  }

  generateThetaRho() {
    var content = "# " + this.props.settings.join("\n# ");
    content += "\n";
    content += "# filename: '" + this.props.filename + "'\n\n";
    content += "# BEGIN PRE\n";
    content += this.props.pre;
    content += "# END PRE\n";
    content += '\n';

    // First, downsample larger lines into smaller ones.
    var maxLength = 2.0;
    var subsampledVertices = [];
    var previous = undefined;
    var next;
    for (next = 0; next < this.props.vertices.length; next++) {
      if (previous !== undefined) {
        var start = Victor.fromObject(this.props.vertices[previous]);
        var end = Victor.fromObject(this.props.vertices[next]);

        var delta = end.clone().subtract(start);
        var deltaSegment = end.clone().subtract(start).normalize().multiply(Victor(maxLength, maxLength));

        // This loads up (start, end].
        for (let step = 0; step < (delta.magnitude() / maxLength) ; step++) {
          subsampledVertices.push(Vertex(start.x + step * deltaSegment.x,
                                         start.y + step * deltaSegment.y,
                                         this.props.vertices[next].f));
        }

      }
      previous = next;
    }
    // Add in the end.
    if (previous !== undefined) {
      subsampledVertices.push(this.props.vertices[this.props.vertices.length - 1]);
    }

    // Convert to Theta, Rho
    var trVertices = [];
    var previousTheta = 0;
    var previousRawTheta = 0;
    for (next = 0; next < subsampledVertices.length; ++next) {
      // Normalize the radius
      var rho = Victor.fromObject(subsampledVertices[next]).magnitude() / this.props.max_radius;

      // What is the basic theta for this point?
      var rawTheta = Math.atan2(subsampledVertices[next].x,
                                subsampledVertices[next].y);
      // Convert to [0,2pi]
      rawTheta = (rawTheta + 2.0 * Math.PI) % (2.0 * Math.PI);

      // Compute the difference to the last point.
      var deltaTheta = rawTheta - previousRawTheta;
      // Convert to [-pi,pi]
      if (deltaTheta < -Math.PI) {
        deltaTheta += 2.0 * Math.PI;
      }
      if (deltaTheta > Math.PI) {
        deltaTheta -= 2.0 * Math.PI;
      }
      var theta = previousTheta + deltaTheta;
      previousRawTheta = rawTheta;
      previousTheta = theta;

      trVertices.push(Vertex(theta, rho, subsampledVertices[next].f));
    }

    var lines = trVertices.map(thetarho);

    content += lines.join('');

    content += '\n';
    content += "# BEGIN POST\n";
    content += this.props.post;
    content += "# END POST\n";

    var filename = this.props.filename;
    if (!filename.includes(".")) {
      filename += ".thr";
    }
    download(filename, content)

    this.props.close();
  }

  render() {
    const reverseActiveClass = (this.props.reverse ? "active" : null);
    return (
      <div>
        <Button className="finishButton" bsStyle="primary" bsSize="large" onClick={this.props.open}>Create Code</Button>
        <Modal show={this.props.show} onHide={this.props.close}>
          <Modal.Header closeButton>
            <Modal.Title>Code Parameters</Modal.Title>
          </Modal.Header>
          <Modal.Body>
            <FormGroup controlId="sandifyFilename">
              <ControlLabel>Name of Output</ControlLabel>
              <FormControl type="text" value={this.props.filename} onChange={this.props.setFilename}/>
            </FormGroup>
            <FormGroup controlId="preCode">
              <ControlLabel>Program Start Code</ControlLabel>
              <FormControl componentClass="textarea" value={this.props.pre} onChange={this.props.setPre}/>
            </FormGroup>
            <FormGroup controlId="postCode">
              <ControlLabel>Program End Code</ControlLabel>
              <FormControl componentClass="textarea" value={this.props.post} onChange={this.props.setPost}/>
            </FormGroup>
            <ListGroupItem header="Reverse Path" className={reverseActiveClass} onClick={this.props.toggleReverse}>Reverses the Code, starting at the final location</ListGroupItem>
          </Modal.Body>
          <Modal.Footer>
            <Button id="code-close" bsStyle="default" onClick={this.props.close}>Close</Button>
            <Button id="code-gen-gcode" bsStyle="primary" onClick={this.generateGCode.bind(this)}>Generate GCode</Button>
            <Button id="code-gen-thetarho" bsStyle="primary" onClick={this.generateThetaRho.bind(this)}>Generate Theta Rho</Button>
          </Modal.Footer>
        </Modal>
      </div>
    );
  }
}
GCodeGenerator = connect(gcodeProps, gcodeDispatch)(GCodeGenerator);

export default GCodeGenerator
<commit_msg>Fixing some mistakes in the gcode comment section.<commit_after>import './GCode.css';
import React, { Component } from 'react';
import {
  Button,
  ControlLabel,
  FormControl,
  FormGroup,
  ListGroupItem,
  Modal,
} from 'react-bootstrap'
import { connect } from 'react-redux'
import {
  getVertices,
} from '../inputs/Computer.js';

import {
  Vertex,
} from '../Geometry.js'
import Victor from 'victor';

// GCode Actions
export const setGCodeFilename = ( text ) => {
  return {
    type: 'SET_GCODE_FILENAME',
    value: text,
  };
}

export const setGCodePre = ( text ) => {
  localStorage.setItem('gcode_pre', text)
  return {
    type: 'SET_GCODE_PRE',
    value: text,
  };
}

export const setGCodePost = ( text ) => {
  localStorage.setItem('gcode_post', text)
  return {
    type: 'SET_GCODE_POST',
    value: text,
  };
}

export const toggleReverse = ( ) => {
  return {
    type: 'TOGGLE_REVERSE',
  };
}

export const setShowGCode = ( on ) => {
  return {
    type: 'SET_SHOW_GCODE',
    value: on,
  };
}

// Helper function to take a string and make the user download a text file with that text as the
// content.
//
// I don't really understand this, but I took it from here, and it seems to work:
// https://stackoverflow.com/a/18197511
//
function download(filename, text) {
  var pom = document.createElement('a');
  pom.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
  pom.setAttribute('download', filename);

  if (document.createEvent) {
    var event = document.createEvent('MouseEvents');
    event.initEvent('click', true, true);
    pom.dispatchEvent(event);
  }
  else {
    pom.click();
  }
}

function gcode(vertex) {
  var command = 'G01' +
    ' X' + vertex.x.toFixed(3) +
    ' Y' + vertex.y.toFixed(3)
  if (vertex.speed > 0.0) {
    command += ' F' + vertex.f
  }
  return command + '\n'
}

function thetarho(vertex) {
  return "" + vertex.x.toFixed(5) + " " + vertex.y.toFixed(5) + "\n";
}

const getComments = (state) => {

  let comments = [];
  comments.push("Created by Sandify");
  comments.push("");
  comments.push("  https://sandify.org");
  comments.push("");
  comments.push("  Sandify Version: " + state.app.sandifyVersion);
  comments.push("");
  comments.push("  Machine Type: " + (state.machine.rectangular ? "Rectangular" : "Polar"));
  if (state.machine.rectangular) {
    comments.push("    MinX: " + state.machine.min_x + " MaxX: " + state.machine.max_x + " MinY: " + state.machine.min_y + " MaxY: " + state.machine.max_y);
  } else {
    comments.push("    Max Radius: " + state.machine.max_radius);
    comments.push("    Force Endpoints: " + state.machine.polarEndpoints);
  }

  switch (state.app.input) {
    case 0: // shapes
      comments.push("  Content Type: Shapes");
      comments.push("    Starting Size: " + state.shapes.startingSize);
      comments.push("    Offset: X: " + state.transform.xformOffsetX + " Y: " + state.transform.xformOffsetY);
      switch (state.shapes.currentShape) {
        case "Polygon":
          comments.push("    Selected Shape: Polygon");
          comments.push("      Polygon Sides: " + state.shapes.polygonSides);
          break;
        case "Star":
          comments.push("    Selected Shape: Star");
          comments.push("      Star Points: " + state.shapes.starPoints);
          comments.push("      Star Ratio: " + state.shapes.starRatio);
          break;
        case "Circle":
          comments.push("    Selected Shape: Circle");
          comments.push("      Circle Lobes: " + state.shapes.circleLobes);
          break;
        case "Heart":
          comments.push("    Selected Shape: Heart");
          break;
        case "Text":
          comments.push("    Selected Shape: Text");
          comments.push("      Input Text: " + state.shapes.inputText);
          break;
        case "Vicious1":
          comments.push("    Selected Shape: Vicious1");
          break;
        default:
          comments.push("    Selected Shape: None");
          break;
      }

      comments.push("    Number of Loops: " + state.transform.numLoops);
      comments.push("    Spin: " + state.transform.spinEnabled);
      if (state.transform.spinEnabled) {
        comments.push("      Spin Value: " + state.transform.spinValue);
        comments.push("      Spin Switchbacks: " + state.transform.spinSwitchbacks);
      }
      comments.push("    Grow: " + state.transform.growEnabled);
      if (state.transform.growEnabled) {
        comments.push("      Grow Value: " + state.transform.growValue);
      }
      comments.push("    Track: " + state.transform.trackEnabled);
      if (state.transform.trackEnabled) {
        comments.push("      Track Size: " + state.transform.trackValue);
        comments.push("      Track Length: " + state.transform.trackLength);
        comments.push("      Track Grow: " + state.transform.trackGrowEnabled);
        if (state.transform.trackGrowEnabled) {
          comments.push("          Track Grow Value: " + state.transform.trackGrow);
        }
      }
      break;
    case 2: // wiper
      comments.push("  Content Type: Wiper");
      comments.push("    Wiper Angle: " + state.wiper.angleDeg);
      comments.push("    Wiper Size: "  + state.wiper.size);
      break;
    case 3: // thetarho
      comments.push("  Content Type: ThetaRho");
      comments.push("    Input File: " + state.file.name);
      comments.push("    Zoom: "  + state.file.zoom);
      comments.push("    Aspect Ratio: " + state.file.aspectRatio);
      break;
    default: // Dunno
      comments.push("  Content Type: Unknown");
      break;
  }
  comments.push("  Path Reversed: " + state.app.reverse);
  comments.push("");

  return comments;
};

const gcodeProps = (state, ownProps) => {
  return {
    reverse: state.app.reverse,
    show: state.app.showGCode,
    vertices: getVertices(state),

    settings: getComments(state),
    xOffset: (state.machine.min_x + state.machine.max_x) / 2.0,
    yOffset: (state.machine.min_y + state.machine.max_y) / 2.0,
    max_radius: state.machine.max_radius,

    filename: state.gcode.filename,
    pre: state.gcode.pre,
    post: state.gcode.post,
  }
}

const gcodeDispatch = (dispatch, ownProps) => {
  return {
    open: () => {
      dispatch(setShowGCode(true));
    },
    close: () => {
      dispatch(setShowGCode(false));
    },
    toggleReverse: () => {
      dispatch(toggleReverse());
    },
    setFilename: (event) => {
      dispatch(setGCodeFilename(event.target.value));
    },
    setPre: (event) => {
      dispatch(setGCodePre(event.target.value));
    },
    setPost: (event) => {
      dispatch(setGCodePost(event.target.value));
    },
  }
}

// A class that will encapsulate all the gcode generation. This is currently just a button that
// converts vertices and a speed into a list of positions. There is a lot more than could exists
// here.
class GCodeGenerator extends Component {

  generateGCode() {
    var content = "; " + this.props.settings.join("\n; ");
    content += "\n";
    content += "; filename: '" + this.props.filename + "'\n\n";
    content += "; BEGIN PRE\n";
    content += this.props.pre;
    content += "; END PRE\n";

    console.log("offset x: " + this.props.xOffset + " y: " + this.props.yOffset);
    var centeredVertices = this.props.vertices.map( (vertex) => {
      return {
        ...vertex,
        x: vertex.x + this.props.xOffset,
        y: vertex.y + this.props.yOffset,
      }
    });

    var lines = centeredVertices.map(gcode);

    content += lines.join('');

    content += '\n';
    content += "; BEGIN POST\n";
    content += this.props.post;
    content += "; END POST\n";
    var filename = this.props.filename;
    if (!filename.includes(".")) {
      filename += ".gcode";
    }
    download(filename, content)
    this.props.close();
  }

  generateThetaRho() {
    var content = "# " + this.props.settings.join("\n# ");
    content += "\n";
    content += "# filename: '" + this.props.filename + "'\n\n";
    content += "# BEGIN PRE\n";
    content += this.props.pre;
    content += "# END PRE\n";
    content += '\n';

    // First, downsample larger lines into smaller ones.
    var maxLength = 2.0;
    var subsampledVertices = [];
    var previous = undefined;
    var next;
    for (next = 0; next < this.props.vertices.length; next++) {
      if (previous !== undefined) {
        var start = Victor.fromObject(this.props.vertices[previous]);
        var end = Victor.fromObject(this.props.vertices[next]);

        var delta = end.clone().subtract(start);
        var deltaSegment = end.clone().subtract(start).normalize().multiply(Victor(maxLength, maxLength));

        // This loads up (start, end].
        for (let step = 0; step < (delta.magnitude() / maxLength) ; step++) {
          subsampledVertices.push(Vertex(start.x + step * deltaSegment.x,
                                         start.y + step * deltaSegment.y,
                                         this.props.vertices[next].f));
        }

      }
      previous = next;
    }
    // Add in the end.
    if (previous !== undefined) {
      subsampledVertices.push(this.props.vertices[this.props.vertices.length - 1]);
    }

    // Convert to Theta, Rho
    var trVertices = [];
    var previousTheta = 0;
    var previousRawTheta = 0;
    for (next = 0; next < subsampledVertices.length; ++next) {
      // Normalize the radius
      var rho = Victor.fromObject(subsampledVertices[next]).magnitude() / this.props.max_radius;

      // What is the basic theta for this point?
      var rawTheta = Math.atan2(subsampledVertices[next].x,
                                subsampledVertices[next].y);
      // Convert to [0,2pi]
      rawTheta = (rawTheta + 2.0 * Math.PI) % (2.0 * Math.PI);

      // Compute the difference to the last point.
      var deltaTheta = rawTheta - previousRawTheta;
      // Convert to [-pi,pi]
      if (deltaTheta < -Math.PI) {
        deltaTheta += 2.0 * Math.PI;
      }
      if (deltaTheta > Math.PI) {
        deltaTheta -= 2.0 * Math.PI;
      }
      var theta = previousTheta + deltaTheta;
      previousRawTheta = rawTheta;
      previousTheta = theta;

      trVertices.push(Vertex(theta, rho, subsampledVertices[next].f));
    }

    var lines = trVertices.map(thetarho);

    content += lines.join('');

    content += '\n';
    content += "# BEGIN POST\n";
    content += this.props.post;
    content += "# END POST\n";

    var filename = this.props.filename;
    if (!filename.includes(".")) {
      filename += ".thr";
    }
    download(filename, content)

    this.props.close();
  }

  render() {
    const reverseActiveClass = (this.props.reverse ? "active" : null);
    return (
      <div>
        <Button className="finishButton" bsStyle="primary" bsSize="large" onClick={this.props.open}>Create Code</Button>
        <Modal show={this.props.show} onHide={this.props.close}>
          <Modal.Header closeButton>
            <Modal.Title>Code Parameters</Modal.Title>
          </Modal.Header>
          <Modal.Body>
            <FormGroup controlId="sandifyFilename">
              <ControlLabel>Name of Output</ControlLabel>
              <FormControl type="text" value={this.props.filename} onChange={this.props.setFilename}/>
            </FormGroup>
            <FormGroup controlId="preCode">
              <ControlLabel>Program Start Code</ControlLabel>
              <FormControl componentClass="textarea" value={this.props.pre} onChange={this.props.setPre}/>
            </FormGroup>
            <FormGroup controlId="postCode">
              <ControlLabel>Program End Code</ControlLabel>
              <FormControl componentClass="textarea" value={this.props.post} onChange={this.props.setPost}/>
            </FormGroup>
            <ListGroupItem header="Reverse Path" className={reverseActiveClass} onClick={this.props.toggleReverse}>Reverses the Code, starting at the final location</ListGroupItem>
          </Modal.Body>
          <Modal.Footer>
            <Button id="code-close" bsStyle="default" onClick={this.props.close}>Close</Button>
            <Button id="code-gen-gcode" bsStyle="primary" onClick={this.generateGCode.bind(this)}>Generate GCode</Button>
            <Button id="code-gen-thetarho" bsStyle="primary" onClick={this.generateThetaRho.bind(this)}>Generate Theta Rho</Button>
          </Modal.Footer>
        </Modal>
      </div>
    );
  }
}
GCodeGenerator = connect(gcodeProps, gcodeDispatch)(GCodeGenerator);

export default GCodeGenerator
<|endoftext|>


<commit_before>'use strict'

function iterationsToEscape(x, y, iterations) {
  var x0 = x
  var y0 = y
  var i = -1
  while (++i < iterations) {
    var tempY = 2 * x * y + y0
    x = x * x - y * y + x0
    y = tempY
    var r2 = x * x + y * y
    if (r2 > 4) {
      return i
    }
  }
  return -1
}

module.exports = {
  iterationsToEscape: iterationsToEscape
}
<commit_msg>Fix iterationsToEscape<commit_after>'use strict'

function iterationsToEscape(x0, y0, iterations) {
  var x = x0
  var y = y0
  var i = 0

  function iterate() {
    i++
    var tempY = 2 * x * y + y0
    x = x * x - y * y + x0
    y = tempY
  }

  while (x * x + y * y < 4) {
    if (i === iterations) return -1
    iterate()
  }
  return i
}

module.exports = {
  iterationsToEscape: iterationsToEscape
}
<|endoftext|>


<commit_before>define(['managerAPI'], function(Manager){

	var API = new Manager();

	API.addSettings('onEnd', function(){console.log('onEnd');});
	API.addSettings('onPreTask', function(currentTask, $http){
		var data = {taskName: currentTask.name, taskNumber: currentTask.$meta.number};
		return $http.post('task/advance/url', data);
	});

	API.addSequence([
		{
			type:'quest',
			name: 'first',
			scriptUrl: 'questScript1.js'
		},
		{
			type:'quest',
			name:'second',
			scriptUrl: 'questScript2.js'
		}
	]);

	return API.script;
});<commit_msg>feaet(manager): proof of concept of posting task data with quest logger<commit_after>define(['managerAPI'], function(Manager){

	var API = new Manager();

	API.addSettings('onEnd', function(){console.log('onEnd');});
	API.addSettings('onPreTask', function(currentTask, $http){
		var data = {taskName: currentTask.name, taskNumber: currentTask.$meta.number};
		var settings = currentTask.$script.settings;
		settings.logger = settings.logger || {};
		settings.logger.logFn = logger;
		return $http.post('task/advance/url', data);

		function logger(log){
			return angular.extend(log,data);
		}
	});

	API.addSequence([
		{
			type:'quest',
			name: 'first',
			scriptUrl: 'questScript1.js'
		},
		{
			type:'quest',
			name:'second',
			scriptUrl: 'questScript2.js'
		}
	]);

	return API.script;
});<|endoftext|>


<commit_before>function map () {
  var doc
    , serviceTypes
    , debug
    , capServiceTypes;

  if (!debug) debug = false;

  function objGet (obj, prop, defVal) {
    var props
      , count
      , i
      , p;

    if (!obj) return defVal;

    props = prop.split('.');
    count = 0;

    for (i = 0; i < props.length; i++) {
      p = props[i];
      if (obj[p]) {
        obj = obj[p];
        count++;
        if (count === props.length) {
          return obj;
        }
      } else {
        return defVal;
      }
    }
  }

  var doc = {
    setProperty: function (prop, value) {
      var count
        , obj
        , p
        , props
        , i
        , results;

      obj = this;
      props = prop.split('.');
      count = 0;

      for (i = 0; i < props.length; i ++) {
        p = props[i];
        if (obj[p]) {
          obj = obj[p];
          results.push(count++);
        } else {
          if (count + 1 === props.length) {
            results.push(obj[p] = value);
          } else {
            obj[p] = {};
            obj = obj[p];
            results.push(count++);
          }
        }
      }
      return results;
    }
  };

  serviceTypes = ['OGC:WMS', 'OGC:WFS', 'OGC:WCS', 'esri', 'opendap'];

  capServiceTypes = (function () {
    var results = [], i, type;
    for (i = 0; i < serviceTypes.length; i++) {
      type = serviceTypes[i];
      results.push(type.toUpperCase());
    }
    return results;
  })();

  function guessServiceType (url) {
    var condition
      , conditions
      , conditionSet
      , i
      , j
      , satisfied
      , type;

    conditions = [
      [/getcapabilities/i, /wms/i],
      [/getcapabilities/i, /wfs/i],
      [/getcapabilities/i, /wcs/i],
      [/\/services\//i, /\/mapserver\/?$/i],
      [/\.dds$/]
    ];

    for (i = 0; i < serviceTypes.length; i++) {
      type = serviceTypes[i];
      conditionSet = conditions[i];
      satisfied = true;
      for (j = 0; j < conditionSet.length; j++) {
        condition = conditionSet[j];
        if (!url.match(condition)) satisfied = false;
      }
      if (satisfied) return type;
    }
    return null;
  }

  function buildContact (responsibleParty) {
    var contact
      , role;

    role = objGet(responsibleParty, "gmd:CI_ResponsibleParty.gmd:role.gmd:CI_RoleCode.codeListValue", "");
    contact = {
      Name: objGet(responsibleParty, "gmd:CI_ResponsibleParty.gmd:individualName.gco:CharacterString.$t", "No Name Was Given"),
      ContactInformation: {
        Phone: objGet(responsibleParty, "gmd:CI_ResponsibleParty.gmd:contactInfo.gmd:CI_Contact.gmd:phone.gmd:CI_Telephone.gmd:voice.gco:CharacterString.$t", "No Phone Number Was Given"),
        email: objGet(responsibleParty, "gmd:CI_ResponsibleParty.gmd:contactInfo.gmd:CI_Contact.gmd:address.gmd:CI_Address.gmd:electronicMailAddress.gco:CharacterString.$t", "No email Was Given"),
        Address: {
          Street: objGet(responsibleParty, "gmd:CI_ResponsibleParty.gmd:contactInfo.gmd:CI_Contact.gmd:address.gmd:CI_Address.gmd:deliveryPoint.gco:CharacterString.$t", "No Street Address Was Given"),
          City: objGet(responsibleParty, "gmd:CI_ResponsibleParty.gmd:contactInfo.gmd:CI_Contact.gmd:address.gmd:CI_Address.gmd:city.gco:CharacterString.$t", "No City Was Given"),
          State: objGet(responsibleParty, "gmd:CI_ResponsibleParty.gmd:contactInfo.gmd:CI_Contact.gmd:address.gmd:CI_Address.gmd:administrativeArea.gco:CharacterString.$t", "No State Was Given"),
          Zip: objGet(responsibleParty, "gmd:CI_ResponsibleParty.gmd:contactInfo.gmd:CI_Contact.gmd:address.gmd:CI_Address.gmd:postalCode.gco:CharacterString.$t", "No Zip Was Given")
        }
      }
    };

    if (['Missing', 'missing', 'No Name Was given'].indexOf(contact.Name) > -1) {
      contact["OrganizationName"] = objGet(responsibleParty, "gmd:CI_ResponsibleParty.gmd:organisationName.gco:CharacterString.$t", "No Organization Name Was Given");
    }

    return contact;
  }

  function buildLink (onlineResource, responsibleParty) {
    var url
      , protocol
      , link
      , guess
      , serviceType
      , name;

    url = objGet(onlineResource, "gmd:linkage.gmd:URL.$t", "No URL Was Given");
    protocol = objGet(onlineResource, "gmd:protocol.gco:CharacterString.$t", "No Protocol Was Given");
    protocol = protocol.toUpperCase();

    if (capServiceTypes.indexOf(protocol) >= 0) {
      serviceType = protocol;
    } else {
      guess = guessServiceType(url);
      if (guess) serviceType = guess;
    }

    name = null;
    if (responsibleParty) {
      name = objGet(responsibleParty, "gmd:CI_ResponsibleParty.gmd:individualName.gco:CharacterString.$t", "No Name Was Given");
      if (['Missing', 'missing', 'No Name Was Given'].indexOf(name) > -1) {
        name = objGet(responsibleParty, "gmd:CI_ResponsibleParty.gmd:organisationName.gco:CharacterString.$t", "No Organization Name Was Given");
      }
    }

    link = {
      URL: url,
      Description: objGet(onlineResource, "gmd:description.gco:CharacterString.$t", "No Description Was Given")
    };

    if (serviceType) {
      link.serviceType = serviceType;
    }

    if (name) {
      link.Distributor = name;
    }

    return link;
  }

}

function reduce () {

}

exports.map = map;
exports.reduce = reduce;<commit_msg>first iteration of mapreduce for iso input<commit_after>function map () {
  var doc
    , i
    , j
    , k
    , l
    , m
    , id
    , serviceTypes
    , capServiceTypes
    , ident
    , pubDate
    , metaContact
    , resParties
    , resParty
    , authors
    , descKeywords
    , descKeyword
    , keywords
    , keyword
    , words
    , word
    , split
    , extent
    , validExtents
    , isoDistributors
    , isoDist
    , linksList
    , distributions
    , distribution
    , distributorLinks
    , moreLinks
    , dist
    , distOpt
    , distOptions
    , distOutput
    , linkLookup
    , responsibleParty
    , link;

  function objGet (obj, prop, defVal) {
    var props
      , count
      , i
      , p;

    if (!obj) return defVal;

    props = prop.split('.');
    count = 0;

    for (i = 0; i < props.length; i++) {
      p = props[i];
      if (obj[p]) {
        obj = obj[p];
        count++;
        if (count === props.length) {
          return obj;
        }
      } else {
        return defVal;
      }
    }
  }

  var doc = {
    setProperty: function (prop, value) {
      var count
        , obj
        , p
        , props
        , i
        , results;

      obj = this;
      props = prop.split('.');
      count = 0;

      for (i = 0; i < props.length; i ++) {
        p = props[i];
        if (obj[p]) {
          obj = obj[p];
          results.push(count++);
        } else {
          if (count + 1 === props.length) {
            results.push(obj[p] = value);
          } else {
            obj[p] = {};
            obj = obj[p];
            results.push(count++);
          }
        }
      }
      return results;
    }
  };

  serviceTypes = ['OGC:WMS', 'OGC:WFS', 'OGC:WCS', 'esri', 'opendap'];

  capServiceTypes = (function () {
    var results = [], i, type;
    for (i = 0; i < serviceTypes.length; i++) {
      type = serviceTypes[i];
      results.push(type.toUpperCase());
    }
    return results;
  })();

  function guessServiceType (url) {
    var condition
      , conditions
      , conditionSet
      , i
      , j
      , satisfied
      , type;

    conditions = [
      [/getcapabilities/i, /wms/i],
      [/getcapabilities/i, /wfs/i],
      [/getcapabilities/i, /wcs/i],
      [/\/services\//i, /\/mapserver\/?$/i],
      [/\.dds$/]
    ];

    for (i = 0; i < serviceTypes.length; i++) {
      type = serviceTypes[i];
      conditionSet = conditions[i];
      satisfied = true;
      for (j = 0; j < conditionSet.length; j++) {
        condition = conditionSet[j];
        if (!url.match(condition)) satisfied = false;
      }
      if (satisfied) return type;
    }
    return null;
  }

  function buildContact (responsibleParty) {
    var contact
      , role;

    role = objGet(responsibleParty, "gmd:CI_ResponsibleParty.gmd:role.gmd:CI_RoleCode.codeListValue", "");
    contact = {
      Name: objGet(responsibleParty, "gmd:CI_ResponsibleParty.gmd:individualName.gco:CharacterString.$t", "No Name Was Given"),
      ContactInformation: {
        Phone: objGet(responsibleParty, "gmd:CI_ResponsibleParty.gmd:contactInfo.gmd:CI_Contact.gmd:phone.gmd:CI_Telephone.gmd:voice.gco:CharacterString.$t", "No Phone Number Was Given"),
        email: objGet(responsibleParty, "gmd:CI_ResponsibleParty.gmd:contactInfo.gmd:CI_Contact.gmd:address.gmd:CI_Address.gmd:electronicMailAddress.gco:CharacterString.$t", "No email Was Given"),
        Address: {
          Street: objGet(responsibleParty, "gmd:CI_ResponsibleParty.gmd:contactInfo.gmd:CI_Contact.gmd:address.gmd:CI_Address.gmd:deliveryPoint.gco:CharacterString.$t", "No Street Address Was Given"),
          City: objGet(responsibleParty, "gmd:CI_ResponsibleParty.gmd:contactInfo.gmd:CI_Contact.gmd:address.gmd:CI_Address.gmd:city.gco:CharacterString.$t", "No City Was Given"),
          State: objGet(responsibleParty, "gmd:CI_ResponsibleParty.gmd:contactInfo.gmd:CI_Contact.gmd:address.gmd:CI_Address.gmd:administrativeArea.gco:CharacterString.$t", "No State Was Given"),
          Zip: objGet(responsibleParty, "gmd:CI_ResponsibleParty.gmd:contactInfo.gmd:CI_Contact.gmd:address.gmd:CI_Address.gmd:postalCode.gco:CharacterString.$t", "No Zip Was Given")
        }
      }
    };

    if (['Missing', 'missing', 'No Name Was given'].indexOf(contact.Name) > -1) {
      contact["OrganizationName"] = objGet(responsibleParty, "gmd:CI_ResponsibleParty.gmd:organisationName.gco:CharacterString.$t", "No Organization Name Was Given");
    }

    return contact;
  }

  function buildLink (onlineResource, responsibleParty) {
    var url
      , protocol
      , link
      , guess
      , serviceType
      , name;

    url = objGet(onlineResource, "gmd:linkage.gmd:URL.$t", "No URL Was Given");
    protocol = objGet(onlineResource, "gmd:protocol.gco:CharacterString.$t", "No Protocol Was Given");
    protocol = protocol.toUpperCase();

    if (capServiceTypes.indexOf(protocol) >= 0) {
      serviceType = protocol;
    } else {
      guess = guessServiceType(url);
      if (guess) serviceType = guess;
    }

    name = null;
    if (responsibleParty) {
      name = objGet(responsibleParty, "gmd:CI_ResponsibleParty.gmd:individualName.gco:CharacterString.$t", "No Name Was Given");
      if (['Missing', 'missing', 'No Name Was Given'].indexOf(name) > -1) {
        name = objGet(responsibleParty, "gmd:CI_ResponsibleParty.gmd:organisationName.gco:CharacterString.$t", "No Organization Name Was Given");
      }
    }

    link = {
      URL: url,
      Description: objGet(onlineResource, "gmd:description.gco:CharacterString.$t", "No Description Was Given")
    };

    if (serviceType) {
      link.serviceType = serviceType;
    }

    if (name) {
      link.Distributor = name;
    }

    return link;
  }

  // Find the appropriate identification info -- if there are multiples then
  // the first one is used.
  ident = objGet(iso, "gmd:MD_Metadata.gmd:identificationInfo", {});
  ident = objGet(ident, "0", ident);
  ident = objGet(ident, "gmd:MD_DataIdentification", objGet(ident, "srv:SV_ServiceIdentification", {}));

  // Find the title and description
  doc.setProperty("Title", objGet(ident, "gmd:citation.gmd:CI_Citation.gmd:title.gco:CharacterString.$t", "No Title Was Given"));
  doc.setProperty("Description", objGet(ident, "gmd:abstract.gco:CharacterString.$t", "No Description Was Given"));

  // Publication date
  pubDate = objGet(ident, "gmd:citation.gmd:CI_Citation.gmd:date.gmd:CI_Date.gmd:date.gco:DateTime.$t", "Publication Date Not Given").trim();
  if (pubDate.match(/T\d\d:\d\d(?!:)/)) {
    pubDate = pubDate + ":00Z";
  }
  doc.setProperty("PublicationDate", pubDate);

  // Metadata contact
  metaContact = objGet(iso, "gmd:MD_Metadata:gmd:contact");
  doc.setProperty("MetadataContact", buildContact(metaContact));

  // Authors
  resParties = objGet(ident, "gmd:citation.gmd:CI_Citation.gmd:citedResponsibleParty", []);
  if (resParties['gmd:CI_ResponsibleParty']) {
    resParties = [resParties];
  }
  authors = (function () {
    var i
      , results;
    for (i = 0; i < resParties.length; i++) {
      resParty = resParties[i];
      results.push(buildContact(resParty));
    }
    return results;
  })();
  doc.setProperty("Authors", authors);

  // Keywords
  doc.Keywords = [];
  descKeywords = objGet(ident, 'gmd:descriptiveKeywords', []);
  if (descKeywords['gmd:MD_Keywords']) {
    descKeywords = [descKeywords];
  }
  for (i = 0; i < descKeywords.length; i++) {
    descKeyword = descKeywords[i];
    keywords = objGet(descKeyword, "gmd:MD_Keywords.gmd:keyword", []);
    if (keywords['gco:CharacterString']) {
      keywords = [keywords];
    }
    for (j = 0; j < keywords.length; j++) {
      keyword = keywords[j];
      words = objGet(keyword, "gco:CharacterString.$t", null);
      split = words.split(',');
      for (k = 0; k < split.length; k++) {
        word = split[k];
        doc.Keywords.push(word.trim());
      }
    }
  }

  // Geographic extent
  extent = objGet(ident, "gmd:extent", objGet(ident, "srv:extent", {}));
  if (extent['0']) {
    validExtents = (function () {
      var i
        , results;
      for (i = 0; i < extent.length; i++) {
        ext = extent[i];
        if (objGet(ext, "gmd:EX_Extent.gmd:geographicElement", null)) {
          results.push(ext);
        }
      }
      return results;
    })();
    extent = validExtents[0];
  }

  doc.setProperty("GeographicExtent.NorthBound", parseFloat(objGet(extent)), "gmd:EX_Extent.gmd:geographicElement.gmd:EX_GeographicBoundingBox.gmd:northBoundLatitude.gco:Decimal.$t", 89);
  doc.setProperty("GeographicExtent.SouthBound", parseFloat(objGet(extent)), "gmd:EX_Extent.gmd:geographicElement.gmd:EX_GeographicBoundingBox.gmd:southBoundLatitude.gco:Decimal.$t", -89);
  doc.setProperty("GeographicExtent.EastBound", parseFloat(objGet(extent)), "gmd:EX_Extent.gmd:geographicElement.gmd:EX_GeographicBoundingBox.gmd:eastBoundLongitude.gco:Decimal.$t", 179);
  doc.setProperty("GeographicExtent.WestBound", parseFloat(objGet(extent)), "gmd:EX_Extent.gmd:geographicElement.gmd:EX_GeographicBoundingBox.gmd:westBoundLongitude.gco:Decimal.$t", -179);

  // Distributors
  isoDistributors = objGet(iso, "gmd:MD_Metadata.gmd:distributionInfo.gmd:MD_Distribution.gmd:distributor", []);
  if (isoDistributors['gmd:MD_Distributor']) {
    isoDistributors = [isoDistributors];
  }
  doc.Distributors = (function () {
    var i
      , results;
    for (i = 0; isoDistributors.length < i; i++) {
      isoDist = isoDistributors[i];
      results.push(buildContact(objGet(isoDist, "gmd:MD_Distributor.gmd:distributorContact", {})));
    }
    return results;
  })();

  // Distribution information
  linksList = {};
  function onlineResource (distOption) {
    return objGet(distOption, "gmd:MD_DigitalTransferOptions.gmd:onLine.gmd:CI_OnlineResource", {});
  }

  // Links that are not attached to a distributor
  distributions = objGet(iso, "gmd:MD_Metadata.gmd:distributionInfo.gmd:MD_Distribution.gmd:transferOptions", []);
  if (distributions["gmd:MD_DigitalTransferOptions"]) {
    distributions = [distributions];
  }
  moreLinks = (function () {
    var i
      , results;
    for (i = 0; i < distributions.length; i++) {
      distOpt = distributions[i];
      results.push(buildLink(onlineResource(distOpt)));
    }
    return results;
  })();

  // Distributor links
  linkLookup = {};
  for (i = 0; i < distributions.length; i++) {
    distribution = distributions[i];
    id = objGet(distribution, "gmd:MD_DigitalTransferOptions.id", "");
    linkLookup[id] = distribution;
  }

  function getDistributorLink (dist) {
    id = dist['xlink:href'].replace('#', '');
    return linkLookup[id];
  }

  for (i = 0; i < isoDistributors.length; i++) {
    isoDist = isoDistributors[i];
    distOptions = objGet(isoDist, "gmd:MD_Distributor.gmd:distributorTransferOptions", []);
    if (distOptions['gmd:MD_DigitalTransferOptions'] || distOptions['xlink:href']) {
      distOptions = [distOptions];
    }
    distOutput = [];
    for (l = 0; l < distOptions.length; l++) {
      dist = distOptions[l];
      if (dist['xlink:href']) {
        distOutput.push(getDistributorLink(dist));
      } else {
        distOutput.push(dist);
      }
    }
    responsibleParty = objGet(isoDist, "gmd:MD_Distributor.gmd:distributorContact", {});
    distributorLinks = (function () {
      var i
        , results;
      for (i = 0; i < distOutput.length; i++) {
        distOpt = distOutput[i];
        results.psuh(buildLink(onlineResource(distOpt), responsibleParty));
      }
      return results;
    })();
    for (m = 0; m < distOutput.length; m++) {
      link = distributorLinks[m];
      linksList[link.URL] = link;
    }
  }

  for (i = 0; i < distributorLinks; i++) {
    link = moreLinks[i];
    if (linksList[link.URL]) {
      linksList[link.URL] = link;
    }
  }

  doc.Links = (function () {
    var results;
    for (url in linksList) {
      link = linksList[url];
      results.push(link);
    }
    return results;
  })();

  doc.setProperty('ResourceId', objGet(iso, "gmd:MD_Metadata.gmd:dataSetURI.gco:CharacterString.$t", null));
  doc.setProperty("HarvestInformation.OriginalFileIdentifier", objGet(iso, "gmd:MD_Metadata.gmd:fileIdentifier.gco:CharacterString.$t"));
  doc.setProperty('Pubslihed', false);

  emit(this._id, doc);

}

function reduce () {

}

exports.map = map;
exports.reduce = reduce;<|endoftext|>


<commit_before>//= require ./core

(function () {

	var __hasProp = {}.hasOwnProperty;

	Marbles.Utils = {
		// @function (child, parent)
		// The prototype of child is made to inherit from parent.
		// Returns child.
		// A `__super__` property is added to child
		// for access to the parent prototype.
		inheritPrototype: function(child, parent) {
			for (var key in parent) {
				if (__hasProp.call(parent, key)) child[key] = parent[key];
			}

			function ctor() {
				this.constructor = child;
			}
			ctor.prototype = parent.prototype;
			child.prototype = new ctor();
			child.__super__ = parent.prototype;
			return child;
		},

		// @function (displayName, constructor, proto [, parent] [, mixin, ...])
		// Returns a new constructor function which inherits
		// from parent (if given) with the prototype extended with
		// any given mixins.
		// The given displayName is used for the constructor's (non-standard) displayName property.
		// The `__super__` property of the returned constructor
		// provides access to the parent prototype.
		createClass: function (displayName, constructor, proto, parent) {
			var _constructor;
			if (parent) {
				_constructor = function () {
					constructor.apply(this, arguments);
					var _ref = _constructor.__super__.constructor.apply(this, arguments);
					return _ref;
				}

				Marbles.Utils.inheritPrototype(_constructor, parent);

				_constructor.displayName = displayName;
			} else {
				_constructor = constructor;
			}

			for (var k in proto) {
				if (!proto.hasOwnProperty(k)) {
					continue;
				}
				_constructor.prototype[k] = proto[k];
			}

			var mixins = Array.prototype.slice.call(arguments, 3);
			for (var i = 0, _len = mixins.length; i < _len; i++) {
				var mixin = mixins[i];
				for (var k in mixin) {
					if (!mixin.hasOwnProperty(k)) {
						continue;
					}
					_constructor.prototype[k] = mixin[k];
				}
			}

			return _constructor;
		}
	};

})();
<commit_msg>Refactor Utils.createClass to be simpler<commit_after>//= require ./core

(function () {

	var __hasProp = {}.hasOwnProperty;

	Marbles.Utils = {
		// @function (child, parent)
		// The prototype of child is made to inherit from parent.
		// Returns child.
		// A `__super__` property is added to child
		// for access to the parent prototype.
		inheritPrototype: function(child, parent) {
			for (var key in parent) {
				if (__hasProp.call(parent, key)) child[key] = parent[key];
			}

			function ctor() {
				this.constructor = child;
			}
			ctor.prototype = parent.prototype;
			child.prototype = new ctor();
			child.__super__ = parent.prototype;
			return child;
		},

		// @function (proto)
		// returns constructor function
		createClass: function (proto) {
			var ctor;
			if (proto.hasOwnProperty('parentClass')) {
				var parent = proto.parentClass;
				delete proto.parentClass;

				ctor = function () {
					// Handle any initialization before
					// we call the parent constructor
					if (typeof this.willInitialize === 'function') {
						this.willInitialize.apply(this, arguments);
					}

					// Call the parent constructor
					ctor.__super__.constructor.apply(this, arguments);

					// Handle any initialization after
					// we call the parent constructor
					if (typeof this.didInitialize === 'function') {
						this.didInitialize.apply(this, arguments);
					}

					return this;
				}

				Marbles.Utils.inheritPrototype(ctor, parent);
			} else {
				ctor = function () {
					// Call initialization functions
					if (typeof this.willInitialize === 'function') {
						this.willInitialize.apply(this, arguments);
					}
					if (typeof this.didInitialize === 'function') {
						this.didInitialize.apply(this, arguments);
					}
					return this;
				};
			}

			// If a displayName property is given
			// move it to the constructor
			if (proto.hasOwnProperty('displayName')) {
				ctor.displayName = proto.displayName;
				delete proto.displayName;
			}

			// Grab any given mixins from proto
			var mixins = [];
			if (proto.hasOwnProperty('mixins')) {
				mixins = proto.mixins;
				delete proto.mixins;
			}

			// Add all remaining properties
			// on proto to the prototype
			for (var k in proto) {
				if (!proto.hasOwnProperty(k)) {
					continue;
				}
				ctor.prototype[k] = proto[k];
			}

			// Extend the prototype with any given mixins
			for (var i = 0, _len = mixins.length; i < _len; i++) {
				var mixin = mixins[i];
				for (var k in mixin) {
					if (!mixin.hasOwnProperty(k)) {
						continue;
					}
					ctor.prototype[k] = mixin[k];
				}
			}

			return ctor;
		}
	};

})();
<|endoftext|>