<repo_name>CHaram0913/twitch-project-react<file_sep>/models/LogSchema.js
let mongoose = require('mongoose');

let LogSchema = mongoose.Schema({
    log_time: {
        type: Number,
        required: true
    },
    user_id: {
        type: String,
        required: true
    },
    user_name: {
        type: String,
        required: true
    },
    viewer_count: {
        type: Number,
        required: true
    },
    follower_count: {
        type: Number,
        required: true
    },
    stream_title: {
        type: String,
        required: true
    },
    start_time: {
        type: Number,
        required: true
    },
    game_id: {
        type: String,
        required: true
    },
    game_name: {
        type: String,
        required: true
    },
    game_art: {
        type: String,
        required: true
    }
});

module.exports = { LogSchema };<file_sep>/client/src/resource/colorArray.js
const generateRandomColor = () => {
    let letters = '0123456789ABCEDF';
    let color = '#';
    for (let i = 0; i < 6; i++) {
        color += letters[Math.floor(Math.random() * 16)];
    }
    return color;
};

const findMatch = (colorArray, key) => {
    return colorArray.find(function(element) {
         return element.game === key;
     })
 };

export const setColor = (gameArray, colorTheme) => {
    let colorArray = [];
    for (let i = 0; i < gameArray.length; i++) {
        let matchFound = findMatch(colorTheme, gameArray[i]);
        
        if (matchFound) {
            colorArray.push(matchFound.color);
        } else {
            colorArray.push(generateRandomColor());
        }
    }
    return colorArray;
};

export const colorSet = [
    {
        game : 'League of Legends',
        color : '#FFCE56'
    },
    {
        game : 'Hearthstone',
        color : '#36A2EB'
    },
    {
        game : 'IRL',
        color : '#FF6384'
    },
    {
        game : 'Games + Demos',
        color : '#840396'
    },
    {
        game : 'FIFA 18',
        color : '#FCF2FC'
    },
    {
        game : 'Stardew Valley',
        color : '#66FFB3'
    },
    {
        game : 'Overwatch',
        color : '#BCBABE'
    },
    {
        game : 'Heavy Rain',
        color : '#323233'
    },
    {
        game : "PLAYERUNKNOWN'S BATTLEGROUNDS",
        color : '#124F2C'
    },
    {
        game : "Mount & Blade: Warband",
        color : '#BBBB77'
    },
    {
        game : "Celeste",
        color : '#99FFFF'
    },
    {
        game : "StarCraft II",
        color : '#FF3333'
    },
    {
        game : "Princess Maker 5",
        color : '#33FFCC'
    },
    {
        game : "MapleStory",
        color : '#FF99FF'
    },
    {
        game : "Cookie Run: OvenBreak",
        color : '#86592D'
    },
    {
        game : "Slay the Spire",
        color : '#E65C00'
    },
    {
        game : "Creative",
        color : '#FFFF80'
    },
];<file_sep>/query_helper/filter_stream_by_length.js
const filterStreamByLength = (streamsArray) => {
    let longEnoughStream = [];
    for (let i = 0; i < streamsArray.length; i++) {
        let fullCount = streamsArray[i].map(stream => stream.count).reduce((acc, val) => acc + val);
        
        if (fullCount > 14) {
            longEnoughStream.push(streamsArray[i]);
        }
    }
    return longEnoughStream;
};

module.exports = { filterStreamByLength };<file_sep>/client/src/components/gamelist_pie_viewer.js
import _ from 'lodash';

import { colorSet, setColor } from './../resource/colorArray';

export default function(props) {
    const colorArray = setColor(_.map(props, '_id'), colorSet);

    const data = {
        labels: _.map(props, '_id'),
        datasets: [{
            data: _.map(props, 'average_view'),
            backgroundColor: colorArray,
            hoverBackgroundColor: colorArray
        }]
    }

    return data;
};<file_sep>/client/src/containers/stream_stat.js
import React, { Component, Fragment } from 'react';
import { connect } from 'react-redux';
import { Line, HorizontalBar } from 'react-chartjs-2';
import moment from 'moment-timezone';
import _ from 'lodash';

import { withStyles } from 'material-ui/styles';
import { Paper, Typography, Grid, Hidden } from 'material-ui';
import streamStatStyles from './../styles/stream_stat_styles';

import { fetchStreamStat } from './../actions/index';

import { barData, lineData } from './../components/stream_graphs';
import BarChartOption from './../styles/bar_chart_options';
import LineChartOption from './../styles/line_chart_options';


class StreamStat extends Component {
    componentDidUpdate(prevProps) {
        if ((prevProps.streamerName === this.props.streamerName) && (prevProps.mode === this.props.mode)) {
        } else {
            this.props.fetchStreamStat(this.props.streamerName, this.props.mode);
        }
    }

    convertCount(singleStream) {
        let min = singleStream.map(stream => stream.count).reduce((acc, val) => acc + val) * 10 ;
        let hours = Math.floor(min / 60);
        let minutes = min % 60;

        if (hours === 0) {
            return `${minutes} minutes`;
        } else {
            return `${hours} hours ${minutes} minutes`;
        }
    }

    averageView(singleStream) {
        let viewerArray = [];
        for (let i = 0; i < singleStream.length; i++) {
            for (let j = 0; j < singleStream[i].at_time.length; j++) {
                viewerArray.push(singleStream[i].at_time[j].viewer_count);
            }
        }
        let averageViewer = Math.floor(viewerArray.reduce((acc, val) => acc + val) / viewerArray.length) ;
        return averageViewer;
    }

    followDifference(singleStream) {
        let follower_at_start = singleStream[0].at_time[0].follower_count ;
        let follower_at_end = singleStream[singleStream.length - 1].at_time[singleStream[singleStream.length - 1].at_time.length - 1].follower_count ;

        return follower_at_end - follower_at_start ;
    }

    render() {
        const { streamlist } = this.props;
        
        if (!streamlist.data) {
            return <div>Fetching streamlist...</div>;
        }

        const streamStatGraph = (streamArray) => {
            const { classes } = this.props;

            let graphArray = [];
            for (let i = 0; i < streamArray.length; i++){
                
                const generate_game_list = (singleStream) => {
                    return _.uniq(singleStream.map(stream => stream._id.game_name));
                };

                graphArray.push (
                    <Paper className={classes.root} elevation={5} key={i}>
                        <Grid container spacing={8} className={classes.container} direction='row-reverse' alignItems='center'>
                            
                            <Grid item xs={12} zeroMinWidth>
                                <Paper className={classes.title} elevation={2}>
                                    <Typography variant='title' className={classes.title_text}>
                                        {`Stream at: ${moment(streamArray[i][0].start_time).tz('Asia/Seoul').format('(YYYY MMM DD) hh:mm a')}`}
                                    </Typography>
                                </Paper>
                            </Grid>

                            <Grid item xs={12} md={2} zeroMinWidth >
                                <Paper className={classes.detail} elevation={0}>
                                    <Typography className={classes.detail_title}>
                                        Stream Stat
                                    </Typography>
                                    <Typography className={classes.detail_subtitle}>
                                        Games Played:
                                    </Typography>
                                    {generate_game_list(streamArray[i]).map(game => 
                                        <Typography className={classes.detail_component} key={game}>
                                            {game}
                                        </Typography>
                                    )}
                                    <Typography className={classes.detail_subtitle}>
                                        Stream Length:
                                    </Typography>
                                    <Typography className={classes.detail_component}>
                                        {this.convertCount(streamArray[i])}
                                    </Typography>
                                    <Typography className={classes.detail_subtitle}>
                                        Average Viewers:
                                    </Typography>
                                    <Typography className={classes.detail_component}>
                                        {`${this.averageView(streamArray[i])} viewers`}
                                    </Typography>
                                    <Typography className={classes.detail_subtitle}>
                                        Followers Gained:
                                    </Typography>
                                    <Typography className={classes.detail_component}>
                                        {`${this.followDifference(streamArray[i])} more followers!`}
                                    </Typography>
                                </Paper>
                            </Grid>
                            
                            <Hidden xsDown>
                                <Grid item xs={12} md={10} zeroMinWidth>
                                    <Paper className={classes.bar} elevation={0}>
                                        <HorizontalBar data={barData(streamArray[i])} options={BarChartOption(streamArray[i])} />
                                    </Paper>

                                    <Paper className={classes.line} elevation={0}>
                                        <Line data={lineData(streamArray[i])} height={300} options={LineChartOption} />
                                    </Paper>
                                </Grid>
                            </Hidden>

                        </Grid>
                    </Paper>
                )
            }
            return graphArray;
        };

        return (
            <Fragment>
                {streamStatGraph(streamlist.data)}
            </Fragment>
        );
    }
};

function mapStateToProps(state) {
    return {
        streamerName : state.streamerName,
        mode : state.mode,
        streamlist : state.streamlist
    }
}

export default withStyles (streamStatStyles) (connect (mapStateToProps, { fetchStreamStat }) (StreamStat));<file_sep>/client/src/reducers/index.js
import { combineReducers } from 'redux';
import SelectedStreamerReducer from './reducer_selected_stream';
import SelectedModeReducer from './reducer_selected_mode';
import GameListReducer from './reducer_game_list';
import StreamListReducer from './reducer_stream_list';
import StreamStatus from './reducer_stream_status';

const rootReducer = combineReducers({
    streamerName : SelectedStreamerReducer,
    mode : SelectedModeReducer,
    gamelist : GameListReducer,
    streamlist : StreamListReducer,
    status: StreamStatus
});

export default rootReducer;<file_sep>/client/src/actions/index.js
import axios from 'axios';
import { streamerArray } from './../resource/streamerArray';
import { STREAMER_SELECTED, MODE_SELECTED, FETCH_GAME_STAT, FETCH_STREAM, FETCH_STREAM_STATUS } from './types';

export function streamSelect(streamerIndex) {
    return {
        type: STREAMER_SELECTED,
        payload: streamerArray[streamerIndex]
    };
};

export function modeSelect(mode) {
    return {
        type: MODE_SELECTED,
        payload: mode
    };
};

export function fetchGameStat(collectionName, mode) {
    return async dispatch => {
        let response = await axios.get(`/api/gamelist/${collectionName}/${mode}`);

        dispatch({
            type : FETCH_GAME_STAT,
            payload : response
        });
    };    
};

export function fetchStreamStat(collectionName, mode) {
    return async dispatch => {
        let response = await axios.get(`/api/allStream/${collectionName}/${mode}`);

        dispatch({
            type : FETCH_STREAM, 
            payload : response
        });
    };
};

export function fetchStreamStatus(collectionName) {
    return async dispatch => {
        let response = await axios.get(`/api/status/${collectionName}`);

        dispatch({
            type : FETCH_STREAM_STATUS, 
            payload : response
        });
    };
};
<file_sep>/client/src/containers/game_stat.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Doughnut } from 'react-chartjs-2';
import _ from 'lodash';

import { withStyles } from 'material-ui/styles';
import { Paper, Grid, GridList, GridListTile, GridListTileBar, Hidden } from 'material-ui';
import gameStatStyles from './../styles/game_stat_styles';

import { fetchGameStat } from './../actions/index';

import PieStreamTime from './../components/gamelist_pie_time';
import PieAverageView from './../components/gamelist_pie_viewer';
import { pie_time_option, pie_view_option } from './../styles/pie_chart_options';
import GameData from './../components/gamelist_image_data';

class GameStat extends Component {
    componentDidUpdate(prevProps) {
        if ((prevProps.streamerName === this.props.streamerName) && (prevProps.mode === this.props.mode)) {
        } else {
            this.props.fetchGameStat(this.props.streamerName, this.props.mode);
        }
    }

    render() {
        const { gamelist } = this.props;
        const { classes } = this.props;
        if (!gamelist.data) {
            return <div>Fetching gamelist...</div>;
        }
        let game_art_data = GameData((_.sortBy(gamelist.data, 'count')).reverse());

        return (

            <Grid container spacing={8} className={classes.root} direction='row-reverse' alignItems='center'>
                
                <Grid item xs={12} md={12} lg={5} zeroMinWidth>
                    <Paper className={classes.gamelist} elevation={4}>
                        <GridList cellHeight={200} cols={4} className={classes.gridlist}>
                            {game_art_data.map(game => 
                                <GridListTile key={game.title}>
                                    <img src={game.img} alt={game.title}  />
                                    <GridListTileBar 
                                        title={game.title} 
                                        // subtitle={`Time: ${game.duration} \n View: ${game.viewer}`}
                                        className={classes.tile_bar}
                                    />
                                </GridListTile>
                            )}
                        </GridList>
                    </Paper>
                </Grid>

                <Hidden xsDown>
                    <Grid item xs={12} md={6} lg={true} zeroMinWidth>
                        <Paper className={classes.pie} elevation={4}>
                            <Doughnut data={PieStreamTime(gamelist.data)} options={pie_time_option}/>
                        </Paper>
                    </Grid>

                    <Grid item xs={12} md={6} lg={true} zeroMinWidth>
                        <Paper className={classes.pie} elevation={4}>
                            <Doughnut data={PieAverageView(gamelist.data)} options={pie_view_option}/>  
                        </Paper>
                    </Grid>
                </Hidden>

            </Grid>

        );
    }
};

function mapStateToProps(state) {
    return { 
        streamerName : state.streamerName,
        mode : state.mode,
        gamelist : state.gamelist
    }
}

export default withStyles (gameStatStyles) (connect (mapStateToProps, { fetchGameStat }) (GameStat));<file_sep>/client/src/styles/bar_chart_options.js
export default function (props) {
    let max = props.map(count => count.count).reduce((acc, val) => acc + val);
    return {
        maintainAspectRatio: false,
    legend: {
        display: false
    },
    layout: {
        padding: {
            left: 0,
            right: 0,
            top: 0,
            bottom: 0
        }
    },
    scales: {
        xAxes: [{
            stacked: true,
            display: false,
            ticks: {
                beginAtZero: true,
                maxTicksLimit: 2,
                max: max
            }
        }],
        yAxes: [{
            stacked: true,
            display: false,
            maxBarThickness: 70
        }]
    },
    tooltips: {
        mode: 'point',
        position: 'nearest',
        callbacks: {
            title: function(t, d){
                return d.datasets[t[0].datasetIndex].label[1];
            },
            label: function(t, d) {
                let minuteTotal = d.datasets[t.datasetIndex].data[0] * 10;
                let hours = Math.floor(minuteTotal / 60);
                let minutes = minuteTotal % 60;
                if (hours === 0) {
                    return `${d.datasets[t.datasetIndex].label[0]}: ${minutes}min`;
                } else {
                    return `${d.datasets[t.datasetIndex].label[0]}: ${hours}hr ${minutes}min`;
                }
                
            }
        }
    }}
};<file_sep>/aggregates/stream_aggregate.js
const each_stream_aggregate = (start_time) => {
    return [
        {
            $match : { 'start_time' : { $in : start_time } }
        },
        {
            $group : {
                _id : { game_name : '$game_name', stream_title : '$stream_title'},
                count : { $sum : 1 },
                game_art : { $first : '$game_art'},
                at_time : { $push : { log_time : '$log_time', viewer_count : '$viewer_count', follower_count : '$follower_count' } },
                start_game_time : { $first : '$log_time' }
            }
        },
        {
            $sort : { start_game_time : 1 }
        },
        // {
        //     $group : {
        //         _id : '$_id.game_name',
        //         title: { $first : '$_id.stream_title' },
        //         count : { $sum : 1 },
        //         game_art : { $first : '$game_art'},
        //     }
        // }
        // {
        //     $group : {
        //         _id : '$game_name',
        //         count : { $sum : 1 },
        //         at_time : { $push : { log_time : '$log_time', viewer_count : '$viewer_count', follower_count : '$follower_count' } },
        //         game_art : { $first : '$game_art'},
        //         start_game_time : { $first : '$log_time' }
        //     }
        // }
        // {
        //     $sort : { start_game_time : 1 }
        // },
        {
            $project : {
                count : '$count',
                start_time : '$start_game_time',
                game_art : '$game_art',
                at_time : '$at_time'     
            }
        }
    ];
}

module.exports = { each_stream_aggregate };<file_sep>/client/src/actions/types.js
export const STREAMER_SELECTED = 'streamer_selected';
export const MODE_SELECTED = 'mode_selected';
export const FETCH_GAME_STAT = 'fetch_game_stat';
export const FETCH_STREAM = 'fetch_stream';
export const FETCH_STREAM_STATUS = 'fetch_stream_status';<file_sep>/client/src/containers/remote_control.js
import React, { Component, Fragment } from 'react';
import { connect } from 'react-redux';
import { animateScroll as scroll } from 'react-scroll';

import { withStyles } from 'material-ui/styles';
import remoteControlStyles from './../styles/remote_control_styles';
import { Paper, Popover, Button } from 'material-ui';
import Radio, { RadioGroup } from 'material-ui/Radio';
import { FormLabel, FormControl, FormControlLabel } from 'material-ui/Form';
import RemoteIcon from '@material-ui/icons/Timelapse';
import UpIcon from '@material-ui/icons/ArrowUpward';


import periodArray from './../resource/periodArray';
import { modeSelect, fetchStreamStatus } from './../actions/index';

class RemoteControl extends Component {
    constructor(props) {
        super(props);

        this.state = { 
            check : 'month', 
            anchorEl : null
        }

        this.onSelection = this.onSelection.bind(this);
        this.openPopover = this.openPopover.bind(this);
        this.closePopover = this.closePopover.bind(this);
        this.createStatusButton = this.createStatusButton.bind(this);
    }

    onSelection(event, value) {
        this.props.modeSelect(value);
        this.setState({ check : value });
    }

    componentDidUpdate(prevProps) {
        if ((prevProps.streamerName === this.props.streamerName) && (prevProps.mode === this.props.mode)) {
        } else {
            this.props.fetchStreamStatus(this.props.streamerName);
        }
    }

    componentDidMount() {
        this.props.modeSelect(this.state.check);
    }

    openPopover(event) {
        this.setState({
            anchorEl : event.currentTarget
        });
    }

    closePopover(event) {
        this.setState({
            anchorEl : null
        });
    }

    scrollToTop() {
        scroll.scrollToTop();
    }

    createStatusButton(status) {
        try {
            if (status.data.status === 'LIVE') {
                return (
                    <Button 
                        variant="raised" 
                        href={`https://www.twitch.tv/${this.props.streamerName}`}
                        target='_blank'
                        className={this.props.classes.live_link_online}
                    >
                        LIVE
                    </Button>
                )
            } else {
                return (
                    <Button 
                        variant="raised" 
                        className={this.props.classes.live_link_offline}
                    >
                        OFFLINE
                    </Button>
                )
            }
        } catch (e) {
            return (
                <div />
            )
        }
    }

    render() {
        const { classes } = this.props;
        return (
            <Fragment>
                <Button
                    className={classes.scrollTopButton}
                    variant='fab'
                    color='secondary'
                    onClick={this.scrollToTop}
                >
                    <UpIcon />
                </Button>
                <Button 
                    className={classes.remoteButton}
                    variant='fab' 
                    color='primary'
                    onClick={this.openPopover}
                >
                    <RemoteIcon />
                </Button>
                <Popover
                    open={Boolean(this.state.anchorEl)}
                    anchorEl={this.state.anchorEl}
                    onClose={this.closePopover}
                    anchorOrigin={{
                        vertical: 'center',
                        horizontal: 'center'
                    }}
                    transformOrigin={{
                        vertical: 'bottom',
                        horizontal: 'right'
                    }}
                >
                    <Paper className={classes.remotePaper}>
                        <FormControl component='fieldset' required className={classes.formControl}>
                            <FormLabel component='legend'>Time Period</FormLabel>
                            <RadioGroup
                                aria-label='time'
                                name='search_period_selection'
                                className={classes.group}
                                value={this.state.check}
                                onChange={this.onSelection}
                            >
                                {periodArray.map(time_periods => 
                                    <FormControlLabel 
                                        key={time_periods} 
                                        value={time_periods} 
                                        control={<Radio />} 
                                        label={time_periods}
                                    />
                                )}
                            </RadioGroup>
                            {this.createStatusButton(this.props.status)}
                        </FormControl>
                    </Paper>
                </Popover>
            </Fragment>
        );
    };
}

function mapStateToProps(state) {
    return {
        streamerName : state.streamerName,
        mode : state.mode,
        status : state.status
    }
}

export default withStyles (remoteControlStyles) (connect (mapStateToProps, { modeSelect, fetchStreamStatus }) (RemoteControl));<file_sep>/query_helper/slice_stream_aggregate.js
const _ = require('lodash');

function createArray(length) {
    var arr = new Array(length || 0),
        i = length;

    if (arguments.length > 1) {
        var args = Array.prototype.slice.call(arguments, 1);
        while (i--) arr[length -1 - i] = createArray.apply(this, args);
    }

    return arr;
}

const slice_aggregate = (singleStream) => {

    let jump = createArray(singleStream.length, 0);
    for (let i = 0; i < singleStream.length; i++) {
        let prev = 0;
    
        for (let j = 0; j < singleStream[i].at_time.length; j++) {
            if (singleStream[i].at_time[j].log_time - prev > 50 * 60 * 1000) {
                prev = singleStream[i].at_time[j].log_time;
                if (j !== 0) {
                    jump[i].push({i, j})
                }
            } else {
                prev = singleStream[i].at_time[j].log_time;
            }
        }
    }

    const separate_at_time = (stream_array, jumpArray) => {
        let at_time_one = stream_array.at_time;
        let newArray = createArray(jumpArray.length + 1, 0);
        let j = 0;
    
        for (let i = 0; i < at_time_one.length; i++) {
            if (i === 0) {
                newArray[j].push(at_time_one[i]);
            } else {
                if (j < jumpArray.length) {
                    if (at_time_one[i].log_time < at_time_one[jumpArray[j].j].log_time) {
                        newArray[j].push(at_time_one[i]);
                    } else if (at_time_one[i].log_time === at_time_one[jumpArray[j].j].log_time){
                        j++ ;
                        newArray[j].push(at_time_one[i]);
                    }
                } else if (j === jumpArray.length) {
                    newArray[j].push(at_time_one[i]);
                }
    
            }
        }
    
        return newArray;
    }

    let finalArray = [];
    let finalFinal = [];
    let sortJump = jump.filter(function(sub) {
        return sub.length;
    });

    if (sortJump.length > 0) {
        for (let i = 0; i < singleStream.length; i++) {
            if (jump[i]) {
                finalArray.push(separate_at_time(singleStream[i], jump[i]));
            } else {
                finalArray.push(singleStream[i]);
            }
            
        }
        for (let i = 0; i < finalArray.length; i++) {
            for (let j = 0; j < finalArray[i].length; j++) {
                finalFinal.push({
                    _id: {
                        game_name: singleStream[i]._id.game_name,
                        stream_title: singleStream[i]._id.stream_title
                    },
                    count: finalArray[i][j].length,
                    start_time: finalArray[i][j][0].log_time,
                    game_art: singleStream[i].game_art,
                    at_time: finalArray[i][j]
                })
            }
        }

        return (_.sortBy(finalFinal, 'start_time'));
    
    } else {
        return singleStream;
    }
};

module.exports = { slice_aggregate };<file_sep>/client/src/styles/line_chart_options.js
import moment from 'moment-timezone';

export default {
    maintainAspectRatio: false,
    legend: {
        display: true,
        width: '12px',
        labels: {
            fontColor: 'rgba(252, 255, 255, 0.9)',
            fontSize: 14
        },
        position: 'bottom'
    },
    layout: {
        padding: {
            left: 0,
            right: 0,
            top: 0,
            bottom: 0
        }
    },
    elements: {
        point: {
            pointStyle: 'star',
            radius: 5
        },
        line: {
            fill: false,
            tension: 0.2,
            borderCapStyle: 'round',
        }
    },
    scales: {
        border: '1px',
        yAxes: [{
            id: 'Views',
            position: 'left',
            display: true,
            gridLines: {
                display: false,
                color: 'rgba(252, 255, 255, 0.9)',
                lineWidth: 2,
                drawTicks: false,
                zeroLineWidth: 2,
                zeroLineColor: 'rgba(252, 255, 255, 0.9)'
            },
            ticks: {display: false}
        }, {
            id: 'Follows',
            position: 'right',
            display: true,
            gridLines: {
                display: false,
                color: 'rgba(252, 255, 255, 0.9)',
                lineWidth: 2,
                drawTicks: false,
                zeroLineWidth: 2,
                zeroLineColor: 'rgba(252, 255, 255, 0.9)'
            },
            ticks: {display: false}
        }],
        xAxes: [{
            position: 'bottom',
            gridLines: {
                display: false,
                color: 'rgba(252, 255, 255, 0.9)',
                lineWidth: 2,
                drawTicks: false,
                zeroLineWidth: 2,
                zeroLineColor: 'rgba(252, 255, 255, 0.9)'
            },
            type: 'time',
            time: {
                unit: 'hour',
                millisecond: 'h:mm a'
            },
            ticks: {
                callback: function(t) {
                    return t;
                },
                fontColor: 'rgba(252, 255, 255, 0.9)',
                fontSize: 14,
                maxRotation: 0,
                minRotation: 0,
                padding: 5
            }
        }]
    },
    tooltips: {
        callbacks: {
            title: function(t, d) {
                return moment(d.labels[t[0].index]).tz('Asia/Seoul').format('YYYY MMM DD, hh:mm:ss a') ;
            }
        },
        mode: 'index',
        position: 'nearest'
    }
};<file_sep>/client/src/styles/top_menu_styles.js
export default 
{
    root: {
        flexGrow: 1,
    },
    tabs: {
        background: 'linear-gradient(180deg, #8c02cc 30%, #c650fc 90%)',
        border: 0,
        color: 'white',
        boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .30)',
    },
    tab: {
        fontFamily: 'Roboto, sans-serif',
    },
};<file_sep>/client/src/styles/stream_stat_styles.js
export default 
{
    root: {
        height: 'auto',
        backgroundColor: 'rgba(40, 44, 52, 1)',
        flexGrow: 1,
        marginTop: 25,
        marginBottom: 25,
        paddingTop: 10,
        paddingBottom: 20
    },
    container: {
        height: '100%',
    },
    title: {
        height: 'auto',
        backgroundColor: 'rgba(40, 44, 52, 1)'
    },
    title_text: {
        color: 'white',
        textAlign: 'center',
        fontWeight: 'bold',
        paddingBottom: 5
    },
    bar: {
        backgroundColor: 'rgba(40, 44, 52, 1)',
        paddingLeft: 18,
        paddingRight: 18
    },
    line: {
        backgroundColor: 'rgba(40, 44, 52, 1)'
    },
    detail: {
        height: 'auto',
        width: 230,
        borderRadius: '13%',
        backgroundColor: 'rgba(181, 71, 232, 0.7)',
        paddingBottom: 15,
        marginLeft: 'auto',
        marginRight: 'auto'
    },
    detail_title: {
        color: 'white',
        textAlign: 'center',
        fontSize: 30,
        fontWeight: 'bold',
        paddingTop: 10
    },
    detail_subtitle: {
        color: 'white',
        textAlign: 'left',
        fontSize: 23,
        fontWeight: 'bold',
        fontStyle: 'oblique',
        paddingTop: 8,
        paddingBottom: 2,
        paddingLeft: 18,
    },
    detail_component: {
        color: 'white',
        textAlign: 'left',
        fontSize: 17,
        paddingLeft: 28
    }
};<file_sep>/client/src/routes/index.js
/**
 * Root
 * */
import RootRoute from './root/root';
import StreamerStat from './root/streamer_stat';

/**
 * Exports
 * */

const mainRoutes = [
    {
        path: '/',
        component:RootRoute,
        wrapper:''
    },
    {
        path: '/streamers',
        component:StreamerStat,
        wrapper:''
    }
];

export{
    mainRoutes
}<file_sep>/client/src/routes/root/root.js
import React, { Component, Fragment } from 'react';
import { withStyles } from 'material-ui/styles';
// import Welcome from './../../components/welcome';
import GameStat from './../../containers/game_stat';
import StreamStat from './../../containers/stream_stat';

const styles = theme => ({
    root: {}
});

class Root extends Component {
    render() {
        return (
            <Fragment>
                <GameStat />
                <StreamStat />
            </Fragment>
            // <Welcome />
        )
    }
}

export default withStyles(styles)(Root);<file_sep>/client/src/resource/periodArray.js
export default ['all', 'month', 'week', 'day'];<file_sep>/query_helper/get_start_time_comparison.js
const moment = require('moment-timezone');

const getStartTimeComp = (mode) => {
    if (mode === 'day') {
        // Setting the base as Korea, today at 00:00:00
        let currentDateKorea = moment().tz('Asia/Seoul').format('YYYYMMDD');
        let dateKorea = `${currentDateKorea}T000000`;
        let KoreaUTC = Number(moment(dateKorea).format('x'));
        let dateUTC = KoreaUTC - 9 * 60 * 60 * 1000;

        return dateUTC - 24 * 60 * 60 * 1000;
    } else if (mode === 'week') {
        let currentDateKorea = moment().tz('Asia/Seoul').format('YYYYMMDD');
        let dateKorea = `${currentDateKorea}T000000`;
        let KoreaUTC = Number(moment(dateKorea).format('x'));
        let dateUTC = KoreaUTC - 9 * 60 * 60 * 1000;

        return dateUTC - 7 * 24 * 60 * 60 * 1000;

    } else if (mode === 'month') {
        let currentDateKorea = moment().tz('Asia/Seoul').format('YYYYMMDD');
        let dateKorea = `${currentDateKorea}T000000`;
        let KoreaUTC = Number(moment(dateKorea).format('x'));
        let dateUTC = KoreaUTC - 9 * 60 * 60 * 1000;

        return dateUTC - 30 * 24 * 60 * 60 * 1000;

    } else if (mode === 'all') {

        return 0;
    }
}

module.exports = { getStartTimeComp };