<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Image, ImageBackground, Platform, StyleSheet, TouchableOpacity, View, ViewPropTypes } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
import Video from 'react-native-video'; // eslint-disable-line

const BackgroundImage = ImageBackground || Image; // fall back to Image if RN < 0.46

const styles = StyleSheet.create({
  preloadingPlaceholder: {
    backgroundColor: 'black',
    justifyContent: 'center',
    alignItems: 'center',
  },
  thumbnail: {
    backgroundColor: 'black',
    justifyContent: 'center',
    alignItems: 'center',
  },
  playButton: {
    backgroundColor: 'rgba(0, 0, 0, 0.6)',
    width: 64,
    height: 64,
    borderRadius: 32,
    justifyContent: 'center',
    alignItems: 'center',
  },
  playArrow: {
    color: 'white',
  },
  video: Platform.Version >= 24 ? {} : {
    backgroundColor: 'black',
  },
  controls: {
    backgroundColor: 'rgba(0, 0, 0, 0.6)',
    height: 48,
    marginTop: -48,
    flexDirection: 'row',
    alignItems: 'center',
  },
  playControl: {
    color: 'white',
    padding: 8,
  },
  extraControl: {
    color: 'white',
    padding: 8,
  },
  seekBar: {
    alignItems: 'center',
    height: 30,
    flexGrow: 1,
    flexDirection: 'row',
    paddingHorizontal: 10,
    marginLeft: -10,
    marginRight: -5,
  },
  seekBarFullWidth: {
    marginLeft: 0,
    marginRight: 0,
    paddingHorizontal: 0,
    marginTop: -3,
    height: 3,
  },
  seekBarProgress: {
    height: 3,
    backgroundColor: '#F00',
  },
  seekBarKnob: {
    width: 20,
    height: 20,
    marginHorizontal: -8,
    marginVertical: -10,
    borderRadius: 10,
    backgroundColor: '#F00',
    transform: [{ scale: 0.8 }],
    zIndex: 1,
  },
  seekBarBackground: {
    backgroundColor: 'rgba(255, 255, 255, 0.5)',
    height: 3,
  },
  overlayButton: {
    flex: 1,
  },
});

export default class VideoPlayer extends Component {
  constructor(props) {
    super(props);

    this.state = {
      isStarted: props.autoplay,
      isPlaying: props.autoplay,
      width: 200,
      progress: 0,
      isMuted: props.defaultMuted,
      isControlsVisible: !props.hideControlsOnStart,
      duration: 0,
      isSeeking: false,
    };

    this.seekBarWidth = 200;
    this.wasPlayingBeforeSeek = props.autoplay;
    this.seekTouchStart = 0;
    this.seekProgressStart = 0;

    this.onLayout = this.onLayout.bind(this);
    this.onStartPress = this.onStartPress.bind(this);
    this.onProgress = this.onProgress.bind(this);
    this.onEnd = this.onEnd.bind(this);
    this.onLoad = this.onLoad.bind(this);
    this.onPlayPress = this.onPlayPress.bind(this);
    this.onMutePress = this.onMutePress.bind(this);
    this.showControls = this.showControls.bind(this);
    this.onToggleFullScreen = this.onToggleFullScreen.bind(this);
    this.onSeekBarLayout = this.onSeekBarLayout.bind(this);
    this.onSeekGrant = this.onSeekGrant.bind(this);
    this.onSeekRelease = this.onSeekRelease.bind(this);
    this.onSeek = this.onSeek.bind(this);
  }

  componentDidMount() {
    if (this.props.autoplay) {
      this.hideControls();
    }
  }

  componentWillUnmount() {
    if (this.controlsTimeout) {
      clearTimeout(this.controlsTimeout);
      this.controlsTimeout = null;
    }
  }

  onLayout(event) {
    const { width } = event.nativeEvent.layout;
    this.setState({
      width,
    });
  }

  onStartPress() {
    if (this.props.onStart) {
      this.props.onStart();
    }

    this.setState(state => ({
      isPlaying: true,
      isStarted: true,
      progress: state.progress === 1 ? 0 : state.progress,
    }));

    this.hideControls();
  }

  onProgress(event) {
    if (this.state.isSeeking) {
      return;
    }
    if (this.props.onProgress) {
      this.props.onProgress(event);
    }
    this.setState({
      progress: event.currentTime / (this.props.duration || this.state.duration),
    });
  }

  onEnd(event) {
    if (this.props.onEnd) {
      this.props.onEnd(event);
    }

    if (this.props.endWithThumbnail) {
      this.setState({ isStarted: false });
      this.player.dismissFullscreenPlayer();
    }

    this.setState({ progress: 1 });

    if (!this.props.loop) {
      this.setState(
        { isPlaying: false },
        () => this.player && this.player.seek(0)
      );
    } else {
      this.player.seek(0);
    }
  }

  onLoad(event) {
    if (this.props.onLoad) {
      this.props.onLoad(event);
    }

    const { duration } = event;
    this.setState({ duration });
  }

  onPlayPress() {
    if (this.props.onPlayPress) {
      this.props.onPlayPress();
    }

    this.setState({
      isPlaying: !this.state.isPlaying,
    });
    this.showControls();
  }

  onMutePress() {
    const isMuted = !this.state.isMuted;
    if (this.props.onMutePress) {
      this.props.onMutePress(isMuted);
    }
    this.setState({
      isMuted,
    });
    this.showControls();

  }

  onToggleFullScreen() {
    this.player.presentFullscreenPlayer();
  }

  onSeekBarLayout({ nativeEvent }) {
    const customStyle = this.props.customStyles.seekBar;
    let padding = 0;
    if (customStyle && customStyle.paddingHorizontal) {
      padding = customStyle.paddingHorizontal * 2;
    } else if (customStyle) {
      padding = customStyle.paddingLeft || 0;
      padding += customStyle.paddingRight ? customStyle.paddingRight : 0;
    } else {
      padding = 20;
    }

    this.seekBarWidth = nativeEvent.layout.width - padding;
  }

  onSeekStartResponder() {
    return true;
  }

  onSeekMoveResponder() {
    return true;
  }

  onSeekGrant(e) {
    this.seekTouchStart = e.nativeEvent.pageX;
    this.seekProgressStart = this.state.progress;
    this.wasPlayingBeforeSeek = this.state.isPlaying;
    this.setState({
      isSeeking: true,
      isPlaying: false,
    });
  }

  onSeekRelease() {
    this.setState({
      isSeeking: false,
      isPlaying: this.wasPlayingBeforeSeek,
    });
    this.showControls();
  }

  onSeek(e) {
    const diff = e.nativeEvent.pageX - this.seekTouchStart;
    const ratio = 100 / this.seekBarWidth;
    const progress = this.seekProgressStart + ((ratio * diff) / 100);

    this.setState({
      progress,
    });

    this.player.seek(progress * this.state.duration);
  }

  getSizeStyles() {
    const { videoWidth, videoHeight } = this.props;
    const { width } = this.state;
    const ratio = videoHeight / videoWidth;
    return {
      height: width * ratio,
      width,
    };
  }

  hideControls() {
    if (this.props.onHideControls) {
      this.props.onHideControls();
    }

    if (this.props.disableControlsAutoHide) {
      return;
    }

    if (this.controlsTimeout) {
      clearTimeout(this.controlsTimeout);
      this.controlsTimeout = null;
    }
    this.controlsTimeout = setTimeout(() => {
      this.setState({ isControlsVisible: false });
    }, this.props.controlsTimeout);
  }

  showControls() {
    if (this.props.onShowControls) {
      this.props.onShowControls();
    }

    this.setState({
      isControlsVisible: true,
    });
    this.hideControls();
  }

  seek(t) {
    this.player.seek(t);
  }

  stop() {
    this.setState({
      isPlaying: false,
      progress: 0,
    });
    this.seek(0);
    this.showControls();
  }

  pause() {
    this.setState({
      isPlaying: false,
    });
    this.showControls();
  }

  resume() {
    this.setState({
      isPlaying: true,
    });
    this.showControls();
  }

  renderStartButton() {
    const { customStyles } = this.props;
    return (
      <TouchableOpacity
        style={[styles.playButton, customStyles.playButton]}
        onPress={this.onStartPress}
      >
        <Icon style={[styles.playArrow, customStyles.playArrow]} name="play-arrow" size={42} />
      </TouchableOpacity>
    );
  }

  renderThumbnail() {
    const { thumbnail, style, customStyles, ...props } = this.props;
    return (
      <BackgroundImage
        {...props}
        style={[
          styles.thumbnail,
          this.getSizeStyles(),
          style,
          customStyles.thumbnail,
        ]}
        source={thumbnail}
      >
        {this.renderStartButton()}
      </BackgroundImage>
    );
  }

  renderSeekBar(fullWidth) {
    const { customStyles, disableSeek } = this.props;
    return (
      <View
        style={[
          styles.seekBar,
          fullWidth ? styles.seekBarFullWidth : {},
          customStyles.seekBar,
          fullWidth ? customStyles.seekBarFullWidth : {},
        ]}
        onLayout={this.onSeekBarLayout}
      >
        <View
          style={[
            { flexGrow: this.state.progress },
            styles.seekBarProgress,
            customStyles.seekBarProgress,
          ]}
        />
        { !fullWidth && !disableSeek ? (
          <View
            style={[
              styles.seekBarKnob,
              customStyles.seekBarKnob,
              this.state.isSeeking ? { transform: [{ scale: 1 }] } : {},
              this.state.isSeeking ? customStyles.seekBarKnobSeeking : {},
            ]}
            hitSlop={{ top: 20, bottom: 20, left: 10, right: 20 }}
            onStartShouldSetResponder={this.onSeekStartResponder}
            onMoveShouldSetPanResponder={this.onSeekMoveResponder}
            onResponderGrant={this.onSeekGrant}
            onResponderMove={this.onSeek}
            onResponderRelease={this.onSeekRelease}
            onResponderTerminate={this.onSeekRelease}
          />
        ) : null }
        <View style={[
          styles.seekBarBackground,
          { flexGrow: 1 - this.state.progress },
          customStyles.seekBarBackground,
        ]} />
      </View>
    );
  }

  renderControls() {
    const { customStyles } = this.props;
    return (
      <View style={[styles.controls, customStyles.controls]}>
        <TouchableOpacity
          onPress={this.onPlayPress}
          style={[customStyles.controlButton, customStyles.playControl]}
        >
          <Icon
            style={[styles.playControl, customStyles.controlIcon, customStyles.playIcon]}
            name={this.state.isPlaying ? 'pause' : 'play-arrow'}
            size={32}
          />
        </TouchableOpacity>
        {this.renderSeekBar()}
        {this.props.muted ? null : (
          <TouchableOpacity onPress={this.onMutePress} style={customStyles.controlButton}>
            <Icon
              style={[styles.extraControl, customStyles.controlIcon]}
              name={this.state.isMuted ? 'volume-off' : 'volume-up'}
              size={24}
            />
          </TouchableOpacity>
        )}
        {(Platform.OS === 'android' || this.props.disableFullscreen) ? null : (
          <TouchableOpacity onPress={this.onToggleFullScreen} style={customStyles.controlButton}>
            <Icon
              style={[styles.extraControl, customStyles.controlIcon]}
              name="fullscreen"
              size={32}
            />
          </TouchableOpacity>
        )}
      </View>
    );
  }

  renderVideo() {
    const {
      video,
      style,
      resizeMode,
      pauseOnPress,
      fullScreenOnLongPress,
      customStyles,
      ...props
    } = this.props;
    return (
      <View style={customStyles.videoWrapper}>
        <Video
          {...props}
          style={[
            styles.video,
            this.getSizeStyles(),
            style,
            customStyles.video,
          ]}
          ref={p => { this.player = p; }}
          muted={this.props.muted || this.state.isMuted}
          paused={this.props.paused
            ? this.props.paused || !this.state.isPlaying
            : !this.state.isPlaying}
          onProgress={this.onProgress}
          onEnd={this.onEnd}
          onLoad={this.onLoad}
          source={video}
          resizeMode={resizeMode}
        />
        <View
          style={[
            this.getSizeStyles(),
            { marginTop: -this.getSizeStyles().height },
          ]}
        >
          <TouchableOpacity
            style={styles.overlayButton}
            onPress={() => {
              this.showControls();
              if (pauseOnPress)
                this.onPlayPress();
            }}
            onLongPress={() => {
              if (fullScreenOnLongPress && Platform.OS !== 'android')
                this.onToggleFullScreen();
            }}
          />
        </View>
        {((!this.state.isPlaying) || this.state.isControlsVisible)
          ? this.renderControls() : this.renderSeekBar(true)}
      </View>
    );
  }

  renderContent() {
    const { thumbnail, style } = this.props;
    const { isStarted } = this.state;

    if (!isStarted && thumbnail) {
      return this.renderThumbnail();
    } else if (!isStarted) {
      return (
        <View style={[styles.preloadingPlaceholder, this.getSizeStyles(), style]}>
          {this.renderStartButton()}
        </View>
      );
    }
    return this.renderVideo();
  }

  render() {
    return (
      <View onLayout={this.onLayout} style={this.props.customStyles.wrapper}>
        {this.renderContent()}
      </View>
    );
  }
}

VideoPlayer.propTypes = {
  video: Video.propTypes.source,
  thumbnail: Image.propTypes.source,
  videoWidth: PropTypes.number,
  videoHeight: PropTypes.number,
  duration: PropTypes.number,
  autoplay: PropTypes.bool,
  paused: PropTypes.bool,
  defaultMuted: PropTypes.bool,
  muted: PropTypes.bool,
  style: ViewPropTypes.style,
  controlsTimeout: PropTypes.number,
  disableControlsAutoHide: PropTypes.bool,
  disableFullscreen: PropTypes.bool,
  loop: PropTypes.bool,
  resizeMode: Video.propTypes.resizeMode,
  hideControlsOnStart: PropTypes.bool,
  endWithThumbnail: PropTypes.bool,
  disableSeek: PropTypes.bool,
  pauseOnPress: PropTypes.bool,
  fullScreenOnLongPress: PropTypes.bool,
  customStyles: PropTypes.shape({
    wrapper: ViewPropTypes.style,
    video: Video.propTypes.style,
    videoWrapper: ViewPropTypes.style,
    controls: ViewPropTypes.style,
    playControl: TouchableOpacity.propTypes.style,
    controlButton: TouchableOpacity.propTypes.style,
    controlIcon: Icon.propTypes.style,
    playIcon: Icon.propTypes.style,
    seekBar: ViewPropTypes.style,
    seekBarFullWidth: ViewPropTypes.style,
    seekBarProgress: ViewPropTypes.style,
    seekBarKnob: ViewPropTypes.style,
    seekBarKnobSeeking: ViewPropTypes.style,
    seekBarBackground: ViewPropTypes.style,
    thumbnail: Image.propTypes.style,
    playButton: TouchableOpacity.propTypes.style,
    playArrow: Icon.propTypes.style,
  }),
  onEnd: PropTypes.func,
  onProgress: PropTypes.func,
  onLoad: PropTypes.func,
  onStart: PropTypes.func,
  onPlayPress: PropTypes.func,
  onHideControls: PropTypes.func,
  onShowControls: PropTypes.func,
  onMutePress: PropTypes.func,
};

VideoPlayer.defaultProps = {
  videoWidth: 1280,
  videoHeight: 720,
  autoplay: false,
  controlsTimeout: 2000,
  loop: false,
  resizeMode: 'contain',
  disableSeek: false,
  pauseOnPress: false,
  fullScreenOnLongPress: false,
  customStyles: {},
};
<commit_msg>working for rn 0.42.0<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Image, ImageBackground, Platform, StyleSheet, TouchableOpacity, View, ViewPropTypes} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
import Video from 'react-native-video'; // eslint-disable-line

const BackgroundImage = ImageBackground || Image; // fall back to Image if RN < 0.46

let ViewPropTypesVar

if (ViewPropTypes) {
  ViewPropTypesVar = ViewPropTypes
} else {
  ViewPropTypesVar = View.propTypes
}

const styles = StyleSheet.create({
  preloadingPlaceholder: {
    backgroundColor: 'black',
    justifyContent: 'center',
    alignItems: 'center',
  },
  thumbnail: {
    backgroundColor: 'black',
    justifyContent: 'center',
    alignItems: 'center',
  },
  playButton: {
    backgroundColor: 'rgba(0, 0, 0, 0.6)',
    width: 64,
    height: 64,
    borderRadius: 32,
    justifyContent: 'center',
    alignItems: 'center',
  },
  playArrow: {
    color: 'white',
  },
  video: Platform.Version >= 24 ? {} : {
    backgroundColor: 'black',
  },
  controls: {
    backgroundColor: 'rgba(0, 0, 0, 0.6)',
    height: 48,
    marginTop: -48,
    flexDirection: 'row',
    alignItems: 'center',
  },
  playControl: {
    color: 'white',
    padding: 8,
  },
  extraControl: {
    color: 'white',
    padding: 8,
  },
  seekBar: {
    alignItems: 'center',
    height: 30,
    flexGrow: 1,
    flexDirection: 'row',
    paddingHorizontal: 10,
    marginLeft: -10,
    marginRight: -5,
  },
  seekBarFullWidth: {
    marginLeft: 0,
    marginRight: 0,
    paddingHorizontal: 0,
    marginTop: -3,
    height: 3,
  },
  seekBarProgress: {
    height: 3,
    backgroundColor: '#F00',
  },
  seekBarKnob: {
    width: 20,
    height: 20,
    marginHorizontal: -8,
    marginVertical: -10,
    borderRadius: 10,
    backgroundColor: '#F00',
    transform: [{ scale: 0.8 }],
    zIndex: 1,
  },
  seekBarBackground: {
    backgroundColor: 'rgba(255, 255, 255, 0.5)',
    height: 3,
  },
  overlayButton: {
    flex: 1,
  },
});

export default class VideoPlayer extends Component {
  constructor(props) {
    super(props);

    this.state = {
      isStarted: props.autoplay,
      isPlaying: props.autoplay,
      width: 200,
      progress: 0,
      isMuted: props.defaultMuted,
      isControlsVisible: !props.hideControlsOnStart,
      duration: 0,
      isSeeking: false,
    };

    this.seekBarWidth = 200;
    this.wasPlayingBeforeSeek = props.autoplay;
    this.seekTouchStart = 0;
    this.seekProgressStart = 0;

    this.onLayout = this.onLayout.bind(this);
    this.onStartPress = this.onStartPress.bind(this);
    this.onProgress = this.onProgress.bind(this);
    this.onEnd = this.onEnd.bind(this);
    this.onLoad = this.onLoad.bind(this);
    this.onPlayPress = this.onPlayPress.bind(this);
    this.onMutePress = this.onMutePress.bind(this);
    this.showControls = this.showControls.bind(this);
    this.onToggleFullScreen = this.onToggleFullScreen.bind(this);
    this.onSeekBarLayout = this.onSeekBarLayout.bind(this);
    this.onSeekGrant = this.onSeekGrant.bind(this);
    this.onSeekRelease = this.onSeekRelease.bind(this);
    this.onSeek = this.onSeek.bind(this);
  }

  componentDidMount() {
    if (this.props.autoplay) {
      this.hideControls();
    }
  }

  componentWillUnmount() {
    if (this.controlsTimeout) {
      clearTimeout(this.controlsTimeout);
      this.controlsTimeout = null;
    }
  }

  onLayout(event) {
    const { width } = event.nativeEvent.layout;
    this.setState({
      width,
    });
  }

  onStartPress() {
    if (this.props.onStart) {
      this.props.onStart();
    }

    this.setState(state => ({
      isPlaying: true,
      isStarted: true,
      progress: state.progress === 1 ? 0 : state.progress,
    }));

    this.hideControls();
  }

  onProgress(event) {
    if (this.state.isSeeking) {
      return;
    }
    if (this.props.onProgress) {
      this.props.onProgress(event);
    }
    this.setState({
      progress: event.currentTime / (this.props.duration || this.state.duration),
    });
  }

  onEnd(event) {
    if (this.props.onEnd) {
      this.props.onEnd(event);
    }

    if (this.props.endWithThumbnail) {
      this.setState({ isStarted: false });
      this.player.dismissFullscreenPlayer();
    }

    this.setState({ progress: 1 });

    if (!this.props.loop) {
      this.setState(
        { isPlaying: false },
        () => this.player && this.player.seek(0)
      );
    } else {
      this.player.seek(0);
    }
  }

  onLoad(event) {
    if (this.props.onLoad) {
      this.props.onLoad(event);
    }

    const { duration } = event;
    this.setState({ duration });
  }

  onPlayPress() {
    if (this.props.onPlayPress) {
      this.props.onPlayPress();
    }

    this.setState({
      isPlaying: !this.state.isPlaying,
    });
    this.showControls();
  }

  onMutePress() {
    const isMuted = !this.state.isMuted;
    if (this.props.onMutePress) {
      this.props.onMutePress(isMuted);
    }
    this.setState({
      isMuted,
    });
    this.showControls();

  }

  onToggleFullScreen() {
    this.player.presentFullscreenPlayer();
  }

  onSeekBarLayout({ nativeEvent }) {
    const customStyle = this.props.customStyles.seekBar;
    let padding = 0;
    if (customStyle && customStyle.paddingHorizontal) {
      padding = customStyle.paddingHorizontal * 2;
    } else if (customStyle) {
      padding = customStyle.paddingLeft || 0;
      padding += customStyle.paddingRight ? customStyle.paddingRight : 0;
    } else {
      padding = 20;
    }

    this.seekBarWidth = nativeEvent.layout.width - padding;
  }

  onSeekStartResponder() {
    return true;
  }

  onSeekMoveResponder() {
    return true;
  }

  onSeekGrant(e) {
    this.seekTouchStart = e.nativeEvent.pageX;
    this.seekProgressStart = this.state.progress;
    this.wasPlayingBeforeSeek = this.state.isPlaying;
    this.setState({
      isSeeking: true,
      isPlaying: false,
    });
  }

  onSeekRelease() {
    this.setState({
      isSeeking: false,
      isPlaying: this.wasPlayingBeforeSeek,
    });
    this.showControls();
  }

  onSeek(e) {
    const diff = e.nativeEvent.pageX - this.seekTouchStart;
    const ratio = 100 / this.seekBarWidth;
    const progress = this.seekProgressStart + ((ratio * diff) / 100);

    this.setState({
      progress,
    });

    this.player.seek(progress * this.state.duration);
  }

  getSizeStyles() {
    const { videoWidth, videoHeight } = this.props;
    const { width } = this.state;
    const ratio = videoHeight / videoWidth;
    return {
      height: width * ratio,
      width,
    };
  }

  hideControls() {
    if (this.props.onHideControls) {
      this.props.onHideControls();
    }

    if (this.props.disableControlsAutoHide) {
      return;
    }

    if (this.controlsTimeout) {
      clearTimeout(this.controlsTimeout);
      this.controlsTimeout = null;
    }
    this.controlsTimeout = setTimeout(() => {
      this.setState({ isControlsVisible: false });
    }, this.props.controlsTimeout);
  }

  showControls() {
    if (this.props.onShowControls) {
      this.props.onShowControls();
    }

    this.setState({
      isControlsVisible: true,
    });
    this.hideControls();
  }

  seek(t) {
    this.player.seek(t);
  }

  stop() {
    this.setState({
      isPlaying: false,
      progress: 0,
    });
    this.seek(0);
    this.showControls();
  }

  pause() {
    this.setState({
      isPlaying: false,
    });
    this.showControls();
  }

  resume() {
    this.setState({
      isPlaying: true,
    });
    this.showControls();
  }

  renderStartButton() {
    const { customStyles } = this.props;
    return (
      <TouchableOpacity
        style={[styles.playButton, customStyles.playButton]}
        onPress={this.onStartPress}
      >
        <Icon style={[styles.playArrow, customStyles.playArrow]} name="play-arrow" size={42} />
      </TouchableOpacity>
    );
  }

  renderThumbnail() {
    const { thumbnail, style, customStyles, ...props } = this.props;
    return (
      <BackgroundImage
        {...props}
        style={[
          styles.thumbnail,
          this.getSizeStyles(),
          style,
          customStyles.thumbnail,
        ]}
        source={thumbnail}
      >
        {this.renderStartButton()}
      </BackgroundImage>
    );
  }

  renderSeekBar(fullWidth) {
    const { customStyles, disableSeek } = this.props;
    return (
      <View
        style={[
          styles.seekBar,
          fullWidth ? styles.seekBarFullWidth : {},
          customStyles.seekBar,
          fullWidth ? customStyles.seekBarFullWidth : {},
        ]}
        onLayout={this.onSeekBarLayout}
      >
        <View
          style={[
            { flexGrow: this.state.progress },
            styles.seekBarProgress,
            customStyles.seekBarProgress,
          ]}
        />
        { !fullWidth && !disableSeek ? (
          <View
            style={[
              styles.seekBarKnob,
              customStyles.seekBarKnob,
              this.state.isSeeking ? { transform: [{ scale: 1 }] } : {},
              this.state.isSeeking ? customStyles.seekBarKnobSeeking : {},
            ]}
            hitSlop={{ top: 20, bottom: 20, left: 10, right: 20 }}
            onStartShouldSetResponder={this.onSeekStartResponder}
            onMoveShouldSetPanResponder={this.onSeekMoveResponder}
            onResponderGrant={this.onSeekGrant}
            onResponderMove={this.onSeek}
            onResponderRelease={this.onSeekRelease}
            onResponderTerminate={this.onSeekRelease}
          />
        ) : null }
        <View style={[
          styles.seekBarBackground,
          { flexGrow: 1 - this.state.progress },
          customStyles.seekBarBackground,
        ]} />
      </View>
    );
  }

  renderControls() {
    const { customStyles } = this.props;
    return (
      <View style={[styles.controls, customStyles.controls]}>
        <TouchableOpacity
          onPress={this.onPlayPress}
          style={[customStyles.controlButton, customStyles.playControl]}
        >
          <Icon
            style={[styles.playControl, customStyles.controlIcon, customStyles.playIcon]}
            name={this.state.isPlaying ? 'pause' : 'play-arrow'}
            size={32}
          />
        </TouchableOpacity>
        {this.renderSeekBar()}
        {this.props.muted ? null : (
          <TouchableOpacity onPress={this.onMutePress} style={customStyles.controlButton}>
            <Icon
              style={[styles.extraControl, customStyles.controlIcon]}
              name={this.state.isMuted ? 'volume-off' : 'volume-up'}
              size={24}
            />
          </TouchableOpacity>
        )}
        {(Platform.OS === 'android' || this.props.disableFullscreen) ? null : (
          <TouchableOpacity onPress={this.onToggleFullScreen} style={customStyles.controlButton}>
            <Icon
              style={[styles.extraControl, customStyles.controlIcon]}
              name="fullscreen"
              size={32}
            />
          </TouchableOpacity>
        )}
      </View>
    );
  }

  renderVideo() {
    const {
      video,
      style,
      resizeMode,
      pauseOnPress,
      fullScreenOnLongPress,
      customStyles,
      ...props
    } = this.props;
    return (
      <View style={customStyles.videoWrapper}>
        <Video
          {...props}
          style={[
            styles.video,
            this.getSizeStyles(),
            style,
            customStyles.video,
          ]}
          ref={p => { this.player = p; }}
          muted={this.props.muted || this.state.isMuted}
          paused={this.props.paused
            ? this.props.paused || !this.state.isPlaying
            : !this.state.isPlaying}
          onProgress={this.onProgress}
          onEnd={this.onEnd}
          onLoad={this.onLoad}
          source={video}
          resizeMode={resizeMode}
        />
        <View
          style={[
            this.getSizeStyles(),
            { marginTop: -this.getSizeStyles().height },
          ]}
        >
          <TouchableOpacity
            style={styles.overlayButton}
            onPress={() => {
              this.showControls();
              if (pauseOnPress)
                this.onPlayPress();
            }}
            onLongPress={() => {
              if (fullScreenOnLongPress && Platform.OS !== 'android')
                this.onToggleFullScreen();
            }}
          />
        </View>
        {((!this.state.isPlaying) || this.state.isControlsVisible)
          ? this.renderControls() : this.renderSeekBar(true)}
      </View>
    );
  }

  renderContent() {
    const { thumbnail, style } = this.props;
    const { isStarted } = this.state;

    if (!isStarted && thumbnail) {
      return this.renderThumbnail();
    } else if (!isStarted) {
      return (
        <View style={[styles.preloadingPlaceholder, this.getSizeStyles(), style]}>
          {this.renderStartButton()}
        </View>
      );
    }
    return this.renderVideo();
  }

  render() {
    return (
      <View onLayout={this.onLayout} style={this.props.customStyles.wrapper}>
        {this.renderContent()}
      </View>
    );
  }
}

VideoPlayer.propTypes = {
  video: Video.propTypes.source,
  thumbnail: Image.propTypes.source,
  videoWidth: PropTypes.number,
  videoHeight: PropTypes.number,
  duration: PropTypes.number,
  autoplay: PropTypes.bool,
  paused: PropTypes.bool,
  defaultMuted: PropTypes.bool,
  muted: PropTypes.bool,
  style: ViewPropTypesVar.style,
  controlsTimeout: PropTypes.number,
  disableControlsAutoHide: PropTypes.bool,
  disableFullscreen: PropTypes.bool,
  loop: PropTypes.bool,
  resizeMode: Video.propTypes.resizeMode,
  hideControlsOnStart: PropTypes.bool,
  endWithThumbnail: PropTypes.bool,
  disableSeek: PropTypes.bool,
  pauseOnPress: PropTypes.bool,
  fullScreenOnLongPress: PropTypes.bool,
  customStyles: PropTypes.shape({
    wrapper: ViewPropTypesVar.style,
    video: Video.propTypes.style,
    videoWrapper: ViewPropTypesVar.style,
    controls: ViewPropTypesVar.style,
    playControl: TouchableOpacity.propTypes.style,
    controlButton: TouchableOpacity.propTypes.style,
    controlIcon: Icon.propTypes.style,
    playIcon: Icon.propTypes.style,
    seekBar: ViewPropTypesVar.style,
    seekBarFullWidth: ViewPropTypesVar.style,
    seekBarProgress: ViewPropTypesVar.style,
    seekBarKnob: ViewPropTypesVar.style,
    seekBarKnobSeeking: ViewPropTypesVar.style,
    seekBarBackground: ViewPropTypesVar.style,
    thumbnail: Image.propTypes.style,
    playButton: TouchableOpacity.propTypes.style,
    playArrow: Icon.propTypes.style,
  }),
  onEnd: PropTypes.func,
  onProgress: PropTypes.func,
  onLoad: PropTypes.func,
  onStart: PropTypes.func,
  onPlayPress: PropTypes.func,
  onHideControls: PropTypes.func,
  onShowControls: PropTypes.func,
  onMutePress: PropTypes.func,
};

VideoPlayer.defaultProps = {
  videoWidth: 1280,
  videoHeight: 720,
  autoplay: false,
  controlsTimeout: 2000,
  loop: false,
  resizeMode: 'contain',
  disableSeek: false,
  pauseOnPress: false,
  fullScreenOnLongPress: false,
  customStyles: {},
};
<|endoftext|>


<commit_before>/**
 * Calculates the outer product of the dimension array.
 * The output will be a collection of array that each is composed of all dimensions.
 * @example
 * // returns [['a', 1], ['b', 1], ['a', 2], ['b', 2]]
 * require('outer-product')([['a', 'b'], [1, 2]])
 * @param {Array.<Array>} dimensions
 * @returns {Array.<Array>} Combinations of all dimensions
 */
module.exports = function outerProduct(dimensions) {
    if (!Array.isArray(dimensions)) throw new Error("Array expected");
    if (!dimensions.length) return [];

    var results = [];
    var positions = [];
    var lengths = [];
    var skips = [];
    var i;
    var dimsCount = dimensions.length;
    var skipMul = 1;
    var dim;
    var result;
    var shouldSkip;
    var len;

    // prepare our states
    for (i = 0; i < dimsCount; i++) {
        var dimSize = dimensions[i].length;
        lengths[i] = dimSize;
        positions[i] = 0;
        skips.push(skipMul);
        skipMul *= dimSize;
    }

    // build product
    for (i = 0; i < skipMul; i++) {
        result = results[i] = [];
        for (dim = 0; dim < dimsCount; dim++) {
            shouldSkip = i % skips[dim] == 0;
            len = lengths[dim];
            if (shouldSkip) {
                positions[dim] = (positions[dim] + 1) % len;
            }
            result.push(dimensions[dim][positions[dim]]);
        }
    }

    return results;
};<commit_msg>using new algorithm<commit_after>/**
 * Calculates the outer product of the dimension array.
 * The output will be a collection of array that each is composed of all dimensions.
 * @example
 * // returns [['a', 1], ['b', 1], ['a', 2], ['b', 2]]
 * require('outer-product')([['a', 'b'], [1, 2]])
 * @param {Array.<Array>} dimensions
 * @returns {Array.<Array>} Combinations of all dimensions
 */
module.exports = function outerProduct(dimensions) {
    if (!Array.isArray(dimensions)) throw new Error("Array expected");
    if(!dimensions.length) return [];

    var results = [];
    var dimsCount = dimensions.length;
    var i;
    // the size of each dimension
    var sizes = [];
    // the position of each dimension
    var positions = [];
    var position;
    var result;
    var total = 1;
    var dim;
    var lastDimOverflowed;

    var l = dimsCount;
    while (l--) {
        positions[l] = 0;
        sizes[l] = dimensions[l].length;
        total *= sizes[l];
    }

    for (i = 0; i < total; i++) {
        result = [];
        lastDimOverflowed = true;
        for (dim = 0; dim < dimsCount; dim++) {
            position = positions[dim];
            result.push(dimensions[dim][position]);
            if(lastDimOverflowed) {
                position = (position + 1) % sizes[dim];
                positions[dim] = position;
                lastDimOverflowed = position == 0;
            }
        }
        results.push(result);
    }

    return results;
};<|endoftext|>


<commit_before>module.exports = function validate(numeroAlmno) {
  if (numeroAlmno.length == 8) {
    return true;
  } else {
    return false;
  }
}
<commit_msg>Initial algorithm commit<commit_after>module.exports = function validate(studentNumber) {
  const givenDigit = studentNumber.split('').reverse().slice(0, 1).join('').toUpperCase();
  const chars = studentNumber.split('').reverse().splice(1);

  let counter = 2;
  let sum = 0;
  for (let char of chars) {
    sum += Number(char) * counter++;
    counter = counter > 8 ? 2 : counter;
  }

  const verificationDigit = (11 - sum % 11 != 10) ? String(11 - sum % 11) : 'J';
  return verificationDigit === givenDigit;
}
<|endoftext|>


<commit_before>import { Meteor } from 'meteor/meteor';
import { Picker } from 'meteor/meteorhacks:picker';
import bodyParser from 'body-parser';

import ShopifyRequest from '../../api/shopify/server/shopify_request';
import Payments from '../../api/payments/collection';
import ShopifyResponse from '../../api/shopify/server/shopify_response';
import CustomersCollection from '../../api/customers/collection';
import Subscription from '../../api/subscriptions/server/subscription';
import Stripe from '../../api/cards/server/stripe';

const RouteHandler = {
  // Verify the incoming shopify request is valid, save the incoming payment
  // details, then redirect to the application root to display payment
  // details and load the Stripe checkout widget.
  incomingPayment(params, req, res) {
    const shopifyRequest = Object.create(ShopifyRequest);
    shopifyRequest.init(req.body);

    if (shopifyRequest.isSignatureValid()) {
      // Store the incoming payment information and redirect to home to
      // show the Stripe checkout form
      const paymentId = Payments.insert(shopifyRequest.request);
      res.writeHead(302, {
        Location: `/?id=${paymentId}`,
      });
    } else {
      // Invalid signature; redirect to shopify
      res.writeHead(302, {
        Location: shopifyRequest.request.x_url_cancel,
      });
    }

    res.end();
  },

  // With this approach it's assumed that a Stripe token has already been
  // created and saved. Verify the incoming Shopify request, then find the
  // matching Stripe token. Save the incoming payment details, create the
  // necessary Stripe charge, and redirect back to Shopify. This option
  // by-passes the Stripe checkout locally.
  incomingPaymentWithToken(params, req, res) {
    const shopifyRequest = Object.create(ShopifyRequest);
    shopifyRequest.init(req.body);
    const payment = shopifyRequest.request;

    if (shopifyRequest.isSignatureValid()) {
      if (payment.stripe_token) {
        // Save incoming Shopify request payment details for reference
        payment.timestamp = new Date();
        const paymentId = Payments.insert(payment);

        try {
          const charge = CustomersCollection.findAndChargeCustomer(payment);

          // Updated saved payment details with successful Stripe charge
          // reference information
          Payments.update(
            { _id: paymentId },
            { $set: { status: 'completed', charge, error: null } }
          );

          // Prepare response data and post back to Shopify
          const shopifyResponse = Object.create(ShopifyResponse);
          shopifyResponse.init(payment);
          res.writeHead(302, {
            Location: `${payment.x_url_complete}?${shopifyResponse.queryString()}`,
          });
        } catch (error) {
          // Unable to create Stripe charge so save error details with payment
          // information and redirect back to the Shopify request cancel URL
          Payments.update(
            { _id: paymentId },
            { $set: { status: 'failed', error, charge: null } }
          );
          res.writeHead(302, { Location: payment.x_url_cancel });
        }
      } else {
        // Missing token; redirect to shopify cancel URL
        res.writeHead(302, { Location: payment.x_url_cancel });
      }
    } else {
      // Invalid signature; redirect to shopify cancel URL
      res.writeHead(302, { Location: payment.x_url_cancel });
    }

    res.end();
  },

  // When the Shopify "Order Payment" event is fired, this webhook can be called
  // to send order data into a 3rd party subscription system.
  orderPayment(params, req, res) {
    const orderData = req.body;
    if (orderData) {
      const lineItems = orderData.line_items;
      lineItems.forEach((lineItem) => {
        if (lineItem.sku.indexOf('TF_SUB') > -1) {
          // Subscription order found; create new subscription in MP
          Subscription.create(orderData);
        }
      });
    }
    res.end();
  },

  updateCard(params, req, res) {
    const cardDetails = req.body;
    let statusCode = 400;
    const updateResponse = {};
    if (cardDetails) {
      try {
        Stripe.updateCard({
          customerId: cardDetails.customerId,
          tokenId: cardDetails.tokenId,
        });
        statusCode = 200;
        updateResponse.success = true;
        updateResponse.message = 'Card updated';
      } catch (error) {
        updateResponse.success = false;
        updateResponse.message = 'Unable to update card';
        updateResponse.details = error;
      }
    } else {
      updateResponse.success = false;
      updateResponse.message = 'Missing card details.';
    }

    const response = res;
    this._setHeaders(req, response);
    response.statusCode = statusCode;
    response.end(JSON.stringify(updateResponse));
  },

  chargeCard(params, req, res) {
    const chargeDetails = req.body;
    let statusCode = 400;
    const chargeResponse = {};
    if (chargeDetails) {
      try {
        Stripe.chargeCard({
          customerId: chargeDetails.stripeCustomerId,
          amount: chargeDetails.amount,
        });
        statusCode = 200;
        chargeResponse.success = true;
        chargeResponse.message = 'Card charged.';
      } catch (error) {
        chargeResponse.success = false;
        chargeResponse.message = 'Unable to charge card.';
        chargeResponse.details = error;
      }
    } else {
      chargeResponse.success = false;
      chargeResponse.message = 'Missing charge details.';
    }

    const response = res;
    this._setHeaders(req, response);
    response.statusCode = statusCode;
    response.end(JSON.stringify(chargeResponse));
  },

  _setHeader(request, response) {
    response.setHeader('Content-Type', 'application/json');
    const allowedOrigins = Meteor.settings.private.cors.allowedOrigins;
    const origin = request.headers.origin;
    if (allowedOrigins.indexOf(origin) > -1) {
      response.setHeader('Access-Control-Allow-Origin', origin);
    }
  },
};

Picker.middleware(bodyParser.json());
Picker.middleware(bodyParser.urlencoded({ extended: false }));

Picker.route(
  '/incoming-payment',
  (params, req, res) => RouteHandler.incomingPayment(params, req, res)
);

Picker.route(
  '/incoming-payment-with-token',
  (params, req, res) => RouteHandler.incomingPaymentWithToken(params, req, res)
);

Picker.route(
  '/order-payment',
  (params, req, res) => RouteHandler.orderPayment(params, req, res)
);

Picker.route(
  '/update-card',
  (params, req, res) => RouteHandler.updateCard(params, req, res)
);

Picker.route(
  '/charge-card',
  (params, req, res) => RouteHandler.chargeCard(params, req, res)
);

export default RouteHandler;
<commit_msg>Wired up fix to prevent subscriptions from being created for every line item.<commit_after>import { Meteor } from 'meteor/meteor';
import { Picker } from 'meteor/meteorhacks:picker';
import bodyParser from 'body-parser';

import ShopifyRequest from '../../api/shopify/server/shopify_request';
import Payments from '../../api/payments/collection';
import ShopifyResponse from '../../api/shopify/server/shopify_response';
import CustomersCollection from '../../api/customers/collection';
import Subscription from '../../api/subscriptions/server/subscription';
import Stripe from '../../api/cards/server/stripe';

const RouteHandler = {
  // Verify the incoming shopify request is valid, save the incoming payment
  // details, then redirect to the application root to display payment
  // details and load the Stripe checkout widget.
  incomingPayment(params, req, res) {
    const shopifyRequest = Object.create(ShopifyRequest);
    shopifyRequest.init(req.body);

    if (shopifyRequest.isSignatureValid()) {
      // Store the incoming payment information and redirect to home to
      // show the Stripe checkout form
      const paymentId = Payments.insert(shopifyRequest.request);
      res.writeHead(302, {
        Location: `/?id=${paymentId}`,
      });
    } else {
      // Invalid signature; redirect to shopify
      res.writeHead(302, {
        Location: shopifyRequest.request.x_url_cancel,
      });
    }

    res.end();
  },

  // With this approach it's assumed that a Stripe token has already been
  // created and saved. Verify the incoming Shopify request, then find the
  // matching Stripe token. Save the incoming payment details, create the
  // necessary Stripe charge, and redirect back to Shopify. This option
  // by-passes the Stripe checkout locally.
  incomingPaymentWithToken(params, req, res) {
    const shopifyRequest = Object.create(ShopifyRequest);
    shopifyRequest.init(req.body);
    const payment = shopifyRequest.request;

    if (shopifyRequest.isSignatureValid()) {
      if (payment.stripe_token) {
        // Save incoming Shopify request payment details for reference
        payment.timestamp = new Date();
        const paymentId = Payments.insert(payment);

        try {
          const charge = CustomersCollection.findAndChargeCustomer(payment);

          // Updated saved payment details with successful Stripe charge
          // reference information
          Payments.update(
            { _id: paymentId },
            { $set: { status: 'completed', charge, error: null } }
          );

          // Prepare response data and post back to Shopify
          const shopifyResponse = Object.create(ShopifyResponse);
          shopifyResponse.init(payment);
          res.writeHead(302, {
            Location: `${payment.x_url_complete}?${shopifyResponse.queryString()}`,
          });
        } catch (error) {
          // Unable to create Stripe charge so save error details with payment
          // information and redirect back to the Shopify request cancel URL
          Payments.update(
            { _id: paymentId },
            { $set: { status: 'failed', error, charge: null } }
          );
          res.writeHead(302, { Location: payment.x_url_cancel });
        }
      } else {
        // Missing token; redirect to shopify cancel URL
        res.writeHead(302, { Location: payment.x_url_cancel });
      }
    } else {
      // Invalid signature; redirect to shopify cancel URL
      res.writeHead(302, { Location: payment.x_url_cancel });
    }

    res.end();
  },

  // When the Shopify "Order Payment" event is fired, this webhook can be called
  // to send order data into a 3rd party subscription system.
  orderPayment(params, req, res) {
    const orderData = req.body;
    if (orderData) {
      let subscriptionProductFound = false;
      const lineItems = orderData.line_items;
      lineItems.forEach((lineItem) => {
        if (lineItem.sku.indexOf('TF_SUB') > -1) {
          subscriptionProductFound = true;
        }
      });
      if (subscriptionProductFound) {
        // Subscription order found; create new subscription in MP
        Subscription.create(orderData);
      }
    }
    res.end();
  },

  updateCard(params, req, res) {
    const cardDetails = req.body;
    let statusCode = 400;
    const updateResponse = {};
    if (cardDetails) {
      try {
        Stripe.updateCard({
          customerId: cardDetails.customerId,
          tokenId: cardDetails.tokenId,
        });
        statusCode = 200;
        updateResponse.success = true;
        updateResponse.message = 'Card updated';
      } catch (error) {
        updateResponse.success = false;
        updateResponse.message = 'Unable to update card';
        updateResponse.details = error;
      }
    } else {
      updateResponse.success = false;
      updateResponse.message = 'Missing card details.';
    }

    const response = res;
    this._setHeaders(req, response);
    response.statusCode = statusCode;
    response.end(JSON.stringify(updateResponse));
  },

  chargeCard(params, req, res) {
    const chargeDetails = req.body;
    let statusCode = 400;
    const chargeResponse = {};
    if (chargeDetails) {
      try {
        Stripe.chargeCard({
          customerId: chargeDetails.stripeCustomerId,
          amount: chargeDetails.amount,
        });
        statusCode = 200;
        chargeResponse.success = true;
        chargeResponse.message = 'Card charged.';
      } catch (error) {
        chargeResponse.success = false;
        chargeResponse.message = 'Unable to charge card.';
        chargeResponse.details = error;
      }
    } else {
      chargeResponse.success = false;
      chargeResponse.message = 'Missing charge details.';
    }

    const response = res;
    this._setHeaders(req, response);
    response.statusCode = statusCode;
    response.end(JSON.stringify(chargeResponse));
  },

  _setHeaders(request, response) {
    response.setHeader('Content-Type', 'application/json');
    const allowedOrigins = Meteor.settings.private.cors.allowedOrigins;
    const origin = request.headers.origin;
    if (allowedOrigins.indexOf(origin) > -1) {
      response.setHeader('Access-Control-Allow-Origin', origin);
    }
  },
};

Picker.middleware(bodyParser.json());
Picker.middleware(bodyParser.urlencoded({ extended: false }));

Picker.route(
  '/incoming-payment',
  (params, req, res) => RouteHandler.incomingPayment(params, req, res)
);

Picker.route(
  '/incoming-payment-with-token',
  (params, req, res) => RouteHandler.incomingPaymentWithToken(params, req, res)
);

Picker.route(
  '/order-payment',
  (params, req, res) => RouteHandler.orderPayment(params, req, res)
);

Picker.route(
  '/update-card',
  (params, req, res) => RouteHandler.updateCard(params, req, res)
);

Picker.route(
  '/charge-card',
  (params, req, res) => RouteHandler.chargeCard(params, req, res)
);

export default RouteHandler;
<|endoftext|>


<commit_before>/*global exports*/
var SignStream = require('./lib/sign-stream');
var VerifyStream = require('./lib/verify-stream');

var ALGORITHMS = [
  'HS256', 'HS384', 'HS512',
  'RS256', 'RS384', 'RS512',
  'ES256', 'ES384', 'ES512'
];

exports.ALGORITHMS = ALGORITHMS;
exports.sign = SignStream.sign;
exports.verify = VerifyStream.verify;
exports.decode = VerifyStream.decode;
exports.isValid = VerifyStream.isValid;
exports.createSign = function createSign(opts) {
  return new SignStream(opts);
};
exports.createVerify = function createVerify(opts) {
  return new VerifyStream(opts);
};
<commit_msg>update jws.ALGORITHMS<commit_after>/*global exports*/
var SignStream = require('./lib/sign-stream');
var VerifyStream = require('./lib/verify-stream');

var ALGORITHMS = [
  'HS256', 'HS384', 'HS512',
  'RS256', 'RS384', 'RS512',
  'PS256', 'PS384', 'PS512',
  'ES256', 'ES384', 'ES512'
];

exports.ALGORITHMS = ALGORITHMS;
exports.sign = SignStream.sign;
exports.verify = VerifyStream.verify;
exports.decode = VerifyStream.decode;
exports.isValid = VerifyStream.isValid;
exports.createSign = function createSign(opts) {
  return new SignStream(opts);
};
exports.createVerify = function createVerify(opts) {
  return new VerifyStream(opts);
};
<|endoftext|>


<commit_before>Oskari.registerLocalization({
    "lang": "en",
    "key": "DivManazer",
    "value": {
        "buttons": {
            "add": "Add",
            "cancel": "Cancel",
            "close": "Close",
            "delete": "Delete",
            "edit": "Edit",
            "ok": "OK",
            "save": "Save",
            "search": "Search"
        },
        "LanguageSelect": {
            "title": "Language",
            "tooltip": "Select language",
            "languages": {
                "af": "Afrikaans",
                "ak": "Akan",
                "am": "Amharic",
                "ar": "Arabic",
                "az": "Azerbaijani",
                "be": "Belarusian",
                "bg": "Bulgarian",
                "bm": "Bambara",
                "bn": "Bengali",
                "bo": "Tibetan",
                "br": "Breton",
                "bs": "Bosnian",
                "ca": "Catalan",
                "cs": "Czech",
                "cy": "Welsh",
                "da": "Danish",
                "de": "German",
                "dz": "Dzongkha",
                "ee": "Ewe",
                "el": "Greek",
                "en": "English",
                "eo": "Esperanto",
                "es": "Spanish",
                "et": "Estonian",
                "eu": "Basque",
                "fa": "Persian",
                "ff": "Fulah",
                "fi": "Finnish",
                "fo": "Faroese",
                "fr": "French",
                "fy": "Western Frisian",
                "ga": "Irish",
                "gd": "Scottish Gaelic",
                "gl": "Galician",
                "gu": "Gujarati",
                "ha": "Hausa",
                "he": "Hebrew",
                "hi": "Hindi",
                "hr": "Croatian",
                "hu": "Hungarian",
                "hy": "Armenian",
                "ia": "Interlingua",
                "id": "Indonesian",
                "ig": "Igbo",
                "is": "Icelandic",
                "it": "Italian",
                "ja": "Japanese",
                "ka": "Georgian",
                "ki": "Kikuyu",
                "kk": "Kazakh",
                "kl": "Kalaallisut",
                "km": "Khmer",
                "kn": "Kannada",
                "ko": "Korean",
                "ks": "Kashmiri",
                "kw": "Cornish",
                "ky": "Kyrgyz",
                "lb": "Luxembourgish",
                "lg": "Ganda",
                "ln": "Lingala",
                "lo": "Lao",
                "lt": "Lithuanian",
                "lu": "Luba-Katanga",
                "lv": "Latvian",
                "mg": "Malagasy",
                "mk": "Macedonian",
                "ml": "Malayalam",
                "mn": "Mongolian",
                "mr": "Marathi",
                "ms": "Malay",
                "mt": "Maltese",
                "my": "Burmese",
                "nb": "Norwegian Bokmål",
                "nd": "North Ndebele",
                "ne": "Nepali",
                "nl": "Dutch",
                "nn": "Norwegian Nynorsk",
                "om": "Oromo",
                "or": "Oriya",
                "os": "Ossetic",
                "pa": "Punjabi",
                "pl": "Polish",
                "ps": "Pashto",
                "pt": "Portuguese",
                "qu": "Quechua",
                "rm": "Romansh",
                "rn": "Rundi",
                "ro": "Romanian",
                "ru": "Russian",
                "rw": "Kinyarwanda",
                "se": "Northern Sami",
                "sg": "Sango",
                "si": "Sinhala",
                "sk": "Slovak",
                "sl": "Slovenian",
                "sn": "Shona",
                "so": "Somali",
                "sq": "Albanian",
                "sr": "Serbian",
                "sv": "Swedish",
                "sw": "Swahili",
                "ta": "Tamil",
                "te": "Telugu",
                "th": "Thai",
                "ti": "Tigrinya",
                "tn": "Tswana",
                "to": "Tongan",
                "tr": "Turkish",
                "ts": "Tsonga",
                "ug": "Uyghur",
                "uk": "Ukrainian",
                "ur": "Urdu",
                "uz": "Uzbek",
                "vi": "Vietnamese",
                "yi": "Yiddish",
                "yo": "Yoruba",
                "zh": "Chinese",
                "zu": "Zulu"
            }
        },
        "VisualizationForm": {
            "tooltips": {
                "dot": "Edit point feature style",
                "area": "Edit area feature style",
                "line": "Edit line feature style"
            },
            "dot": {
                "title": "Point feature style",
                "tooltip": "",
                "symbol": {
                    "label": "Icon"
                },
                "size": {
                    "label": "Size"
                },
                "color": {
                    "label": "Colour",
                    "labelOr": "or",
                    "labelCustom": "Custom colour (RGB 0-255)"
                },
                "preview": {
                    "label": "Preview"
                },
                "buttons": {
                    "save": "Save",
                    "cancel": "Cancel"
                }
            },
            "line": {
                "title": "Line feature style",
                "tooltip": "",
                "style": {
                    "label": "Dash"
                },
                "cap": {
                    "label": "Endings"
                },
                "corner": {
                    "label": "Corners"
                },
                "width": {
                    "label": "Width"
                },
                "color": {
                    "label": "Colour",
                    "labelOr": "or",
                    "labelCustom": "Custom colour (RGB 0-255)"
                },
                "preview": {
                    "label": "Preview"
                },
                "buttons": {
                    "save": "Save",
                    "cancel": "Cancel"
                }
            },
            "area": {
                "title": "Area feature style",
                "tooltip": "",
                "linestyle": {
                    "label": "Line dash"
                },
                "linecap": {
                    "label": "Line endings"
                },
                "linecorner": {
                    "label": "Line corners"
                },
                "linewidth": {
                    "label": "Line width"
                },
                "linecolor": {
                    "label": "Line colour",
                    "labelOr": "or",
                    "labelCustom": "Custom colour (RGB 0-255)"
                },
                "color": {
                    "label": "Fill colour",
                    "labelOr": "or",
                    "labelCustom": "Custom colour (RGB 0-255)"
                },
                "fill": {
                    "label": "Fill pattern"
                },
                "preview": {
                    "label": "Preview"
                },
                "buttons": {
                    "save": "Save",
                    "cancel": "Cancel"
                }
            }
        },
        "Grid": {
            "columnSelector": {
                "title": "NOT TRANSLATED",
                "tooltip": "NOT TRANSLATED"
            },
            "export": {
                "title": "NOT TRANSLATED",
                "csv": "CSV",
                "excel": "Excel"
            }
        }
    }
});
<commit_msg>divmanazer/locale/en --> Grid<commit_after>Oskari.registerLocalization({
    "lang": "en",
    "key": "DivManazer",
    "value": {
        "buttons": {
            "add": "Add",
            "cancel": "Cancel",
            "close": "Close",
            "delete": "Delete",
            "edit": "Edit",
            "ok": "OK",
            "save": "Save",
            "search": "Search"
        },
        "LanguageSelect": {
            "title": "Language",
            "tooltip": "Select language",
            "languages": {
                "af": "Afrikaans",
                "ak": "Akan",
                "am": "Amharic",
                "ar": "Arabic",
                "az": "Azerbaijani",
                "be": "Belarusian",
                "bg": "Bulgarian",
                "bm": "Bambara",
                "bn": "Bengali",
                "bo": "Tibetan",
                "br": "Breton",
                "bs": "Bosnian",
                "ca": "Catalan",
                "cs": "Czech",
                "cy": "Welsh",
                "da": "Danish",
                "de": "German",
                "dz": "Dzongkha",
                "ee": "Ewe",
                "el": "Greek",
                "en": "English",
                "eo": "Esperanto",
                "es": "Spanish",
                "et": "Estonian",
                "eu": "Basque",
                "fa": "Persian",
                "ff": "Fulah",
                "fi": "Finnish",
                "fo": "Faroese",
                "fr": "French",
                "fy": "Western Frisian",
                "ga": "Irish",
                "gd": "Scottish Gaelic",
                "gl": "Galician",
                "gu": "Gujarati",
                "ha": "Hausa",
                "he": "Hebrew",
                "hi": "Hindi",
                "hr": "Croatian",
                "hu": "Hungarian",
                "hy": "Armenian",
                "ia": "Interlingua",
                "id": "Indonesian",
                "ig": "Igbo",
                "is": "Icelandic",
                "it": "Italian",
                "ja": "Japanese",
                "ka": "Georgian",
                "ki": "Kikuyu",
                "kk": "Kazakh",
                "kl": "Kalaallisut",
                "km": "Khmer",
                "kn": "Kannada",
                "ko": "Korean",
                "ks": "Kashmiri",
                "kw": "Cornish",
                "ky": "Kyrgyz",
                "lb": "Luxembourgish",
                "lg": "Ganda",
                "ln": "Lingala",
                "lo": "Lao",
                "lt": "Lithuanian",
                "lu": "Luba-Katanga",
                "lv": "Latvian",
                "mg": "Malagasy",
                "mk": "Macedonian",
                "ml": "Malayalam",
                "mn": "Mongolian",
                "mr": "Marathi",
                "ms": "Malay",
                "mt": "Maltese",
                "my": "Burmese",
                "nb": "Norwegian Bokmål",
                "nd": "North Ndebele",
                "ne": "Nepali",
                "nl": "Dutch",
                "nn": "Norwegian Nynorsk",
                "om": "Oromo",
                "or": "Oriya",
                "os": "Ossetic",
                "pa": "Punjabi",
                "pl": "Polish",
                "ps": "Pashto",
                "pt": "Portuguese",
                "qu": "Quechua",
                "rm": "Romansh",
                "rn": "Rundi",
                "ro": "Romanian",
                "ru": "Russian",
                "rw": "Kinyarwanda",
                "se": "Northern Sami",
                "sg": "Sango",
                "si": "Sinhala",
                "sk": "Slovak",
                "sl": "Slovenian",
                "sn": "Shona",
                "so": "Somali",
                "sq": "Albanian",
                "sr": "Serbian",
                "sv": "Swedish",
                "sw": "Swahili",
                "ta": "Tamil",
                "te": "Telugu",
                "th": "Thai",
                "ti": "Tigrinya",
                "tn": "Tswana",
                "to": "Tongan",
                "tr": "Turkish",
                "ts": "Tsonga",
                "ug": "Uyghur",
                "uk": "Ukrainian",
                "ur": "Urdu",
                "uz": "Uzbek",
                "vi": "Vietnamese",
                "yi": "Yiddish",
                "yo": "Yoruba",
                "zh": "Chinese",
                "zu": "Zulu"
            }
        },
        "VisualizationForm": {
            "tooltips": {
                "dot": "Edit point feature style",
                "area": "Edit area feature style",
                "line": "Edit line feature style"
            },
            "dot": {
                "title": "Point feature style",
                "tooltip": "",
                "symbol": {
                    "label": "Icon"
                },
                "size": {
                    "label": "Size"
                },
                "color": {
                    "label": "Colour",
                    "labelOr": "or",
                    "labelCustom": "Custom colour (RGB 0-255)"
                },
                "preview": {
                    "label": "Preview"
                },
                "buttons": {
                    "save": "Save",
                    "cancel": "Cancel"
                }
            },
            "line": {
                "title": "Line feature style",
                "tooltip": "",
                "style": {
                    "label": "Dash"
                },
                "cap": {
                    "label": "Endings"
                },
                "corner": {
                    "label": "Corners"
                },
                "width": {
                    "label": "Width"
                },
                "color": {
                    "label": "Colour",
                    "labelOr": "or",
                    "labelCustom": "Custom colour (RGB 0-255)"
                },
                "preview": {
                    "label": "Preview"
                },
                "buttons": {
                    "save": "Save",
                    "cancel": "Cancel"
                }
            },
            "area": {
                "title": "Area feature style",
                "tooltip": "",
                "linestyle": {
                    "label": "Line dash"
                },
                "linecap": {
                    "label": "Line endings"
                },
                "linecorner": {
                    "label": "Line corners"
                },
                "linewidth": {
                    "label": "Line width"
                },
                "linecolor": {
                    "label": "Line colour",
                    "labelOr": "or",
                    "labelCustom": "Custom colour (RGB 0-255)"
                },
                "color": {
                    "label": "Fill colour",
                    "labelOr": "or",
                    "labelCustom": "Custom colour (RGB 0-255)"
                },
                "fill": {
                    "label": "Fill pattern"
                },
                "preview": {
                    "label": "Preview"
                },
                "buttons": {
                    "save": "Save",
                    "cancel": "Cancel"
                }
            }
        },
        "Grid": {
            "columnSelector": {
                "title": "Properties",
                "tooltip": "NOT TRANSLATED"
            },
            "export": {
                "title": "Export data",
                "csv": "CSV",
                "excel": "Excel"
            }
        }
    }
});
<|endoftext|>


<commit_before>'use strict';
var fs = require('fs')
var Path = require('path')
var ejs = require('ejs')
var inquirer = require('inquirer')
var mkdirp = require('mkdirp')
var templates = {
    "server": fs.readFileSync(Path.join(__dirname, './template/server'), 'utf-8'),
    "index": fs.readFileSync(Path.join(__dirname, './template/index.html'), 'utf-8'),
}

module.exports = function(path, options) {
    options.port = options.port || 1024
    if (options.engine)!options.views && (options.views = 'views')

    var serverPath = 'server.js'
    var packagePath = 'package.json'
    var IndexPath = 'index.html'
    var serverFile = ejs.render(templates.server, options)
    var existServer = fs.existsSync(serverPath)
    var existPackage = fs.existsSync(packagePath)
    var existIndex = fs.existsSync(IndexPath)
    var questions = []
    var writeServer = true

    /**
     * write static folder and default index.html
     */
    if(options.public !== '.') mkdirp.sync(options.public);

    if(!existIndex){
        fs.writeFileSync(options.public + '/index.html', templates.index, 'utf-8')
        console.log('Done, index.html is created!')
    }

    /**
     *  set package.json
     */
    var packageJSON
    if (existPackage) {
        try {
            packageJSON = (packageJSON = fs.readFileSync('package.json', 'utf-8')) ? JSON.parse(packageJSON):{}
        } catch (e) {
            console.log('Your "package.json" file has syntax error : ' + e)
            return process.exit(1)
        }
    } else {
        packageJSON = {}
    }

    packageJSON.name === undefined && (packageJSON.name = Path.basename(process.cwd()) || '')
    packageJSON.scripts = packageJSON.scripts || {}
    packageJSON.scripts.start = 'node server'
    packageJSON.dependencies = packageJSON.dependencies || {}

    // custom dependencies
    var deps = ['express', 'colors']
    switch (true) {
        case !!options.compress: deps.push('compression')
        case !!options.engine: deps.push(options.engine)
        case !!options.watch: deps.push('express-livereload')
    }
    deps.forEach(function (dep) {
        packageJSON.dependencies[dep] = '*'
    })

    fs.writeFileSync('package.json', JSON.stringify(packageJSON, null, '\t'))

    /**
     *  write server.js file
     */
    if (existServer) {
        questions.push({
            type: "confirm",
            name: "writeServer",
            message: "server.js is already exist, still rewrite?",
            default: true
        })
        inquirer.prompt(questions, function (answers) {
            existServer && (writeServer = answers.writeServer)
            writeServerFile()
        })
    } else {
        writeServerFile()
    }
    function writeServerFile () {
        if (writeServer) {
            console.log('\nDone, server.js is created!')
            fs.writeFileSync('server.js', serverFile, 'utf-8')
        }
        console.log('Done, ' + (existPackage ? 'package.json is updated!':'package.json is created!'))
        console.log('\nPlease use "npm install && npm start" to run server.')
    }
}
<commit_msg>[UPD] do not over wirte when index.html is exit<commit_after>'use strict';
var fs = require('fs')
var Path = require('path')
var ejs = require('ejs')
var inquirer = require('inquirer')
var mkdirp = require('mkdirp')
var templates = {
    "server": fs.readFileSync(Path.join(__dirname, './template/server'), 'utf-8'),
    "index": fs.readFileSync(Path.join(__dirname, './template/index.html'), 'utf-8'),
}

module.exports = function(path, options) {
    options.port = options.port || 1024
    if (options.engine)!options.views && (options.views = 'views')

    var serverPath = 'server.js'
    var packagePath = 'package.json'
    var IndexPath = Path.join(options.public, 'index.html')
    var serverFile = ejs.render(templates.server, options)
    var existServer = fs.existsSync(serverPath)
    var existPackage = fs.existsSync(packagePath)
    var existIndex = fs.existsSync(IndexPath)
    var questions = []
    var writeServer = true

    /**
     * write static folder and default index.html
     */
    if(options.public !== '.') mkdirp.sync(options.public);

    if(!existIndex){
        fs.writeFileSync(IndexPath, templates.index, 'utf-8')
        console.log('Done, index.html is created!')
    }

    /**
     *  set package.json
     */
    var packageJSON
    if (existPackage) {
        try {
            packageJSON = (packageJSON = fs.readFileSync('package.json', 'utf-8')) ? JSON.parse(packageJSON):{}
        } catch (e) {
            console.log('Your "package.json" file has syntax error : ' + e)
            return process.exit(1)
        }
    } else {
        packageJSON = {}
    }

    packageJSON.name === undefined && (packageJSON.name = Path.basename(process.cwd()) || '')
    packageJSON.scripts = packageJSON.scripts || {}
    packageJSON.scripts.start = 'node server'
    packageJSON.dependencies = packageJSON.dependencies || {}

    // custom dependencies
    var deps = ['express', 'colors']
    switch (true) {
        case !!options.compress: deps.push('compression')
        case !!options.engine: deps.push(options.engine)
        case !!options.watch: deps.push('express-livereload')
    }
    deps.forEach(function (dep) {
        packageJSON.dependencies[dep] = '*'
    })

    fs.writeFileSync('package.json', JSON.stringify(packageJSON, null, '\t'))

    /**
     *  write server.js file
     */
    if (existServer) {
        questions.push({
            type: "confirm",
            name: "writeServer",
            message: "server.js is already exist, still rewrite?",
            default: true
        })
        inquirer.prompt(questions, function (answers) {
            existServer && (writeServer = answers.writeServer)
            writeServerFile()
        })
    } else {
        writeServerFile()
    }
    function writeServerFile () {
        if (writeServer) {
            console.log('\nDone, server.js is created!')
            fs.writeFileSync('server.js', serverFile, 'utf-8')
        }
        console.log('Done, ' + (existPackage ? 'package.json is updated!':'package.json is created!'))
        console.log('\nPlease use "npm install && npm start" to run server.')
    }
}
<|endoftext|>


<commit_before><commit_msg>removed index.js<commit_after><|endoftext|>


<commit_before>var loaderUtils = require('loader-utils');
var webfontsGenerator = require('@vusion/webfonts-generator');
var path = require('path');
var glob = require('glob');
var url = require('url');
var hashFiles = require('./utils').hashFiles;

var mimeTypes = {
  'eot': 'application/vnd.ms-fontobject',
  'svg': 'image/svg+xml',
  'ttf': 'application/x-font-ttf',
  'woff': 'application/font-woff',
  'woff2': 'font/woff2'
};

function getFilesAndDeps (patterns, context) {
  var files = [];
  var filesDeps = [];
  var directoryDeps = [];

  function addFile (file) {
    filesDeps.push(file);
    files.push(path.resolve(context, file));
  }

  function addByGlob (globExp) {
    var globOptions = {
      cwd: context
    };

    var foundFiles = glob.sync(globExp, globOptions);
    files = files.concat(foundFiles.map(file => {
      return path.resolve(context, file);
    }));

    var globDirs = glob.sync(path.dirname(globExp) + '/', globOptions);
    directoryDeps = directoryDeps.concat(globDirs.map(file => {
      return path.resolve(context, file);
    }));
  }

  // Re-work the files array.
  patterns.forEach(function (pattern) {
    if (glob.hasMagic(pattern)) {
      addByGlob(pattern);
    } else {
      addFile(pattern);
    }
  });

  return {
    files: files,
    dependencies: {
      directories: directoryDeps,
      files: filesDeps
    }
  };
}

// Futureproof webpack option parsing
function wpGetOptions (context) {
  if (typeof context.query === 'string') return loaderUtils.getOptions(context);
  return context.query;
}

module.exports = function (content) {
  this.cacheable();

  var webpackOptions = this.options || {}; // only makes sense in Webpack 1.x, or when LoaderOptionsPlugin is used
  var options = wpGetOptions(this) || {};
  var rawFontConfig;
  try {
    rawFontConfig = JSON.parse(content);
  } catch (ex) {
    rawFontConfig = this.exec(content, this.resourcePath);
  }
  var fontConfig = Object.assign({}, options, rawFontConfig);

  var filesAndDeps = getFilesAndDeps(fontConfig.files, this.context);
  filesAndDeps.dependencies.files.forEach(this.addDependency.bind(this));
  filesAndDeps.dependencies.directories.forEach(this.addContextDependency.bind(this));
  fontConfig.files = filesAndDeps.files;

  // With everything set up, let's make an ACTUAL config.
  var formats = fontConfig.types || ['eot', 'woff', 'woff2', 'ttf', 'svg'];
  if (formats.constructor !== Array) {
    formats = [formats];
  }

  var generatorOptions = {
    files: fontConfig.files,
    fontName: fontConfig.fontName,
    types: formats,
    order: formats,
    fontHeight: fontConfig.fontHeight || 1000, // Fixes conversion issues with small svgs,
    codepoints: fontConfig.codepoints || {},
    templateOptions: {
      baseSelector: fontConfig.baseSelector || '.icon',
      classPrefix: 'classPrefix' in fontConfig ? fontConfig.classPrefix : 'icon-'
    },
    scssFile: fontConfig.scssFile || false,
    dest: fontConfig.dest || '',
    html: fontConfig.html || false,
    htmlDest: fontConfig.htmlDest || undefined,
    writeFiles: fontConfig.writeFiles || false,
    cssFontsUrl: fontConfig.cssFontsUrl || '',
    embed: fontConfig.embed || false,
    formatOptions: fontConfig.formatOptions || {}
  };

  // Add key only if it exists in config object to avoid fs errors
  if ('htmlTemplate' in fontConfig) {
    generatorOptions.htmlTemplate = fontConfig.htmlTemplate;
  }

  // This originally was in the object notation itself.
  // Unfortunately that actually broke my editor's syntax-highlighting...
  // ... what a shame.
  if (typeof fontConfig.rename === 'function') {
    generatorOptions.rename = fontConfig.rename;
  } else {
    generatorOptions.rename = function (f) {
      return path.basename(f, '.svg');
    };
  }

  if (fontConfig.cssTemplate) {
    generatorOptions.cssTemplate = path.resolve(this.context, fontConfig.cssTemplate);
  }

  if (fontConfig.cssFontsUrl) {
    generatorOptions.cssFontsUrl = path.resolve(this.context, fontConfig.cssFontsUrl);
  }

  if (fontConfig.htmlTemplate) {
    generatorOptions.htmlTemplate = path.resolve(this.context, fontConfig.htmlTemplate);
  }

  if (fontConfig.htmlDest) {
    generatorOptions.htmlDest = path.resolve(this.context, fontConfig.htmlDest);
  }

  if (fontConfig.dest) {
    generatorOptions.dest = path.resolve(this.context, fontConfig.dest);
  }

  // Spit out SCSS file to same path as CSS file to easily use mixins (scssFile must be true)
  if (fontConfig.scssFile === true) {
    generatorOptions.cssDest = path.resolve(this.context, fontConfig.dest, fontConfig.fontName + '.scss');
  }

  // svgicons2svgfont stuff
  var keys = [
    'fixedWidth',
    'centerHorizontally',
    'normalize',
    'fontHeight',
    'round',
    'descent'
  ];
  for (var x in keys) {
    if (typeof fontConfig[keys[x]] !== 'undefined') {
      generatorOptions[keys[x]] = fontConfig[keys[x]];
    }
  }

  var cb = this.async();

  var publicPath = options.publicPath || (webpackOptions.output && webpackOptions.output.publicPath) || '/';
  var embed = !!generatorOptions.embed;

  if (generatorOptions.cssTemplate) {
    this.addDependency(generatorOptions.cssTemplate);
  }

  if (generatorOptions.cssFontsPath) {
    this.addDependency(generatorOptions.cssFontsPath);
  }

  webfontsGenerator(generatorOptions, (err, res) => {
    if (err) {
      return cb(err);
    }
    var urls = {};
    for (var i in formats) {
      var format = formats[i];
      var filename = fontConfig.fileName || options.fileName || '[chunkhash]-[fontname].[ext]';
      var chunkHash = filename.indexOf('[chunkhash]') !== -1
        ? hashFiles(generatorOptions.files, options.hashLength) : '';

      filename = filename
        .replace('[chunkhash]', chunkHash)
        .replace('[fontname]', generatorOptions.fontName)
        .replace('[ext]', format);

      if (!embed) {
        var formatFilename = loaderUtils.interpolateName(this,
          filename,
          {
            context: this.rootContext || this.options.context || this.context,
            content: res[format]
          }
        );
        urls[format] = url.resolve(publicPath, formatFilename.replace(/\\/g, '/'));
        this.emitFile(formatFilename, res[format]);
      } else {
        urls[format] = 'data:' +
        mimeTypes[format] +
        ';charset=utf-8;base64,' +
        (Buffer.from(res[format]).toString('base64'));
      }
    }
    var emitCodepointsOptions = fontConfig.emitCodepoints || options.emitCodepoints || null;
    if (emitCodepointsOptions) {
      const emitCodepoints = require('./emit-codepoints');
      emitCodepoints.emitFiles(this, emitCodepointsOptions, generatorOptions, options);
    }

    cb(null, res.generateCss(urls));
  });
};
<commit_msg>use PublicPath from Webpack Config<commit_after>var loaderUtils = require('loader-utils');
var webfontsGenerator = require('@vusion/webfonts-generator');
var path = require('path');
var glob = require('glob');
var url = require('url');
var hashFiles = require('./utils').hashFiles;

var mimeTypes = {
  'eot': 'application/vnd.ms-fontobject',
  'svg': 'image/svg+xml',
  'ttf': 'application/x-font-ttf',
  'woff': 'application/font-woff',
  'woff2': 'font/woff2'
};

function getFilesAndDeps (patterns, context) {
  var files = [];
  var filesDeps = [];
  var directoryDeps = [];

  function addFile (file) {
    filesDeps.push(file);
    files.push(path.resolve(context, file));
  }

  function addByGlob (globExp) {
    var globOptions = {
      cwd: context
    };

    var foundFiles = glob.sync(globExp, globOptions);
    files = files.concat(foundFiles.map(file => {
      return path.resolve(context, file);
    }));

    var globDirs = glob.sync(path.dirname(globExp) + '/', globOptions);
    directoryDeps = directoryDeps.concat(globDirs.map(file => {
      return path.resolve(context, file);
    }));
  }

  // Re-work the files array.
  patterns.forEach(function (pattern) {
    if (glob.hasMagic(pattern)) {
      addByGlob(pattern);
    } else {
      addFile(pattern);
    }
  });

  return {
    files: files,
    dependencies: {
      directories: directoryDeps,
      files: filesDeps
    }
  };
}

// Futureproof webpack option parsing
function wpGetOptions (context) {
  if (typeof context.query === 'string') return loaderUtils.getOptions(context);
  return context.query;
}

module.exports = function (content) {
  this.cacheable();

  var webpackOptions = this.options || {}; // only makes sense in Webpack 1.x, or when LoaderOptionsPlugin is used
  var options = wpGetOptions(this) || {};
  var rawFontConfig;
  try {
    rawFontConfig = JSON.parse(content);
  } catch (ex) {
    rawFontConfig = this.exec(content, this.resourcePath);
  }
  var fontConfig = Object.assign({}, options, rawFontConfig);

  var filesAndDeps = getFilesAndDeps(fontConfig.files, this.context);
  filesAndDeps.dependencies.files.forEach(this.addDependency.bind(this));
  filesAndDeps.dependencies.directories.forEach(this.addContextDependency.bind(this));
  fontConfig.files = filesAndDeps.files;

  // With everything set up, let's make an ACTUAL config.
  var formats = fontConfig.types || ['eot', 'woff', 'woff2', 'ttf', 'svg'];
  if (formats.constructor !== Array) {
    formats = [formats];
  }

  var generatorOptions = {
    files: fontConfig.files,
    fontName: fontConfig.fontName,
    types: formats,
    order: formats,
    fontHeight: fontConfig.fontHeight || 1000, // Fixes conversion issues with small svgs,
    codepoints: fontConfig.codepoints || {},
    templateOptions: {
      baseSelector: fontConfig.baseSelector || '.icon',
      classPrefix: 'classPrefix' in fontConfig ? fontConfig.classPrefix : 'icon-'
    },
    scssFile: fontConfig.scssFile || false,
    dest: fontConfig.dest || '',
    html: fontConfig.html || false,
    htmlDest: fontConfig.htmlDest || undefined,
    writeFiles: fontConfig.writeFiles || false,
    cssFontsUrl: fontConfig.cssFontsUrl || '',
    embed: fontConfig.embed || false,
    formatOptions: fontConfig.formatOptions || {}
  };

  // Add key only if it exists in config object to avoid fs errors
  if ('htmlTemplate' in fontConfig) {
    generatorOptions.htmlTemplate = fontConfig.htmlTemplate;
  }

  // This originally was in the object notation itself.
  // Unfortunately that actually broke my editor's syntax-highlighting...
  // ... what a shame.
  if (typeof fontConfig.rename === 'function') {
    generatorOptions.rename = fontConfig.rename;
  } else {
    generatorOptions.rename = function (f) {
      return path.basename(f, '.svg');
    };
  }

  if (fontConfig.cssTemplate) {
    generatorOptions.cssTemplate = path.resolve(this.context, fontConfig.cssTemplate);
  }

  if (fontConfig.cssFontsUrl) {
    generatorOptions.cssFontsUrl = path.resolve(this.context, fontConfig.cssFontsUrl);
  }

  if (fontConfig.htmlTemplate) {
    generatorOptions.htmlTemplate = path.resolve(this.context, fontConfig.htmlTemplate);
  }

  if (fontConfig.htmlDest) {
    generatorOptions.htmlDest = path.resolve(this.context, fontConfig.htmlDest);
  }

  if (fontConfig.dest) {
    generatorOptions.dest = path.resolve(this.context, fontConfig.dest);
  }

  // Spit out SCSS file to same path as CSS file to easily use mixins (scssFile must be true)
  if (fontConfig.scssFile === true) {
    generatorOptions.cssDest = path.resolve(this.context, fontConfig.dest, fontConfig.fontName + '.scss');
  }

  // svgicons2svgfont stuff
  var keys = [
    'fixedWidth',
    'centerHorizontally',
    'normalize',
    'fontHeight',
    'round',
    'descent'
  ];
  for (var x in keys) {
    if (typeof fontConfig[keys[x]] !== 'undefined') {
      generatorOptions[keys[x]] = fontConfig[keys[x]];
    }
  }

  var cb = this.async();

  const publicPath = typeof options.publicPath === 'string'
  ? options.publicPath === '' || options.publicPath.endsWith('/')
  ? options.publicPath
  : `${options.publicPath}/`
  : typeof options.publicPath === 'function'
  ? options.publicPath(this.resourcePath, this.rootContext)
  : this._compilation.outputOptions.publicPath;

  var embed = !!generatorOptions.embed;

  if (generatorOptions.cssTemplate) {
    this.addDependency(generatorOptions.cssTemplate);
  }

  if (generatorOptions.cssFontsPath) {
    this.addDependency(generatorOptions.cssFontsPath);
  }

  webfontsGenerator(generatorOptions, (err, res) => {
    if (err) {
      return cb(err);
    }
    var urls = {};
    for (var i in formats) {
      var format = formats[i];
      var filename = fontConfig.fileName || options.fileName || '[chunkhash]-[fontname].[ext]';
      var chunkHash = filename.indexOf('[chunkhash]') !== -1
        ? hashFiles(generatorOptions.files, options.hashLength) : '';

      filename = filename
        .replace('[chunkhash]', chunkHash)
        .replace('[fontname]', generatorOptions.fontName)
        .replace('[ext]', format);

      if (!embed) {
        var formatFilename = loaderUtils.interpolateName(this,
          filename,
          {
            context: this.rootContext || this.options.context || this.context,
            content: res[format]
          }
        );
        urls[format] = url.resolve(publicPath, formatFilename.replace(/\\/g, '/'));
        this.emitFile(formatFilename, res[format]);
      } else {
        urls[format] = 'data:' +
        mimeTypes[format] +
        ';charset=utf-8;base64,' +
        (Buffer.from(res[format]).toString('base64'));
      }
    }
    var emitCodepointsOptions = fontConfig.emitCodepoints || options.emitCodepoints || null;
    if (emitCodepointsOptions) {
      const emitCodepoints = require('./emit-codepoints');
      emitCodepoints.emitFiles(this, emitCodepointsOptions, generatorOptions, options);
    }

    cb(null, res.generateCss(urls));
  });
};
<|endoftext|>