<commit_before>import { Button, Checkbox, Form, Icon, Input, notification, Popover, Select, Spin } from 'antd';
import axios from 'axios';
import _ from 'lodash';
import moment from 'moment';
import React, { Component } from 'react';
import { Clock, MapPin } from 'react-feather';
import Gravatar from 'react-gravatar';
import { Fade, Slide } from 'react-reveal';
import {
    EmailIcon,
    EmailShareButton,
    FacebookIcon,
    FacebookShareButton,
    TwitterIcon,
    TwitterShareButton,
} from 'react-share';
import { Link } from 'react-static';
import InlineSVG from 'svg-inline-react';
import uuidv4 from 'uuid/v4';

import brandIconLight from '../assets/brandicon-light.svg';
import bgLeft from '../assets/misc/alumni-2019-bg-left.jpg';
import bgRight from '../assets/misc/alumni-2019-bg-right.jpg';
import brandLogo from '../assets/misc/alumni-2019-brand.svg';
import divider from '../assets/misc/divider.svg';
import ogImage from '../assets/misc/alumni-2019.jpg';
import Helmet from '../components/Helmet';
import Navbar from '../components/Navbar';
import DisqusThread from '../components/DisqusThread';

const jdenticon = require('jdenticon')

const theme = {
    text: 'font-light alumni-2019-theme-text--color mt-2',
    link: 'alumni-2019-theme-text--color mt-2 no-underline hover:text-orange',
}

const FormItem = Form.Item;
const Option = Select.Option;
const yearStartRange = _.range(2000, (new Date()).getFullYear(), 1)
const yearEndRange = _.range(2004, (new Date()).getFullYear(), 1)
const courses = [
    {
        name: 'Bachelor of Science in Information Management',
        value: 'bsim'
    },
    {
        name: 'Bachelor of Science in Information Technology',
        value: 'bsit'
    },
    {
        name: 'Bachelor of Science in Information Systems',
        value: 'bsis'
    },
    {
        name: 'Bachelor of Science in Computer Science',
        value: 'bscs'
    },
    {
        name: 'Masters in Information Technology',
        value: 'mit'
    },
]
class Alumni extends Component {
    constructor(props) {
        super(props)
        this.state = {
            attendees: [],
            email: '',
            fname: '',
            mname: '',
            sname: '',
            ystart: '',
            yend: '',
            course: '',
            company: '',
            contact: '',
            noGravatar: false,
            submitting: false,
            count: 0,
            loadingAttendees: true,
            formKey: uuidv4()
        }
    }

    handleSubmit = (e) => {
        e.preventDefault();
        this.setState({ submitting: true })
        const { fname, mname, sname, ystart, yend, course, company, contact, email, noGravatar } = this.state
        axios.get('https://us-central1-cict-online.cloudfunctions.net/addNewEntry', {
            params: {
                data: [
                    moment().format('MMMM Do YYYY, h:mm:ss a'),
                    fname,
                    mname,
                    sname,
                    ystart,
                    yend,
                    course,
                    company,
                    contact,
                    email,
                    noGravatar
                ]
            }
        }).then(res => {
            const app = this
            if (res) {
                notification['success']({
                    message: 'See you soon!',
                    description: 'You are now registered! Please check our Facebook group for updates.',
                    onClose: () => {
                        app.getLatestData();
                    }
                });
            } else {
                notification.open({
                    message: 'Ooops!',
                    description: 'Sorry and error occured. Please contact us on our Facebook page.',
                });
            }
            setTimeout(() => {
                this.props.form.resetFields();
                this.setState({
                    submitting: false,
                    formKey: uuidv4()
                })
            }, 1000)
        })
    }

    handleSelectionChange = (value, name) => {
        this.setState({
            [name]: value
        })
    }

    handleChange = e => {
        const { name, value } = e.target
        this.setState({
            [name]: value
        })
    }

    getLatestData = (start, end) => {
        const app = this
        const attendeesQuery = `https://us-central1-cict-online.cloudfunctions.net/getRegisteredEntries?start=${start || 2}&end=${end || 5}`;
        axios.get(attendeesQuery).then(res => {
            if (Object.keys(res.data) !== 0) {
                app.setState({ attendees: res.data.reverse() })
            }
        })

        const countQuery = `https://us-central1-cict-online.cloudfunctions.net/countAllRegistered`;
        axios.get(countQuery).then(res => {
            if (Object.keys(res.data) !== 0) {
                app.setState({ count: res.data.length, loadingAttendees: false })
            }
        })
    }

    componentDidMount() {
        const app = this
        app.getLatestData()
    }

    onCheckboxChange = e => {
        const { name, checked } = e.target
        this.setState({ [name]: checked })
    }

    countAttendees = count => {
        switch (count) {
            case 0:
                return 'Be the first to register!'
            case 1:
                return 'Wow! You are the first to register!'
            default:
                return <React.Fragment>{count} CICTzens are attending!</React.Fragment>
        }
    }

    render() {
        const { attendees, email, noGravatar, submitting, formKey, count, loadingAttendees } = this.state
        const url = 'http://cictwvsu.com/alumni/';
        const quote = 'Register now!';
        return (
            <React.Fragment>
                <Helmet
                    title="Online Registration"
                    description="CICT Alumni Homecoming Registration"
                    ogImage={ogImage}
                    url="https://cictwvsu.com/alumni"
                />
                <Navbar />
                <div className="w-full text-center bg-no-repeat bg-left-bottom" style={{ backgroundImage: `url(${bgLeft})` }}>
                    <div className="w-full text-center bg-no-repeat bg-right-bottom" style={{ backgroundImage: `url(${bgRight})` }}>

                            <Slide top>

                            </Slide>
                            <Fade>

#tweet16

<MapPin className={[theme.text, 'w-4 h-4']} /> West Visayas State University, CICT Grounds, Iloilo City

<Clock className={[theme.text, 'w-4 h-4']} /> 8:30 AM - 6:00 PM

                            </Fade>
                            <Fade>
                                <Spin spinning={submitting}>
                                    <Form key={formKey} onSubmit={this.handleSubmit} className="alumni-registration-form px-4 lg:px-auto mx-auto py-8 text-left sm:px-4 xs:px-4">
                                        * Required Fields
                                        <FormItem required label="Basic Info" className="my-0">
                                            <FormItem className="mt-0">
                                                <Input addonBefore="First Name" required size="large" name="fname" prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="* Your First Name" onChange={e => this.handleChange(e, 'fname')} />
                                            </FormItem>
                                            <FormItem>
                                                <Input addonBefore="Middle Name" required size="large" name="mname" prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="* Your Middle Name" onChange={e => this.handleChange(e, 'mname')} />
                                            </FormItem>
                                            <FormItem>
                                                <Input addonBefore="Last Name" required size="large" name="sname" prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="* Your Last Name" onChange={e => this.handleChange(e, 'sname')} />
                                            </FormItem>
                                        </FormItem>

                                        <FormItem required label="Year Entered the College">
                                            <Select showSearch size="large" placeholder="Select a Year" onChange={e => this.handleSelectionChange(e, 'ystart')}>
                                                {yearStartRange.map(i => (
                                                    <Option key={i} value={i}>{i}</Option>
                                                ))}
                                            </Select>
                                        </FormItem>
                                        <FormItem required label="Year Graduated from the College">
                                            <Select showSearch size="large" placeholder="Select a Year" onChange={e => this.handleSelectionChange(e, 'yend')}>
                                                {yearEndRange.map(i => (
                                                    <Option key={i} value={i}>{i}</Option>
                                                ))}
                                            </Select>
                                        </FormItem>
                                        <FormItem required label="Course">
                                            <Select showSearch size="large" placeholder="Select a Course" onChange={e => this.handleSelectionChange(e, 'course')}>
                                                {courses.map(i => (
                                                    <Option key={i.value} value={i.value}>{i.name}</Option>
                                                ))}
                                            </Select>
                                        </FormItem>
                                        <FormItem required label="Company Affiliated">
                                            <Input required addonBefore="Details" name="company" size="large" placeholder="Where are you working now?" onChange={e => this.handleChange(e, 'company')} />
                                        </FormItem>
                                        <FormItem required label="Profile Email">
                                            <FormItem>

                                                    {
                                                        noGravatar ?
                                                            <InlineSVG src={jdenticon.toSvg(email, 150)} className="rounded-full mx-0 my-4" /> :
                                                            <Gravatar default="monsterid" size={150} className="rounded-full mx-0 my-4" email={email} />
                                                    }

                                                <Input addonBefore={noGravatar ? "Email" : "Gravatar Email"} type="email" size="large" prefix={<Icon type="mail" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder={noGravatar ? "Email" : "Gravatar Email"} onChange={e => this.handleChange(e, 'email')} name="email" />

Create your own Gravatar

                                                <Checkbox name="noGravatar" checked={noGravatar} onChange={this.onCheckboxChange}>I don't have a Gravatar email.</Checkbox>
                                            </FormItem>
                                            <FormItem required label="Mobile/Landline">
                                                <Input name="contact" size="large" placeholder="Your Number" onChange={e => this.handleChange(e, 'contact')} />
                                            </FormItem>

                                        </FormItem>

                                            <Button loading={submitting} type="primary" htmlType="submit" className="w-full">
                                                Register Now
                                        </Button>

                                    </Form>
                                </Spin>

Share with your friends!

                                            <FacebookShareButton
                                                url={url}
                                                quote={quote}
                                                className="mx-2"
                                            >
                                                <FacebookIcon
                                                    size={32}
                                                    round />
                                            </FacebookShareButton>

                                            <TwitterShareButton
                                                className="mx-2"
                                                url={url}
                                                title={quote}
                                            >
                                                <TwitterIcon
                                                    size={32}

                                                    round />
                                            </TwitterShareButton>

                                            <EmailShareButton
                                                className="mx-2"
                                                url={url}
                                                subject={quote}
                                                body="Register for CICT Alumni Homecoming 2019!"
                                            >
                                                <EmailIcon
                                                    size={32}
                                                    round />
                                            </EmailShareButton>

                            </Fade>

{this.countAttendees(count)}

                            <Spin className="mx-auto w-full" spinning={submitting}>

                                    {loadingAttendees && <Spin className="mx-auto" />}
                                    {attendees && attendees.map(i => (

                                            <Popover content={

                                                    Batch {i[5]}, {_.upperCase(i[6])}

                                            } title={`${i[3]}, ${i[2]} ${i[1]}`}>

                                                    {
                                                        JSON.parse(i[10]) ?
                                                            <InlineSVG src={jdenticon.toSvg(i[9], 44)} className="w-16 h-auto rounded-full" /> :
                                                            <Gravatar default="monsterid" size={100} className="w-16 h-auto rounded-full" email={i[9]} />
                                                    }

                                            </Popover>

                                    )
                                    )}

                                    <Link to="/homecoming2019" className="w-16 h-16 border-2 mb-4 rounded-full alumni-2019-theme-border--color p-2 zoom">

                                            +{count - 4}

                                    </Link>

                            </Spin>

                        <Link className="font-bold mt-8" to="/homecoming2019">View All</Link>

                            <DisqusThread
                                id="main"
                                title="CICT Allumni Homecoming"
                                path="https://cictwvsu.com/alumni/"
                            />

Help us build a better college website!

                            <Button href="https://github.com/wvsu-cict-code/cict-online" target="_blank" icon="github">Contribute</Button>

                        <Link className="mx-4 p-4" to="/"></Link>

                                </> with <3 by CICTzens | 2016 - Present

            </React.Fragment>
        )
    }
}

const WrappedForm = Form.create()(Alumni);

export default WrappedForm<commit_msg>Fix for loading UI inconsistencies<commit_after>import { Button, Checkbox, Form, Icon, Input, notification, Popover, Select, Spin } from 'antd';
import axios from 'axios';
import _ from 'lodash';
import moment from 'moment';
import React, { Component } from 'react';
import { Clock, MapPin } from 'react-feather';
import Gravatar from 'react-gravatar';
import { Fade, Slide } from 'react-reveal';
import {
    EmailIcon,
    EmailShareButton,
    FacebookIcon,
    FacebookShareButton,
    TwitterIcon,
    TwitterShareButton,
} from 'react-share';
import { Link } from 'react-static';
import InlineSVG from 'svg-inline-react';
import uuidv4 from 'uuid/v4';

import brandIconLight from '../assets/brandicon-light.svg';
import bgLeft from '../assets/misc/alumni-2019-bg-left.jpg';
import bgRight from '../assets/misc/alumni-2019-bg-right.jpg';
import brandLogo from '../assets/misc/alumni-2019-brand.svg';
import divider from '../assets/misc/divider.svg';
import ogImage from '../assets/misc/alumni-2019.jpg';
import Helmet from '../components/Helmet';
import Navbar from '../components/Navbar';
import DisqusThread from '../components/DisqusThread';

const jdenticon = require('jdenticon')

const theme = {
    text: 'font-light alumni-2019-theme-text--color mt-2',
    link: 'alumni-2019-theme-text--color mt-2 no-underline hover:text-orange',
}

const FormItem = Form.Item;
const Option = Select.Option;
const yearStartRange = _.range(2000, (new Date()).getFullYear(), 1)
const yearEndRange = _.range(2004, (new Date()).getFullYear(), 1)
const courses = [
    {
        name: 'Bachelor of Science in Information Management',
        value: 'bsim'
    },
    {
        name: 'Bachelor of Science in Information Technology',
        value: 'bsit'
    },
    {
        name: 'Bachelor of Science in Information Systems',
        value: 'bsis'
    },
    {
        name: 'Bachelor of Science in Computer Science',
        value: 'bscs'
    },
    {
        name: 'Masters in Information Technology',
        value: 'mit'
    },
]
class Alumni extends Component {
    constructor(props) {
        super(props)
        this.state = {
            attendees: [],
            email: '',
            fname: '',
            mname: '',
            sname: '',
            ystart: '',
            yend: '',
            course: '',
            company: '',
            contact: '',
            noGravatar: false,
            submitting: false,
            count: 0,
            loadingAttendees: true,
            formKey: uuidv4()
        }
    }

    handleSubmit = (e) => {
        e.preventDefault();
        this.setState({ submitting: true })
        const { fname, mname, sname, ystart, yend, course, company, contact, email, noGravatar } = this.state
        axios.get('https://us-central1-cict-online.cloudfunctions.net/addNewEntry', {
            params: {
                data: [
                    moment().format('MMMM Do YYYY, h:mm:ss a'),
                    fname,
                    mname,
                    sname,
                    ystart,
                    yend,
                    course,
                    company,
                    contact,
                    email,
                    noGravatar
                ]
            }
        }).then(res => {
            const app = this
            if (res) {
                notification['success']({
                    message: 'See you soon!',
                    description: 'You are now registered! Please check our Facebook group for updates.',
                    onClose: () => {
                        app.getLatestData();
                    }
                });
            } else {
                notification.open({
                    message: 'Ooops!',
                    description: 'Sorry and error occured. Please contact us on our Facebook page.',
                });
            }
            setTimeout(() => {
                this.props.form.resetFields();
                this.setState({
                    submitting: false,
                    formKey: uuidv4()
                })
            }, 1000)
        })
    }

    handleSelectionChange = (value, name) => {
        this.setState({
            [name]: value
        })
    }

    handleChange = e => {
        const { name, value } = e.target
        this.setState({
            [name]: value
        })
    }

    getLatestData = (start, end) => {
        const app = this
        const attendeesQuery = `https://us-central1-cict-online.cloudfunctions.net/getRegisteredEntries?start=${start || 2}&end=${end || 5}`;
        axios.get(attendeesQuery).then(res => {
            if (Object.keys(res.data) !== 0) {
                app.setState({ attendees: res.data.reverse() })
            }
        })

        const countQuery = `https://us-central1-cict-online.cloudfunctions.net/countAllRegistered`;
        axios.get(countQuery).then(res => {
            if (Object.keys(res.data) !== 0) {
                app.setState({ count: res.data.length, loadingAttendees: false })
            }
        })
    }

    componentDidMount() {
        const app = this
        app.getLatestData()
    }

    onCheckboxChange = e => {
        const { name, checked } = e.target
        this.setState({ [name]: checked })
    }

    countAttendees = count => {
        switch (count) {
            case 0:
                return 'Be the first to register!'
            case 1:
                return 'Wow! You are the first to register!'
            default:
                return <React.Fragment>{count} CICTzens are attending!</React.Fragment>
        }
    }

    render() {
        const { attendees, email, noGravatar, submitting, formKey, count, loadingAttendees } = this.state
        const url = 'http://cictwvsu.com/alumni/';
        const quote = 'Register now!';
        return (
            <React.Fragment>
                <Helmet
                    title="Online Registration"
                    description="CICT Alumni Homecoming Registration"
                    ogImage={ogImage}
                    url="https://cictwvsu.com/alumni"
                />
                <Navbar />
                <div className="w-full text-center bg-no-repeat bg-left-bottom" style={{ backgroundImage: `url(${bgLeft})` }}>
                    <div className="w-full text-center bg-no-repeat bg-right-bottom" style={{ backgroundImage: `url(${bgRight})` }}>

                            <Slide top>

                            </Slide>
                            <Fade>

#tweet16

<MapPin className={[theme.text, 'w-4 h-4']} /> West Visayas State University, CICT Grounds, Iloilo City

<Clock className={[theme.text, 'w-4 h-4']} /> 8:30 AM - 6:00 PM

                            </Fade>
                            <Fade>
                                <Spin spinning={submitting}>
                                    <Form key={formKey} onSubmit={this.handleSubmit} className="alumni-registration-form px-4 lg:px-auto mx-auto py-8 text-left sm:px-4 xs:px-4">
                                        * Required Fields
                                        <FormItem required label="Basic Info" className="my-0">
                                            <FormItem className="mt-0">
                                                <Input addonBefore="First Name" required size="large" name="fname" prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="* Your First Name" onChange={e => this.handleChange(e, 'fname')} />
                                            </FormItem>
                                            <FormItem>
                                                <Input addonBefore="Middle Name" required size="large" name="mname" prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="* Your Middle Name" onChange={e => this.handleChange(e, 'mname')} />
                                            </FormItem>
                                            <FormItem>
                                                <Input addonBefore="Last Name" required size="large" name="sname" prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="* Your Last Name" onChange={e => this.handleChange(e, 'sname')} />
                                            </FormItem>
                                        </FormItem>

                                        <FormItem required label="Year Entered the College">
                                            <Select showSearch size="large" placeholder="Select a Year" onChange={e => this.handleSelectionChange(e, 'ystart')}>
                                                {yearStartRange.map(i => (
                                                    <Option key={i} value={i}>{i}</Option>
                                                ))}
                                            </Select>
                                        </FormItem>
                                        <FormItem required label="Year Graduated from the College">
                                            <Select showSearch size="large" placeholder="Select a Year" onChange={e => this.handleSelectionChange(e, 'yend')}>
                                                {yearEndRange.map(i => (
                                                    <Option key={i} value={i}>{i}</Option>
                                                ))}
                                            </Select>
                                        </FormItem>
                                        <FormItem required label="Course">
                                            <Select showSearch size="large" placeholder="Select a Course" onChange={e => this.handleSelectionChange(e, 'course')}>
                                                {courses.map(i => (
                                                    <Option key={i.value} value={i.value}>{i.name}</Option>
                                                ))}
                                            </Select>
                                        </FormItem>
                                        <FormItem required label="Company Affiliated">
                                            <Input required addonBefore="Details" name="company" size="large" placeholder="Where are you working now?" onChange={e => this.handleChange(e, 'company')} />
                                        </FormItem>
                                        <FormItem required label="Profile Email">
                                            <FormItem>

                                                    {
                                                        noGravatar ?
                                                            <InlineSVG src={jdenticon.toSvg(email, 150)} className="rounded-full mx-0 my-4" /> :
                                                            <Gravatar default="monsterid" size={150} className="rounded-full mx-0 my-4" email={email} />
                                                    }

                                                <Input addonBefore={noGravatar ? "Email" : "Gravatar Email"} type="email" size="large" prefix={<Icon type="mail" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder={noGravatar ? "Email" : "Gravatar Email"} onChange={e => this.handleChange(e, 'email')} name="email" />

Create your own Gravatar

                                                <Checkbox name="noGravatar" checked={noGravatar} onChange={this.onCheckboxChange}>I don't have a Gravatar email.</Checkbox>
                                            </FormItem>
                                            <FormItem required label="Mobile/Landline">
                                                <Input name="contact" size="large" placeholder="Your Number" onChange={e => this.handleChange(e, 'contact')} />
                                            </FormItem>

                                        </FormItem>

                                            <Button loading={submitting} type="primary" htmlType="submit" className="w-full">
                                                Register Now
                                        </Button>

                                    </Form>
                                </Spin>

Share with your friends!

                                            <FacebookShareButton
                                                url={url}
                                                quote={quote}
                                                className="mx-2"
                                            >
                                                <FacebookIcon
                                                    size={32}
                                                    round />
                                            </FacebookShareButton>

                                            <TwitterShareButton
                                                className="mx-2"
                                                url={url}
                                                title={quote}
                                            >
                                                <TwitterIcon
                                                    size={32}

                                                    round />
                                            </TwitterShareButton>

                                            <EmailShareButton
                                                className="mx-2"
                                                url={url}
                                                subject={quote}
                                                body="Register for CICT Alumni Homecoming 2019!"
                                            >
                                                <EmailIcon
                                                    size={32}
                                                    round />
                                            </EmailShareButton>

                            </Fade>

{this.countAttendees(count)}

                            <Spin className="mx-auto w-full" spinning={submitting}>

                                    {loadingAttendees && <Spin className="mx-auto" />}
                                    {attendees && attendees.map(i => (

                                            <Popover content={

                                                    Batch {i[5]}, {_.upperCase(i[6])}

                                            } title={`${i[3]}, ${i[2]} ${i[1]}`}>

                                                    {
                                                        JSON.parse(i[10]) ?
                                                            <InlineSVG src={jdenticon.toSvg(i[9], 44)} className="w-16 h-auto rounded-full" /> :
                                                            <Gravatar default="monsterid" size={100} className="w-16 h-auto rounded-full" email={i[9]} />
                                                    }

                                            </Popover>

                                    )
                                    )}

                                    {!loadingAttendees && <Link to="/homecoming2019" className="w-16 h-16 border-2 mb-4 rounded-full alumni-2019-theme-border--color p-2 zoom">

                                            +{count - 4}

                                    </Link>}

                            </Spin>

                        <Link className="font-bold mt-8" to="/homecoming2019">View All</Link>

                            <DisqusThread
                                id="main"
                                title="CICT Allumni Homecoming"
                                path="https://cictwvsu.com/alumni/"
                            />

Help us build a better college website!

                            <Button href="https://github.com/wvsu-cict-code/cict-online" target="_blank" icon="github">Contribute</Button>

                        <Link className="mx-4 p-4" to="/"></Link>

                                </> with <3 by CICTzens | 2016 - Present

            </React.Fragment>
        )
    }
}

const WrappedForm = Form.create()(Alumni);

export default WrappedForm<|endoftext|>


<commit_before>import jetpack from 'fs-jetpack'
import path from 'path'
import _ from 'lodash'

const DEFAULT_PANEL_CONF = getConfig(__dirname, '..', 'config', 'defaultPanelConfig.json')
const CONFIG = getConfig(__dirname, '..', 'config', 'config.json')

/**
 * getConfigPaths - Evaluates the panel config locations defined in the config.json
 * and returns valid OS dependent path
 *
 * @return {array}  An array of paths to the panel configurations
 */
function getConfigPaths() {
  let userHome = process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME']

  return CONFIG.panelConfigDirectories.map((_dirParts) => {
    _dirParts = _dirParts.map((__dirPart) => __dirPart.replace(/\%USERHOME\%/i, userHome))
    return path.join(..._dirParts)
  }).reduce((_configPaths, _configPath) => {

    if(jetpack.exists(_configPath) == 'dir') {
      _configPaths.push(_configPath)
    }

    return _configPaths

  }, [])
}

/**
 * validatePath - Joins the multiple path parts and validates if they match the
 * specified type (i.e. dir, file)
 *
 * @param  {string} _type         The type to check the path against (dir, file)
 * @param  {string} ..._pathParts Path parts to be joined an evaluated
 * @return {string}               Returns the joined version of the given path parts if they match the given type else false
 */
function validatePath(_type, ..._pathParts) {
  let _path = path.join(..._pathParts)
  return jetpack.exists(_path) == _type ? _path : false
}

/**
 * getItems - Extracts "items" from the given path parts and stores them in an
 * handy object. An item can either be a panel or one of the defined custom
 * elements. Therefore they are de facto HTML files which should be loaded.
 *
 * Returns only valid items
 *
 * @param  {string} ..._pathParts The path parts pointing to a directory of items
 * @return {array}                An array of "item" objects which contain the item name and resolved path
 */
function getItems(..._pathParts) {

  let _items = []
  let _itemsPath = validatePath('dir', ..._pathParts)

  if(!_itemsPath) return _items

  jetpack.list(_itemsPath).reduce((__items, __cItemName) => {
    let __itemPath = validatePath('file', _itemsPath, __cItemName, 'index.html')

    if(__itemPath) {
      __items.push({
        name: __cItemName,
        path: __itemPath,
      })
    }

    return __items
  }, _items)

  return _items
}

/**
 * getConfig - Reads the config file of the given path parts if the path is valid
 *
 * @param  {string} ..._pathParts The path parts pointing to the json config file
 * @return {object}               Either empty if the path does not point to a valid json file or the config from the json file
 */
function getConfig(..._pathParts) {

  let _config = {}
  let _configPath = validatePath('file', ..._pathParts)

  if(!_configPath) return _config

  return jetpack.read(_configPath, 'json')
}

/**
 * getPanelsFromPath - Returns an array of panel objects from a given path.
 * All valid panels in the provided path will be returned. Each panel is
 * described in an object and contains all source files (including local and global
 * custom elements) and the panel specific configuration which consists of the
 * local panel config file, the global panels config file and the default panel
 * config.
 *
 * @param  {string} _panelsPath Path to panel configuration location
 * @return {array}              Array of panel objects each containing all relevant information in order to build the panel
 */
function getPanelsFromPath(_panelsPath) {
  let _globalConfig = getConfig(_panelsPath, 'panels', `${CONFIG.panelConfigFileName}.json`)
  let _globalElements = getItems(_panelsPath, 'elements')
  let _panels = getItems(_panelsPath, 'panels')

  _panels.map((__panel) => {
    let __panelConfig = getConfig(__panel.path, '..', `${CONFIG.panelConfigFileName}.json`)
    let __panelElements = getItems(__panel.path, '..', 'elements')

    __panel.elements = _.uniq(__panelElements.concat(_globalElements), 'name')
    __panel.config = _.merge(DEFAULT_PANEL_CONF, _globalConfig, __panelConfig)

    return __panel
  })

  return _panels
}

/**
 * export - Default export for all panels of all configuration locations
 *
 * @return {array}  array of panel objects each containing all relevant information in order to build the panel
 */
export default function() {
  let _panels = []

  getConfigPaths().forEach((__configPath) => {
    _panels = _panels.concat(getPanelsFromPath(__configPath))
  })

  return _panels
}
<commit_msg>FIX: panel config merging<commit_after>import jetpack from 'fs-jetpack'
import path from 'path'
import _ from 'lodash'

const DEFAULT_PANEL_CONF = getConfig(__dirname, '..', 'config', 'defaultPanelConfig.json')
const CONFIG = getConfig(__dirname, '..', 'config', 'config.json')

/**
 * getConfigPaths - Evaluates the panel config locations defined in the config.json
 * and returns valid OS dependent path
 *
 * @return {array}  An array of paths to the panel configurations
 */
function getConfigPaths() {
  let userHome = process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME']

  return CONFIG.panelConfigDirectories.map((_dirParts) => {
    _dirParts = _dirParts.map((__dirPart) => __dirPart.replace(/\%USERHOME\%/i, userHome))
    return path.join(..._dirParts)
  }).reduce((_configPaths, _configPath) => {

    if(jetpack.exists(_configPath) == 'dir') {
      _configPaths.push(_configPath)
    }

    return _configPaths

  }, [])
}

/**
 * validatePath - Joins the multiple path parts and validates if they match the
 * specified type (i.e. dir, file)
 *
 * @param  {string} _type         The type to check the path against (dir, file)
 * @param  {string} ..._pathParts Path parts to be joined an evaluated
 * @return {string}               Returns the joined version of the given path parts if they match the given type else false
 */
function validatePath(_type, ..._pathParts) {
  let _path = path.join(..._pathParts)
  return jetpack.exists(_path) == _type ? _path : false
}

/**
 * getItems - Extracts "items" from the given path parts and stores them in an
 * handy object. An item can either be a panel or one of the defined custom
 * elements. Therefore they are de facto HTML files which should be loaded.
 *
 * Returns only valid items
 *
 * @param  {string} ..._pathParts The path parts pointing to a directory of items
 * @return {array}                An array of "item" objects which contain the item name and resolved path
 */
function getItems(..._pathParts) {

  let _items = []
  let _itemsPath = validatePath('dir', ..._pathParts)

  if(!_itemsPath) return _items

  jetpack.list(_itemsPath).reduce((__items, __cItemName) => {
    let __itemPath = validatePath('file', _itemsPath, __cItemName, 'index.html')

    if(__itemPath) {
      __items.push({
        name: __cItemName,
        path: __itemPath,
      })
    }

    return __items
  }, _items)

  return _items
}

/**
 * getConfig - Reads the config file of the given path parts if the path is valid
 *
 * @param  {string} ..._pathParts The path parts pointing to the json config file
 * @return {object}               Either empty if the path does not point to a valid json file or the config from the json file
 */
function getConfig(..._pathParts) {

  let _config = {}
  let _configPath = validatePath('file', ..._pathParts)

  if(!_configPath) return _config

  return jetpack.read(_configPath, 'json')
}

/**
 * getPanelsFromPath - Returns an array of panel objects from a given path.
 * All valid panels in the provided path will be returned. Each panel is
 * described in an object and contains all source files (including local and global
 * custom elements) and the panel specific configuration which consists of the
 * local panel config file, the global panels config file and the default panel
 * config.
 *
 * @param  {string} _panelsPath Path to panel configuration location
 * @return {array}              Array of panel objects each containing all relevant information in order to build the panel
 */
function getPanelsFromPath(_panelsPath) {
  let _globalConfig = getConfig(_panelsPath, 'panels', `${CONFIG.panelConfigFileName}.json`)
  let _globalElements = getItems(_panelsPath, 'elements')
  let _panels = getItems(_panelsPath, 'panels')

  _panels.map((__panel) => {
    let __panelConfig = getConfig(__panel.path, '..', `${CONFIG.panelConfigFileName}.json`)
    let __panelElements = getItems(__panel.path, '..', 'elements')

    __panel.elements = _.uniq(__panelElements.concat(_globalElements), 'name')
    __panel.config = _.merge({}, DEFAULT_PANEL_CONF, _globalConfig, __panelConfig)

    return __panel
  })

  return _panels
}

/**
 * export - Default export for all panels of all configuration locations
 *
 * @return {array}  array of panel objects each containing all relevant information in order to build the panel
 */
export default function() {
  let _panels = []

  getConfigPaths().forEach((__configPath) => {
    _panels = _panels.concat(getPanelsFromPath(__configPath))
  })

  return _panels
}
<|endoftext|>


<commit_before>/**
@license
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/

import * as utils from '../utils.js';
import {shadyDataForNode} from '../shady-data.js';
import {addEventListener, removeEventListener} from '../patch-events.js';

export const SlotPatches = utils.getOwnPropertyDescriptors({

  /**
   * @this {HTMLSlotElement}
   * @param {Object=} options
   */
  assignedNodes(options) {
    if (this.localName === 'slot') {
      // Force any containing shadowRoot to flush so that distribution occurs
      // and this node has assignedNodes.
      const root = this[utils.SHADY_PREFIX + 'getRootNode']();
      if (root && utils.isShadyRoot(root)) {
        root._render();
      }
      const nodeData = shadyDataForNode(this);
      return nodeData ?
        ((options && options.flatten ? nodeData.flattenedNodes :
          nodeData.assignedNodes) || []) :
        [];
    }
  },

  /**
   * @this {HTMLSlotElement}
   * @param {string} type
   * @param {Function} fn
   * @param {Object|boolean=} optionsOrCapture
   */
  addEventListener(type, fn, optionsOrCapture) {
    if (typeof optionsOrCapture !== 'object') {
      optionsOrCapture = {
        capture: Boolean(optionsOrCapture)
      }
    }
    if (type === 'slotchange') {
      addEventListener.call(this, type, fn, optionsOrCapture);
    } else {
      const parent = this[utils.SHADY_PREFIX + 'parentNode'];
      if (!parent) {
        throw new Error('ShadyDOM cannot attach event to slot unless it has a `parentNode`');
      }
      optionsOrCapture.__shadyTarget = this;
      parent[utils.SHADY_PREFIX + 'addEventListener'](type, fn, optionsOrCapture);
    }
  },

  /**
   * @this {HTMLSlotElement}
   * @param {string} type
   * @param {Function} fn
   * @param {Object|boolean=} optionsOrCapture
   */
  removeEventListener(type, fn, optionsOrCapture) {
    if (typeof optionsOrCapture !== 'object') {
      optionsOrCapture = {
        capture: Boolean(optionsOrCapture)
      }
    }
    if (type === 'slotchange') {
      removeEventListener.call(this, type, fn, optionsOrCapture);
    } else {
      const parent = this[utils.SHADY_PREFIX + 'parentNode'];
      if (!parent) {
        throw new Error('ShadyDOM cannot attach event to slot unless it has a `parentNode`');
      }
      optionsOrCapture.__shadyTarget = this;
      parent[utils.SHADY_PREFIX + 'removeEventListener'](type, fn, optionsOrCapture);
    }
  }

});
<commit_msg>Fix patch to work on browsers that don't have `<slot>` element<commit_after>/**
@license
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/

import * as utils from '../utils.js';
import {shadyDataForNode} from '../shady-data.js';
import {addEventListener, removeEventListener} from '../patch-events.js';

export const SlotPatches = utils.getOwnPropertyDescriptors({

  /**
   * @this {HTMLSlotElement}
   * @param {Object=} options
   */
  assignedNodes(options) {
    if (this.localName === 'slot') {
      // Force any containing shadowRoot to flush so that distribution occurs
      // and this node has assignedNodes.
      const root = this[utils.SHADY_PREFIX + 'getRootNode']();
      if (root && utils.isShadyRoot(root)) {
        root._render();
      }
      const nodeData = shadyDataForNode(this);
      return nodeData ?
        ((options && options.flatten ? nodeData.flattenedNodes :
          nodeData.assignedNodes) || []) :
        [];
    }
  },

  /**
   * @this {HTMLSlotElement}
   * @param {string} type
   * @param {Function} fn
   * @param {Object|boolean=} optionsOrCapture
   */
  addEventListener(type, fn, optionsOrCapture) {
    if (typeof optionsOrCapture !== 'object') {
      optionsOrCapture = {
        capture: Boolean(optionsOrCapture)
      }
    }
    // NOTE, check if this is a `slot` because these patches are installed on
    // Element where browsers don't have `<slot>`
    if (this.localName !== 'slot' || type === 'slotchange') {
      addEventListener.call(this, type, fn, optionsOrCapture);
    } else {
      const parent = this[utils.SHADY_PREFIX + 'parentNode'];
      if (!parent) {
        throw new Error('ShadyDOM cannot attach event to slot unless it has a `parentNode`');
      }
      optionsOrCapture.__shadyTarget = this;
      parent[utils.SHADY_PREFIX + 'addEventListener'](type, fn, optionsOrCapture);
    }
  },

  /**
   * @this {HTMLSlotElement}
   * @param {string} type
   * @param {Function} fn
   * @param {Object|boolean=} optionsOrCapture
   */
  removeEventListener(type, fn, optionsOrCapture) {
    if (typeof optionsOrCapture !== 'object') {
      optionsOrCapture = {
        capture: Boolean(optionsOrCapture)
      }
    }
    // NOTE, check if this is a `slot` because these patches are installed on
    // Element where browsers don't have `<slot>`
    if (this.localName !== 'slot' || type === 'slotchange') {
      removeEventListener.call(this, type, fn, optionsOrCapture);
    } else {
      const parent = this[utils.SHADY_PREFIX + 'parentNode'];
      if (!parent) {
        throw new Error('ShadyDOM cannot attach event to slot unless it has a `parentNode`');
      }
      optionsOrCapture.__shadyTarget = this;
      parent[utils.SHADY_PREFIX + 'removeEventListener'](type, fn, optionsOrCapture);
    }
  }

});
<|endoftext|>


<commit_before>PiCard.Chart = PiCard.defineClass(
    [ PiCard.Configurable, PiCard.Localized ],

    function(container, data, options) {
        PiCard.Configurable.call(this, options);
        PiCard.Localized.call(this, this.options.locale);
        this.container = container;
        this.data = data;
        this.initialize();
    },

    {
        defaultOptions: {
            axisWidth:          1,
            plotPadding:        10,
            labelMargin:        10,
            plotMarkerSize:     6,
            plotMarkerWidth:    1,
            minPieRadius:       2,
            maxPieRadius:       20,
            startAngle:         -90,
            clockwise:          true,
            drawAllPlotMarkers: false,
            dotScale:           "quad",
            legendFormat:       "{0} ({1})",
            fontFamily:         "Verdana, Arial, Helvetica, sans-serif",
            fontSize:           12,
            activeOpacity:      1.0,
            inactiveOpacity:    0.2,
            axisColor:          "#666",
            plotMarkerColor:    "#999",
            axisLabelColor:     "#666",
            pieColors:          [
                "#C90", "#0C9", "#90C", "#9C0", "#09C", "#C09",
                "#C00", "#0C0", "#00C", "#099", "#909", "#990",
                "#C66", "#6C6", "#66C", "#999"
            ],
            userColors:         {},
            usersKey:           ".users"
        },

        initialize: function() {
            var that = this;
            that.determineUserNames();
            that.calculateTotals();
            that.determineMaximum();
            that.setUserColors();
            that.calculateMeasurements();
            that.createPlotArea();
            that.createPlots();
            that.createAxes();
            that.createLegend();
            that.prepareContainer();
            that.createStage();
            that.container.trigger("picard.ready", [ that ]);
        },

        determineUserNames: function() {
            var that = this;
            if (that.options.usersKey !== undefined
                    && that.options.usersKey in that.data) {
                that.users = that.data[that.options.usersKey];
                delete that.data[that.options.usersKey];
            } else {
                that.users = that.sortUserNames();
            }
        },

        sortUserNames: function() {
            var that = this;
            var users = [];
            $.each(that.data, function(user, perDay) {
                users.push(user);
            });
            users.sort();
            return users;
        },

        prepareContainer: function() {
            var that = this;
            var id = that.container.attr("id") + "-chart";
            that.chartContainer = $("<div>")
                .attr("class", "picard-chart")
                .attr("id", id);
            that.container
                .empty()
                .append(that.legend)
                .append(that.chartContainer);
        },

        createStage: function() {
            var that = this;
            that.stage = new Kinetic.Stage({
                container: that.chartContainer.attr("id"),
                width:     that.measure.width,
                height:    that.measure.height
            });
            that.stage.add(that.plotArea);
            $.each(that.plots, function(user, plot) {
                that.stage.add(plot);
            });
            that.stage.add(that.axes);
        },

        createLegend: function() {
            var that = this;
            var userTotals = {};
            var grandTotal = 0;
            $.each(that.data, function(user, perDay) {
                var total = 0;
                $.each(perDay, function(d, perHour) {
                    $.each(perHour, function(h, amount) {
                        total += amount;
                    });
                });
                userTotals[user] = total;
                grandTotal += total;
            });
            that.legend = $("<div/>")
                .attr("class", "picard-legend")
                .append($("<span/>")
                    .attr("class", "picard-legend-label")
                    .text(that.locale.summaryLabel + " "
                        + that.formatNumber(grandTotal)));
            $.each(that.users, function(i, user) {
                var strings = [
                    user,
                    that.formatNumber(userTotals[user])
                ];
                var code = that.options.legendFormat.replace(
                    /\{([0-9]+)\}/g,
                    function(m0, m1) {
                        return strings[parseInt(m1, 10)];
                    });
                that.legend.append(" ");
                that.legend.append($("<span>")
                    .attr("class", "picard-legend-item")
                    .css("color", that.userColors[user])
                    .mouseover({ user: user, that: that }, that.setActive)
                    .mouseout({ user: null, that: that }, that.setActive)
                    .html(code));
            });
        },

        setActive: function(event) {
            var user = event.data.user;
            var that = event.data.that;
            that.container.trigger("picard.activate", [ that, user ]);
            $.each(that.plots, function(u, plot) {
                that.setOpacity(plot, (user === null || user == u)
                    ? that.options.activeOpacity
                    : that.options.inactiveOpacity);
            });
            that.setOpacity(that.plotArea, (user === null)
                ? that.options.activeOpacity
                : that.options.inactiveOpacity);
        },

        setOpacity: function(layer, opacity) {
            var that = this;
            if (layer.getOpacity() != opacity) {
                layer.setOpacity(opacity);
                layer.draw();
            }
        },

        createPlotArea: function() {
            var that = this;
            that.plotArea = new Kinetic.Layer();
            var x0 = that.measure.yLabelWidth + that.options.labelMargin
                + that.options.axisWidth + that.options.plotPadding
                + that.options.maxPieRadius;
            var y = that.options.plotPadding + that.options.maxPieRadius;
            var s = that.options.plotMarkerSize / 2;
            for (var d = 0; d < 7; d++) {
                var x = x0;
                for (var h = 0; h < 24; h++) {
                    if (that.options.drawAllPlotMarkers || !that.totals[d][h]) {
                        that.plotArea.add(new Kinetic.Line({
                            points:      [ x - s, y, x + s, y ],
                            stroke:      that.options.plotMarkerColor,
                            strokeWidth: that.options.plotMarkerWidth
                        }));
                        that.plotArea.add(new Kinetic.Line({
                            points:      [ x, y - s, x, y + s ],
                            stroke:      that.options.plotMarkerColor,
                            strokeWidth: that.options.plotMarkerWidth
                        }));
                    }
                    x += that.options.maxPieRadius * 2;
                }
                y += that.options.maxPieRadius * 2;
            }
        },

        createPlots: function() {
            var that = this;
            that.plots = {};
            $.each(that.userColors, function(user, color) {
                that.plots[user] = new Kinetic.Layer();
                that.plots[user].setOpacity(that.options.activeOpacity);
            });
            var x0 = that.measure.yLabelWidth + that.options.labelMargin
                + that.options.axisWidth + that.options.plotPadding
                + that.options.maxPieRadius;
            var y = that.options.plotPadding + that.options.maxPieRadius;
            for (var d = 0; d < 7; d++) {
                var x = x0;
                for (var h = 0; h < 24; h++) {
                    if (that.totals[d] && that.totals[d][h]) {
                        that.plotPie(d, h, x, y);
                    }
                    x += that.options.maxPieRadius * 2;
                }
                y += that.options.maxPieRadius * 2;
            }
        },

        plotPie: function(d, h, x, y) {
            var that = this;
            var total = that.totals[d][h];
            var ratio = that.getRatio(total);
            if (ratio <= 0) {
                return;
            }
            var radius = Math.max(that.options.minPieRadius,
                ratio * that.options.maxPieRadius);
            var angle = (that.options.startAngle === null)
                ? Math.random() * 360 : that.options.startAngle;
            $.each(that.data, function(user, perDay) {
                if (perDay[d] && perDay[d][h]) {
                    var degrees = 360 * (perDay[d][h] / total);
                    if (that.options.clockWise) {
                        degrees = -degrees;
                    }
                    var wedge = new Kinetic.Wedge({
                        x:           x,
                        y:           y,
                        radius:      radius,
                        rotationDeg: angle,
                        angleDeg:    degrees,
                        fill:        that.userColors[user]
                    });
                    that.plots[user].add(wedge);
                    angle += degrees;
                }
            });
        },

        getRatio: function(value) {
            var that = this;
            if (value <= 0) {
                return 0;
            }
            var transform = (that.options.scale == "quad") ? Math.sqrt
                : (that.options.scale == "log") ? Math.log
                : function(n) { return n; };
            return transform(value) / transform(that.maximum);
        },

        createAxes: function() {
            var that = this;
            that.axes = new Kinetic.Layer();
            that.createXAxis();
            that.createYAxis();
        },

        createXAxis: function(axes) {
            var that = this;
            that.axes.add(new Kinetic.Line({
                points:      [
                    that.measure.yLabelWidth + that.options.labelMargin,
                    that.measure.plotHeight + that.options.axisWidth / 2,
                    that.measure.width,
                    that.measure.plotHeight + that.options.axisWidth / 2
                ],
                stroke:      that.options.axisColor,
                strokeWidth: that.options.axisWidth
            }));
            var x = that.measure.yLabelWidth + that.options.labelMargin
                + that.options.axisWidth + that.options.plotPadding
                + that.options.maxPieRadius;
            var y = that.measure.plotHeight + that.options.axisWidth
                + that.options.labelMargin;
            for (var h = 0; h < 24; h++) {
                var text = that.createText((h < 10) ? "0" + h : h,
                    x, y, that.options.axisLabelColor);
                text.setOffset({
                    x: text.getWidth() / 2
                });
                that.axes.add(text);
                x += that.options.maxPieRadius * 2;
            }
        },

        createYAxis: function() {
            var that = this;
            that.axes.add(new Kinetic.Line({
                points:      [
                    that.measure.yLabelWidth + that.options.labelMargin
                        + that.options.axisWidth / 2,
                    0,
                    that.measure.yLabelWidth + that.options.labelMargin
                        + that.options.axisWidth / 2,
                    that.measure.plotHeight + that.options.axisWidth
                ],
                stroke:      that.options.axisColor,
                strokeWidth: that.options.axisWidth
            }));
            var x = that.measure.yLabelWidth;
            var y = that.options.plotPadding + that.options.maxPieRadius
                - that.measure.labelHeight / 2;
            for (var d = 0; d < 7; d++) {
                var text = that.createText(that.locale.dayNames[d],
                    x, y, that.options.axisLabelColor);
                text.setOffset({
                    x: text.getWidth()
                });
                that.axes.add(text);
                y += that.options.maxPieRadius * 2;
            }
        },

        calculateTotals: function() {
            var that = this;
            that.totals = [];
            for (var d = 0; d < 7; d++) {
                var dayTotals = [];
                for (var h = 0; h < 24; h++) {
                    dayTotals[h] = 0;
                    $.each(that.data, function(user, perDay) {
                        if (perDay[d] && perDay[d][h]) {
                            dayTotals[h] += perDay[d][h];
                        }
                    });
                }
                that.totals[d] = dayTotals;
            }
        },

        determineMaximum: function() {
            var that = this;
            that.maximum = 0;
            for (var d = 0; d < 7; d++) {
                for (var h = 0; h < 24; h++) {
                    if (that.totals[d] && that.totals[d][h]) {
                        that.maximum = Math.max(that.maximum, that.totals[d][h]);
                    }
                }
            }
        },

        setUserColors: function() {
            var that = this;
            that.userColors = {};
            var i = 0;
            var numPieColors = that.options.pieColors.length;
            $.each(that.users, function(idx, user) {
                that.userColors[user] = that.options.userColors[user]
                    || that.options.pieColors[i++ % numPieColors];
            });
        },

        calculateMeasurements: function() {
            var that = this;
            var yLabelWidth = 0;
            for (var d = 0; d < 7; d++) {
                var text = that.createText(that.locale.dayNames[d], 0, 0, "black");
                yLabelWidth = Math.max(yLabelWidth, text.getWidth());
            }
            var labelHeight = that.createText("X", 0, 0, "black").getHeight();

            var plotWidth = that.options.plotPadding
                + that.options.maxPieRadius * 2 * 24 + that.options.plotPadding;
            var plotHeight = that.options.plotPadding
                + that.options.maxPieRadius * 2 * 7 + that.options.plotPadding;
            var width = yLabelWidth + that.options.labelMargin
                + that.options.axisWidth + plotWidth;
            var height = plotHeight + that.options.axisWidth
                + that.options.labelMargin + labelHeight;

            that.measure = {
                width:       width,
                height:      height,
                plotWidth:   plotWidth,
                plotHeight:  plotHeight,
                yLabelWidth: yLabelWidth,
                labelHeight: labelHeight
            };
        },

        createText: function(text, x, y, color) {
            var that = this;
            return new Kinetic.Text({
                text:       text,
                fontFamily: that.options.fontFamily,
                fontSize:   that.options.fontSize,
                fill:       color,
                x:          x,
                y:          y
            });
        }
    }
);
<commit_msg>Adding option to use legend background color instead<commit_after>PiCard.Chart = PiCard.defineClass(
    [ PiCard.Configurable, PiCard.Localized ],

    function(container, data, options) {
        PiCard.Configurable.call(this, options);
        PiCard.Localized.call(this, this.options.locale);
        this.container = container;
        this.data = data;
        this.initialize();
    },

    {
        defaultOptions: {
            axisWidth:           1,
            plotPadding:         10,
            labelMargin:         10,
            plotMarkerSize:      6,
            plotMarkerWidth:     1,
            minPieRadius:        2,
            maxPieRadius:        20,
            startAngle:          -90,
            clockwise:           true,
            useLegendBackground: false,
            drawAllPlotMarkers:  false,
            dotScale:            "quad",
            legendFormat:        "{0} ({1})",
            fontFamily:          "Verdana, Arial, Helvetica, sans-serif",
            fontSize:            12,
            activeOpacity:       1.0,
            inactiveOpacity:     0.2,
            axisColor:           "#666",
            plotMarkerColor:     "#999",
            axisLabelColor:      "#666",
            pieColors:           [
                "#C90", "#0C9", "#90C", "#9C0", "#09C", "#C09",
                "#C00", "#0C0", "#00C", "#099", "#909", "#990",
                "#C66", "#6C6", "#66C", "#999"
            ],
            userColors:          {},
            usersKey:            ".users"
        },

        initialize: function() {
            var that = this;
            that.determineUserNames();
            that.calculateTotals();
            that.determineMaximum();
            that.setUserColors();
            that.calculateMeasurements();
            that.createPlotArea();
            that.createPlots();
            that.createAxes();
            that.createLegend();
            that.prepareContainer();
            that.createStage();
            that.container.trigger("picard.ready", [ that ]);
        },

        determineUserNames: function() {
            var that = this;
            if (that.options.usersKey !== undefined
                    && that.options.usersKey in that.data) {
                that.users = that.data[that.options.usersKey];
                delete that.data[that.options.usersKey];
            } else {
                that.users = that.sortUserNames();
            }
        },

        sortUserNames: function() {
            var that = this;
            var users = [];
            $.each(that.data, function(user, perDay) {
                users.push(user);
            });
            users.sort();
            return users;
        },

        prepareContainer: function() {
            var that = this;
            var id = that.container.attr("id") + "-chart";
            that.chartContainer = $("<div>")
                .attr("class", "picard-chart")
                .attr("id", id);
            that.container
                .empty()
                .append(that.legend)
                .append(that.chartContainer);
        },

        createStage: function() {
            var that = this;
            that.stage = new Kinetic.Stage({
                container: that.chartContainer.attr("id"),
                width:     that.measure.width,
                height:    that.measure.height
            });
            that.stage.add(that.plotArea);
            $.each(that.plots, function(user, plot) {
                that.stage.add(plot);
            });
            that.stage.add(that.axes);
        },

        createLegend: function() {
            var that = this;
            var userTotals = {};
            var grandTotal = 0;
            $.each(that.data, function(user, perDay) {
                var total = 0;
                $.each(perDay, function(d, perHour) {
                    $.each(perHour, function(h, amount) {
                        total += amount;
                    });
                });
                userTotals[user] = total;
                grandTotal += total;
            });
            var legendProperty = that.options.useLegendBackground
                ? "background-color" : "color";
            that.legend = $("<div/>")
                .attr("class", "picard-legend")
                .append($("<span/>")
                    .attr("class", "picard-legend-label")
                    .text(that.locale.summaryLabel + " "
                        + that.formatNumber(grandTotal)));
            $.each(that.users, function(i, user) {
                var strings = [
                    user,
                    that.formatNumber(userTotals[user])
                ];
                var code = that.options.legendFormat.replace(
                    /\{([0-9]+)\}/g,
                    function(m0, m1) {
                        return strings[parseInt(m1, 10)];
                    });
                that.legend.append(" ");
                that.legend.append($("<span>")
                    .attr("class", "picard-legend-item")
                    .css(legendProperty, that.userColors[user])
                    .mouseover({ user: user, that: that }, that.setActive)
                    .mouseout({ user: null, that: that }, that.setActive)
                    .html(code));
            });
        },

        setActive: function(event) {
            var user = event.data.user;
            var that = event.data.that;
            that.container.trigger("picard.activate", [ that, user ]);
            $.each(that.plots, function(u, plot) {
                that.setOpacity(plot, (user === null || user == u)
                    ? that.options.activeOpacity
                    : that.options.inactiveOpacity);
            });
            that.setOpacity(that.plotArea, (user === null)
                ? that.options.activeOpacity
                : that.options.inactiveOpacity);
        },

        setOpacity: function(layer, opacity) {
            var that = this;
            if (layer.getOpacity() != opacity) {
                layer.setOpacity(opacity);
                layer.draw();
            }
        },

        createPlotArea: function() {
            var that = this;
            that.plotArea = new Kinetic.Layer();
            var x0 = that.measure.yLabelWidth + that.options.labelMargin
                + that.options.axisWidth + that.options.plotPadding
                + that.options.maxPieRadius;
            var y = that.options.plotPadding + that.options.maxPieRadius;
            var s = that.options.plotMarkerSize / 2;
            for (var d = 0; d < 7; d++) {
                var x = x0;
                for (var h = 0; h < 24; h++) {
                    if (that.options.drawAllPlotMarkers || !that.totals[d][h]) {
                        that.plotArea.add(new Kinetic.Line({
                            points:      [ x - s, y, x + s, y ],
                            stroke:      that.options.plotMarkerColor,
                            strokeWidth: that.options.plotMarkerWidth
                        }));
                        that.plotArea.add(new Kinetic.Line({
                            points:      [ x, y - s, x, y + s ],
                            stroke:      that.options.plotMarkerColor,
                            strokeWidth: that.options.plotMarkerWidth
                        }));
                    }
                    x += that.options.maxPieRadius * 2;
                }
                y += that.options.maxPieRadius * 2;
            }
        },

        createPlots: function() {
            var that = this;
            that.plots = {};
            $.each(that.userColors, function(user, color) {
                that.plots[user] = new Kinetic.Layer();
                that.plots[user].setOpacity(that.options.activeOpacity);
            });
            var x0 = that.measure.yLabelWidth + that.options.labelMargin
                + that.options.axisWidth + that.options.plotPadding
                + that.options.maxPieRadius;
            var y = that.options.plotPadding + that.options.maxPieRadius;
            for (var d = 0; d < 7; d++) {
                var x = x0;
                for (var h = 0; h < 24; h++) {
                    if (that.totals[d] && that.totals[d][h]) {
                        that.plotPie(d, h, x, y);
                    }
                    x += that.options.maxPieRadius * 2;
                }
                y += that.options.maxPieRadius * 2;
            }
        },

        plotPie: function(d, h, x, y) {
            var that = this;
            var total = that.totals[d][h];
            var ratio = that.getRatio(total);
            if (ratio <= 0) {
                return;
            }
            var radius = Math.max(that.options.minPieRadius,
                ratio * that.options.maxPieRadius);
            var angle = (that.options.startAngle === null)
                ? Math.random() * 360 : that.options.startAngle;
            $.each(that.data, function(user, perDay) {
                if (perDay[d] && perDay[d][h]) {
                    var degrees = 360 * (perDay[d][h] / total);
                    if (that.options.clockWise) {
                        degrees = -degrees;
                    }
                    var wedge = new Kinetic.Wedge({
                        x:           x,
                        y:           y,
                        radius:      radius,
                        rotationDeg: angle,
                        angleDeg:    degrees,
                        fill:        that.userColors[user]
                    });
                    that.plots[user].add(wedge);
                    angle += degrees;
                }
            });
        },

        getRatio: function(value) {
            var that = this;
            if (value <= 0) {
                return 0;
            }
            var transform = (that.options.scale == "quad") ? Math.sqrt
                : (that.options.scale == "log") ? Math.log
                : function(n) { return n; };
            return transform(value) / transform(that.maximum);
        },

        createAxes: function() {
            var that = this;
            that.axes = new Kinetic.Layer();
            that.createXAxis();
            that.createYAxis();
        },

        createXAxis: function(axes) {
            var that = this;
            that.axes.add(new Kinetic.Line({
                points:      [
                    that.measure.yLabelWidth + that.options.labelMargin,
                    that.measure.plotHeight + that.options.axisWidth / 2,
                    that.measure.width,
                    that.measure.plotHeight + that.options.axisWidth / 2
                ],
                stroke:      that.options.axisColor,
                strokeWidth: that.options.axisWidth
            }));
            var x = that.measure.yLabelWidth + that.options.labelMargin
                + that.options.axisWidth + that.options.plotPadding
                + that.options.maxPieRadius;
            var y = that.measure.plotHeight + that.options.axisWidth
                + that.options.labelMargin;
            for (var h = 0; h < 24; h++) {
                var text = that.createText((h < 10) ? "0" + h : h,
                    x, y, that.options.axisLabelColor);
                text.setOffset({
                    x: text.getWidth() / 2
                });
                that.axes.add(text);
                x += that.options.maxPieRadius * 2;
            }
        },

        createYAxis: function() {
            var that = this;
            that.axes.add(new Kinetic.Line({
                points:      [
                    that.measure.yLabelWidth + that.options.labelMargin
                        + that.options.axisWidth / 2,
                    0,
                    that.measure.yLabelWidth + that.options.labelMargin
                        + that.options.axisWidth / 2,
                    that.measure.plotHeight + that.options.axisWidth
                ],
                stroke:      that.options.axisColor,
                strokeWidth: that.options.axisWidth
            }));
            var x = that.measure.yLabelWidth;
            var y = that.options.plotPadding + that.options.maxPieRadius
                - that.measure.labelHeight / 2;
            for (var d = 0; d < 7; d++) {
                var text = that.createText(that.locale.dayNames[d],
                    x, y, that.options.axisLabelColor);
                text.setOffset({
                    x: text.getWidth()
                });
                that.axes.add(text);
                y += that.options.maxPieRadius * 2;
            }
        },

        calculateTotals: function() {
            var that = this;
            that.totals = [];
            for (var d = 0; d < 7; d++) {
                var dayTotals = [];
                for (var h = 0; h < 24; h++) {
                    dayTotals[h] = 0;
                    $.each(that.data, function(user, perDay) {
                        if (perDay[d] && perDay[d][h]) {
                            dayTotals[h] += perDay[d][h];
                        }
                    });
                }
                that.totals[d] = dayTotals;
            }
        },

        determineMaximum: function() {
            var that = this;
            that.maximum = 0;
            for (var d = 0; d < 7; d++) {
                for (var h = 0; h < 24; h++) {
                    if (that.totals[d] && that.totals[d][h]) {
                        that.maximum = Math.max(that.maximum, that.totals[d][h]);
                    }
                }
            }
        },

        setUserColors: function() {
            var that = this;
            that.userColors = {};
            var i = 0;
            var numPieColors = that.options.pieColors.length;
            $.each(that.users, function(idx, user) {
                that.userColors[user] = that.options.userColors[user]
                    || that.options.pieColors[i++ % numPieColors];
            });
        },

        calculateMeasurements: function() {
            var that = this;
            var yLabelWidth = 0;
            for (var d = 0; d < 7; d++) {
                var text = that.createText(that.locale.dayNames[d], 0, 0, "black");
                yLabelWidth = Math.max(yLabelWidth, text.getWidth());
            }
            var labelHeight = that.createText("X", 0, 0, "black").getHeight();

            var plotWidth = that.options.plotPadding
                + that.options.maxPieRadius * 2 * 24 + that.options.plotPadding;
            var plotHeight = that.options.plotPadding
                + that.options.maxPieRadius * 2 * 7 + that.options.plotPadding;
            var width = yLabelWidth + that.options.labelMargin
                + that.options.axisWidth + plotWidth;
            var height = plotHeight + that.options.axisWidth
                + that.options.labelMargin + labelHeight;

            that.measure = {
                width:       width,
                height:      height,
                plotWidth:   plotWidth,
                plotHeight:  plotHeight,
                yLabelWidth: yLabelWidth,
                labelHeight: labelHeight
            };
        },

        createText: function(text, x, y, color) {
            var that = this;
            return new Kinetic.Text({
                text:       text,
                fontFamily: that.options.fontFamily,
                fontSize:   that.options.fontSize,
                fill:       color,
                x:          x,
                y:          y
            });
        }
    }
);
<|endoftext|>


<commit_before>define(["util", "guiders", "jquery", "ui"], function (util, guiders, $, ui) {
  var assert = util.assert;
  var walkthrough = util.Module("walkthrough");

  // FIXME: not sure I should do this so aggressively.
  var link = $('<link rel="stylesheet">').attr("href", TowTruck.baseUrl + "/towtruck/libs/Guider-JS/guiders-1.3.0.css");
  $("head").append(link);

  // These are options that are added to the individual guides if the guides don't
  // have these options themselves:
  var defaultGuideOptions = {
    buttons:
      [{
       name: "Back",
       classString: "towtruck-walkthru-back-button"
       },
       {
         name: "Get started",
         classString: "towtruck-walkthru-getstarted-button",
         onclick: guiders.hideAll
        },
      {
       name: "Next",
       classString: "towtruck-walkthru-next-button"
       }],

    // buttons: [{name: "Get started", onclick: guiders.hideAll},{name: "Back"}, {name: "Next"}],
    // This is assigned to the first item.buttons in the guide:
    firstButtons:
      [{
        name: "Get started",
        classString: "towtruck-walkthru-getstarted-button",
        onclick: guiders.hideAll
       },
      {
       name: "Next",
       classString: "towtruck-walkthru-next-button"
       }],
    // This is assigned to the last item.buttons in the guide:
    lastButtons:
      [{
        name: "Get started",
        classString: "towtruck-walkthru-getstarted-button",
        onclick: guiders.hideAll
       }],
    position: 9,
	  overlay: true,
	  width:400,
    closeOnEscape: true,
    onHide: hideWindow,
    xButton: true
  };

  function showSettings(){
    ui.displayWindow('#towtruck-about');
  }
  function hideWindow(){
    ui.hideWindow();
  }

  // See here for information about the options for Guiders:
  //   https://github.com/jeff-optimizely/Guiders-JS
  var guide = [
    {
      overlay: true,
      title: "Welcome to TowTruck!",
      description: "
\
                    \
                    \

\

TowTruck is a service for your website that makes it easy to collaborate in real-time.
",
	    onHide: hideWindow
    },
    {
      overlay: true,
      attachTo: "#towtruck-about-button",
      title: "Connect with friends",
      description: "
Click here to start your TowTruck session.  Just copy and paste the TowTruck link, and send it to your friend!

lorem ipsum

lorem ipsum

lorem ipsum
"
    },
    {
      overlay: true,
      attachTo: "#towtruck-audio-button",
      title: "Talk with friends",
      description: "If your browser supports it, you can audio chat live with your friend over the browser just like magic!"
    },
    {
      overlay: true,
      attachTo: "#towtruck-chat-button",
      onHide: hideWindow,
      title: "Chat with friends",
      description: "You know how this works :)"
    },
    {
      overlay: true,
      attachTo: "#towtruck-anchor",
      title: "Move the dock",
      description: "Grab here to move the dock to the right or left side of the browser."
    },
    {
      overlay: true,
      attachTo: "#towtruck-interface",
      title: "Start TowTruck!",
      description: "Alright, you're ready to use TowTruck! Now get collaboratin :)"
    }
  ];

  var builtGuiders = null;

  var idCount = 1;

  walkthrough.start = function () {
    if (! builtGuiders) {
      builtGuiders = [];
      guide.forEach(function (item) {
        if (! item.id) {
          item.id = "help-" + (idCount++);
        }
      });
      guide.forEach(function (item, index) {
        var options = util.extend(util.extend(defaultGuideOptions), item);
        if (options.next === undefined && guide[index+1]) {
          options.next = guide[index+1].id;
        }
        if (index === 0 && options.buttons === defaultGuideOptions.buttons) {
          options.buttons = options.firstButtons;
        }
        if (index === guide.length-1 && options.buttons === defaultGuideOptions.buttons) {
          options.buttons = options.lastButtons;
        }
        console.log("creating", JSON.stringify(options, null, "  "));
        guiders.createGuider(options);
      });
    }
    console.log("starting", builtGuiders[0]);
    guiders.show("help-1");
  };

  return walkthrough;
});
<commit_msg>Clean up a little whitespace and string formatting.  And the all important apostrophe on collaboratin'.<commit_after>define(["util", "guiders", "jquery", "ui"], function (util, guiders, $, ui) {
  var assert = util.assert;
  var walkthrough = util.Module("walkthrough");

  // FIXME: not sure I should do this so aggressively.
  var link = $('<link rel="stylesheet">').attr("href", TowTruck.baseUrl + "/towtruck/libs/Guider-JS/guiders-1.3.0.css");
  $("head").append(link);

  // These are options that are added to the individual guides if the guides don't
  // have these options themselves:
  var defaultGuideOptions = {
    buttons:
      [{
       name: "Back",
       classString: "towtruck-walkthru-back-button"
       },
       {
         name: "Get started",
         classString: "towtruck-walkthru-getstarted-button",
         onclick: guiders.hideAll
        },
      {
       name: "Next",
       classString: "towtruck-walkthru-next-button"
       }],

    // buttons: [{name: "Get started", onclick: guiders.hideAll},{name: "Back"}, {name: "Next"}],
    // This is assigned to the first item.buttons in the guide:
    firstButtons:
      [{
        name: "Get started",
        classString: "towtruck-walkthru-getstarted-button",
        onclick: guiders.hideAll
       },
      {
       name: "Next",
       classString: "towtruck-walkthru-next-button"
       }],
    // This is assigned to the last item.buttons in the guide:
    lastButtons:
      [{
        name: "Get started",
        classString: "towtruck-walkthru-getstarted-button",
        onclick: guiders.hideAll
       }],
    position: 9,
    overlay: true,
    width:400,
    closeOnEscape: true,
    onHide: hideWindow,
    xButton: true
  };

  function showSettings(){
    ui.displayWindow('#towtruck-about');
  }
  function hideWindow(){
    ui.hideWindow();
  }

  // See here for information about the options for Guiders:
  //   https://github.com/jeff-optimizely/Guiders-JS
  var guide = [
    {
      overlay: true,
      title: "Welcome to TowTruck!",
      description: (
        "
\n" +
            "" +
            "" +
            "
\n" +
			"
TowTruck is a service for your website that makes it easy to collaborate in real-time.
"
        ),
      onHide: hideWindow
    },
    {
      overlay: true,
      attachTo: "#towtruck-about-button",
      title: "Connect with friends",
      description: "
Click here to start your TowTruck session.  Just copy and paste the TowTruck link, and send it to your friend!

lorem ipsum

lorem ipsum

lorem ipsum
"
    },
    {
      overlay: true,
      attachTo: "#towtruck-audio-button",
      title: "Talk with friends",
      description: "If your browser supports it, you can audio chat live with your friend over the browser just like magic!"
    },
    {
      overlay: true,
      attachTo: "#towtruck-chat-button",
      onHide: hideWindow,
      title: "Chat with friends",
      description: "You know how this works :)"
    },
    {
      overlay: true,
      attachTo: "#towtruck-anchor",
      title: "Move the dock",
      description: "Grab here to move the dock to the right or left side of the browser."
    },
    {
      overlay: true,
      attachTo: "#towtruck-interface",
      title: "Start TowTruck!",
      description: "Alright, you're ready to use TowTruck! Now get collaboratin' :)"
    }
  ];

  var builtGuiders = null;

  var idCount = 1;

  walkthrough.start = function () {
    if (! builtGuiders) {
      builtGuiders = [];
      guide.forEach(function (item) {
        if (! item.id) {
          item.id = "help-" + (idCount++);
        }
      });
      guide.forEach(function (item, index) {
        var options = util.extend(util.extend(defaultGuideOptions), item);
        if (options.next === undefined && guide[index+1]) {
          options.next = guide[index+1].id;
        }
        if (index === 0 && options.buttons === defaultGuideOptions.buttons) {
          options.buttons = options.firstButtons;
        }
        if (index === guide.length-1 && options.buttons === defaultGuideOptions.buttons) {
          options.buttons = options.lastButtons;
        }
        console.log("creating", JSON.stringify(options, null, "  "));
        guiders.createGuider(options);
      });
    }
    console.log("starting", builtGuiders[0]);
    guiders.show("help-1");
  };

  return walkthrough;
});
<|endoftext|>


<commit_before>'use strict';

//
// Implements input/output for text files.
//

var fs = require('fs');
var assert = require('chai').assert;

module.exports = function (filePath) {
	assert.isString(filePath, "Expected 'filePath' parameter to 'file data source' to be a string.");

	return {

		//
		// Async read from a text file.
		//
		read: function () {

			return new Promise(function (resolve, reject) {
				fs.readFile(filePath, 'utf-8', function (err, fileData) {
					if (err) {
						reject(err);
						return;
					}

					resolve(fileData);
				});
			});
		},

		//
		// Async write to a text file.
		//
		write: function (fileData) {
			assert.isString(fileData, "Expected 'fileData' parameter to 'file.write' to be a string.");

			return new Promise(function (resolve, reject) {
				fs.writeFile(filePath, fileData, function (err) {
					if (err) {
						reject(err);
					}
					else {
						resolve();
					}
				});
			});
		},

		//
		// Sync read from a text file.
		//
		readSync: function () {
			return fs.readFileSync(filePath, 'utf-8');
		},

		//
		// Sync write to a text file.
		//
		writeSync: function (fileData) {
			fs.writeFileSync(filePath, fileData);
		},
	};
};

<commit_msg>Deleted the file data source plugin. I'm removing the need to care about sync/async from data forge.<commit_after><|endoftext|>


<commit_before>(function() {
	var opt = GoogleElectionMapOptions = {
		primary: true,
		state: 'mi',
		//party: 'democrat',
		//party: 'republican',
		baseUrl: 'http://gmaps-samples.googlecode.com/svn/trunk/',
		_: null
	};
	var time = (new Date).getTime();
	var base = opt.baseUrl + 'elections/2008/primary/';
	document.write( [
		'<script type="text/javascript" src="', base, 'states/', opt.state, '/data.js?t=', time, '">',
		'<\/script>',
		'<script type="text/javascript" src="', base, 'map.js?t=', time, '">',
		'<\/script>'
	].join('') );
})();
<commit_msg>Switch to Florida<commit_after>(function() {
	var opt = GoogleElectionMapOptions = {
		primary: true,
		state: 'fl',
		//party: 'democrat',
		//party: 'republican',
		baseUrl: 'http://gmaps-samples.googlecode.com/svn/trunk/',
		_: null
	};
	var time = (new Date).getTime();
	var base = opt.baseUrl + 'elections/2008/primary/';
	document.write( [
		'<script type="text/javascript" src="', base, 'states/', opt.state, '/data.js?t=', time, '">',
		'<\/script>',
		'<script type="text/javascript" src="', base, 'map.js?t=', time, '">',
		'<\/script>'
	].join('') );
})();
<|endoftext|>


<commit_before>var parse = require('./parse');

module.exports = function(scope, path) {
  var id = 0;
  var keys = parse(path);
  var total = keys.length;
  while ((scope = scope[keys[id++]]) && id < total) {/*!*/}
  return id < total ? undefined : scope;
};
<commit_msg>style: nomenclature<commit_after>var parse = require('./parse');

module.exports = function(scope, notation) {
  var id = 0;
  var keys = parse(notation);
  var total = keys.length;
  while ((scope = scope[keys[id++]]) && id < total) {/*!*/}
  return id < total ? undefined : scope;
};
<|endoftext|>


<commit_before>const path = require('path');
const defaultResolver = require('react-docgen').resolver
  .findAllExportedComponentDefinitions;
const annotationResolver = require('react-docgen-annotation-resolver').default;
const { readdirSync, lstatSync, existsSync } = require('fs');

const isDirectory = s => lstatSync(s).isDirectory();
const isFile = s => lstatSync(s).isFile();
const getDirectories = s =>
  readdirSync(s)
    .map(name => path.join(s, name))
    .filter(isDirectory);
const getFiles = s =>
  readdirSync(s)
    .map(name => path.join(s, name))
    .filter(isFile);

const componentSections = p => {
  return getDirectories(p).map(name => {
    const section = {
      name: path.basename(name),
      components: getFiles(name).filter(
        f => path.basename(f) !== 'index.js' && path.extname(f) === '.js',
      ),
    };
    if (existsSync(path.join(name, 'README.md')))
      section.content = path.join(name, 'README.md');
    return section;
  });
};

module.exports = {
  title: 'Bandwidth Shared React Components',
  styleguideDir: 'docsDist',
  pagePerSection: true,
  skipComponentsWithoutExample: true,
  sections: [
    {
      name: 'About',
      sections: [
        {
          name: 'Home',
          content: 'docs/introduction.md',
        },
        {
          name: 'Color',
          content: 'docs/color.md',
        },
        {
          name: 'Typography',
          content: 'docs/typography.md',
        },
        {
          name: 'Layout',
          content: 'docs/layout.md',
        },
      ],
    },
    {
      name: 'Components',
      components: 'src/components/**/[A-Z]*.js',
      // sections: componentSections('./src/components'),
    },
    {
      name: 'Layouts',
      components: 'src/layouts/**/[A-Z]*.js',
      // sections: componentSections('./src/layouts'),
    },
    {
      name: 'Behaviors',
      components: 'src/behaviors/*/[A-Z]*.js',
    },
    {
      name: 'Animations',
      components: 'src/animations/*/[A-Z]*.js',
    },
  ],
  theme: {
    fontSize: {
      base: 14,
    },
    fontFamily: {
      base: '"Overpass", Raleway, "Open Sans", arial, sans-serif',
      monospace: '"Source Code Pro", monospace',
    },
  },
  ignore: ['src/components/**/index.js'],
  require: [
    'styled-components',
    path.join(__dirname, 'src'),
    path.join(__dirname, 'fonts/fonts.css'),
  ],
  styleguideComponents: {
    Logo: path.join(__dirname, 'tools/styleguide/Logo'),
    Wrapper: path.join(__dirname, 'tools/styleguide/Wrapper'),
    ComponentsList: path.join(__dirname, 'tools/styleguide/ComponentsList'),
    TableRenderer: path.join(__dirname, 'tools/styleguide/TableRenderer'),
    StyleGuideRenderer: path.join(
      __dirname,
      'tools/styleguide/StyleGuideRenderer',
    ),
  },
  /**
   * Fix for styled-components; see
   * https://github.com/styled-components/styled-components/issues/945#issuecomment-339209956
   */
  resolver: (ast, recast) => {
    const annotatedComponents = annotationResolver(ast, recast);
    const defaultComponents = defaultResolver(ast, recast);
    return annotatedComponents.concat(defaultComponents);
  },
  webpackConfig: {
    devtool: 'cheap-module-eval-source-map',
    resolve: {
      modules: ['node_modules'].concat(
        process.env.NODE_PATH.split(path.delimiter).filter(Boolean),
      ),
    },
    module: {
      rules: [
        // Babel loader, will use your project’s .babelrc
        {
          test: /\.js?$/,
          exclude: /node_modules/,
          use: {
            loader: 'babel-loader',
          },
        },
        {
          test: /\.css$/,
          use: [
            'style-loader',
            {
              loader: 'css-loader',
              options: {
                modules: true,
                importLoaders: 1,
                localIdentName: 'cat__[local]_[path]',
              },
            },
            'postcss-loader',
          ],
        },
        {
          test: /\.(jpg|jpeg|png|webp|ico)$/,
          use: 'file-loader',
        },
        {
          test: /\.(svg|woff|woff2|eot|otf|ttf)$/,
          use: 'file-loader',
        },
      ],
    },
  },
};
<commit_msg>remove postcss loader to fix styleguidist<commit_after>const path = require('path');
const defaultResolver = require('react-docgen').resolver
  .findAllExportedComponentDefinitions;
const annotationResolver = require('react-docgen-annotation-resolver').default;
const { readdirSync, lstatSync, existsSync } = require('fs');

const isDirectory = s => lstatSync(s).isDirectory();
const isFile = s => lstatSync(s).isFile();
const getDirectories = s =>
  readdirSync(s)
    .map(name => path.join(s, name))
    .filter(isDirectory);
const getFiles = s =>
  readdirSync(s)
    .map(name => path.join(s, name))
    .filter(isFile);

const componentSections = p => {
  return getDirectories(p).map(name => {
    const section = {
      name: path.basename(name),
      components: getFiles(name).filter(
        f => path.basename(f) !== 'index.js' && path.extname(f) === '.js',
      ),
    };
    if (existsSync(path.join(name, 'README.md')))
      section.content = path.join(name, 'README.md');
    return section;
  });
};

module.exports = {
  title: 'Bandwidth Shared React Components',
  styleguideDir: 'docsDist',
  pagePerSection: true,
  skipComponentsWithoutExample: true,
  sections: [
    {
      name: 'About',
      sections: [
        {
          name: 'Home',
          content: 'docs/introduction.md',
        },
        {
          name: 'Color',
          content: 'docs/color.md',
        },
        {
          name: 'Typography',
          content: 'docs/typography.md',
        },
        {
          name: 'Layout',
          content: 'docs/layout.md',
        },
      ],
    },
    {
      name: 'Components',
      components: 'src/components/**/[A-Z]*.js',
      // sections: componentSections('./src/components'),
    },
    {
      name: 'Layouts',
      components: 'src/layouts/**/[A-Z]*.js',
      // sections: componentSections('./src/layouts'),
    },
    {
      name: 'Behaviors',
      components: 'src/behaviors/*/[A-Z]*.js',
    },
    {
      name: 'Animations',
      components: 'src/animations/*/[A-Z]*.js',
    },
  ],
  theme: {
    fontSize: {
      base: 14,
    },
    fontFamily: {
      base: '"Overpass", Raleway, "Open Sans", arial, sans-serif',
      monospace: '"Source Code Pro", monospace',
    },
  },
  ignore: ['src/components/**/index.js'],
  require: [
    'styled-components',
    path.join(__dirname, 'src'),
    path.join(__dirname, 'fonts/fonts.css'),
  ],
  styleguideComponents: {
    Logo: path.join(__dirname, 'tools/styleguide/Logo'),
    Wrapper: path.join(__dirname, 'tools/styleguide/Wrapper'),
    ComponentsList: path.join(__dirname, 'tools/styleguide/ComponentsList'),
    TableRenderer: path.join(__dirname, 'tools/styleguide/TableRenderer'),
    StyleGuideRenderer: path.join(
      __dirname,
      'tools/styleguide/StyleGuideRenderer',
    ),
  },
  /**
   * Fix for styled-components; see
   * https://github.com/styled-components/styled-components/issues/945#issuecomment-339209956
   */
  resolver: (ast, recast) => {
    const annotatedComponents = annotationResolver(ast, recast);
    const defaultComponents = defaultResolver(ast, recast);
    return annotatedComponents.concat(defaultComponents);
  },
  webpackConfig: {
    devtool: 'cheap-module-eval-source-map',
    resolve: {
      modules: ['node_modules'].concat(
        process.env.NODE_PATH.split(path.delimiter).filter(Boolean),
      ),
    },
    module: {
      rules: [
        // Babel loader, will use your project’s .babelrc
        {
          test: /\.js?$/,
          exclude: /node_modules/,
          use: {
            loader: 'babel-loader',
          },
        },
        {
          test: /\.css$/,
          use: [
            'style-loader',
            {
              loader: 'css-loader',
              options: {
                modules: true,
                importLoaders: 1,
                localIdentName: 'cat__[local]_[path]',
              },
            }
          ],
        },
        {
          test: /\.(jpg|jpeg|png|webp|ico)$/,
          use: 'file-loader',
        },
        {
          test: /\.(svg|woff|woff2|eot|otf|ttf)$/,
          use: 'file-loader',
        },
      ],
    },
  },
};
<|endoftext|>


<commit_before>class i18n {
  fallbackLanguage = 'en';
  whiteListLanguages = [];
}

export default i18n;<commit_msg>- refactoring<commit_after><|endoftext|>