<commit_before>import React, { PureComponent } from 'react';
import ReactSelect from 'react-select';
import ReactCreatableSelect from 'react-select/creatable';
import PropTypes from 'prop-types';
import { IconCloseBadgedSmallFilled, IconChevronDownSmallOutline } from '@teamleader/ui-icons';
import Box, { omitBoxProps, pickBoxProps } from '../box';
import Icon from '../icon';
import ValidationText from '../validationText';
import { COLOR } from '../../constants';
import theme from './theme.css';
import cx from 'classnames';
import uiUtilities from '@teamleader/ui-utilities';

class Select extends PureComponent {
  getClearIndicatorStyles = base => {
    const { inverse } = this.props;

    return {
      ...base,
      color: inverse ? COLOR.TEAL.LIGHTEST : COLOR.TEAL.DARK,
      '&:hover': {
        color: inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
      },
      cursor: 'pointer',
      svg: {
        height: '14px',
        width: '14px',
      },
    };
  };

  getControlStyles = (base, { isDisabled, isFocused }) => {
    const { error, inverse, size, success, warning, width } = this.props;

    const commonStyles = {
      ...base,
      minHeight: size === 'small' ? '30px' : size === 'medium' ? '36px' : '48px',
      width,
    };

    if (inverse) {
      return {
        ...commonStyles,
        backgroundColor: isDisabled ? COLOR.TEAL.DARK : COLOR.TEAL.NORMAL,
        '&:hover': {
          borderColor: !isFocused && !error && !warning && !success && COLOR.TEAL.LIGHT,
        },
        borderColor: isFocused
          ? COLOR.TEAL.LIGHT
          : error
          ? COLOR.RUBY.LIGHT
          : warning
          ? COLOR.GOLD.LIGHT
          : success
          ? COLOR.MINT.LIGHT
          : isDisabled
          ? COLOR.TEAL.DARK
          : COLOR.TEAL.NORMAL,
        boxShadow: isFocused
          ? `0 0 0 1px ${COLOR.TEAL.LIGHT}`
          : error
          ? `0 0 0 1px ${COLOR.RUBY.LIGHT}`
          : warning
          ? `0 0 0 1px ${COLOR.GOLD.LIGHT}`
          : success
          ? `0 0 0 1px ${COLOR.MINT.LIGHT}`
          : 'none',
      };
    }

    return {
      ...commonStyles,
      backgroundColor: isDisabled ? COLOR.NEUTRAL.NORMAL : COLOR.NEUTRAL.LIGHTEST,
      '&:hover': {
        borderColor: !isFocused && !error && !warning && !success && COLOR.NEUTRAL.DARKEST,
      },
      borderColor: isFocused
        ? COLOR.NEUTRAL.DARKEST
        : error
        ? COLOR.RUBY.DARK
        : warning
        ? COLOR.GOLD.DARK
        : success
        ? COLOR.MINT.DARK
        : isDisabled
        ? COLOR.NEUTRAL.NORMAL
        : COLOR.NEUTRAL.DARK,
      boxShadow: isFocused
        ? `0 0 0 1px ${COLOR.NEUTRAL.DARKEST}`
        : error
        ? `0 0 0 1px ${COLOR.RUBY.DARK}`
        : warning
        ? `0 0 0 1px ${COLOR.GOLD.DARK}`
        : success
        ? `0 0 0 1px ${COLOR.MINT.DARK}`
        : 'none',
    };
  };

  getGroupStyles = base => {
    const { inverse } = this.props;

    return {
      ...base,
      borderBottomColor: inverse ? COLOR.TEAL.LIGHT : COLOR.NEUTRAL.NORMAL,
      borderBottomStyle: 'solid',
      borderBottomWidth: '1px',
      '&:last-child': {
        borderWidth: 0,
      },
    };
  };

  getGroupHeadingStyles = base => {
    const { inverse } = this.props;

    return {
      ...base,
      color: inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
      fontSize: '12px',
      fontWeight: '700',
      letterSpacing: '0.6px',
    };
  };

  getInput = base => {
    const { size, value } = this.props;

    return {
      ...base,
      marginLeft: value && value.length === 0 && size !== 'large' ? '6px' : '2px',
    };
  };

  getMenuPortalStyles = base => {
    const { inverse } = this.props;

    return {
      ...base,
      backgroundColor: inverse ? COLOR.TEAL.NORMAL : COLOR.NEUTRAL.LIGHTEST,
      fontFamily: 'Inter-UI-Regular',
      fontSize: '14px',
      fontSmoothing: 'antialiased',
      MozOsxFontSmoothing: 'grayscale',
      WebkitFontSmoothing: 'antialiased',
      zIndex: 500,
    };
  };

  getMultiValueStyles = base => {
    const { inverse } = this.props;

    return {
      ...base,
      borderColor: inverse ? COLOR.TEAL.DARK : COLOR.NEUTRAL.NORMAL,
      borderStyle: 'solid',
      borderWidth: '1px',
      borderRadius: '4px',
      margin: '1px',
    };
  };

  getMultiValueLabelStyles = base => {
    const { inverse, size } = this.props;

    return {
      ...base,
      backgroundColor: inverse ? COLOR.TEAL.DARK : COLOR.NEUTRAL.LIGHT,
      borderRadius: 0,
      color: inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
      fontFamily: 'Inter-UI-Medium',
      fontSize: size === 'small' ? '12px' : '14px',
      lineHeight: size === 'small' ? '1' : '18px',
      padding: size === 'large' ? '9px' : '6px',
    };
  };

  getMultiValueRemoveStyles = base => {
    const { inverse } = this.props;

    return {
      ...base,
      backgroundColor: inverse ? COLOR.TEAL.DARK : COLOR.NEUTRAL.LIGHT,
      borderRadius: 0,
      color: inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
      '&:hover': {
        backgroundColor: inverse ? COLOR.TEAL.DARKEST : COLOR.NEUTRAL.NORMAL,
        color: inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
      },
      paddingLeft: '6px',
      paddingRight: '6px',
      transition: 'background-color .35s cubic-bezier(.4, 0, .2, 1)',
    };
  };

  getOptionStyles = (base, { isDisabled, isFocused, isSelected }) => {
    const commonStyles = {
      ...base,
      wordBreak: 'break-all',
      padding: '8px 12px',
    };

    if (this.props.inverse) {
      return {
        ...commonStyles,
        color: isDisabled
          ? COLOR.TEAL.LIGHT
          : isSelected
          ? COLOR.NEUTRAL.LIGHTEST
          : isFocused
          ? COLOR.TEAL.DARK
          : COLOR.NEUTRAL.LIGHTEST,
        backgroundColor: isSelected ? COLOR.TEAL.DARK : isFocused ? COLOR.TEAL.LIGHT : COLOR.TEAL.NORMAL,
        '&:active': {
          backgroundColor: isDisabled ? COLOR.TEAL.NORMAL : COLOR.TEAL.DARK,
          color: isDisabled ? COLOR.TEAL.LIGHT : COLOR.NEUTRAL.LIGHTEST,
        },
      };
    }

    return {
      ...commonStyles,
      color: isDisabled ? COLOR.NEUTRAL.DARK : COLOR.TEAL.DARK,
      backgroundColor: isSelected ? COLOR.AQUA.LIGHTEST : isFocused ? COLOR.NEUTRAL.LIGHT : COLOR.NEUTRAL.LIGHTEST,
      '&:active': {
        backgroundColor: isDisabled ? COLOR.NEUTRAL.LIGHTEST : COLOR.AQUA.LIGHTEST,
        color: isDisabled ? COLOR.NEUTRAL.DARK : COLOR.TEAL.DARK,
      },
    };
  };

  getPlaceholderStyles = (base, { isDisabled, isMulti }) => {
    const { inverse, size } = this.props;

    const commonStyles = {
      ...base,
      marginLeft: isMulti && size !== 'large' ? '6px' : '2px',
      marginRight: isMulti && size !== 'large' ? '6px' : '2px',
      whiteSpace: 'nowrap',
    };

    if (inverse) {
      return {
        ...commonStyles,
        color: isDisabled ? COLOR.TEAL.NORMAL : COLOR.TEAL.LIGHT,
      };
    }

    return {
      ...commonStyles,
      color: COLOR.NEUTRAL.DARKEST,
    };
  };

  getSingleValueStyles = base => ({
    ...base,
    color: this.props.inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
  });

  getValueContainerStyles = (base, { isMulti }) => {
    const { size } = this.props;

    return {
      ...base,
      minHeight: size === 'small' ? '28px' : size === 'medium' ? '34px' : '46px',
      padding: isMulti && size !== 'large' ? '0' : '0 4px',
    };
  };

  getStyles = () => ({
    clearIndicator: this.getClearIndicatorStyles,
    control: this.getControlStyles,
    group: this.getGroupStyles,
    groupHeading: this.getGroupHeadingStyles,
    input: this.getInput,
    menuPortal: this.getMenuPortalStyles,
    multiValue: this.getMultiValueStyles,
    multiValueLabel: this.getMultiValueLabelStyles,
    multiValueRemove: this.getMultiValueRemoveStyles,
    option: this.getOptionStyles,
    placeholder: this.getPlaceholderStyles,
    singleValue: this.getSingleValueStyles,
    valueContainer: this.getValueContainerStyles,
  });

  getClearIndicator = () => ({ innerProps }) => {
    const { inverse } = this.props;

    return (
      <Icon color={inverse ? 'teal' : 'neutral'} display="flex" tint={inverse ? 'lightest' : 'darkest'} {...innerProps}>
        <IconCloseBadgedSmallFilled />
      </Icon>
    );
  };

  getDropDownIndicator = () => () => {
    const { inverse } = this.props;

    return (
      <Icon
        alignItems="center"
        className={theme['dropdown-indicator']}
        color={inverse ? 'teal' : 'neutral'}
        display="flex"
        justifyContent="center"
        tint={inverse ? 'lightest' : 'darkest'}
      >
        <IconChevronDownSmallOutline />
      </Icon>
    );
  };

  render() {
    const { components, creatable, error, inverse, helpText, size, success, warning, ...otherProps } = this.props;

    const boxProps = pickBoxProps(otherProps);
    const restProps = omitBoxProps(otherProps);

    const wrapperClassnames = cx(theme[`is-${size}`], {
      [theme['has-error']]: error,
      [theme['is-inverse']]: inverse,
    });

    const Element = creatable ? ReactCreatableSelect : ReactSelect;

    return (
      <Box className={wrapperClassnames} {...boxProps}>
        <Element
          className={cx(uiUtilities['reset-font-smoothing'], theme['select'])}
          components={{
            ClearIndicator: this.getClearIndicator(),
            DropdownIndicator: this.getDropDownIndicator(),
            IndicatorSeparator: null,
            ...components,
          }}
          styles={this.getStyles()}
          {...restProps}
        />
        <ValidationText error={error} help={helpText} inverse={inverse} success={success} warning={warning} />
      </Box>
    );
  }
}

Select.propTypes = {
  /** Override default components with your own. Pass an object with correct the key and its replacing component */
  components: PropTypes.object,
  /** If true, it's possible to create a new option that is not in the list. */
  creatable: PropTypes.bool,
  /** The text string/element to use as error message below the input. */
  error: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
  /** The text string to use as help text below the input. */
  helpText: PropTypes.string,
  /** Boolean indicating whether the select should render as inverse. */
  inverse: PropTypes.bool,
  /** The HTML DOM node on which the portal should append */
  menuPortalTarget: PropTypes.instanceOf(Element),
  /** Size of the input element. */
  size: PropTypes.oneOf(['small', 'medium', 'large']),
  /** The text string/element to use as success message below the input. */
  success: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
  /** Selected option value(s) */
  value: PropTypes.oneOfType([PropTypes.object, PropTypes.array, PropTypes.func]),
  /** The text to use as warning message below the input. */
  warning: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
  /** A custom width for the input field */
  width: PropTypes.string,
};

Select.defaultProps = {
  creatable: false,
  inverse: false,
  menuPortalTarget: document.body,
  size: 'medium',
  width: '100%',
};

export default Select;
<commit_msg>Select: use Inter istead of Inter-UI fonts<commit_after>import React, { PureComponent } from 'react';
import ReactSelect from 'react-select';
import ReactCreatableSelect from 'react-select/creatable';
import PropTypes from 'prop-types';
import { IconCloseBadgedSmallFilled, IconChevronDownSmallOutline } from '@teamleader/ui-icons';
import Box, { omitBoxProps, pickBoxProps } from '../box';
import Icon from '../icon';
import ValidationText from '../validationText';
import { COLOR } from '../../constants';
import theme from './theme.css';
import cx from 'classnames';
import uiUtilities from '@teamleader/ui-utilities';

class Select extends PureComponent {
  getClearIndicatorStyles = base => {
    const { inverse } = this.props;

    return {
      ...base,
      color: inverse ? COLOR.TEAL.LIGHTEST : COLOR.TEAL.DARK,
      '&:hover': {
        color: inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
      },
      cursor: 'pointer',
      svg: {
        height: '14px',
        width: '14px',
      },
    };
  };

  getControlStyles = (base, { isDisabled, isFocused }) => {
    const { error, inverse, size, success, warning, width } = this.props;

    const commonStyles = {
      ...base,
      minHeight: size === 'small' ? '30px' : size === 'medium' ? '36px' : '48px',
      width,
    };

    if (inverse) {
      return {
        ...commonStyles,
        backgroundColor: isDisabled ? COLOR.TEAL.DARK : COLOR.TEAL.NORMAL,
        '&:hover': {
          borderColor: !isFocused && !error && !warning && !success && COLOR.TEAL.LIGHT,
        },
        borderColor: isFocused
          ? COLOR.TEAL.LIGHT
          : error
          ? COLOR.RUBY.LIGHT
          : warning
          ? COLOR.GOLD.LIGHT
          : success
          ? COLOR.MINT.LIGHT
          : isDisabled
          ? COLOR.TEAL.DARK
          : COLOR.TEAL.NORMAL,
        boxShadow: isFocused
          ? `0 0 0 1px ${COLOR.TEAL.LIGHT}`
          : error
          ? `0 0 0 1px ${COLOR.RUBY.LIGHT}`
          : warning
          ? `0 0 0 1px ${COLOR.GOLD.LIGHT}`
          : success
          ? `0 0 0 1px ${COLOR.MINT.LIGHT}`
          : 'none',
      };
    }

    return {
      ...commonStyles,
      backgroundColor: isDisabled ? COLOR.NEUTRAL.NORMAL : COLOR.NEUTRAL.LIGHTEST,
      '&:hover': {
        borderColor: !isFocused && !error && !warning && !success && COLOR.NEUTRAL.DARKEST,
      },
      borderColor: isFocused
        ? COLOR.NEUTRAL.DARKEST
        : error
        ? COLOR.RUBY.DARK
        : warning
        ? COLOR.GOLD.DARK
        : success
        ? COLOR.MINT.DARK
        : isDisabled
        ? COLOR.NEUTRAL.NORMAL
        : COLOR.NEUTRAL.DARK,
      boxShadow: isFocused
        ? `0 0 0 1px ${COLOR.NEUTRAL.DARKEST}`
        : error
        ? `0 0 0 1px ${COLOR.RUBY.DARK}`
        : warning
        ? `0 0 0 1px ${COLOR.GOLD.DARK}`
        : success
        ? `0 0 0 1px ${COLOR.MINT.DARK}`
        : 'none',
    };
  };

  getGroupStyles = base => {
    const { inverse } = this.props;

    return {
      ...base,
      borderBottomColor: inverse ? COLOR.TEAL.LIGHT : COLOR.NEUTRAL.NORMAL,
      borderBottomStyle: 'solid',
      borderBottomWidth: '1px',
      '&:last-child': {
        borderWidth: 0,
      },
    };
  };

  getGroupHeadingStyles = base => {
    const { inverse } = this.props;

    return {
      ...base,
      color: inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
      fontSize: '12px',
      fontWeight: '700',
      letterSpacing: '0.6px',
    };
  };

  getInput = base => {
    const { size, value } = this.props;

    return {
      ...base,
      marginLeft: value && value.length === 0 && size !== 'large' ? '6px' : '2px',
    };
  };

  getMenuPortalStyles = base => {
    const { inverse } = this.props;

    return {
      ...base,
      backgroundColor: inverse ? COLOR.TEAL.NORMAL : COLOR.NEUTRAL.LIGHTEST,
      fontFamily: 'Inter-Regular',
      fontSize: '14px',
      fontSmoothing: 'antialiased',
      MozOsxFontSmoothing: 'grayscale',
      WebkitFontSmoothing: 'antialiased',
      zIndex: 500,
    };
  };

  getMultiValueStyles = base => {
    const { inverse } = this.props;

    return {
      ...base,
      borderColor: inverse ? COLOR.TEAL.DARK : COLOR.NEUTRAL.NORMAL,
      borderStyle: 'solid',
      borderWidth: '1px',
      borderRadius: '4px',
      margin: '1px',
    };
  };

  getMultiValueLabelStyles = base => {
    const { inverse, size } = this.props;

    return {
      ...base,
      backgroundColor: inverse ? COLOR.TEAL.DARK : COLOR.NEUTRAL.LIGHT,
      borderRadius: 0,
      color: inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
      fontFamily: 'Inter-Medium',
      fontSize: size === 'small' ? '12px' : '14px',
      lineHeight: size === 'small' ? '1' : '18px',
      padding: size === 'large' ? '9px' : '6px',
    };
  };

  getMultiValueRemoveStyles = base => {
    const { inverse } = this.props;

    return {
      ...base,
      backgroundColor: inverse ? COLOR.TEAL.DARK : COLOR.NEUTRAL.LIGHT,
      borderRadius: 0,
      color: inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
      '&:hover': {
        backgroundColor: inverse ? COLOR.TEAL.DARKEST : COLOR.NEUTRAL.NORMAL,
        color: inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
      },
      paddingLeft: '6px',
      paddingRight: '6px',
      transition: 'background-color .35s cubic-bezier(.4, 0, .2, 1)',
    };
  };

  getOptionStyles = (base, { isDisabled, isFocused, isSelected }) => {
    const commonStyles = {
      ...base,
      wordBreak: 'break-all',
      padding: '8px 12px',
    };

    if (this.props.inverse) {
      return {
        ...commonStyles,
        color: isDisabled
          ? COLOR.TEAL.LIGHT
          : isSelected
          ? COLOR.NEUTRAL.LIGHTEST
          : isFocused
          ? COLOR.TEAL.DARK
          : COLOR.NEUTRAL.LIGHTEST,
        backgroundColor: isSelected ? COLOR.TEAL.DARK : isFocused ? COLOR.TEAL.LIGHT : COLOR.TEAL.NORMAL,
        '&:active': {
          backgroundColor: isDisabled ? COLOR.TEAL.NORMAL : COLOR.TEAL.DARK,
          color: isDisabled ? COLOR.TEAL.LIGHT : COLOR.NEUTRAL.LIGHTEST,
        },
      };
    }

    return {
      ...commonStyles,
      color: isDisabled ? COLOR.NEUTRAL.DARK : COLOR.TEAL.DARK,
      backgroundColor: isSelected ? COLOR.AQUA.LIGHTEST : isFocused ? COLOR.NEUTRAL.LIGHT : COLOR.NEUTRAL.LIGHTEST,
      '&:active': {
        backgroundColor: isDisabled ? COLOR.NEUTRAL.LIGHTEST : COLOR.AQUA.LIGHTEST,
        color: isDisabled ? COLOR.NEUTRAL.DARK : COLOR.TEAL.DARK,
      },
    };
  };

  getPlaceholderStyles = (base, { isDisabled, isMulti }) => {
    const { inverse, size } = this.props;

    const commonStyles = {
      ...base,
      marginLeft: isMulti && size !== 'large' ? '6px' : '2px',
      marginRight: isMulti && size !== 'large' ? '6px' : '2px',
      whiteSpace: 'nowrap',
    };

    if (inverse) {
      return {
        ...commonStyles,
        color: isDisabled ? COLOR.TEAL.NORMAL : COLOR.TEAL.LIGHT,
      };
    }

    return {
      ...commonStyles,
      color: COLOR.NEUTRAL.DARKEST,
    };
  };

  getSingleValueStyles = base => ({
    ...base,
    color: this.props.inverse ? COLOR.NEUTRAL.LIGHTEST : COLOR.TEAL.DARKEST,
  });

  getValueContainerStyles = (base, { isMulti }) => {
    const { size } = this.props;

    return {
      ...base,
      minHeight: size === 'small' ? '28px' : size === 'medium' ? '34px' : '46px',
      padding: isMulti && size !== 'large' ? '0' : '0 4px',
    };
  };

  getStyles = () => ({
    clearIndicator: this.getClearIndicatorStyles,
    control: this.getControlStyles,
    group: this.getGroupStyles,
    groupHeading: this.getGroupHeadingStyles,
    input: this.getInput,
    menuPortal: this.getMenuPortalStyles,
    multiValue: this.getMultiValueStyles,
    multiValueLabel: this.getMultiValueLabelStyles,
    multiValueRemove: this.getMultiValueRemoveStyles,
    option: this.getOptionStyles,
    placeholder: this.getPlaceholderStyles,
    singleValue: this.getSingleValueStyles,
    valueContainer: this.getValueContainerStyles,
  });

  getClearIndicator = () => ({ innerProps }) => {
    const { inverse } = this.props;

    return (
      <Icon color={inverse ? 'teal' : 'neutral'} display="flex" tint={inverse ? 'lightest' : 'darkest'} {...innerProps}>
        <IconCloseBadgedSmallFilled />
      </Icon>
    );
  };

  getDropDownIndicator = () => () => {
    const { inverse } = this.props;

    return (
      <Icon
        alignItems="center"
        className={theme['dropdown-indicator']}
        color={inverse ? 'teal' : 'neutral'}
        display="flex"
        justifyContent="center"
        tint={inverse ? 'lightest' : 'darkest'}
      >
        <IconChevronDownSmallOutline />
      </Icon>
    );
  };

  render() {
    const { components, creatable, error, inverse, helpText, size, success, warning, ...otherProps } = this.props;

    const boxProps = pickBoxProps(otherProps);
    const restProps = omitBoxProps(otherProps);

    const wrapperClassnames = cx(theme[`is-${size}`], {
      [theme['has-error']]: error,
      [theme['is-inverse']]: inverse,
    });

    const Element = creatable ? ReactCreatableSelect : ReactSelect;

    return (
      <Box className={wrapperClassnames} {...boxProps}>
        <Element
          className={cx(uiUtilities['reset-font-smoothing'], theme['select'])}
          components={{
            ClearIndicator: this.getClearIndicator(),
            DropdownIndicator: this.getDropDownIndicator(),
            IndicatorSeparator: null,
            ...components,
          }}
          styles={this.getStyles()}
          {...restProps}
        />
        <ValidationText error={error} help={helpText} inverse={inverse} success={success} warning={warning} />
      </Box>
    );
  }
}

Select.propTypes = {
  /** Override default components with your own. Pass an object with correct the key and its replacing component */
  components: PropTypes.object,
  /** If true, it's possible to create a new option that is not in the list. */
  creatable: PropTypes.bool,
  /** The text string/element to use as error message below the input. */
  error: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
  /** The text string to use as help text below the input. */
  helpText: PropTypes.string,
  /** Boolean indicating whether the select should render as inverse. */
  inverse: PropTypes.bool,
  /** The HTML DOM node on which the portal should append */
  menuPortalTarget: PropTypes.instanceOf(Element),
  /** Size of the input element. */
  size: PropTypes.oneOf(['small', 'medium', 'large']),
  /** The text string/element to use as success message below the input. */
  success: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
  /** Selected option value(s) */
  value: PropTypes.oneOfType([PropTypes.object, PropTypes.array, PropTypes.func]),
  /** The text to use as warning message below the input. */
  warning: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
  /** A custom width for the input field */
  width: PropTypes.string,
};

Select.defaultProps = {
  creatable: false,
  inverse: false,
  menuPortalTarget: document.body,
  size: 'medium',
  width: '100%',
};

export default Select;
<|endoftext|>


<commit_before>let isIE = navigator.userAgent.toLowerCase().indexOf("msie") !== -1

let _splitNodes = function([node, ...remains]) {
  if (typeof(node) === "undefined") {
    return [[],[]]
  }
  var [textNodes, elNodes] = _splitNodes(remains)
  let isText = node.nodeType === 3
  if ( isText ) {
    textNodes.push(node)
  } else {
    let isIgnored = node.getAttribute('data-no-enterplz')
    let isPreformatted = node.nodeName === 'PRE'
    let isAlreadyDone = node.getAttribute('data-word') === ''

    if ( !isIgnored && !isPreformatted && !isAlreadyDone ) {
      elNodes.push(node)
    }
  }
  return [textNodes, elNodes]
}

let traverse = function(parent) {
  var [textNodes, elNodes] = _splitNodes(parent.childNodes)
  for (var child of textNodes) {
    console.log(child.textContent)
  }
  for (var child of elNodes) {
    traverse(child)
  }
}

export default {
  run: function(options) {
    options = options || {};
    let rootNode = options.include || document.body
    if (isIE) { rootNode.style.wordBreak = 'keep-all'; }
    else {
      traverse(rootNode);
    }
  }
}
<commit_msg>works well<commit_after>let isIE = (() => {
  var isIE11 = navigator.userAgent.indexOf(".NET CLR") > -1;
  var isIE11orLess = isIE11 || navigator.appVersion.indexOf("MSIE") != -1;
  return isIE11orLess;
})()

let _splitNodes = function([node, ...remains]) {
  if (typeof(node) === "undefined") {
    return [[],[]]
  }
  var [textNodes, elNodes] = _splitNodes(remains)
  let isText = node.nodeType === 3
  if ( isText ) {
    textNodes.push(node)
  } else {
    let isIgnored = node.getAttribute('data-no-enterplz') === ''
    let isPreformatted = node.nodeName === 'PRE'
    let isAlreadyDone = node.getAttribute('data-word') === ''
    if ( !isIgnored && !isPreformatted && !isAlreadyDone ) {
      elNodes.push(node)
    }
  }
  return [textNodes, elNodes]
}

let makeWord = (text) => {
  var span = document.createElement('span')
  span.style.whiteSpace = 'nowrap'
  span.setAttribute('data-word', '')
  span.appendChild(document.createTextNode(text))
  return span
}

let makeBlank = () => document.createTextNode(' ')

let traverse = function(parent) {
  var [textNodes, elNodes] = _splitNodes(parent.childNodes)
  for (var child of textNodes) {
    console.log(child.textContent)
    for (var text of child.textContent.split(/\s/).filter((t) => t !== "")) {
      var word = makeWord(text)
      var blank = makeBlank()
      parent.insertBefore(word, child)
      parent.insertBefore(blank, child)
    }
    child.remove()
  }
  for (var child of elNodes) {
    traverse(child)
  }
}

export default {
  run: function(options) {
    options = options || {};
    let rootNode = options.include || document.body
    if (isIE) { rootNode.style.wordBreak = 'keep-all'; }
    else {
      traverse(rootNode);
    }
  }
}
<|endoftext|>


<commit_before>"use strict";
(function(fixtures){
    if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {
        // NodeJS
        module.exports = fixtures;
    } else if (typeof define === 'function' && define.amd){
        define(function(){
            return fixtures;
        });
    } else{
        var global = (false || eval)('this');
        global.fixtures = fixtures;
    }

}(new function(){
        var fixturesCache = {};
        var self = this;

        self.containerId = 'js-fixtures';
        self.path = 'spec/javascripts/fixtures';
        self.window = function(){
            var iframe = document.getElementById(self.containerId);
            if (!iframe) return null;

            return iframe.contentWindow || iframe.contentDocument;
        };
        self.body = function(){
            if (!self.window()) return null;

            var content = self.window().document.body.innerHTML;
            return content;
        };
        self.load = function(html){
            var cb = typeof arguments[arguments.length - 1] === 'function' ? arguments[arguments.length -1] : null;
            addToContainer(self.read.apply(self, arguments), cb);
        };
        self.set = function(html){
            addToContainer(html);
        };
        self.cache = function(){
            self.read.apply(self, arguments);
        };
        self.sandbox = function(obj){
            addToContainer(objToHTML(obj));
        };
        self.read = function(){
            var htmlChunks = '';

            Array.prototype.slice.call(arguments, 0).forEach(function(argument){
                if (typeof argument === 'string') htmlChunks += getFixtureHtml(argument);
            });
            return htmlChunks;
        };
        self.clearCache = function(){
            fixturesCache = {};
        };
        self.cleanUp = function(){
            var iframe = document.getElementById(self.containerId);
            if(!iframe) return null;

            iframe.parentNode.removeChild(iframe);
        };
        var createContainer  = function(html){
            var cb = typeof arguments[arguments.length - 1] === 'function' ? arguments[arguments.length -1] : null;
            var iframe = document.createElement('iframe');
            iframe.setAttribute('id', self.containerId);
            iframe.style.opacity = 0;
            iframe.style.filter = 'alpha(0)';

            document.body.appendChild(iframe);
            var doc = iframe.contentWindow || iframe.contentDocument;
            doc = doc.document ? doc.document : doc;

            if (cb){
                var iframeReady = setInterval(function(){
                    if (doc.readyState === 'complete'){
                        clearInterval(iframeReady);
                        cb();
                    }
                }, 0);
            }

            doc.open();
            doc.defaultView.onerror = captureErrors;
            doc.write(html);
            doc.close();
        };
        var addToContainer = function(html, cb){
            var container = document.getElementById(self.containerId);
            if (!container) createContainer.apply(self, arguments);
            else self.window().document.body.innerHTML += html;
        };
        var captureErrors = function(){
            if (window.onerror){
                // Rewrite the message prefix to indicate that the error
                // occurred in the fixture.
                arguments[0] = arguments[0].replace(/^[^:]*/, "Uncaught fixture error");
                window.onerror.apply(window, arguments);
            }
            return true;
        };
        var getFixtureHtml = function(url){
            if (typeof fixturesCache[url] === 'undefined'){
                loadFixtureIntoCache(url);
            }
            return fixturesCache[url];
        };
        var loadFixtureIntoCache = function(relativeUrl){
            var url = makeFixtureUrl(relativeUrl);
            var request = new XMLHttpRequest();
            request.open('GET', url + '?' + new Date().getTime(), false);
            request.send(null);
            fixturesCache[relativeUrl] = request.responseText;
        };
        var makeFixtureUrl = function(relativeUrl){
            return self.path.match('/$') ? self.path + relativeUrl : self.path + '/' + relativeUrl;
        };
        var objToHTML = function(obj){
            var divElem = document.createElement('div');
            for (var key in obj){
                if (key === 'class'){ // IE < 9 compatibility
                    divElem.className = obj[key];
                    continue;
                }
                divElem.setAttribute(key, obj[key]);
            }
            return divElem.outerHTML;
        };
    }
));
<commit_msg>doc.defaultView doesn't work in IE8. Add fallback to parentWindow for that case<commit_after>"use strict";
(function(fixtures){
    if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {
        // NodeJS
        module.exports = fixtures;
    } else if (typeof define === 'function' && define.amd){
        define(function(){
            return fixtures;
        });
    } else{
        var global = (false || eval)('this');
        global.fixtures = fixtures;
    }

}(new function(){
        var fixturesCache = {};
        var self = this;

        self.containerId = 'js-fixtures';
        self.path = 'spec/javascripts/fixtures';
        self.window = function(){
            var iframe = document.getElementById(self.containerId);
            if (!iframe) return null;

            return iframe.contentWindow || iframe.contentDocument;
        };
        self.body = function(){
            if (!self.window()) return null;

            var content = self.window().document.body.innerHTML;
            return content;
        };
        self.load = function(html){
            var cb = typeof arguments[arguments.length - 1] === 'function' ? arguments[arguments.length -1] : null;
            addToContainer(self.read.apply(self, arguments), cb);
        };
        self.set = function(html){
            addToContainer(html);
        };
        self.cache = function(){
            self.read.apply(self, arguments);
        };
        self.sandbox = function(obj){
            addToContainer(objToHTML(obj));
        };
        self.read = function(){
            var htmlChunks = '';

            Array.prototype.slice.call(arguments, 0).forEach(function(argument){
                if (typeof argument === 'string') htmlChunks += getFixtureHtml(argument);
            });
            return htmlChunks;
        };
        self.clearCache = function(){
            fixturesCache = {};
        };
        self.cleanUp = function(){
            var iframe = document.getElementById(self.containerId);
            if(!iframe) return null;

            iframe.parentNode.removeChild(iframe);
        };
        var createContainer  = function(html){
            var cb = typeof arguments[arguments.length - 1] === 'function' ? arguments[arguments.length -1] : null;
            var iframe = document.createElement('iframe');
            iframe.setAttribute('id', self.containerId);
            iframe.style.opacity = 0;
            iframe.style.filter = 'alpha(0)';

            document.body.appendChild(iframe);
            var doc = iframe.contentWindow || iframe.contentDocument;
            doc = doc.document ? doc.document : doc;

            if (cb){
                var iframeReady = setInterval(function(){
                    if (doc.readyState === 'complete'){
                        clearInterval(iframeReady);
                        cb();
                    }
                }, 0);
            }

            doc.open();
            doc['defaultView' in doc ? 'defaultView' : 'parentWindow'].onerror = captureErrors;
            doc.write(html);
            doc.close();
        };
        var addToContainer = function(html, cb){
            var container = document.getElementById(self.containerId);
            if (!container) createContainer.apply(self, arguments);
            else self.window().document.body.innerHTML += html;
        };
        var captureErrors = function(){
            if (window.onerror){
                // Rewrite the message prefix to indicate that the error
                // occurred in the fixture.
                arguments[0] = arguments[0].replace(/^[^:]*/, "Uncaught fixture error");
                window.onerror.apply(window, arguments);
            }
            return true;
        };
        var getFixtureHtml = function(url){
            if (typeof fixturesCache[url] === 'undefined'){
                loadFixtureIntoCache(url);
            }
            return fixturesCache[url];
        };
        var loadFixtureIntoCache = function(relativeUrl){
            var url = makeFixtureUrl(relativeUrl);
            var request = new XMLHttpRequest();
            request.open('GET', url + '?' + new Date().getTime(), false);
            request.send(null);
            fixturesCache[relativeUrl] = request.responseText;
        };
        var makeFixtureUrl = function(relativeUrl){
            return self.path.match('/$') ? self.path + relativeUrl : self.path + '/' + relativeUrl;
        };
        var objToHTML = function(obj){
            var divElem = document.createElement('div');
            for (var key in obj){
                if (key === 'class'){ // IE < 9 compatibility
                    divElem.className = obj[key];
                    continue;
                }
                divElem.setAttribute(key, obj[key]);
            }
            return divElem.outerHTML;
        };
    }
));
<|endoftext|>


<commit_before>'use strict';

function fizzBuzz(input) {
  var output = [];

  for(var i in input) {
    if ((input[i] % 3 == 0) && (input[i] % 5 == 0)) {
      output.push('FizzBuzz')
    } else if (input[i] % 3 == 0) {
      output.push('Fizz');
    } else if (input[i] % 5 == 0) {
      output.push('Buzz');
    } else {
      output.push(input[i]);
    }
  }

  return output.join(' ');
}

function fizzBuzzBazz(input) {
  var output = [];

  for(var i in input) {
    if ((input[i] % 3 == 0) && (input[i] % 5 == 0)) {
      output.push('FizzBuzz')
    } else if (input[i] % 3 == 0) {
      output.push('Fizz');
    } else if (input[i] % 5 == 0) {
      output.push('Buzz');
    } else if (input[i-1] && input[i-2] && ((input[i-1] % 5 == 0 || input[i-1] % 3 == 0) && (input[i-2] % 5 == 0 || input[i-2] % 3 == 0))) {
      output.push('Bazz');
    } else {
      output.push(input[i]);
    }
  }

  return output.join(' ');
}

function assert(condition, test) {
  var type = condition ? "PASS" : "FAIL";
  console.log(type + " >>> " + test);
}

function assertEqual(condition, test) {
  var output = condition == test ? "PASS" : "FAIL";

  if (output == "FAIL") {
    output += " >>> expecting \"" + condition + "\", \"" + test + "\" given";
  }

  console.log(output);
}

assertEqual(fizzBuzz([12, 13, 14, 15, 16]), 'Fizz 13 14 FizzBuzz 16');
assertEqual(fizzBuzz([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), '1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz');
assertEqual(fizzBuzz([45, 46, 47, 48, 49, 50]), 'FizzBuzz 46 47 Fizz 49 Buzz');

assertEqual(fizzBuzzBazz([4, 5, 6, 7, 8, 9, 10, 11]), '4 Buzz Fizz Bazz 8 Fizz Buzz Bazz');
assertEqual(fizzBuzzBazz([18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]), 'Fizz 19 Buzz Fizz Bazz 23 Fizz Buzz Bazz Fizz 28 29 FizzBuzz');
//assertEqual(fizzBuzzBazz([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), '1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz');
//assertEqual(fizzBuzzBazz([45, 46, 47, 48, 49, 50]), 'FizzBuzz 46 47 Fizz 49 Buzz');

//console.log(fizzBuzzBazz([4, 5, 6, 7, 8]));<commit_msg>minor improvement<commit_after>'use strict';

function fizzBuzz(input) {
  var output = [];
  var _output;

  for(var i in input) {
    if ((input[i] % 3 == 0) && (input[i] % 5 == 0)) {
      _output = 'FizzBuzz';
    } else if (input[i] % 3 == 0) {
      _output = 'Fizz';
    } else if (input[i] % 5 == 0) {
      _output = 'Buzz';
    } else {
      _output = input[i];
    }

    output.push(_output);
  }

  return output.join(' ');
}

function fizzBuzzBazz(input) {
  var output = [];
  var _output;

  for(var i in input) {
    if ((input[i] % 3 == 0) && (input[i] % 5 == 0)) {
      _output = 'FizzBuzz';
    } else if (input[i] % 3 == 0) {
      _output = 'Fizz';
    } else if (input[i] % 5 == 0) {
      _output = 'Buzz';
    } else if (input[i-1] && input[i-2] && ((input[i-1] % 5 == 0 || input[i-1] % 3 == 0) && (input[i-2] % 5 == 0 || input[i-2] % 3 == 0))) {
      _output = 'Bazz';
    } else {
      _output = input[i];
    }

    output.push(_output);
  }

  return output.join(' ');
}

function assert(condition, test) {
  var type = condition ? "PASS" : "FAIL";
  console.log(type + " >>> " + test);
}

function assertEqual(condition, test) {
  var output = condition == test ? "PASS" : "FAIL";

  if (output == "FAIL") {
    output += " >>> expecting \"" + condition + "\", \"" + test + "\" given";
  }

  console.log(output);
}

assertEqual(fizzBuzz([12, 13, 14, 15, 16]), 'Fizz 13 14 FizzBuzz 16');
assertEqual(fizzBuzz([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), '1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz');
assertEqual(fizzBuzz([45, 46, 47, 48, 49, 50]), 'FizzBuzz 46 47 Fizz 49 Buzz');

assertEqual(fizzBuzzBazz([4, 5, 6, 7, 8, 9, 10, 11]), '4 Buzz Fizz Bazz 8 Fizz Buzz Bazz');
assertEqual(fizzBuzzBazz([18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]), 'Fizz 19 Buzz Fizz Bazz 23 Fizz Buzz Bazz Fizz 28 29 FizzBuzz');
//assertEqual(fizzBuzzBazz([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), '1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz');
//assertEqual(fizzBuzzBazz([45, 46, 47, 48, 49, 50]), 'FizzBuzz 46 47 Fizz 49 Buzz');

//console.log(fizzBuzzBazz([4, 5, 6, 7, 8]));<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom/server';
import Helmet from 'react-helmet';
import { Provider } from 'react-redux';

import { conf } from '../helpers/config';

import style from '../../common/style/vanilla/css/footer.css';

const GAID = conf.get('GOOGLE_ANALYTICS_ID');
const OPTID = conf.get('GOOGLE_OPTIMIZE_ID');
const GTMID = conf.get('GOOGLE_TAG_MANAGER_ID');
const SENTRY_DSN = conf.get('SENTRY_DSN');

const googleOptimizePageHideCss = GAID && OPTID ?


<commit_before>/*
    ***** BEGIN LICENSE BLOCK *****

    Copyright © 2009 Center for History and New Media
                     George Mason University, Fairfax, Virginia, USA
                     http://zotero.org

    This file is part of Zotero.

    Zotero is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Zotero is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with Zotero.  If not, see <http://www.gnu.org/licenses/>.

    ***** END LICENSE BLOCK *****
*/

Zotero.Debug = new function () {
	var _console, _stackTrace, _store, _level, _lastTime, _output = [];
	var _slowTime = false;
	var _colorOutput = false;
	var _consoleViewer = false;
	var _consoleViewerQueue = [];
	var _consoleViewerListener;

	/**
	 * Initialize debug logging
	 *
	 * Debug logging can be set in several different ways:
	 *
	 *   - via the debug.log pref in the client or connector
	 *   - by enabling debug output logging in the Advanced prefs in the client
	 *   - by passing -ZoteroDebug or -ZoteroDebugText on the command line
	 *
	 * In the client, debug.log and -ZoteroDebugText enable logging via the terminal, while -ZoteroDebug
	 * enables logging via an in-app HTML-based window.
	 *
	 * @param {Integer} [forceDebugLog = 0] - Force output even if pref disabled
	 *    2: window (-ZoteroDebug)
	 *    1: text console (-ZoteroDebugText)
	 *    0: disabled
	 */
	this.init = function (forceDebugLog = 0) {
		_console = Zotero.Prefs.get('debug.log') || forceDebugLog == 1;
		_consoleViewer = forceDebugLog == 2;
		// When logging to the text console from the client on Mac/Linux, colorize output
		if (_console && Zotero.isFx && !Zotero.isBookmarklet) {
			_colorOutput = true;

			// Time threshold in ms above which intervals should be colored red in terminal output
			_slowTime = Zotero.Prefs.get('debug.log.slowTime');
		}
		_store = Zotero.Prefs.get('debug.store');
		if (_store) {
			Zotero.Prefs.set('debug.store', false);
		}
		_level = Zotero.Prefs.get('debug.level');
		_stackTrace = Zotero.Prefs.get('debug.stackTrace');

		this.storing = _store;
		this.updateEnabled();

		if (Zotero.isStandalone) {
			// Enable dump() from window (non-XPCOM) scopes when terminal or viewer logging is enabled.
			// (These will always go to the terminal, even in viewer mode.)
			Zotero.Prefs.set('browser.dom.window.dump.enabled', _console || _consoleViewer, true);

			if (_consoleViewer) {
				setTimeout(function () {
					Zotero.openInViewer("chrome://zotero/content/debugViewer.html");
				}, 1000);
			}
		}
	}

	this.log = function (message, level, maxDepth, stack) {
		if (!this.enabled) {
			return;
		}

		if (typeof message != 'string') {
			message = Zotero.Utilities.varDump(message, 0, maxDepth);
		}

		if (!level) {
			level = 3;
		}

		// If level above debug.level value, don't display
		if (level > _level) {
			return;
		}

		var deltaStr = '';
		var deltaStrStore = '';
		var delta = 0;
		var d = new Date();
		if (_lastTime) {
			delta = d - _lastTime;
		}
		_lastTime = d;
		var slowPrefix = "";
		var slowSuffix = "";
		if (_slowTime && delta > _slowTime) {
			slowPrefix = "\x1b[31;40m";
			slowSuffix = "\x1b[0m";
		}

		// TODO: Replace with String.prototype.padStart once available (Fx48)
		while (("" + delta).length < 7) {
			delta = '0' + delta;
		}

		deltaStr = "(" + slowPrefix + "+" + delta + slowSuffix + ")";
		if (_store) {
			deltaStrStore = "(+" + delta + ")";
		}

		if (stack === true) {
			// Display stack starting from where this was called
			stack = Components.stack.caller;
		} else if (stack >= 0) {
			let i = stack;
			stack = Components.stack.caller;
			while(stack && i--) {
				stack = stack.caller;
			}
		} else if (_stackTrace) {
			// Stack trace enabled globally
			stack = Components.stack.caller;
		} else {
			stack = undefined;
		}

		if (stack) {
			message += '\n' + Zotero.Debug.stackToString(stack);
		}

		if (_console || _consoleViewer) {
			var output = '(' + level + ')' + deltaStr + ': ' + message;
			if (Zotero.isFx && !Zotero.isBookmarklet) {
				// Text console
				if (_console) {
					dump("zotero" + output + "\n\n");
				}
				// Console window
				if (_consoleViewer) {
					// If there's a listener, pass line immediately
					if (_consoleViewerListener) {
						_consoleViewerListener(output);
					}
					// Otherwise add to queue
					else {
						_consoleViewerQueue.push(output);
					}
				}
			} else if(window.console) {
				window.console.log(output);
			}
		}
		if (_store) {
			if (Math.random() < 1/1000) {
				// Remove initial lines if over limit
				var overage = this.count() - Zotero.Prefs.get('debug.store.limit');
				if (overage > 0) {
					_output.splice(0, Math.abs(overage));
				}
			}
			_output.push('(' + level + ')' + deltaStrStore + ': ' + message);
		}
	}

	this.get = Zotero.Promise.method(function(maxChars, maxLineLength) {
		var output = _output;
		var total = output.length;

		if (total == 0) {
			return "";
		}

		if (maxLineLength) {
			for (var i=0, len=output.length; i<len; i++) {
				if (output[i].length > maxLineLength) {
					output[i] = Zotero.Utilities.ellipsize(output[i], maxLineLength, false, true);
				}
			}
		}

		output = output.join('\n\n');

		if (maxChars) {
			output = output.substr(maxChars * -1);
			// Cut at two newlines
			for (var i=1, len=output.length; i<len; i++) {
				if (output[i] == '\n' && output[i-1] == '\n') {
					output = output.substr(i + 1);
					break;
				}
			}
		}

		if (Zotero.getErrors) {
			return Zotero.getSystemInfo().then(function(sysInfo) {
				return Zotero.getErrors(true).join('\n\n') +
					"\n\n" + sysInfo + "\n\n" +
					"=========================================================\n\n" +
					output;
			});
		} else {
			return output;
		}
	});

	this.getConsoleViewerOutput = function () {
		var queue = _consoleViewerQueue;
		_consoleViewerQueue = [];
		return queue;
	}

	this.addConsoleViewerListener = function (listener) {
		_consoleViewerListener = listener;
	};

	this.removeConsoleViewerListener = function () {
		_consoleViewerListener = null;
		// At least for now, stop logging once console viewer is closed
		_consoleViewer = false;
		this.updateEnabled();
	};

	this.setStore = function (enable) {
		if (enable) {
			this.clear();
		}
		_store = enable;
		this.updateEnabled();
		this.storing = _store;
	}

	this.updateEnabled = function () {
		this.enabled = _console || _consoleViewer || _store;
	};

	this.count = function () {
		return _output.length;
	}

	this.clear = function () {
		_output = [];
	}

	/**
	 * Format a stack trace for output in the same way that Error.stack does
	 * @param {Components.stack} stack
	 * @param {Integer} [lines=5] Number of lines to format
	 */
	this.stackToString = function (stack, lines) {
		if (!lines) lines = 5;
		var str = '';
		while(stack && lines--) {
			str += '\n  ' + (stack.name || '') + '@' + stack.filename
				+ ':' + stack.lineNumber;
			stack = stack.caller;
		}
		return str.substr(1);
	};

	/**
	 * Strip Bluebird lines from a stack trace
	 *
	 * @param {String} stack
	 */
	this.filterStack = function (stack) {
		return stack.split(/\n/).filter(line => line.indexOf('zotero/bluebird') == -1).join('\n');
	}
}
<commit_msg>Address debug reporting in connector (zotero/zotero-connectors#97)<commit_after>/*
    ***** BEGIN LICENSE BLOCK *****

    Copyright © 2009 Center for History and New Media
                     George Mason University, Fairfax, Virginia, USA
                     http://zotero.org

    This file is part of Zotero.

    Zotero is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Zotero is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with Zotero.  If not, see <http://www.gnu.org/licenses/>.

    ***** END LICENSE BLOCK *****
*/

Zotero.Debug = new function () {
	var _console, _stackTrace, _store, _level, _lastTime, _output = [];
	var _slowTime = false;
	var _colorOutput = false;
	var _consoleViewer = false;
	var _consoleViewerQueue = [];
	var _consoleViewerListener;

	/**
	 * Initialize debug logging
	 *
	 * Debug logging can be set in several different ways:
	 *
	 *   - via the debug.log pref in the client or connector
	 *   - by enabling debug output logging in the Advanced prefs in the client
	 *   - by passing -ZoteroDebug or -ZoteroDebugText on the command line
	 *
	 * In the client, debug.log and -ZoteroDebugText enable logging via the terminal, while -ZoteroDebug
	 * enables logging via an in-app HTML-based window.
	 *
	 * @param {Integer} [forceDebugLog = 0] - Force output even if pref disabled
	 *    2: window (-ZoteroDebug)
	 *    1: text console (-ZoteroDebugText)
	 *    0: disabled
	 */
	this.init = function (forceDebugLog = 0) {
		_console = Zotero.Prefs.get('debug.log') || forceDebugLog == 1;
		_consoleViewer = forceDebugLog == 2;
		// When logging to the text console from the client on Mac/Linux, colorize output
		if (_console && Zotero.isFx && !Zotero.isBookmarklet) {
			_colorOutput = true;

			// Time threshold in ms above which intervals should be colored red in terminal output
			_slowTime = Zotero.Prefs.get('debug.log.slowTime');
		}
		_store = Zotero.Prefs.get('debug.store');
		if (_store) {
			Zotero.Prefs.set('debug.store', false);
		}
		_level = Zotero.Prefs.get('debug.level');
		_stackTrace = Zotero.Prefs.get('debug.stackTrace');

		this.storing = _store;
		this.updateEnabled();

		if (Zotero.isStandalone) {
			// Enable dump() from window (non-XPCOM) scopes when terminal or viewer logging is enabled.
			// (These will always go to the terminal, even in viewer mode.)
			Zotero.Prefs.set('browser.dom.window.dump.enabled', _console || _consoleViewer, true);

			if (_consoleViewer) {
				setTimeout(function () {
					Zotero.openInViewer("chrome://zotero/content/debugViewer.html");
				}, 1000);
			}
		}
	}

	this.log = function (message, level, maxDepth, stack) {
		if (!this.enabled) {
			return;
		}

		if (typeof message != 'string') {
			message = Zotero.Utilities.varDump(message, 0, maxDepth);
		}

		if (!level) {
			level = 3;
		}

		// If level above debug.level value, don't display
		if (level > _level) {
			return;
		}

		var deltaStr = '';
		var deltaStrStore = '';
		var delta = 0;
		var d = new Date();
		if (_lastTime) {
			delta = d - _lastTime;
		}
		_lastTime = d;
		var slowPrefix = "";
		var slowSuffix = "";
		if (_slowTime && delta > _slowTime) {
			slowPrefix = "\x1b[31;40m";
			slowSuffix = "\x1b[0m";
		}

		// TODO: Replace with String.prototype.padStart once available (Fx48)
		while (("" + delta).length < 7) {
			delta = '0' + delta;
		}

		deltaStr = "(" + slowPrefix + "+" + delta + slowSuffix + ")";
		if (_store) {
			deltaStrStore = "(+" + delta + ")";
		}

		if (stack === true) {
			// Display stack starting from where this was called
			stack = Components.stack.caller;
		} else if (stack >= 0) {
			let i = stack;
			stack = Components.stack.caller;
			while(stack && i--) {
				stack = stack.caller;
			}
		} else if (_stackTrace) {
			// Stack trace enabled globally
			stack = Components.stack.caller;
		} else {
			stack = undefined;
		}

		if (stack) {
			message += '\n' + Zotero.Debug.stackToString(stack);
		}

		if (_console || _consoleViewer) {
			var output = '(' + level + ')' + deltaStr + ': ' + message;
			if (Zotero.isFx && !Zotero.isBookmarklet) {
				// Text console
				if (_console) {
					dump("zotero" + output + "\n\n");
				}
				// Console window
				if (_consoleViewer) {
					// If there's a listener, pass line immediately
					if (_consoleViewerListener) {
						_consoleViewerListener(output);
					}
					// Otherwise add to queue
					else {
						_consoleViewerQueue.push(output);
					}
				}
			} else if(window.console) {
				window.console.log(output);
			}
		}
		if (_store) {
			if (Math.random() < 1/1000) {
				// Remove initial lines if over limit
				var overage = this.count() - Zotero.Prefs.get('debug.store.limit');
				if (overage > 0) {
					_output.splice(0, Math.abs(overage));
				}
			}
			_output.push('(' + level + ')' + deltaStrStore + ': ' + message);
		}
	}

	this.get = Zotero.Promise.method(function(maxChars, maxLineLength) {
		var output = _output;
		var total = output.length;

		if (total == 0) {
			return "";
		}

		if (maxLineLength) {
			for (var i=0, len=output.length; i<len; i++) {
				if (output[i].length > maxLineLength) {
					output[i] = Zotero.Utilities.ellipsize(output[i], maxLineLength, false, true);
				}
			}
		}

		output = output.join('\n\n');

		if (maxChars) {
			output = output.substr(maxChars * -1);
			// Cut at two newlines
			for (var i=1, len=output.length; i<len; i++) {
				if (output[i] == '\n' && output[i-1] == '\n') {
					output = output.substr(i + 1);
					break;
				}
			}
		}

		return Zotero.getSystemInfo().then(function(sysInfo) {
			if (Zotero.isConnector) {
				return Zotero.Error.getErrors().then(function(errors) {
					return errors.join('\n\n') +
						"\n\n" + sysInfo + "\n\n" +
						"=========================================================\n\n" +
						output;
				});
			}
			else {
				return Zotero.getErrors(true).join('\n\n') +
					"\n\n" + sysInfo + "\n\n" +
					"=========================================================\n\n" +
					output;
			}
		});
	});

	this.getConsoleViewerOutput = function () {
		var queue = _consoleViewerQueue;
		_consoleViewerQueue = [];
		return queue;
	}

	this.addConsoleViewerListener = function (listener) {
		_consoleViewerListener = listener;
	};

	this.removeConsoleViewerListener = function () {
		_consoleViewerListener = null;
		// At least for now, stop logging once console viewer is closed
		_consoleViewer = false;
		this.updateEnabled();
	};

	this.setStore = function (enable) {
		if (enable) {
			this.clear();
		}
		_store = enable;
		this.updateEnabled();
		this.storing = _store;
	}

	this.updateEnabled = function () {
		this.enabled = _console || _consoleViewer || _store;
	};

	this.count = function () {
		return _output.length;
	}

	this.clear = function () {
		_output = [];
	}

	/**
	 * Format a stack trace for output in the same way that Error.stack does
	 * @param {Components.stack} stack
	 * @param {Integer} [lines=5] Number of lines to format
	 */
	this.stackToString = function (stack, lines) {
		if (!lines) lines = 5;
		var str = '';
		while(stack && lines--) {
			str += '\n  ' + (stack.name || '') + '@' + stack.filename
				+ ':' + stack.lineNumber;
			stack = stack.caller;
		}
		return str.substr(1);
	};

	/**
	 * Strip Bluebird lines from a stack trace
	 *
	 * @param {String} stack
	 */
	this.filterStack = function (stack) {
		return stack.split(/\n/).filter(line => line.indexOf('zotero/bluebird') == -1).join('\n');
	}
}
<|endoftext|>


<commit_before>var httpProxy = require('../lib/http-proxy/passes/web-incoming'),
    expect = require('expect.js');

describe('lib/http-proxy/passes/web.js', function() {
  describe('#deleteLength', function() {
    it('should change `content-length`', function() {
      var stubRequest = {
        method: 'DELETE',
        headers: {}
      };
      httpProxy.deleteLength(stubRequest, {}, {});
      expect(stubRequest.headers['content-length']).to.eql('0');
    })
  });

  describe('#timeout', function() {
    it('should set timeout on the socket', function() {
      var done = false, stubRequest = {
        socket: {
          setTimeout: function(value) { done = value; }
        }
      }

      httpProxy.timeout(stubRequest, {}, { timeout: 5000});
      expect(done).to.eql(5000);
    });
  });

  describe('#XHeaders', function () {
    var stubRequest = {
      connection: {
        remoteAddress: '192.168.1.2',
        remotePort: '8080'
      },
      headers: {}
    }

    it('set the correct x-forwarded-* headers', function () {
      httpProxy.XHeaders(stubRequest, {}, { xfwd: true });
      expect(stubRequest.headers['x-forwarded-for']).to.be('192.168.1.2');
      expect(stubRequest.headers['x-forwarded-port']).to.be('8080');
      expect(stubRequest.headers['x-forwarded-proto']).to.be('http');
    });
  });
});
<commit_msg>[tests] move contributions of @mmoulton to correct place<commit_after>var webPasses = require('../lib/http-proxy/passes/web-incoming'),
    httpProxy = require('../lib/http-proxy'),
    expect    = require('expect.js'),
    http      = require('http');

describe('lib/http-proxy/passes/web.js', function() {
  describe('#deleteLength', function() {
    it('should change `content-length`', function() {
      var stubRequest = {
        method: 'DELETE',
        headers: {}
      };
      webPasses.deleteLength(stubRequest, {}, {});
      expect(stubRequest.headers['content-length']).to.eql('0');
    })
  });

  describe('#timeout', function() {
    it('should set timeout on the socket', function() {
      var done = false, stubRequest = {
        socket: {
          setTimeout: function(value) { done = value; }
        }
      }

      webPasses.timeout(stubRequest, {}, { timeout: 5000});
      expect(done).to.eql(5000);
    });
  });

  describe('#XHeaders', function () {
    var stubRequest = {
      connection: {
        remoteAddress: '192.168.1.2',
        remotePort: '8080'
      },
      headers: {}
    }

    it('set the correct x-forwarded-* headers', function () {
      webPasses.XHeaders(stubRequest, {}, { xfwd: true });
      expect(stubRequest.headers['x-forwarded-for']).to.be('192.168.1.2');
      expect(stubRequest.headers['x-forwarded-port']).to.be('8080');
      expect(stubRequest.headers['x-forwarded-proto']).to.be('http');
    });
  });
});

describe('#createProxyServer.web() using own http server', function () {
  it('should proxy the request using the web proxy handler', function (done) {
    var proxy = httpProxy.createProxyServer({
      target: 'http://127.0.0.1:8080'
    });

    function requestHandler(req, res) {
      proxy.web(req, res);
    }

    var proxyServer = http.createServer(requestHandler);

    var source = http.createServer(function(req, res) {
      source.close();
      proxyServer.close();
      expect(req.method).to.eql('GET');
      expect(req.headers.host.split(':')[1]).to.eql('8081');
      done();
    });

    proxyServer.listen('8081');
    source.listen('8080');

    http.request('http://127.0.0.1:8081', function() {}).end();
  });

  it('should proxy the request and handle error via callback', function(done) {
    var proxy = httpProxy.createProxyServer({
      target: 'http://127.0.0.1:8080'
    });

    var proxyServer = http.createServer(requestHandler);

    function requestHandler(req, res) {
      proxy.web(req, res, function (err) {
        proxyServer.close();
        expect(err).to.be.an(Error);
        expect(err.code).to.be('ECONNREFUSED');
        done();
      });
    }

    proxyServer.listen('8081');

    http.request({
      hostname: '127.0.0.1',
      port: '8081',
      method: 'GET',
    }, function() {}).end();
  });

  it('should proxy the request and handle error via event listener', function(done) {
    var proxy = httpProxy.createProxyServer({
      target: 'http://127.0.0.1:8080'
    });

    var proxyServer = http.createServer(requestHandler);

    function requestHandler(req, res) {
      proxy.once('error', function (err, errReq, errRes) {
        proxyServer.close();
        expect(err).to.be.an(Error);
        expect(errReq).to.be.equal(req);
        expect(errRes).to.be.equal(res);
        expect(err.code).to.be('ECONNREFUSED');
        done();
      });

      proxy.web(req, res);
    }

    proxyServer.listen('8081');

    http.request({
      hostname: '127.0.0.1',
      port: '8081',
      method: 'GET',
    }, function() {}).end();
  });
});<|endoftext|>


<commit_before>import * as moment from 'moment';

export class DateFormatValueConverter {
   toView(value) {
      return moment.default(value).format('DD/MM/YYYY hh:mm');
   }
}<commit_msg>display hours from 00 to 23<commit_after>import * as moment from 'moment';

export class DateFormatValueConverter {
   toView(value) {
      return moment.default(value).format('DD/MM/YYYY HH:mm');
   }
}
<|endoftext|>


<commit_before>$(window).scroll(function() {
    // get current scroll top in px, add window height and
    // check if this is greater than the document height minus 300
    if ($(window).scrollTop() + $(window).height() >= $(document).height() - 300) {
        loadMoreContent();
    }
});

function loadMoreContent() {
    // there should be a button, which leads to next posts
    var next = $("a.next").first();
    var paginationnav = $("div.paginationnav").first();
    next.each(function(key, value) {
        var url = $(value).attr('href');
        // remove paginationnav, so we can't load multiple times
        next.remove();
        // adding a temp. dom object to load the next page
        var list = $("

");
        // call load method and get the div.post-list node
        list.load(url + " div.post-list", function(response, status, xhr) {
            // check if we doesn't get any error
            if ( status != "error" ) {
                // copy all childrens of our temp container to the real container
                // note: jQuery load will copy the div.post-list node as well,
                // so use the childrens and move them
	        var $masonry_actu = $('div.post-list').first();
                list.children("div.post-list").children().each(
                    function(key, value){
			$masonry_actu.append(value)
//                         $masonry_actu.isotope( 'appended', value);
                    }
                );
            }
        });
	paginationnav.load(url + " div.paginationnav");
    });

}

// Modify fitColumns layout mode to not resize container
// and support percentage width items
var FitColumns = Isotope.LayoutMode.modes.fitColumns;
FitColumns.prototype._getContainerSize = function() {};

FitColumns.prototype.needsResizeLayout = function() {
  // don't trigger if size did not change
  var size = getSize( this.isotope.element );
  if ( this.isotope.size && size ) {
    return size.innerHeight !== this.isotope.size.innerHeight ||
      size.innerWidth !== this.isotope.size.innerWidth;
  } else {
    return false;
  }
};

/* ********* WINDOW LOAD ********** */
$(window).ready(function() {
    masonry_actu();
    var paginationnav = $("div.paginationnav").first();
    paginationnav.hide();
});

function masonry_actu()
{
  $(function(){
      var $masonry_actu = $('div.post-list').first();
      if ( $masonry_actu.length > 0 ) {
	$masonry_actu.isotope({
	  layoutMode: 'fitColumns',
	  percentPosition: true,
	  itemSelector: '.post'
	});
      }
    });
}
<commit_msg>layout<commit_after>$(window).scroll(function() {
    // get current scroll top in px, add window height and
    // check if this is greater than the document height minus 300
    if ($(window).scrollTop() + $(window).height() >= $(document).height() - 300) {
        loadMoreContent();
    }
});

function loadMoreContent() {
    // there should be a button, which leads to next posts
    var next = $("a.next").first();
    var paginationnav = $("div.paginationnav").first();
    next.each(function(key, value) {
        var url = $(value).attr('href');
        // remove paginationnav, so we can't load multiple times
        next.remove();
        // adding a temp. dom object to load the next page
        var list = $("

");
        // call load method and get the div.post-list node
        list.load(url + " div.post-list", function(response, status, xhr) {
            // check if we doesn't get any error
            if ( status != "error" ) {
                // copy all childrens of our temp container to the real container
                // note: jQuery load will copy the div.post-list node as well,
                // so use the childrens and move them
	        var $masonry_actu = $('div.post-list').first();
                list.children("div.post-list").children().each(
                    function(key, value){
			$masonry_actu.append(value)
                        $masonry_actu.isotope( 'appended', value);
			$masonry_actu.isotope('layout')
                    }
                );
            }
        });
	paginationnav.load(url + " div.paginationnav");
    });

}

// Modify fitColumns layout mode to not resize container
// and support percentage width items
var FitColumns = Isotope.LayoutMode.modes.fitColumns;
FitColumns.prototype._getContainerSize = function() {};

FitColumns.prototype.needsResizeLayout = function() {
  // don't trigger if size did not change
  var size = getSize( this.isotope.element );
  if ( this.isotope.size && size ) {
    return size.innerHeight !== this.isotope.size.innerHeight ||
      size.innerWidth !== this.isotope.size.innerWidth;
  } else {
    return false;
  }
};

/* ********* WINDOW LOAD ********** */
$(window).ready(function() {
    masonry_actu();
    var paginationnav = $("div.paginationnav").first();
    paginationnav.hide();
});

function masonry_actu()
{
  $(function(){
      var $masonry_actu = $('div.post-list').first();
      if ( $masonry_actu.length > 0 ) {
	$masonry_actu.isotope({
	  layoutMode: 'fitColumns',
	  percentPosition: true,
	  itemSelector: '.post'
	});
      }
    });
}
<|endoftext|>


<commit_before>//I wanted to call this file math, but that's already a thing in JS.
var Maths = {
  /**getting the correct location for translated elements is a nightmare (but a
   necessary one, because we want to use <g> tags to group our elements and the
   only way to locate a <g> correctly is.... translate! Thankfully, this SO person
   is Good People: https://stackoverflow.com/questions/26049488/how-to-get-absolute-coordinates-of-object-inside-a-g-group
  **/
  makeAbsoluteContext: function (element) {
    return function(x,y) {
      var offset = document.getElementById(svgElementId).getBoundingClientRect();
      var matrix = element.getScreenCTM();
      return {
        x: (matrix.a * x) + (matrix.c * y) + matrix.e - offset.left,
        y: (matrix.b * x) + (matrix.d * y) + matrix.f - offset.top
      };
    };
  }

};
<commit_msg>stubbed some math methods that when implemented should make it easier to choose where an arrow goes<commit_after>//I wanted to call this file math, but that's already a thing in JS.
var Maths = {
  /**getting the correct location for translated elements is a nightmare (but a
   necessary one, because we want to use <g> tags to group our elements and the
   only way to locate a <g> correctly is.... translate! Thankfully, this SO person
   is Good People: https://stackoverflow.com/questions/26049488/how-to-get-absolute-coordinates-of-object-inside-a-g-group
  **/
  makeAbsoluteContext: function (element) {
    return function(x,y) {
      var offset = document.getElementById(svgElementId).getBoundingClientRect();
      var matrix = element.getScreenCTM();
      return {
        x: (matrix.a * x) + (matrix.c * y) + matrix.e - offset.left,
        y: (matrix.b * x) + (matrix.d * y) + matrix.f - offset.top
      };
    };
  },
  intersection: function(line1, line2) {
    //maths go here :D
  },
  boxLineIntersection: function(box, line) {
    //maths here to deconstruct the box into 4 lines and see if any of them
    //intersect with the box. Return which line and the coords.
  }
};
<|endoftext|>


<commit_before>var usb = exports = module.exports = require("bindings")("usb_bindings")
var events = require('events')
var util = require('util')

// convenience method for finding a device by vendor and product id
exports.findByIds = function(vid, pid) {
	var devices = usb.getDeviceList()

	for (var i = 0; i < devices.length; i++) {
		var deviceDesc = devices[i].deviceDescriptor
		if ((deviceDesc.idVendor == vid) && (deviceDesc.idProduct == pid)) {
			return devices[i]
		}
	}
}

usb.Device.prototype.timeout = 1000

usb.Device.prototype.open = function(){
	this.__open()
	this.interfaces = []
	var len = this.configDescriptor.interfaces.length
	for (var i=0; i<len; i++){
		this.interfaces[i] = new Interface(this, i)
	}
}

usb.Device.prototype.close = function(){
	this.__close()
	this.interfaces = null
}

Object.defineProperty(usb.Device.prototype, "configDescriptor", {
    get: function() {
        return this.configDescriptor = this.__getConfigDescriptor()
    }
});

usb.Device.prototype.interface = function(addr){
	if (!this.interfaces){
		throw new Error("Device must be open before searching for interfaces")
	}
	addr = addr || 0
	for (var i=0; i<this.interfaces.length; i++){
		if (this.interfaces[i].interfaceNumber == addr){
			return this.interfaces[i]
		}
	}
}

var SETUP_SIZE = usb.LIBUSB_CONTROL_SETUP_SIZE

usb.Device.prototype.controlTransfer =
function(bmRequestType, bRequest, wValue, wIndex, data_or_length, callback){
	var self = this
	var timeout = 1000
	var isIn = !!(bmRequestType & usb.LIBUSB_ENDPOINT_IN)
	var wLength

	if (isIn){
		if (!(data_or_length >= 0)){
			throw new TypeError("Expected size number for IN transfer (based on bmRequestType)")
		}
		wLength = data_or_length
	}else{
		if (!Buffer.isBuffer(data_or_length)){
			throw new TypeError("Expected buffer for OUT transfer (based on bmRequestType)")
		}
		wLength = data_or_length.length
	}

	// Buffer for the setup packet
	// http://libusbx.sourceforge.net/api-1.0/structlibusb__control__setup.html
	var buf = new Buffer(wLength + SETUP_SIZE)
	buf.writeUInt8(   bmRequestType, 0)
	buf.writeUInt8(   bRequest,      1)
	buf.writeUInt16LE(wValue,        2)
	buf.writeUInt16LE(wIndex,        4)
	buf.writeUInt16LE(wLength,       6)

	if (!isIn){
		data_or_length.copy(buf, SETUP_SIZE)
	}

	var transfer = new usb.Transfer(this, 0, usb.LIBUSB_TRANSFER_TYPE_CONTROL, timeout,
		function(error, buf, actual){
			if (callback){
				if (isIn){
					callback.call(self, error, buf.slice(SETUP_SIZE, SETUP_SIZE + actual))
				}else{
					callback.call(self, error)
				}
			}
		}
	)
	return transfer.submit(buf)
}

function Interface(device, id){
	this.device = device
	this.id = id
	this.altSetting = 0;
	this.__refresh()
}

Interface.prototype.__refresh = function(){
	this.descriptor = this.device.configDescriptor.interfaces[this.id][this.altSetting]
	this.interfaceNumber = this.descriptor.bInterfaceNumber
	this.endpoints = []
	var len = this.descriptor.endpoints.length
	for (var i=0; i<len; i++){
		var desc = this.descriptor.endpoints[i]
		var c = (desc.bEndpointAddress&(1 << 7) == usb.LIBUSB_ENDPOINT_IN)?InEndpoint:OutEndpoint
		this.endpoints[i] = new c(this.device, desc)
	}
}

Interface.prototype.claim = function(){
	this.device.__claimInterface(this.id)
}

Interface.prototype.release = function(cb){
	var self = this;
	this.device.__releaseInterface(this.id, function(err){
		if (!err){
			self.altSetting = 0;
			self.__refresh()
		}
		cb.call(self, err)
	})
}

Interface.prototype.isKernelDriverActive = function(){
	return this.device.__isKernelDriverActive(this.id)
}

Interface.prototype.detachKernelDriver = function() {
	return this.device.__detachKernelDriver(this.id)
};

Interface.prototype.attachKernelDriver = function() {
	return this.device.__attachKernelDriver(this.id)
};

Interface.prototype.setAltSetting = function(altSetting, cb){
	var self = this;
	this.device.__setInterface(this.id, altSetting, function(err){
		if (!err){
			self.altSetting = altSetting;
			self.__refresh();
		}
		cb.call(self, err)
	})

}

Interface.prototype.endpoint = function(addr){
	for (var i=0; i<this.endpoints.length; i++){
		if (this.endpoints[i].address == addr){
			return this.endpoints[i]
		}
	}
}

function Endpoint(device, descriptor){
	this.device = device
	this.descriptor = descriptor
	this.address = descriptor.bEndpointAddress
	this.transferType = descriptor.bmAttributes&0x03
}
util.inherits(Endpoint, events.EventEmitter)

Endpoint.prototype.makeTransfer = function(timeout, callback){
	return new usb.Transfer(this.device, this.address, this.transferType, timeout, callback)
}

Endpoint.prototype.startStream = function(nTransfers, transferSize, callback){
	if (this.streamTransfers){
		throw new Error("Stream already active")
	}

	nTransfers = nTransfers || 3;
	this.streamTransferSize = transferSize || this.maxPacketSize;
	this.streamActive = true
	this.streamPending = 0

	var transfers = []
	for (var i=0; i<nTransfers; i++){
		transfers[i] = this.makeTransfer(0, callback)
	}
	return transfers;
}

Endpoint.prototype.stopStream = function(){
	for (var i=0; i<this.streamTransfers.length; i++){
		this.streamTransfers[i].cancel()
	}
	this.streamActive = false
}

function InEndpoint(device, descriptor){
	Endpoint.call(this, device, descriptor)
}

exports.InEndpoint = InEndpoint
util.inherits(InEndpoint, Endpoint)
InEndpoint.prototype.direction = "in"

InEndpoint.prototype.transfer = function(length, cb){
	var self = this
	var buffer = new Buffer(length)

	function callback(error, buf, actual){
		cb.call(self, error, buffer.slice(0, actual))
	}

	return this.makeTransfer(this.device.timeout, callback).submit(buffer)
}

InEndpoint.prototype.startStream = function(nTransfers, transferSize){
	var self = this
	this.streamTransfers = InEndpoint.super_.prototype.startStream.call(this, nTransfers, transferSize, transferDone)

	function transferDone(error, buf, actual){
		if (!error){
			self.emit("data", buf.slice(0, actual))
		}else if (error.errno != usb.LIBUSB_TRANSFER_CANCELLED){
			self.emit("error", error)
			self.stopStream()
		}

		if (self.streamActive){
			startTransfer(this)
		}else{
			self.streamPending--

			if (self.streamPending == 0){
				self.emit('end')
			}
		}
	}

	function startTransfer(t){
		t.submit(new Buffer(self.streamTransferSize), transferDone)
	}

	this.streamTransfers.forEach(startTransfer)
	self.streamPending = this.streamTransfers.length
}

function OutEndpoint(device, descriptor){
	Endpoint.call(this, device, descriptor)
}
exports.OutEndpoint = OutEndpoint
util.inherits(OutEndpoint, Endpoint)
OutEndpoint.prototype.direction = "out"

OutEndpoint.prototype.transfer = function(buffer, cb){
	var self = this
	if (!buffer){
		buffer = new Buffer(0)
	}else if (!Buffer.isBuffer(buffer)){
		buffer = new Buffer(buffer)
	}

	function callback(error, buf, actual){
		if (cb) cb.call(self, error)
	}

	return this.makeTransfer(this.device.timeout, callback).submit(buffer)
}

OutEndpoint.prototype.startStream = function startStream(n_transfers, transfer_size){
	n_transfers = n_transfers || 3;
	transfer_size = transfer_size || this.maxPacketSize;
	this._streamTransfers = n_transfers;
	this._pendingTransfers = 0;
	var self = this
	process.nextTick(function(){
		for (var i=0; i<n_transfers; i++) self.emit('drain')
	})
}

function out_ep_callback(err, d){
	if (err) this.emit('error', err);
	this._pendingTransfers--;
	if (this._pendingTransfers < this._streamTransfers){
		this.emit('drain');
	}
	if (this._pendingTransfers <= 0 && this._streamTransfers == 0){
		this.emit('end');
	}
}

usb.OutEndpoint.prototype.write = function write(data){
	this.transfer(data, out_ep_callback);
	this._pendingTransfers++;
}

usb.OutEndpoint.prototype.stopStream = function stopStream(){
	this._streamTransfers = 0;
	if (this._pendingTransfers == 0) this.emit('end');
}
<commit_msg>Fix operator precedence bug in direction bit test. Fixes issue #8.<commit_after>var usb = exports = module.exports = require("bindings")("usb_bindings")
var events = require('events')
var util = require('util')

// convenience method for finding a device by vendor and product id
exports.findByIds = function(vid, pid) {
	var devices = usb.getDeviceList()

	for (var i = 0; i < devices.length; i++) {
		var deviceDesc = devices[i].deviceDescriptor
		if ((deviceDesc.idVendor == vid) && (deviceDesc.idProduct == pid)) {
			return devices[i]
		}
	}
}

usb.Device.prototype.timeout = 1000

usb.Device.prototype.open = function(){
	this.__open()
	this.interfaces = []
	var len = this.configDescriptor.interfaces.length
	for (var i=0; i<len; i++){
		this.interfaces[i] = new Interface(this, i)
	}
}

usb.Device.prototype.close = function(){
	this.__close()
	this.interfaces = null
}

Object.defineProperty(usb.Device.prototype, "configDescriptor", {
    get: function() {
        return this.configDescriptor = this.__getConfigDescriptor()
    }
});

usb.Device.prototype.interface = function(addr){
	if (!this.interfaces){
		throw new Error("Device must be open before searching for interfaces")
	}
	addr = addr || 0
	for (var i=0; i<this.interfaces.length; i++){
		if (this.interfaces[i].interfaceNumber == addr){
			return this.interfaces[i]
		}
	}
}

var SETUP_SIZE = usb.LIBUSB_CONTROL_SETUP_SIZE

usb.Device.prototype.controlTransfer =
function(bmRequestType, bRequest, wValue, wIndex, data_or_length, callback){
	var self = this
	var timeout = 1000
	var isIn = !!(bmRequestType & usb.LIBUSB_ENDPOINT_IN)
	var wLength

	if (isIn){
		if (!(data_or_length >= 0)){
			throw new TypeError("Expected size number for IN transfer (based on bmRequestType)")
		}
		wLength = data_or_length
	}else{
		if (!Buffer.isBuffer(data_or_length)){
			throw new TypeError("Expected buffer for OUT transfer (based on bmRequestType)")
		}
		wLength = data_or_length.length
	}

	// Buffer for the setup packet
	// http://libusbx.sourceforge.net/api-1.0/structlibusb__control__setup.html
	var buf = new Buffer(wLength + SETUP_SIZE)
	buf.writeUInt8(   bmRequestType, 0)
	buf.writeUInt8(   bRequest,      1)
	buf.writeUInt16LE(wValue,        2)
	buf.writeUInt16LE(wIndex,        4)
	buf.writeUInt16LE(wLength,       6)

	if (!isIn){
		data_or_length.copy(buf, SETUP_SIZE)
	}

	var transfer = new usb.Transfer(this, 0, usb.LIBUSB_TRANSFER_TYPE_CONTROL, timeout,
		function(error, buf, actual){
			if (callback){
				if (isIn){
					callback.call(self, error, buf.slice(SETUP_SIZE, SETUP_SIZE + actual))
				}else{
					callback.call(self, error)
				}
			}
		}
	)
	return transfer.submit(buf)
}

function Interface(device, id){
	this.device = device
	this.id = id
	this.altSetting = 0;
	this.__refresh()
}

Interface.prototype.__refresh = function(){
	this.descriptor = this.device.configDescriptor.interfaces[this.id][this.altSetting]
	this.interfaceNumber = this.descriptor.bInterfaceNumber
	this.endpoints = []
	var len = this.descriptor.endpoints.length
	for (var i=0; i<len; i++){
		var desc = this.descriptor.endpoints[i]
		var c = (desc.bEndpointAddress&usb.LIBUSB_ENDPOINT_IN)?InEndpoint:OutEndpoint
		this.endpoints[i] = new c(this.device, desc)
	}
}

Interface.prototype.claim = function(){
	this.device.__claimInterface(this.id)
}

Interface.prototype.release = function(cb){
	var self = this;
	this.device.__releaseInterface(this.id, function(err){
		if (!err){
			self.altSetting = 0;
			self.__refresh()
		}
		cb.call(self, err)
	})
}

Interface.prototype.isKernelDriverActive = function(){
	return this.device.__isKernelDriverActive(this.id)
}

Interface.prototype.detachKernelDriver = function() {
	return this.device.__detachKernelDriver(this.id)
};

Interface.prototype.attachKernelDriver = function() {
	return this.device.__attachKernelDriver(this.id)
};

Interface.prototype.setAltSetting = function(altSetting, cb){
	var self = this;
	this.device.__setInterface(this.id, altSetting, function(err){
		if (!err){
			self.altSetting = altSetting;
			self.__refresh();
		}
		cb.call(self, err)
	})

}

Interface.prototype.endpoint = function(addr){
	for (var i=0; i<this.endpoints.length; i++){
		if (this.endpoints[i].address == addr){
			return this.endpoints[i]
		}
	}
}

function Endpoint(device, descriptor){
	this.device = device
	this.descriptor = descriptor
	this.address = descriptor.bEndpointAddress
	this.transferType = descriptor.bmAttributes&0x03
}
util.inherits(Endpoint, events.EventEmitter)

Endpoint.prototype.makeTransfer = function(timeout, callback){
	return new usb.Transfer(this.device, this.address, this.transferType, timeout, callback)
}

Endpoint.prototype.startStream = function(nTransfers, transferSize, callback){
	if (this.streamTransfers){
		throw new Error("Stream already active")
	}

	nTransfers = nTransfers || 3;
	this.streamTransferSize = transferSize || this.maxPacketSize;
	this.streamActive = true
	this.streamPending = 0

	var transfers = []
	for (var i=0; i<nTransfers; i++){
		transfers[i] = this.makeTransfer(0, callback)
	}
	return transfers;
}

Endpoint.prototype.stopStream = function(){
	for (var i=0; i<this.streamTransfers.length; i++){
		this.streamTransfers[i].cancel()
	}
	this.streamActive = false
}

function InEndpoint(device, descriptor){
	Endpoint.call(this, device, descriptor)
}

exports.InEndpoint = InEndpoint
util.inherits(InEndpoint, Endpoint)
InEndpoint.prototype.direction = "in"

InEndpoint.prototype.transfer = function(length, cb){
	var self = this
	var buffer = new Buffer(length)

	function callback(error, buf, actual){
		cb.call(self, error, buffer.slice(0, actual))
	}

	return this.makeTransfer(this.device.timeout, callback).submit(buffer)
}

InEndpoint.prototype.startStream = function(nTransfers, transferSize){
	var self = this
	this.streamTransfers = InEndpoint.super_.prototype.startStream.call(this, nTransfers, transferSize, transferDone)

	function transferDone(error, buf, actual){
		if (!error){
			self.emit("data", buf.slice(0, actual))
		}else if (error.errno != usb.LIBUSB_TRANSFER_CANCELLED){
			self.emit("error", error)
			self.stopStream()
		}

		if (self.streamActive){
			startTransfer(this)
		}else{
			self.streamPending--

			if (self.streamPending == 0){
				self.emit('end')
			}
		}
	}

	function startTransfer(t){
		t.submit(new Buffer(self.streamTransferSize), transferDone)
	}

	this.streamTransfers.forEach(startTransfer)
	self.streamPending = this.streamTransfers.length
}

function OutEndpoint(device, descriptor){
	Endpoint.call(this, device, descriptor)
}
exports.OutEndpoint = OutEndpoint
util.inherits(OutEndpoint, Endpoint)
OutEndpoint.prototype.direction = "out"

OutEndpoint.prototype.transfer = function(buffer, cb){
	var self = this
	if (!buffer){
		buffer = new Buffer(0)
	}else if (!Buffer.isBuffer(buffer)){
		buffer = new Buffer(buffer)
	}

	function callback(error, buf, actual){
		if (cb) cb.call(self, error)
	}

	return this.makeTransfer(this.device.timeout, callback).submit(buffer)
}

OutEndpoint.prototype.startStream = function startStream(n_transfers, transfer_size){
	n_transfers = n_transfers || 3;
	transfer_size = transfer_size || this.maxPacketSize;
	this._streamTransfers = n_transfers;
	this._pendingTransfers = 0;
	var self = this
	process.nextTick(function(){
		for (var i=0; i<n_transfers; i++) self.emit('drain')
	})
}

function out_ep_callback(err, d){
	if (err) this.emit('error', err);
	this._pendingTransfers--;
	if (this._pendingTransfers < this._streamTransfers){
		this.emit('drain');
	}
	if (this._pendingTransfers <= 0 && this._streamTransfers == 0){
		this.emit('end');
	}
}

usb.OutEndpoint.prototype.write = function write(data){
	this.transfer(data, out_ep_callback);
	this._pendingTransfers++;
}

usb.OutEndpoint.prototype.stopStream = function stopStream(){
	this._streamTransfers = 0;
	if (this._pendingTransfers == 0) this.emit('end');
}
<|endoftext|>


<commit_before>'use strict';

var Home = React.createClass({
    displayName: 'Home',

    render: function render() {
        var socials = [{ link: 'https://github.com/aligos', icon: 'github' }, { link: 'http://linkedin.com/in/aligos', icon: 'linkedin' }, { link: 'https://speakerdeck.com/aligos', icon: 'slideshare' }, { link: 'http://twitter.com/rahmataligos', icon: 'twitter' }, { link: 'http://facebook.com/matt.aligos', icon: 'facebook' }];
        return React.createElement(
            'div',
            { className: 'about' },
            React.createElement(
                'img',
                { src: 'img/header.png', className: 'aligos' }
            ),
            React.createElement(
                'h1',
                { className: 'jumbo-title' },
                'just a stupid child, who was told to learn JavaScript.'
            ),
            React.createElement(
                'p',
                { className: 'jumbo-desc' },
                'Aligos - I Love JavaScript'
            ),
            React.createElement(
                'button',
                { className: 'btn btn-default' },
                'Font Line'
            ),
            React.createElement(
                'div',
                { className: 'social' },
                socials.map(function (item) {
                    return React.createElement(
                        'a',
                        { href: item.link },
                        React.createElement('i', { className: 'fa fa-' + item.icon })
                    );
                })
            )
        );
    }
});
<commit_msg>Update home.js<commit_after>'use strict';

var Home = React.createClass({
    displayName: 'Home',

    render: function render() {
        var socials = [{ link: 'https://github.com/aligos', icon: 'github' }, { link: 'http://linkedin.com/in/aligos', icon: 'linkedin' }, { link: 'https://speakerdeck.com/aligos', icon: 'slideshare' }, { link: 'http://twitter.com/rahmataligos', icon: 'twitter' }, { link: 'http://facebook.com/matt.aligos', icon: 'facebook' }];
        return React.createElement(
            'div',
            { className: 'about' },
            React.createElement(
                'img',
                { src: 'img/header.png', className: 'aligos' }
            ),
            React.createElement(
                'h1',
                { className: 'jumbo-title' },
                'just a stupid child, who was told to learn JavaScript.'
            ),
            React.createElement(
                'p',
                { className: 'jumbo-desc' },
                'Aligos - I Love JavaScript'
            ),
            React.createElement(
                'button',
                { className: 'btn btn-default' href: '/fontline' },
                'Font Line'
            ),
            React.createElement(
                'div',
                { className: 'social' },
                socials.map(function (item) {
                    return React.createElement(
                        'a',
                        { href: item.link },
                        React.createElement('i', { className: 'fa fa-' + item.icon })
                    );
                })
            )
        );
    }
});
<|endoftext|>


<commit_before>/**
 * Class representing device rows.
 *
 * @module Users
 */
var Q = require('Q');
var Db = Q.require('Db');
var Users = Q.require('Users');

/**
 * Class representing 'Device' rows in the 'Users' database
 * @namespace Users
 * @class Device
 * @extends Base.Users.Device
 * @constructor
 * @param fields {object} The fields values to initialize table row as
 * an associative array of `{column: value}` pairs
 */
function Users_Device (fields) {

	// Run constructors of mixed in objects
	Users_Device.constructors.apply(this, arguments);

	/*
	 * Add any privileged methods to the model class here.
	 * Public methods should probably be added further below.
	 * If file 'Device.js.inc' exists, its content is included
	 * * * */

	/* * * */
}

/**
 * @method pushNotification
 * @param {Object} notification
 * @param {String|Object} [notification.alert] Either the text of an alert to show,
 *  or an object with the following fields:
 * @param {string|array} [notification.alert] Either the text of an alert to show,
 *  or an object with the following fields:
 * @param {String} [notification.alert.title] The title of the notification
 * @param {String} [notification.alert.body] The body of the notification
 * @param {String} [notification.alert.titleLocKey] Apple-only
 * @param {String} [notification.alert.titleLocArgs] Apple-only
 * @param {String} [notification.alert.actionLocKey] Apple-only
 * @param {String} [notification.alert.locKey] Apple-only
 * @param {String} [notification.alert.locArgs] Apple-only
 * @param {String} [notification.alert.launchImage] Apple-only
 * @param {String} [notification.badge] The badge
 * @param {String} [notification.sound] The name of the sound file in the app bundle or Library/Sounds folder
 * @param {String} [notification.icon] Url of icon, can be png any square size
 * @param {String} [notification.url] Url to which the notifiation will be linked
 * @param {array} [notification.actions] Array of up to two arrays with keys 'action' and 'title'.
 * @param {String} [notification.category] Apple-only. The name of the category for actions registered on the client side.
 * @param {Object} [notification.payload] Put all your custom notification fields here
 * @param {Object} [options]
 * @param {String} [options.view] Optionally set a view to render for the alert body
 * @param {Boolean} [options.isSource] If true, uses Q.Handlebars.renderSource instead of render
 * @param {timestamp} [options.expiry] A UNIX timestamp for when the notification expires
 * @param {String} [options.priority="high"] Can be set to "normal" to make it lower priority
 * @param {String} [options.collapseId] A string under 64 bytes for collapsing notifications
 * @param {String} [options.id] You can provide your own uuid for the notification
 * @param {boolean} [options.silent=false] Deliver a silent notification, may throw an exception
 * @param {Function} [callback] This is called after the notification was sent. The first parameter might contain any errors. The "this" object is the Users.Device
 */
Users_Device.prototype.pushNotification = function (notification, options, callback) {
	if (typeof options === 'function') {
		callback = options;
		options = {};
	}
	var o = Q.extend({}, options);
	var n = Q.copy(notification);
	if (!Q.isInteger(o.priority)) {
		o.priority = (o.priority === 'high') ? 10 : 5;
	}
	if (o.priority) {
		notification.priority = o.priority;
	}
	if (o.expiry) {
		n.expiry = o.expiry;
	}
	if (o.collapseId) {
		n.collapseId = o.collapseId;
	}
	if (n.alert && n.alert.title) {
		// if subject is object - get subject from text file
		if (Array.isArray(n.alert.title)) {
			n.alert.title = Q.getObject(n.alert.title[1], Q.Text.get(n.alert.title[0], o.language));
		}

		n.alert.title = Q.Handlebars.renderSource(n.alert.title, o.fields);
	}
	if (o && o.view) {
		var body = Q.view(o.view, o.fields, {language: o.language, source: o.isSource});
		Q.setObject(['alert', 'body'], body, n);
	}
	return this.handlePushNotification(n, o, callback);
};

/**
 * Sends a push notification.
 * This default implementation, just throws an error.
 * @method handlePushNotification
 */
Users_Device.prototype.handlePushNotification = function () {
	throw new Q.Error("Users.Device.prototype.handlePushNotification: not implemented");
};

/**
 * Called by various Db methods to get a custom row object
 * @param {Object} fields Any fields to set in the row
 * @param {Boolean} retrieved whether the row is retrieved
 * @return {Users.Device}
 */
Users_Device.newRow = function (fields, retrieved) {
	if (!fields.platform) {
		throw new Q.Error("Users.Device.newRow: missing fields.platform");
	}
	var platform = fields.platform.toLowerCase().toCapitalized();
	var PlatformDevice = Users_Device[platform];
	return new PlatformDevice(fields, retrieved);
};

Q.mixin(Users_Device, Q.require('Base/Users/Device'));

/*
 * Add any public methods here by assigning them to Users_Device.prototype
 */

/**
 * The setUp() method is called the first time
 * an object of this class is constructed.
 * @method setUp
 */
Users_Device.prototype.setUp = function () {
	// put any code here
	// overrides the Base class
};

module.exports = Users.Device = Users_Device;

Q.require('Users/Device/Ios');
Q.require('Users/Device/Android');
Q.require('Users/Device/Chrome');
Q.require('Users/Device/Firefox');
Q.require('Users/Device/Safari');<commit_msg>Modified Users_Device.prototype.pushNotification Allow notification.alert.title, notification.alert.body and notification.actions.title be as array with path to text in lang json files.<commit_after>/**
 * Class representing device rows.
 *
 * @module Users
 */
var Q = require('Q');
var Db = Q.require('Db');
var Users = Q.require('Users');

/**
 * Class representing 'Device' rows in the 'Users' database
 * @namespace Users
 * @class Device
 * @extends Base.Users.Device
 * @constructor
 * @param fields {object} The fields values to initialize table row as
 * an associative array of `{column: value}` pairs
 */
function Users_Device (fields) {

	// Run constructors of mixed in objects
	Users_Device.constructors.apply(this, arguments);

	/*
	 * Add any privileged methods to the model class here.
	 * Public methods should probably be added further below.
	 * If file 'Device.js.inc' exists, its content is included
	 * * * */

	/* * * */
}

/**
 * @method pushNotification
 * @param {Object} notification
 * @param {String|Object} [notification.alert] Either the text of an alert to show,
 *  or an object with the following fields:
 * @param {String|array} [notification.alert.title] The title of the notification
 * You can also pass an [source, [$key1, ...]] to use Q.Text.get to obtain the title.
 * @param {String|array} [notification.alert.body] The body of the notification
 * You can also pass an [source, [$key1, ...]] to use Q.Text.get to obtain the body.
 * @param {String} [notification.alert.titleLocKey] Apple-only
 * @param {String} [notification.alert.titleLocArgs] Apple-only
 * @param {String} [notification.alert.actionLocKey] Apple-only
 * @param {String} [notification.alert.locKey] Apple-only
 * @param {String} [notification.alert.locArgs] Apple-only
 * @param {String} [notification.alert.launchImage] Apple-only
 * @param {String} [notification.badge] The badge
 * @param {String} [notification.sound] The name of the sound file in the app bundle or Library/Sounds folder
 * @param {String} [notification.icon] Url of icon, can be png any square size
 * @param {String} [notification.url] Url to which the notifiation will be linked
 * @param {array} [notification.actions] Array of up to two arrays with keys 'action', 'title' and optionally 'icon'.
 * @param {string|array} [notification.actions.title] Action title
 * You can also pass an array($source, array($key1, ...)) to use Q_Text to obtain the title.
 * @param {String} [notification.category] Apple-only. The name of the category for actions registered on the client side.
 * @param {Object} [notification.payload] Put all your custom notification fields here
 * @param {Object} [options]
 * @param {String} [options.view] Optionally set a view to render for the alert body
 * @param {Boolean} [options.isSource] If true, uses Q.Handlebars.renderSource instead of render
 * @param {timestamp} [options.expiry] A UNIX timestamp for when the notification expires
 * @param {String} [options.priority="high"] Can be set to "normal" to make it lower priority
 * @param {String} [options.collapseId] A string under 64 bytes for collapsing notifications
 * @param {String} [options.id] You can provide your own uuid for the notification
 * @param {boolean} [options.silent=false] Deliver a silent notification, may throw an exception
 * @param {Function} [callback] This is called after the notification was sent. The first parameter might contain any errors. The "this" object is the Users.Device
 */
Users_Device.prototype.pushNotification = function (notification, options, callback) {
	if (typeof options === 'function') {
		callback = options;
		options = {};
	}
	var o = Q.extend({}, options);
	var n = Q.copy(notification);
	if (!Q.isInteger(o.priority)) {
		o.priority = (o.priority === 'high') ? 10 : 5;
	}
	if (o.priority) {
		notification.priority = o.priority;
	}
	if (o.expiry) {
		n.expiry = o.expiry;
	}
	if (o.collapseId) {
		n.collapseId = o.collapseId;
	}

	// process title and body
	['alert', 'actions'].forEach(function(item1){
		['title', 'body'].forEach(function(item2){
			if (!Q.getObject([item1, item2], n)) {
				return;
			}

			// if item is object - get item from text file
			if (Array.isArray(n[item1][item2])) {
				n[item1][item2] = Q.getObject(n[item1][item2][1], Q.Text.get(n[item1][item2][0], o.language));
			}

			n[item1][item2] = Q.Handlebars.renderSource(n[item1][item2], o.fields);
		});
	});

	// if view defined, it rewrite the body
	if (o && o.view) {
		var body = Q.view(o.view, o.fields, {language: o.language, source: o.isSource});
		Q.setObject(['alert', 'body'], body, n);
	}
	return this.handlePushNotification(n, o, callback);
};

/**
 * Sends a push notification.
 * This default implementation, just throws an error.
 * @method handlePushNotification
 */
Users_Device.prototype.handlePushNotification = function () {
	throw new Q.Error("Users.Device.prototype.handlePushNotification: not implemented");
};

/**
 * Called by various Db methods to get a custom row object
 * @param {Object} fields Any fields to set in the row
 * @param {Boolean} retrieved whether the row is retrieved
 * @return {Users.Device}
 */
Users_Device.newRow = function (fields, retrieved) {
	if (!fields.platform) {
		throw new Q.Error("Users.Device.newRow: missing fields.platform");
	}
	var platform = fields.platform.toLowerCase().toCapitalized();
	var PlatformDevice = Users_Device[platform];
	return new PlatformDevice(fields, retrieved);
};

Q.mixin(Users_Device, Q.require('Base/Users/Device'));

/*
 * Add any public methods here by assigning them to Users_Device.prototype
 */

/**
 * The setUp() method is called the first time
 * an object of this class is constructed.
 * @method setUp
 */
Users_Device.prototype.setUp = function () {
	// put any code here
	// overrides the Base class
};

module.exports = Users.Device = Users_Device;

Q.require('Users/Device/Ios');
Q.require('Users/Device/Android');
Q.require('Users/Device/Chrome');
Q.require('Users/Device/Firefox');
Q.require('Users/Device/Safari');<|endoftext|>