<commit_before>
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Author: Bradley Kennedy (bk@co60.ca)
*/

import React from 'react';
import ReactDOM from 'react-dom';

import {Button, Nav, NavItem, MenuItem, NavDropdown, ControlLabel,
FormControl, InputGroup, FormGroup, ButtonToolbar, DropdownButton} from 'react-bootstrap';

import InfoModal from './InfoModal';
import ClientConstants from '../client/ClientConstants';

import PageStore from '../stores/PageStore';
import PageActions from '../actions/PageActions';

var RevisionSetter = React.createClass({
  getInitialState: function() {
    return {revision: PageStore.getRevision(), revision_list: PageStore.getRevisionList()}
  },
  componentDidMount: function() {
    PageStore.addChangeListener(this._onChange, 'query');
  },
  componentWillUnmount: function() {
    PageStore.removeChangeListener(this._onChange, 'query');
  },
  _onChange: function() {
    this.setState({revision: PageStore.getRevision()});
  },
  handleR: function(e) {
    this.setState({revision: e.target.value});
  },
  doSet: function() {
    PageActions.setRevision(this.state.revision);
  },
  renderRevisions: function() {
      var revision_list = [];
      for (var i in this.state.revision_list) {

          var buildDate = new Date(this.state.revision_list[i].build.date * 1000).toISOString();
          var buildRevision = this.state.revision_list[i].build.revision12;
          var buildCount = this.state.revision_list[i].count;

          revision_list.push(
            <option value={buildRevision}>
              {buildDate} | {buildRevision} | {buildCount}
            </option>);
      }
      return revision_list;
  },
  render: function() {
    return (
      <FormGroup>
        <ControlLabel>Revision ID</ControlLabel>
        <InputGroup>
          <FormControl onChange={this.handleR} type="text" placeholder="Revision"
            value={this.state.revision || ""} />
          <InputGroup.Button>
            <Button onClick={this.doSet}>Set</Button>
          </InputGroup.Button>
        </InputGroup>
        <ControlLabel>Select Revision (Last 2 months)</ControlLabel>
        <FormControl onChange={this.handleR} value={this.state.value}  onClick={this.doSet} componentClass="select">
          <option>Select a revision...</option>
            {this.renderRevisions()}
        </FormControl>
      </FormGroup>
    );
  }
});

var NavButton = React.createClass({
  render: function() {
    return (
      <Button onClick={this.props.callback}>

      </Button>
    );
  }
});

var NavOptions = React.createClass({
  getInitialState: function() {
    return {};
  },
  componentDidMount: function() {
    PageStore.addChangeListener(this._onChange);
  },
  componentWillUnmount: function() {
    PageStore.removeChangeListener(this._onChange);
  },
  _onChange: function() {
    this.forceUpdate();
  },
  handleSelect: function(key) {
    return () => {
      PageActions.change(key);
    };
  },
  render: function() {
    var shown = !PageStore.getCollapsed();
    var items = [];
    if (shown) {
      var allItems = PageStore.getAll();
      var dirs = {};
      // Object works well with for each
      for (var key in allItems) {
        if (allItems[key].query.hasOwnProperty('path')) {
          // Has path
          if (!dirs.hasOwnProperty(allItems[key].query.path)) {
            dirs[allItems[key].query.path] = [];
          }
          dirs[allItems[key].query.path].push(
            <MenuItem onSelect={this.handleSelect(key)} key={key}>
              {allItems[key].query.filter_revision && "R* "}
              {allItems[key].query.drills_down && "D* "}
              {allItems[key].title}
            </MenuItem>
          );

        } else {
          // Root
          items.push(
            <NavItem
            onSelect={this.handleSelect(key)}
            key={key}>
              {allItems[key].query.filter_revision && "R* "}
              {allItems[key].query.drills_down && "D* "}
              {allItems[key].title}
            </NavItem>
          );
        }
      }
      Object.keys(dirs).forEach((key) => {
        items.push(<NavDropdown id={key} key={key} title={key}>{dirs[key]}</NavDropdown>);
      });
    }
    return (

        {items}

    );
  }
});

var PropertyViewer = React.createClass({
  getInitialState: function() {
    return {"hidden": true};
  },
  componentWillMount: function() {
    PageStore.addChangeListener(this._onChange, 'drill');
    this._onChange();
  },
  componentWillUnmount: function() {
    PageStore.removeChangeListener(this._onChange, 'drill');
  },
  _onChange: function() {
    var ctx = PageStore.getContext();
    if (ctx) {
      this.setState({hidden: false, value: ctx});
    } else {
      this.setState({hidden: true});
    }
  },
  upLevel: function() {
    PageActions.setSelected("");
    PageActions.setContext(PageStore.getQuery().drillUp(PageStore.getContext()));
    PageStore.emitChange('query');
  },
  render: function() {
    if (this.state.hidden) return (

);
    return (
      <FormGroup>
      <ControlLabel>{this.props.header}</ControlLabel>
      <InputGroup>
        <FormControl type="text" value={this.state.value}
        placeholder="Context" disabled />
        <InputGroup.Button>
          <Button onClick={this.upLevel}>Drill Up</Button>
        </InputGroup.Button>
      </InputGroup>
      </FormGroup>
    );
  }
});

var Sidebar = React.createClass({
  getInitialState: function() {
        return {"collapsed": false, "opening": false};
  },
  componentWillMount: function() {
    PageStore.addChangeListener(this._onChange);
    PageStore.addChangeListener(this._onChange, 'query');
    // Seed the Sidebar with queries

    ClientConstants.forEach((q) => {
      PageActions.create(q.name, q.obj);
    });
  },
  componentWillUnmount: function() {
    PageStore.removeChangeListener(this._onChange);
    PageStore.removeChangeListener(this._onChange, 'query');
  },
  _onChange: function() {
    var pscollapsed = PageStore.getCollapsed();
    if (this.state.collapsed && !pscollapsed) {
      this.setState({"collapsed": pscollapsed, "opening": true});

      setTimeout(() => {
        this.setState({"opening": false});
      }, 500);
   } else {
    this.setState({"collapsed": pscollapsed});
   }
  },
  render: function() {
    var classnametxt = "sidebar";
    var imgico = ;
    var banner =

          Coco made with ♥ by the Code Coverage team

;

    var contextview = <PropertyViewer header={'Context'} />;

    // This creates the animation
    if (this.state.collapsed) {
      classnametxt += " collapsed";
    }
    var displayChildren = true;
    if (this.state.collapsed || this.state.opening) {
      displayChildren = false;
    }
    return (

          <NavButton callback={function() {
            PageActions.toggleSidebar();
          }}/>
          {displayChildren && imgico}

        {displayChildren &&

          {this.props.children}
          {contextview}
          {PageStore.getQuery().filter_revision}
          <RevisionSetter />
          <InfoModal/>

        }
        {displayChildren && banner}

    );
  }
});

export {Sidebar, NavOptions};
<commit_msg>Implemented onChange action for the revision list selctor<commit_after>
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Author: Bradley Kennedy (bk@co60.ca)
*/

import React from 'react';
import ReactDOM from 'react-dom';

import {Button, Nav, NavItem, MenuItem, NavDropdown, ControlLabel,
FormControl, InputGroup, FormGroup, ButtonToolbar, DropdownButton} from 'react-bootstrap';

import InfoModal from './InfoModal';
import ClientConstants from '../client/ClientConstants';

import PageStore from '../stores/PageStore';
import PageActions from '../actions/PageActions';

var RevisionSetter = React.createClass({
  getInitialState: function() {
    return {revision: PageStore.getRevision(), revision_list: PageStore.getRevisionList()}
  },
  componentDidMount: function() {
    PageStore.addChangeListener(this._onChange, 'query');
  },
  componentWillUnmount: function() {
    PageStore.removeChangeListener(this._onChange, 'query');
  },
  _onChange: function() {
    this.setState({revision: PageStore.getRevision()});
  },
  handleR: function(e) {
    this.setState({revision: e.target.value});
    PageActions.setRevision(e.target.value);
  },
  doSet: function() {
    PageActions.setRevision(this.state.revision);
  },
  doSetByRevisionList: function (e) {
      this.setState({revision: e.target.value});
      PageActions.setRevision(e.target.value);
  },
  renderRevisions: function() {
      var revision_list = [];
      for (var i in this.state.revision_list) {
          var buildDate = new Date(this.state.revision_list[i].build.date * 1000).toISOString();
          var buildRevision = this.state.revision_list[i].build.revision12;
          var buildCount = this.state.revision_list[i].count;
          revision_list.push(
            <option value={buildRevision}>
              {buildDate} | {buildRevision} | {buildCount}
            </option>);
      }
      return revision_list;
  },
  render: function() {
    return (
      <FormGroup>
        <ControlLabel>Revision ID</ControlLabel>
        <InputGroup>
          <FormControl onChange={this.handleR} type="text" placeholder="Revision"
            value={this.state.revision || ""} />
          <InputGroup.Button>
            <Button onClick={this.doSet}>Set</Button>
          </InputGroup.Button>
        </InputGroup>

        <ControlLabel>Select Revision (Last 2 months)</ControlLabel>
        <FormControl onChange={this.doSetByRevisionList} value={this.state.value} componentClass="select">
          <option selected="selected" disabled>Select a revision...</option>
          {this.renderRevisions()}
        </FormControl>
      </FormGroup>
    );
  }
});

var NavButton = React.createClass({
  render: function() {
    return (
      <Button onClick={this.props.callback}>

      </Button>
    );
  }
});

var NavOptions = React.createClass({
  getInitialState: function() {
    return {};
  },
  componentDidMount: function() {
    PageStore.addChangeListener(this._onChange);
  },
  componentWillUnmount: function() {
    PageStore.removeChangeListener(this._onChange);
  },
  _onChange: function() {
    this.forceUpdate();
  },
  handleSelect: function(key) {
    return () => {
      PageActions.change(key);
    };
  },
  render: function() {
    var shown = !PageStore.getCollapsed();
    var items = [];
    if (shown) {
      var allItems = PageStore.getAll();
      var dirs = {};
      // Object works well with for each
      for (var key in allItems) {
        if (allItems[key].query.hasOwnProperty('path')) {
          // Has path
          if (!dirs.hasOwnProperty(allItems[key].query.path)) {
            dirs[allItems[key].query.path] = [];
          }
          dirs[allItems[key].query.path].push(
            <MenuItem onSelect={this.handleSelect(key)} key={key}>
              {allItems[key].query.filter_revision && "R* "}
              {allItems[key].query.drills_down && "D* "}
              {allItems[key].title}
            </MenuItem>
          );

        } else {
          // Root
          items.push(
            <NavItem
            onSelect={this.handleSelect(key)}
            key={key}>
              {allItems[key].query.filter_revision && "R* "}
              {allItems[key].query.drills_down && "D* "}
              {allItems[key].title}
            </NavItem>
          );
        }
      }
      Object.keys(dirs).forEach((key) => {
        items.push(<NavDropdown id={key} key={key} title={key}>{dirs[key]}</NavDropdown>);
      });
    }
    return (

        {items}

    );
  }
});

var PropertyViewer = React.createClass({
  getInitialState: function() {
    return {"hidden": true};
  },
  componentWillMount: function() {
    PageStore.addChangeListener(this._onChange, 'drill');
    this._onChange();
  },
  componentWillUnmount: function() {
    PageStore.removeChangeListener(this._onChange, 'drill');
  },
  _onChange: function() {
    var ctx = PageStore.getContext();
    if (ctx) {
      this.setState({hidden: false, value: ctx});
    } else {
      this.setState({hidden: true});
    }
  },
  upLevel: function() {
    PageActions.setSelected("");
    PageActions.setContext(PageStore.getQuery().drillUp(PageStore.getContext()));
    PageStore.emitChange('query');
  },
  render: function() {
    if (this.state.hidden) return (

);
    return (
      <FormGroup>
      <ControlLabel>{this.props.header}</ControlLabel>
      <InputGroup>
        <FormControl type="text" value={this.state.value}
        placeholder="Context" disabled />
        <InputGroup.Button>
          <Button onClick={this.upLevel}>Drill Up</Button>
        </InputGroup.Button>
      </InputGroup>
      </FormGroup>
    );
  }
});

var Sidebar = React.createClass({
  getInitialState: function() {
        return {"collapsed": false, "opening": false};
  },
  componentWillMount: function() {
    PageStore.addChangeListener(this._onChange);
    PageStore.addChangeListener(this._onChange, 'query');
    // Seed the Sidebar with queries

    ClientConstants.forEach((q) => {
      PageActions.create(q.name, q.obj);
    });
  },
  componentWillUnmount: function() {
    PageStore.removeChangeListener(this._onChange);
    PageStore.removeChangeListener(this._onChange, 'query');
  },
  _onChange: function() {
    var pscollapsed = PageStore.getCollapsed();
    if (this.state.collapsed && !pscollapsed) {
      this.setState({"collapsed": pscollapsed, "opening": true});

      setTimeout(() => {
        this.setState({"opening": false});
      }, 500);
   } else {
    this.setState({"collapsed": pscollapsed});
   }
  },
  render: function() {
    var classnametxt = "sidebar";
    var imgico = ;
    var banner =

          Coco made with ♥ by the Code Coverage team

;

    var contextview = <PropertyViewer header={'Context'} />;

    // This creates the animation
    if (this.state.collapsed) {
      classnametxt += " collapsed";
    }
    var displayChildren = true;
    if (this.state.collapsed || this.state.opening) {
      displayChildren = false;
    }
    return (

          <NavButton callback={function() {
            PageActions.toggleSidebar();
          }}/>
          {displayChildren && imgico}

        {displayChildren &&

          {this.props.children}
          {contextview}
          {PageStore.getQuery().filter_revision}
          <RevisionSetter />
          <InfoModal/>

        }
        {displayChildren && banner}

    );
  }
});

export {Sidebar, NavOptions};
<|endoftext|>


<commit_before>/* eslint react/jsx-sort-props: 0 */

import {
    IconButton,
    Paper,
    SvgIcon,
    Styles,
} from 'material-ui';
import React, { PropTypes } from 'react';
import { Line, Rect, Circle, Ellipse, Measure } from '../components/Shape';
import * as MODE from '../constants/Mode';
import * as SHAPE from '../constants/Shape';

const Style = {
    Toolbar: {
        width: '100%',
        display: 'flex',
        alignItems: 'center',
        overflow: 'hidden',
        overflowX: 'auto',
        WebkitOverflowScrolling: 'touch',
    },
    Group: {
        flex: '0 1 auto',
        display: 'flex',
        alignItems: 'center',
    },
    Separator: {
        flex: '0 0 1px',
        height: 24,
        backgroundColor: Styles.Colors.grey600,
        margin: '0 2px',
    },
    SelectedColor: Styles.Colors.pink500,
    Button: {
        flex: '0 0 48px',
        width: 48,
    },
};

const ModeButton = ({name, mode, icon, setMode}) => (
    <IconButton
        iconClassName="material-icons"
        iconStyle={{
            color: name === mode
                ? Style.SelectedColor
                : null,
        }}
        style={Style.Button}
        onTouchTap={() => setMode(name)}
    >
        {icon}
    </IconButton>
);
ModeButton.propTypes = {
    icon: PropTypes.string.isRequired,
    mode: PropTypes.string.isRequired,
    name: PropTypes.string.isRequired,
    setMode: PropTypes.func.isRequired,
};

const ShapeButton = ({
    name,
    shape,
    fill,
    stroke,
    icon,
    children,
    setShape,
}) => {
    if (icon) {
        const style = name === shape
            ? {
                color: fill === 'none' ? stroke : fill,
            } : {
                color: Styles.Colors.grey300,
            };

        return (
            <IconButton
                iconClassName="material-icons"
                iconStyle={style}
                style={Style.Button}
                onTouchTap={() => setShape(name)}
            >
                {icon}
            </IconButton>
        );
    }

    const svgStyle = name === shape
        ? {
            stroke,
            fill,
        } : {
            stroke: Styles.Colors.grey300,
            fill: 'none',
        };

    return (
        <IconButton style={Style.Button} onTouchTap={() => setShape(name)}>
            <SvgIcon>
                <g style={svgStyle}>
                    {children}
                </g>
            </SvgIcon>
        </IconButton>
    );
};
ShapeButton.propTypes = {
    mode: PropTypes.string.isRequired,
    name: PropTypes.string.isRequired,
    setMode: PropTypes.func.isRequired,
    setShape: PropTypes.func.isRequired,
    shape: PropTypes.string.isRequired,
    children: PropTypes.element,
    fill: PropTypes.string,
    icon: PropTypes.string,
    stroke: PropTypes.string,
};

export const Toolbar = (props) => {
    const {
        mode,
        shape,
        fill,
        stroke,
        snap,
        open,
        setMode,
        setShape,
        setSnap,
    } = props;
    const menuProps = {
        mode,
        setMode,
    };
    const shapeProps = {
        shape,
        fill,
        stroke,
        setShape,
    };

    return (
        <Paper style={Style.Toolbar}>
            <ModeButton
                {...menuProps}
                name={MODE.MOVE}
                icon="open_with"
            />
            <ModeButton
                {...menuProps}
                name={MODE.EDIT}
                icon="editor"
            />
            <ModeButton
                {...menuProps}
                name={MODE.ERASE}
                icon="delete"
            />

            <IconButton
                iconClassName="material-icons"
                iconStyle={{
                    color: snap ? null : Styles.Colors.grey300,
                }}
                style={Style.Button}
                onTouchTap={() => setSnap(!snap)}
            >
                grid_on
            </IconButton>
            {mode === MODE.EDIT ? (

                    <ShapeButton
                        {...shapeProps}
                        name={SHAPE.PIECE}
                        icon="place"
                    />
                    <ShapeButton
                        {...shapeProps}
                        name={SHAPE.LINE}
                    >
                        <Line
                            x1={24} x2={0}
                            y1={0} y2={24}
                        />
                    </ShapeButton>
                    <ShapeButton
                        {...shapeProps}
                        name={SHAPE.RECT}
                    >
                        <Rect
                            x={0} y={0}
                            width={24} height={24}
                        />
                    </ShapeButton>
                    <ShapeButton
                        {...shapeProps}
                        name={SHAPE.CIRCLE}
                    >
                        <Circle cx={12} cy={12} r={11} />
                    </ShapeButton>
                    <ShapeButton
                        {...shapeProps}
                        name={SHAPE.ELLIPSE}
                    >
                        <Ellipse
                            cx={12} cy={12}
                            rx={11} ry={6}
                        />
                    </ShapeButton>
                    <ShapeButton
                        {...shapeProps}
                        icon="text_fields"
                        name={SHAPE.TEXT}
                    />
                    <ShapeButton
                        {...shapeProps}
                        name={SHAPE.MEASURE}
                    >
                        <Measure
                            fill={
                                shape === SHAPE.MEASURE
                                ? fill
                                : Styles.Colors.grey300
                            }
                            fontSize={10}
                            gridSize={24}
                            stroke={
                                shape === SHAPE.MEASURE
                                ? stroke
                                : Styles.Colors.grey300
                            }
                            x1={0} x2={24}
                            y1={24} y2={0}
                        />
                    </ShapeButton>

                    <IconButton
                        iconClassName="material-icons"
                        onTouchTap={() => open('editStyle')}
                    >
                        color_lens
                    </IconButton>

            ) : null}
        </Paper>
    );
};
Toolbar.propTypes = {
    open: PropTypes.func.isRequired,
    setMode: PropTypes.func.isRequired,
    setShape: PropTypes.func.isRequired,
    setSnap: PropTypes.func.isRequired,
    fill: PropTypes.string,
    mode: PropTypes.string,
    shape: PropTypes.string,
    snap: PropTypes.bool,
    stroke: PropTypes.string,
};<commit_msg>Fix toolbar style<commit_after>/* eslint react/jsx-sort-props: 0 */

import {
    IconButton,
    Paper,
    SvgIcon,
    Styles,
} from 'material-ui';
import React, { PropTypes } from 'react';
import { Line, Rect, Circle, Ellipse, Measure } from '../components/Shape';
import * as MODE from '../constants/Mode';
import * as SHAPE from '../constants/Shape';

const Style = {
    Toolbar: {
        width: '100%',
        display: 'flex',
        alignItems: 'center',
        overflow: 'hidden',
        overflowX: 'auto',
        WebkitOverflowScrolling: 'touch',
    },
    Group: {
        flex: '0 1 auto',
        display: 'flex',
        alignItems: 'center',
    },
    Separator: {
        flex: '0 0 1px',
        height: 24,
        backgroundColor: Styles.Colors.grey600,
        margin: '0 2px',
    },
    SelectedColor: Styles.Colors.pink500,
    Button: {
        flex: '0 0 auto',
        width: 48,
    },
};

const ModeButton = ({name, mode, icon, setMode}) => (
    <IconButton
        iconClassName="material-icons"
        iconStyle={{
            color: name === mode
                ? Style.SelectedColor
                : null,
        }}
        style={Style.Button}
        onTouchTap={() => setMode(name)}
    >
        {icon}
    </IconButton>
);
ModeButton.propTypes = {
    icon: PropTypes.string.isRequired,
    mode: PropTypes.string.isRequired,
    name: PropTypes.string.isRequired,
    setMode: PropTypes.func.isRequired,
};

const ShapeButton = ({
    name,
    shape,
    fill,
    stroke,
    icon,
    children,
    setShape,
}) => {
    if (icon) {
        const style = name === shape
            ? {
                color: fill === 'none' ? stroke : fill,
            } : {
                color: Styles.Colors.grey300,
            };

        return (
            <IconButton
                iconClassName="material-icons"
                iconStyle={style}
                style={Style.Button}
                onTouchTap={() => setShape(name)}
            >
                {icon}
            </IconButton>
        );
    }

    const svgStyle = name === shape
        ? {
            stroke,
            fill,
        } : {
            stroke: Styles.Colors.grey300,
            fill: 'none',
        };

    return (
        <IconButton style={Style.Button} onTouchTap={() => setShape(name)}>
            <SvgIcon>
                <g style={svgStyle}>
                    {children}
                </g>
            </SvgIcon>
        </IconButton>
    );
};
ShapeButton.propTypes = {
    mode: PropTypes.string.isRequired,
    name: PropTypes.string.isRequired,
    setMode: PropTypes.func.isRequired,
    setShape: PropTypes.func.isRequired,
    shape: PropTypes.string.isRequired,
    children: PropTypes.element,
    fill: PropTypes.string,
    icon: PropTypes.string,
    stroke: PropTypes.string,
};

export const Toolbar = (props) => {
    const {
        mode,
        shape,
        fill,
        stroke,
        snap,
        open,
        setMode,
        setShape,
        setSnap,
    } = props;
    const menuProps = {
        mode,
        setMode,
    };
    const shapeProps = {
        shape,
        fill,
        stroke,
        setShape,
    };

    return (
        <Paper style={Style.Toolbar}>
            <ModeButton
                {...menuProps}
                name={MODE.MOVE}
                icon="open_with"
            />
            <ModeButton
                {...menuProps}
                name={MODE.EDIT}
                icon="editor"
            />
            <ModeButton
                {...menuProps}
                name={MODE.ERASE}
                icon="delete"
            />

            <IconButton
                iconClassName="material-icons"
                iconStyle={{
                    color: snap ? null : Styles.Colors.grey300,
                }}
                style={Style.Button}
                onTouchTap={() => setSnap(!snap)}
            >
                grid_on
            </IconButton>
            {mode === MODE.EDIT ? (

                    <ShapeButton
                        {...shapeProps}
                        name={SHAPE.PIECE}
                        icon="place"
                    />
                    <ShapeButton
                        {...shapeProps}
                        name={SHAPE.LINE}
                    >
                        <Line
                            x1={24} x2={0}
                            y1={0} y2={24}
                        />
                    </ShapeButton>
                    <ShapeButton
                        {...shapeProps}
                        name={SHAPE.RECT}
                    >
                        <Rect
                            x={0} y={0}
                            width={24} height={24}
                        />
                    </ShapeButton>
                    <ShapeButton
                        {...shapeProps}
                        name={SHAPE.CIRCLE}
                    >
                        <Circle cx={12} cy={12} r={11} />
                    </ShapeButton>
                    <ShapeButton
                        {...shapeProps}
                        name={SHAPE.ELLIPSE}
                    >
                        <Ellipse
                            cx={12} cy={12}
                            rx={11} ry={6}
                        />
                    </ShapeButton>
                    <ShapeButton
                        {...shapeProps}
                        icon="text_fields"
                        name={SHAPE.TEXT}
                    />
                    <ShapeButton
                        {...shapeProps}
                        name={SHAPE.MEASURE}
                    >
                        <Measure
                            fill={
                                shape === SHAPE.MEASURE
                                ? fill
                                : Styles.Colors.grey300
                            }
                            fontSize={10}
                            gridSize={24}
                            stroke={
                                shape === SHAPE.MEASURE
                                ? stroke
                                : Styles.Colors.grey300
                            }
                            x1={0} x2={24}
                            y1={24} y2={0}
                        />
                    </ShapeButton>

                    <IconButton
                        iconClassName="material-icons"
                        onTouchTap={() => open('editStyle')}
                    >
                        color_lens
                    </IconButton>

            ) : null}
        </Paper>
    );
};
Toolbar.propTypes = {
    open: PropTypes.func.isRequired,
    setMode: PropTypes.func.isRequired,
    setShape: PropTypes.func.isRequired,
    setSnap: PropTypes.func.isRequired,
    fill: PropTypes.string,
    mode: PropTypes.string,
    shape: PropTypes.string,
    snap: PropTypes.bool,
    stroke: PropTypes.string,
};<|endoftext|>


<commit_before>/* See license.txt for terms of usage */

/**
 * This file defines Breakpoints API for test drivers.
 */

(function() {

// ********************************************************************************************* //
// Breakpoints API

/**
 * Set a breakpoint
 * @param {Object} chrome Firebug chrome object. If null, the default is used.
 * @param {Object} url URL of the target file. If null, the current file is used.
 * @param {Object} lineNo Source line number.
 * @param {Object} attributes Additional breakpoint attributes
 * @param {Object} callback Asynchronous callback is called as soon as the breakpoint is set.
 */
this.setBreakpoint = function(chrome, url, lineNo, attributes, callback)
{
    // FIXME: xxxpedro Test case for Issue 4553 is failing sometimes and it seems
    // to be something inside this FBTest.setBreakpoint() function
    if (!chrome)
        chrome = FW.Firebug.chrome;

    var panel = FBTest.selectPanel("script");
    if (!url)
        url = panel.getObjectLocation(panel.location);

    FBTest.sysout("setBreakpoint; " + url + ", " + lineNo);

    // FIXME: xxxpedro this function seems to be hacky, and could be the source
    // of the problem with the test case for Issue 4553
    FBTest.selectSourceLine(url, lineNo, "js", chrome, function(row)
    {
        var hasBreakpoint = FBTest.hasBreakpoint(lineNo);
        FBTest.ok(!hasBreakpoint, "There must not be a breakpoint at line: " + lineNo);

        FBTest.sysout("setBreakpoint; source line selected", row);

        if (false && attributes && attributes.condition)
        {
            // Right click on the target element.
            var eventDetails = {type: "mousedown", button: 2};
            FBTest.synthesizeMouse(target, 2, 2, eventDetails);

            var editor = panel.panelNode.querySelector(".conditionEditor .completionInput");
            FBTest.ok(editor, "Editor must exist");

            // xxxHonza: TODO
        }
        else
        {
            var config = {tagName: "div", classes: "breakpoint"};
            FBTest.waitForDisplayedElement("script", config, function(element)
            {
                FBTest.sysout("setBreakpoint; breakpoint created");

                // The source view may have been rebuilt, refetch the row.
                var row = FBTest.getSourceLineNode(lineNo, chrome);
                callback(row);
            });

            var target = row.querySelector(".CodeMirror-linenumber");
            FBTest.synthesizeMouse(target, 2, 2);
            target = null;
        }
    });
};

/**
 * Wait till specific breakpoint is set (response from the backend received)
 *
 * @param {String} url URL of the breakpoint we are waiting for.
 * @param {Number} lineNo Line number where the breakpoint should be set.
 * @param {Function} callback Executed when the breakpoint is set.
 */
this.waitForBreakpoint = function(url, lineNo, callback)
{
    var browser = FBTest.getCurrentTabBrowser();

    var listener =
    {
        onBreakpointAdded: function(bp)
        {
            if (bp.lineNo+1 != lineNo || bp.href != url)
                return;

            DebuggerController.removeListener(browser, listener);

            callback();
        }
    };

    DebuggerController.addListener(browser, listener);
}

this.removeBreakpoint = function(chrome, url, lineNo, callback)
{
    if (!callback)
    {
        FBTest.sysout("removeBreakpoint; ERROR missing callback");
        return;
    }

    if (!chrome)
        chrome = FW.Firebug.chrome;

    var panel = FBTestFirebug.selectPanel("script");
    if (!url)
        url = panel.getObjectLocation(panel.location);

    FBTestFirebug.selectSourceLine(url, lineNo, "js", chrome, function(row)
    {
        var hasBreakpoint = FBTest.hasBreakpoint(lineNo);
        FBTest.ok(hasBreakpoint, "There must be a breakpoint at line: " + lineNo);

        var browser = FBTestFirebug.getCurrentTabBrowser();
        DebuggerController.listenOnce(browser, "onBreakpointRemoved", function()
        {
            hasBreakpoint = FBTest.hasBreakpoint(lineNo);
            FBTest.ok(!hasBreakpoint, "Breakpoint must be removed");

            callback();
        });

        // Click to remove a breakpoint.
        var target = row.querySelector(".CodeMirror-linenumber");
        FBTest.synthesizeMouse(target, 2, 2);
    });
};

this.hasBreakpoint = function(line, chrome)
{
    var line = line;
    if (typeof(line) == "number")
        line = FBTest.getSourceLineNode(line, chrome);

    if (!line)
    {
        FBTrace.sysout("hasBreakpoint ERROR undefined line");
        return false;
    }

    var bpNode = line.getElementsByClassName("breakpoint");
    return (bpNode.length > 0);
};

this.waitForDisplayedBreakpoint = function(chrome, url, lineNo, callback)
{
    FBTest.selectSourceLine(url, lineNo, "js", chrome, function(row)
    {
        var config = {tagName: "div", classes: "breakpoint"};
        FBTest.waitForDisplayedElement("script", config, function(element)
        {
            callback(row);
        });
    });
};

this.removeAllBreakpoints = function(callback)
{
    FW.Firebug.Debugger.clearAllBreakpoints(null, callback);
}

// ********************************************************************************************* //
}).apply(FBTest);
<commit_msg>Add a note related to changes of 72c04be and issue 7267<commit_after>/* See license.txt for terms of usage */

/**
 * This file defines Breakpoints API for test drivers.
 */

(function() {

// ********************************************************************************************* //
// Breakpoints API

/**
 * Set a breakpoint
 * @param {Object} chrome Firebug chrome object. If null, the default is used.
 * @param {Object} url URL of the target file. If null, the current file is used.
 * @param {Object} lineNo Source line number.
 * @param {Object} attributes Additional breakpoint attributes
 * @param {Object} callback Asynchronous callback is called as soon as the breakpoint is set.
 */
this.setBreakpoint = function(chrome, url, lineNo, attributes, callback)
{
    // FIXME: xxxpedro Test case for Issue 4553 is failing sometimes and it seems
    // to be something inside this FBTest.setBreakpoint() function
    if (!chrome)
        chrome = FW.Firebug.chrome;

    var panel = FBTest.selectPanel("script");
    if (!url)
        url = panel.getObjectLocation(panel.location);

    FBTest.sysout("setBreakpoint; " + url + ", " + lineNo);

    // FIXME: xxxpedro this function seems to be hacky, and could be the source
    // of the problem with the test case for Issue 4553
    FBTest.selectSourceLine(url, lineNo, "js", chrome, function(row)
    {
        var hasBreakpoint = FBTest.hasBreakpoint(lineNo);
        FBTest.ok(!hasBreakpoint, "There must not be a breakpoint at line: " + lineNo);

        FBTest.sysout("setBreakpoint; source line selected", row);

        if (false && attributes && attributes.condition)
        {
            // Right click on the target element.
            var eventDetails = {type: "mousedown", button: 2};
            FBTest.synthesizeMouse(target, 2, 2, eventDetails);

            var editor = panel.panelNode.querySelector(".conditionEditor .completionInput");
            FBTest.ok(editor, "Editor must exist");

            // xxxHonza: TODO
        }
        else
        {
            var config = {tagName: "div", classes: "breakpoint"};
            FBTest.waitForDisplayedElement("script", config, function(element)
            {
                FBTest.sysout("setBreakpoint; breakpoint created");

                // The source view may have been rebuilt, refetch the row.
                var row = FBTest.getSourceLineNode(lineNo, chrome);
                callback(row);
            });

            var target = row.querySelector(".CodeMirror-linenumber");

            // Note: Don't synthesize a mousedown event: this would make
            // console/breakOnError/breakOnError fail in timeout (see issue 7267).
            FBTest.synthesizeMouse(target, 2, 2);
            target = null;
        }
    });
};

/**
 * Wait till specific breakpoint is set (response from the backend received)
 *
 * @param {String} url URL of the breakpoint we are waiting for.
 * @param {Number} lineNo Line number where the breakpoint should be set.
 * @param {Function} callback Executed when the breakpoint is set.
 */
this.waitForBreakpoint = function(url, lineNo, callback)
{
    var browser = FBTest.getCurrentTabBrowser();

    var listener =
    {
        onBreakpointAdded: function(bp)
        {
            if (bp.lineNo+1 != lineNo || bp.href != url)
                return;

            DebuggerController.removeListener(browser, listener);

            callback();
        }
    };

    DebuggerController.addListener(browser, listener);
};

this.removeBreakpoint = function(chrome, url, lineNo, callback)
{
    if (!callback)
    {
        FBTest.sysout("removeBreakpoint; ERROR missing callback");
        return;
    }

    if (!chrome)
        chrome = FW.Firebug.chrome;

    var panel = FBTestFirebug.selectPanel("script");
    if (!url)
        url = panel.getObjectLocation(panel.location);

    FBTestFirebug.selectSourceLine(url, lineNo, "js", chrome, function(row)
    {
        var hasBreakpoint = FBTest.hasBreakpoint(lineNo);
        FBTest.ok(hasBreakpoint, "There must be a breakpoint at line: " + lineNo);

        var browser = FBTestFirebug.getCurrentTabBrowser();
        DebuggerController.listenOnce(browser, "onBreakpointRemoved", function()
        {
            hasBreakpoint = FBTest.hasBreakpoint(lineNo);
            FBTest.ok(!hasBreakpoint, "Breakpoint must be removed");

            callback();
        });

        // Click to remove a breakpoint.
        var target = row.querySelector(".CodeMirror-linenumber");

        // Note: Don't synthesize a mousedown event: this would make
        // console/breakOnError/breakOnError fail in timeout (see issue 7267).
        FBTest.synthesizeMouse(target, 2, 2);
    });
};

this.hasBreakpoint = function(line, chrome)
{
    if (typeof(line) == "number")
        line = FBTest.getSourceLineNode(line, chrome);

    if (!line)
    {
        FBTrace.sysout("hasBreakpoint ERROR undefined line");
        return false;
    }

    var bpNode = line.getElementsByClassName("breakpoint");
    return (bpNode.length > 0);
};

this.waitForDisplayedBreakpoint = function(chrome, url, lineNo, callback)
{
    FBTest.selectSourceLine(url, lineNo, "js", chrome, function(row)
    {
        var config = {tagName: "div", classes: "breakpoint"};
        FBTest.waitForDisplayedElement("script", config, function(element)
        {
            callback(row);
        });
    });
};

this.removeAllBreakpoints = function(callback)
{
    FW.Firebug.Debugger.clearAllBreakpoints(null, callback);
};

// ********************************************************************************************* //
}).apply(FBTest);
<|endoftext|>


<commit_before>//@flow

/*******************************************************************************
 * Imports
 *******************************************************************************/

import React from 'react'

/*******************************************************************************
 * Private
 *******************************************************************************/

const Version  = process.env.VERSION
const Revision = process.env.REVISION
const Origin   = `https://github.com/ostera/tldr.jsx/tree/${Revision}`

/*******************************************************************************
 * Public API
 *******************************************************************************/

export default () =>
  {Version}
<commit_msg>Add small v in front of version<commit_after>//@flow

/*******************************************************************************
 * Imports
 *******************************************************************************/

import React from 'react'

/*******************************************************************************
 * Private
 *******************************************************************************/

const Version  = process.env.VERSION
const Revision = process.env.REVISION
const Origin   = `https://github.com/ostera/tldr.jsx/tree/${Revision}`

/*******************************************************************************
 * Public API
 *******************************************************************************/

export default () =>
  v{Version}
<|endoftext|>


<commit_before>var util =         require('util');
var EventEmitter = require('events').EventEmitter;

function MySensors(options, log, onCreated) {
    if (!(this instanceof MySensors)) return new MySensors(options, log, onCreated);
    this._interface = null;
    this._interfaceParser = null;
    this.serialConnected = false;
    var clients = {};
    var lastMessageTs;
    var serialport;
	var that = this;

	function openSerial() {
		// serial;
        try {
            serialport = serialport || require('serialport');//.SerialPort;
        } catch (e) {
            console.warn('Serial port is not available');
        }
        if (serialport) {
            var portConfig = {baudRate: parseInt(options.baudRate,10) || 115200, autoOpen: false};
            var SerialPort = serialport; //.SerialPort;

            if (options.comName) {
                try {
                    that._interface = new SerialPort(options.comName, portConfig/*, false*/);
                    that._interfaceParser = that._interface.pipe(new Readline());
					that._interface.on('error', function (error) {
					    log.error('Failed to use serial port: ' + error);
					});
                    that._interface.open(function (error) {
                        if (error) {
                            log.error('Failed to open serial port: ' + error);
                        } else {
                            log.info('Serial port opened');
                            // forward data
                            that._interfaceParser.on('data', function (data) {
                                data = data.toString();

                                // Do not reset timeout too often
                                if (options.connTimeout && (!lastMessageTs || new Date().getTime() - lastMessageTs > 1000)) {
                                    if (that.disconnectTimeout) clearTimeout(that.disconnectTimeout);
                                    that.disconnectTimeout = setTimeout(that.disconnected.bind(that), options.connTimeout);
                                }

                                lastMessageTs = new Date().getTime();

                                if (!that.serialConnected) {
                                    if (log) log.info('Connected');
                                    that.serialConnected = true;
                                    that.emit('connectionChange', true);
                                }

                                if (data.split(';').length < 6) {
                                    if (log) log.warn('Wrong serial data: ' + data);
                                } else {
                                    if (log) log.debug('Serial data received: ' + data);
                                    that.emit('data', data);
                                }
                            }.bind(that));

                            that._interface.on('error', function (err) {
                                if (log && err) log.error('Serial error: ' + err);
                            });
                            if (onCreated) onCreated();
                        }
                    }.bind(that));
                } catch (e) {
                    if (log) log.error('Cannot open serial port "' + options.comName + '": ' + e);
                    that._interface = null;
                    that._interfaceParser = null;
                }
            } else {
                if (log) log.error('No serial port defined');
            }
        }
	}

	function openTcpClient() {
        var net = require('net');
        that._interface = new net.Socket();

        that._interface.connect(options.port || 2323, options.ip, function() {
            if (!that.serialConnected) {
                if (log) log.info('Connected');
                that.serialConnected = true;

                if (onCreated) {
                    onCreated();
                }

                setImmediate(function () {
                    that.emit('connectionChange', true);
                });
            }
        });

        var buffer = '';
        that._interface.on('data', function (data) {
            buffer += data.toString();
            var cmds = buffer.split('\n');
            for (var c = 0; c < cmds.length; c++) {
                if (cmds[c].split(';').length < 6) {
                    if (c === cmds.length - 1) {
                        buffer = cmds[c];
                        break;
                    } else {
                        if (log) log.warn('Wrong TCP data received: ' + cmds[c].replace('\n', ''));
                    }
                } else {
                    if (log) log.debug('TCP data received from: ' + cmds[c].replace('\n', ''));
                    setImmediate(function (cmd) {
                        that.emit('data', cmd);
                    }, cmds[c]);
                }
            }
        });

        that._interface.on('close', function() {
            // request closed unexpectedly
            if (log) log.warn('Connection closed unexpectedly');
            that.disconnected();
            try {
                that._interface.close();
            } catch (e) {

            }
            setTimeout(openTcpClient, options.connTimeout);
        });

        that._interface.on('error', function (err) {
            if (log && err) log.error('Error: ' + err);
            that.disconnected();
        });

    }

    if (options.type === 'udp') {
        var dgram = require('dgram');
        this._interface = dgram.createSocket('udp4');

        this._interface.on('error', function (err) {
            if (log) log.error('UDP server error: ' + err);
        });

        this._interface.on('message', function (data, rinfo) {
            data = data.toString();

            // this must be per connection
            if (!clients[rinfo.address] || !clients[rinfo.address].connected) {
                if (log) log.info('Connected ' + rinfo.address + ':' + rinfo.port);
                clients[rinfo.address] = clients[rinfo.address] || {};
                clients[rinfo.address].connected = true;
                clients[rinfo.address].port      = rinfo.port;

                var addresses = [];
                for (var addr in clients) {
                    if (clients[addr].connected) addresses.push(addr);
                }

                this.emit('connectionChange', addresses.join(', '), rinfo.address, rinfo.port);
            }

            // Do not reset timeout too often
            if (options.connTimeout && (!clients[rinfo.address] || !clients[rinfo.address].lastMessageTs || new Date().getTime() - clients[rinfo.address].lastMessageTs > 1000)) {
                if (clients[rinfo.address].disconnectTimeout) clearTimeout(clients[rinfo.address].disconnectTimeout);
                clients[rinfo.address].disconnectTimeout = setTimeout(function (addr, port) {
                    this.disconnected(addr, port);
                }.bind(this), options.connTimeout, rinfo.address, rinfo.port);
            }

            clients[rinfo.address].lastMessageTs = new Date().getTime();

            if (data.split(';').length < 6) {
                if (log) log.warn('Wrong UDP data received from ' + rinfo.address + ':' + rinfo.port + ': ' + data);
            } else {
                if (log) log.debug('UDP data received from ' + rinfo.address + ':' + rinfo.port + ': ' + data);
                this.emit('data', data, rinfo.address, rinfo.port);
            }
        }.bind(this));

        this._interface.on('listening', function () {
            if (log) log.info('UDP server listening on port ' + options.port || 5003);
            if (onCreated) onCreated();
        }.bind(this));

        if (options.mode === 'server') {
            this._interface.bind(options.port || 5003, options.bind || undefined);
        } else {

        }
    } else
    if (options.type === 'tcp') {

        var net = require('net');

        this._interface = net.createServer(function(socket) {
            var ip   = socket.remoteAddress;
            var port = socket.remotePort;

            // this must be per connection
            if (!clients[ip] || !clients[ip].connected) {
                if (log) log.info('Connected ' + ip + ':' + socket.remotePort);
                clients[ip] = clients[ip] || {};
                clients[ip].connected = true;
                clients[ip].port      = socket.remotePort;
                clients[ip].socket    = socket;

                var addresses = [];
                for (var addr in clients) {
                    if (clients[addr].connected) addresses.push(addr);
                }

                this.emit('connectionChange', addresses.join(', '), ip, port);
            }
            var buffer = '';

            socket.on('data', function (data) {
                data = data.toString();

                buffer += data;
                if (data.split(';').length < 6) {
                    if (log) log.warn('Wrong TCP data received from ' + ip + ':' + port + ': ' + data.replace('\n', ''));
                } else {
                    if (log) log.debug('TCP data received from ' + ip + ':' + port + ': ' + data.replace('\n', ''));
                    setImmediate(function () {
                        this.emit('data', data, ip, port);
                    }.bind(this));
                }
            }.bind(this));

            socket.on('error', function (err) {
                if (log && err) log.error('Error for "' + ip + '": ' + err);
                if (clients[ip]) clients[ip].socket = null;
                this.disconnected(ip, port);
                socket.destroy();
            }.bind(this));

            socket.on('close', function() {
                // request closed unexpectedly
                if (clients[ip] && clients[ip].socket) {
                    clients[ip].socket = null;
                    if (log) log.warn('Connection "' + ip + '" closed unexpectedly');
                    this.disconnected(ip, port);
                    socket.destroy();
                }
            }.bind(this));

            socket.on('end', function() {
                buffer = '';
            }.bind(this));

        }.bind(this));

        this._interface.on('error', function (err) {
            if (log) log.error('TCP server error: ' + err);
        });

        this._interface.listen(options.port || 5003, options.bind || undefined, function (err) {
            if (log && err) log.error('TCP server error: ' + err);
            if (err) process.exit(1);
            if (log) log.info('TCP server listening on port ' + options.port || 5003);
            if (onCreated) onCreated();
        });
    }  else
    if (options.type === 'tcpclient') {
        openTcpClient();
    } else {
        openSerial();
    }

    this.write = function (data, ip) {
        if (this._interface) {
            if (log) log.debug('Send raw data: ' + data);

            if (options.type === 'udp') {
                if (clients[ip] && clients[ip].connected && clients[ip].port) {
                    this._interface.send(new Buffer(data), 0, data.length, clients[ip].port, ip, function(err) {
                        if (log) {
                            if (err) {
                                log.error('Cannot send to ' + ip + '[' + data + ']: ' + err);
                            } else {
                                log.debug('Sent to ' + ip + ' ' + data);
                            }
                        }
                    });
                } else if (!ip) {
                    for (var i in clients) {
                        this._interface.send(new Buffer(data), 0, data.length, clients[i].port, i, function(err) {
                            if (log) {
                                if (err) {
                                    log.error('Cannot send to ' + ip + '[' + data + ']: ' + err);
                                } else {
                                    log.debug('Sent to ' + ip + ' ' + data);
                                }
                            }
                        });
                    }
                } else if (log) {
                    log.error('Cannot send to ' + ip + ' because not connected');
                }
            } else if (options.type === 'tcp') {
                if (clients[ip] && clients[ip].connected && clients[ip].socket) {
                    clients[ip].socket.write(data + '\n', function(err) {
                        if (log) {
                            if (err) {
                                log.error('Cannot send to ' + ip + '[' + data + ']: ' + err);
                            } else {
                                log.debug('Sent to ' + ip + ' ' + data);
                            }
                        }
                    });
                } else if (!ip) {
                    for (var _ip in clients) {
                        if (!clients.hasOwnProperty(_ip)) continue;

                        clients[_ip].socket.write(data + '\n', function (err) {
                            if (log) {
                                if (err) {
                                    log.error('Cannot send [' + data + ']: ' + err);
                                } else {
                                    log.debug('Sent ' + data);
                                }
                            }
                        });
                    }
                } else if (log) {
                    log.error('Cannot send to ' + ip + ' because not connected');
                }
            } if (options.type === 'tcpclient') {
                this._interface.write(data + '\n', function (error) {
                    if (log && error) {
                        log.error('Cannot send: ' + error);
                        if (this.serialConnected) {
                            this._interface.close();
                        }
                        that._interface = null;
                        that.disconnected();
                        log.error('Cannot send_: ' + error);
                        setTimeout(function () {
                            openTcpClient();
                        }, options.connTimeout);
                    }
                }.bind(this));
            }else {
                //serial
				try {
					this._interface.write(data + '\n', function (error) {
						if (log && error) {
							log.error('Cannot send: ' + error);
                            if (this._interface && this._interface.isOpen) {
                                this._interface.pause();
                                this._interface.close();
                            }
                            that._interface = null;
                            that._interfaceParser = null;
                            that.disconnected();
							log.error('Cannot send_: ' + error);
							setTimeout(function () {
								openSerial();
							}, 500);
						}
					}.bind(this));
				} catch (error) {
                    if (this._interface && this._interface.isOpen) {
                        this._interface.pause();
                        this._interface.close();
                    }
					this._interface = null;
                    that._interfaceParser = null;
					this.disconnected();
					log.error('Cannot send_: ' + error);
					setTimeout(openSerial, 500);
				}
            }
        } else {
            if (log) log.warn('Wrong serial data: ' + data);
        }
    };

    this.isConnected = function (addr) {
        if (addr) {
            return clients[addr] && clients[addr].connected;
        } else {
            return this.serialConnected;
        }
    };

    this.disconnected = function (addr) {
        if (addr) {
            if (clients[addr] && clients[addr].connected) {
                clients[addr].connected = false;
                var addresses = [];
                for (var _addr in clients) {
                    if (!clients.hasOwnProperty(_addr)) continue;
                    if (clients[_addr].connected) addresses.push(_addr);
                }
                this.emit('connectionChange', addresses.join(', '), addr, clients[addr].port);
                // stop timer
                if (clients[addr].disconnectTimeout) clearTimeout(clients[addr].disconnectTimeout);
                clients[addr].disconnectTimeout = null;
            }
        } else
        if (this.serialConnected) {
            if (log) log.info('disconnected ' + (addr || ''));
            this.serialConnected = false;
            this.emit('connectionChange', false);
            // stop timer
            if (this.disconnectTimeout) clearTimeout(this.disconnectTimeout);
            this.disconnectTimeout = null;
        }
    };

    this.destroy = function () {
        try {
            if (this._interface) {
                if (options.type === 'udp') {
                    this._interface.close();
                } else if (options.type === 'tcp') {
                    this._interface.close();
                } else if (options.type === 'tcpclient') {
                    this._interface.close();
                } else {
                    //serial
                    this._interface.close();
                }
            }
        } catch (e) {

        }
    };

    return this;
}

// extend the EventEmitter class using our Radio class
util.inherits(MySensors, EventEmitter);

module.exports = MySensors;
<commit_msg>fix readline<commit_after>var util =         require('util');
var EventEmitter = require('events').EventEmitter;

function MySensors(options, log, onCreated) {
    if (!(this instanceof MySensors)) return new MySensors(options, log, onCreated);
    this._interface = null;
    this._interfaceParser = null;
    this.serialConnected = false;
    var clients = {};
    var lastMessageTs;
    var serialport;
	var that = this;

	function openSerial() {
		// serial;
        try {
            serialport = serialport || require('serialport');//.SerialPort;
        } catch (e) {
            console.warn('Serial port is not available');
        }
        if (serialport) {
            var portConfig = {baudRate: parseInt(options.baudRate,10) || 115200, autoOpen: false};
            var SerialPort = serialport; //.SerialPort;

            if (options.comName) {
                try {
                    that._interface = new SerialPort(options.comName, portConfig/*, false*/);
                    that._interfaceParser = that._interface.pipe(new serialport.parsers.Readline());
					that._interface.on('error', function (error) {
					    log.error('Failed to use serial port: ' + error);
					});
                    that._interface.open(function (error) {
                        if (error) {
                            log.error('Failed to open serial port: ' + error);
                        } else {
                            log.info('Serial port opened');
                            // forward data
                            that._interfaceParser.on('data', function (data) {
                                data = data.toString();

                                // Do not reset timeout too often
                                if (options.connTimeout && (!lastMessageTs || new Date().getTime() - lastMessageTs > 1000)) {
                                    if (that.disconnectTimeout) clearTimeout(that.disconnectTimeout);
                                    that.disconnectTimeout = setTimeout(that.disconnected.bind(that), options.connTimeout);
                                }

                                lastMessageTs = new Date().getTime();

                                if (!that.serialConnected) {
                                    if (log) log.info('Connected');
                                    that.serialConnected = true;
                                    that.emit('connectionChange', true);
                                }

                                if (data.split(';').length < 6) {
                                    if (log) log.warn('Wrong serial data: ' + data);
                                } else {
                                    if (log) log.debug('Serial data received: ' + data);
                                    that.emit('data', data);
                                }
                            }.bind(that));

                            that._interface.on('error', function (err) {
                                if (log && err) log.error('Serial error: ' + err);
                            });
                            if (onCreated) onCreated();
                        }
                    }.bind(that));
                } catch (e) {
                    if (log) log.error('Cannot open serial port "' + options.comName + '": ' + e);
                    that._interface = null;
                    that._interfaceParser = null;
                }
            } else {
                if (log) log.error('No serial port defined');
            }
        }
	}

	function openTcpClient() {
        var net = require('net');
        that._interface = new net.Socket();

        that._interface.connect(options.port || 2323, options.ip, function() {
            if (!that.serialConnected) {
                if (log) log.info('Connected');
                that.serialConnected = true;

                if (onCreated) {
                    onCreated();
                }

                setImmediate(function () {
                    that.emit('connectionChange', true);
                });
            }
        });

        var buffer = '';
        that._interface.on('data', function (data) {
            buffer += data.toString();
            var cmds = buffer.split('\n');
            for (var c = 0; c < cmds.length; c++) {
                if (cmds[c].split(';').length < 6) {
                    if (c === cmds.length - 1) {
                        buffer = cmds[c];
                        break;
                    } else {
                        if (log) log.warn('Wrong TCP data received: ' + cmds[c].replace('\n', ''));
                    }
                } else {
                    if (log) log.debug('TCP data received from: ' + cmds[c].replace('\n', ''));
                    setImmediate(function (cmd) {
                        that.emit('data', cmd);
                    }, cmds[c]);
                }
            }
        });

        that._interface.on('close', function() {
            // request closed unexpectedly
            if (log) log.warn('Connection closed unexpectedly');
            that.disconnected();
            try {
                that._interface.close();
            } catch (e) {

            }
            setTimeout(openTcpClient, options.connTimeout);
        });

        that._interface.on('error', function (err) {
            if (log && err) log.error('Error: ' + err);
            that.disconnected();
        });

    }

    if (options.type === 'udp') {
        var dgram = require('dgram');
        this._interface = dgram.createSocket('udp4');

        this._interface.on('error', function (err) {
            if (log) log.error('UDP server error: ' + err);
        });

        this._interface.on('message', function (data, rinfo) {
            data = data.toString();

            // this must be per connection
            if (!clients[rinfo.address] || !clients[rinfo.address].connected) {
                if (log) log.info('Connected ' + rinfo.address + ':' + rinfo.port);
                clients[rinfo.address] = clients[rinfo.address] || {};
                clients[rinfo.address].connected = true;
                clients[rinfo.address].port      = rinfo.port;

                var addresses = [];
                for (var addr in clients) {
                    if (clients[addr].connected) addresses.push(addr);
                }

                this.emit('connectionChange', addresses.join(', '), rinfo.address, rinfo.port);
            }

            // Do not reset timeout too often
            if (options.connTimeout && (!clients[rinfo.address] || !clients[rinfo.address].lastMessageTs || new Date().getTime() - clients[rinfo.address].lastMessageTs > 1000)) {
                if (clients[rinfo.address].disconnectTimeout) clearTimeout(clients[rinfo.address].disconnectTimeout);
                clients[rinfo.address].disconnectTimeout = setTimeout(function (addr, port) {
                    this.disconnected(addr, port);
                }.bind(this), options.connTimeout, rinfo.address, rinfo.port);
            }

            clients[rinfo.address].lastMessageTs = new Date().getTime();

            if (data.split(';').length < 6) {
                if (log) log.warn('Wrong UDP data received from ' + rinfo.address + ':' + rinfo.port + ': ' + data);
            } else {
                if (log) log.debug('UDP data received from ' + rinfo.address + ':' + rinfo.port + ': ' + data);
                this.emit('data', data, rinfo.address, rinfo.port);
            }
        }.bind(this));

        this._interface.on('listening', function () {
            if (log) log.info('UDP server listening on port ' + options.port || 5003);
            if (onCreated) onCreated();
        }.bind(this));

        if (options.mode === 'server') {
            this._interface.bind(options.port || 5003, options.bind || undefined);
        } else {

        }
    } else
    if (options.type === 'tcp') {

        var net = require('net');

        this._interface = net.createServer(function(socket) {
            var ip   = socket.remoteAddress;
            var port = socket.remotePort;

            // this must be per connection
            if (!clients[ip] || !clients[ip].connected) {
                if (log) log.info('Connected ' + ip + ':' + socket.remotePort);
                clients[ip] = clients[ip] || {};
                clients[ip].connected = true;
                clients[ip].port      = socket.remotePort;
                clients[ip].socket    = socket;

                var addresses = [];
                for (var addr in clients) {
                    if (clients[addr].connected) addresses.push(addr);
                }

                this.emit('connectionChange', addresses.join(', '), ip, port);
            }
            var buffer = '';

            socket.on('data', function (data) {
                data = data.toString();

                buffer += data;
                if (data.split(';').length < 6) {
                    if (log) log.warn('Wrong TCP data received from ' + ip + ':' + port + ': ' + data.replace('\n', ''));
                } else {
                    if (log) log.debug('TCP data received from ' + ip + ':' + port + ': ' + data.replace('\n', ''));
                    setImmediate(function () {
                        this.emit('data', data, ip, port);
                    }.bind(this));
                }
            }.bind(this));

            socket.on('error', function (err) {
                if (log && err) log.error('Error for "' + ip + '": ' + err);
                if (clients[ip]) clients[ip].socket = null;
                this.disconnected(ip, port);
                socket.destroy();
            }.bind(this));

            socket.on('close', function() {
                // request closed unexpectedly
                if (clients[ip] && clients[ip].socket) {
                    clients[ip].socket = null;
                    if (log) log.warn('Connection "' + ip + '" closed unexpectedly');
                    this.disconnected(ip, port);
                    socket.destroy();
                }
            }.bind(this));

            socket.on('end', function() {
                buffer = '';
            }.bind(this));

        }.bind(this));

        this._interface.on('error', function (err) {
            if (log) log.error('TCP server error: ' + err);
        });

        this._interface.listen(options.port || 5003, options.bind || undefined, function (err) {
            if (log && err) log.error('TCP server error: ' + err);
            if (err) process.exit(1);
            if (log) log.info('TCP server listening on port ' + options.port || 5003);
            if (onCreated) onCreated();
        });
    }  else
    if (options.type === 'tcpclient') {
        openTcpClient();
    } else {
        openSerial();
    }

    this.write = function (data, ip) {
        if (this._interface) {
            if (log) log.debug('Send raw data: ' + data);

            if (options.type === 'udp') {
                if (clients[ip] && clients[ip].connected && clients[ip].port) {
                    this._interface.send(new Buffer(data), 0, data.length, clients[ip].port, ip, function(err) {
                        if (log) {
                            if (err) {
                                log.error('Cannot send to ' + ip + '[' + data + ']: ' + err);
                            } else {
                                log.debug('Sent to ' + ip + ' ' + data);
                            }
                        }
                    });
                } else if (!ip) {
                    for (var i in clients) {
                        this._interface.send(new Buffer(data), 0, data.length, clients[i].port, i, function(err) {
                            if (log) {
                                if (err) {
                                    log.error('Cannot send to ' + ip + '[' + data + ']: ' + err);
                                } else {
                                    log.debug('Sent to ' + ip + ' ' + data);
                                }
                            }
                        });
                    }
                } else if (log) {
                    log.error('Cannot send to ' + ip + ' because not connected');
                }
            } else if (options.type === 'tcp') {
                if (clients[ip] && clients[ip].connected && clients[ip].socket) {
                    clients[ip].socket.write(data + '\n', function(err) {
                        if (log) {
                            if (err) {
                                log.error('Cannot send to ' + ip + '[' + data + ']: ' + err);
                            } else {
                                log.debug('Sent to ' + ip + ' ' + data);
                            }
                        }
                    });
                } else if (!ip) {
                    for (var _ip in clients) {
                        if (!clients.hasOwnProperty(_ip)) continue;

                        clients[_ip].socket.write(data + '\n', function (err) {
                            if (log) {
                                if (err) {
                                    log.error('Cannot send [' + data + ']: ' + err);
                                } else {
                                    log.debug('Sent ' + data);
                                }
                            }
                        });
                    }
                } else if (log) {
                    log.error('Cannot send to ' + ip + ' because not connected');
                }
            } if (options.type === 'tcpclient') {
                this._interface.write(data + '\n', function (error) {
                    if (log && error) {
                        log.error('Cannot send: ' + error);
                        if (this.serialConnected) {
                            this._interface.close();
                        }
                        that._interface = null;
                        that.disconnected();
                        log.error('Cannot send_: ' + error);
                        setTimeout(function () {
                            openTcpClient();
                        }, options.connTimeout);
                    }
                }.bind(this));
            }else {
                //serial
				try {
					this._interface.write(data + '\n', function (error) {
						if (log && error) {
							log.error('Cannot send: ' + error);
                            if (this._interface && this._interface.isOpen) {
                                this._interface.pause();
                                this._interface.close();
                            }
                            that._interface = null;
                            that._interfaceParser = null;
                            that.disconnected();
							log.error('Cannot send_: ' + error);
							setTimeout(function () {
								openSerial();
							}, 500);
						}
					}.bind(this));
				} catch (error) {
                    if (this._interface && this._interface.isOpen) {
                        this._interface.pause();
                        this._interface.close();
                    }
					this._interface = null;
                    that._interfaceParser = null;
					this.disconnected();
					log.error('Cannot send_: ' + error);
					setTimeout(openSerial, 500);
				}
            }
        } else {
            if (log) log.warn('Wrong serial data: ' + data);
        }
    };

    this.isConnected = function (addr) {
        if (addr) {
            return clients[addr] && clients[addr].connected;
        } else {
            return this.serialConnected;
        }
    };

    this.disconnected = function (addr) {
        if (addr) {
            if (clients[addr] && clients[addr].connected) {
                clients[addr].connected = false;
                var addresses = [];
                for (var _addr in clients) {
                    if (!clients.hasOwnProperty(_addr)) continue;
                    if (clients[_addr].connected) addresses.push(_addr);
                }
                this.emit('connectionChange', addresses.join(', '), addr, clients[addr].port);
                // stop timer
                if (clients[addr].disconnectTimeout) clearTimeout(clients[addr].disconnectTimeout);
                clients[addr].disconnectTimeout = null;
            }
        } else
        if (this.serialConnected) {
            if (log) log.info('disconnected ' + (addr || ''));
            this.serialConnected = false;
            this.emit('connectionChange', false);
            // stop timer
            if (this.disconnectTimeout) clearTimeout(this.disconnectTimeout);
            this.disconnectTimeout = null;
        }
    };

    this.destroy = function () {
        try {
            if (this._interface) {
                if (options.type === 'udp') {
                    this._interface.close();
                } else if (options.type === 'tcp') {
                    this._interface.close();
                } else if (options.type === 'tcpclient') {
                    this._interface.close();
                } else {
                    //serial
                    this._interface.close();
                }
            }
        } catch (e) {

        }
    };

    return this;
}

// extend the EventEmitter class using our Radio class
util.inherits(MySensors, EventEmitter);

module.exports = MySensors;
<|endoftext|>


<commit_before>//TO-DO
//requst the JSON from stackoverflow website
//setup javascript promises
//using promise send one link at a time to the scrapeStack function
//save each site in a new folder with a new folder name

var request = require("superagent");
var scraper = require('website-scraper');

var express = require("express");
var app = express();

var webSite = "http://stackoverflow.com/questions/513832/how-do-i-compare-strings-in-java";
var name = "siteName";

app.get('/', function(req, res) {
    res.send('Hello World!');
});

app.get('/scrape', function(req, res) {
    requestStack();
});

app.listen(3000, function() {
    console.log('Example app listening on port 3000!');
});

function requestStack() {
    request
        .get("https://api.stackexchange.com/2.2/tags/javascript/faq?site=stackoverflow")
        .end(function(err, res) {
            res.body.items.forEach(function(item) {
                console.log(item.link);
                var stuff = item.link;

                var promises = stuff.toString()
                  .split('\n')
                  .map((link) => scrapeStack(link, item.question_id));

                return Promise.all(promises);
            })
        })
}

function scrapeStack(site, directory) {
    return scraper.scrape({
        urls: [
            site
        ],
        directory: '/home/shail/Documents/code/stackcache/cache/' + directory,
        subdirectories: [
            { directory: 'img', extensions: ['.jpg', '.png', '.svg'] },
            { directory: 'js', extensions: ['.js'] },
            { directory: 'css', extensions: ['.css'] }
        ],
        sources: [
            { selector: 'img', attr: 'src' },
            { selector: 'link[rel="stylesheet"]', attr: 'href' },
            { selector: 'script', attr: 'src' }
        ],
        request: {
            headers: {
                //'User-Agent': 'Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 4 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19'
            }
        }
    }).then(function(result) {
        console.log(result);
    }).catch(function(err) {
        console.log(err);
    });
}
<commit_msg>scrape github with more starred<commit_after>//TO-DO
//requst the JSON from stackoverflow website
//setup javascript promises
//using promise send one link at a time to the scrapeStack function
//save each site in a new folder with a new folder name

var request = require("superagent");
var scraper = require('website-scraper');

var express = require("express");
var app = express();

app.get('/', function(req, res) {
    res.send('Hello World!');
});

//scrapping stackoverflow
app.get('/scrapestackoverflow', function(req, res) {
    requestStack();
});
//scrapping github
app.get('/scrapegithub', function(req, res) {
    requestGithub();
});

app.listen(3000, function() {
    console.log('Example app listening on port 3000!');
});

function requestGithub() {
    request
        .get("https://api.github.com/search/repositories?q=language:javascript&sort=stars&order=desc")
        .end(function(err, res) {
            res.body.items.forEach(function(item) {
                console.log(item.html_url);
                var gitlinks = item.html_url;
                var promises = gitlinks.toString()
                    .split('\n')
                    .map(html_url => scrapeGithub(html_url, item.name))

                return Promise.all(promises);
            })
        })
}

function scrapeGithub(site, directory) {
    return scraper.scrape({
        urls: [
            site
        ],
        directory: '/home/shail/Documents/code/stackcache/cacheGithub/' + directory,
        subdirectories: [
            { directory: 'img', extensions: ['.jpg', '.png', '.svg'] },
            { directory: 'js', extensions: ['.js'] },
            { directory: 'css', extensions: ['.css'] }
        ],
        sources: [
            { selector: 'img', attr: 'src' },
            { selector: 'link[rel="stylesheet"]', attr: 'href' },
            { selector: 'script', attr: 'src' }
        ],
        request: {
            headers: {
                //'User-Agent': 'Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 4 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19'
            }
        }
    }).then(function(result) {
        console.log(result);
    }).catch(function(err) {
        console.log(err);
    });
}

function requestStack() {
    request
        .get("https://api.stackexchange.com/2.2/tags/javascript/faq?site=stackoverflow")
        .end(function(err, res) {
            res.body.items.forEach(function(item) {
                console.log(item.link);
                var stacklinks = item.link;
                var promises = stacklinks.toString()
                    .split('\n')
                    .map((link) => scrapeStack(link, item.question_id));

                return Promise.all(promises);
            })
        })
}

function scrapeStack(site, directory) {
    return scraper.scrape({
        urls: [
            site
        ],
        directory: '/home/shail/Documents/code/stackcache/cacheStackOverFLow/' + directory,
        subdirectories: [
            { directory: 'img', extensions: ['.jpg', '.png', '.svg'] },
            { directory: 'js', extensions: ['.js'] },
            { directory: 'css', extensions: ['.css'] }
        ],
        sources: [
            { selector: 'img', attr: 'src' },
            { selector: 'link[rel="stylesheet"]', attr: 'href' },
            { selector: 'script', attr: 'src' }
        ],
        request: {
            headers: {
                //'User-Agent': 'Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 4 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19'
            }
        }
    }).then(function(result) {
        console.log(result);
    }).catch(function(err) {
        console.log(err);
    });
}
<|endoftext|>


<commit_before>const Countries = require('../src');

describe('Countries', () => {

  describe('package.json tasks', () => {

    const pkg = require('../package') || {};

    it('installed world-countries package', () => {
      expect(pkg.dependencies).to.contain('world-countries');
    });

    it('named properly', () => {
      const projectName = 'country-utilities';
      expect(pkg.name).to.equal(projectName);
    })

  });

  describe('#all([settings])', () => {

    it(`loads all the countries by setting loadAll = true`, () => {

      const result = Countries.all({ loadAll: true });

      expect(result).to.not.be.empty();
      expect(result.length).to.be.greaterThan(15);
    });

    it(`fetches a 15 countries by default, and the first page of data`, () => {
      const result = Countries.all({ index: 0, pageSize: 15});

      expect(result.length).to.equal(15);
    });

    it(`fetches a 15 countries, and the second page of data`, () => {
      const first = Countries.all({ loadAll: true })[0];
      const results = Countries.all({ index: 1, pageSize: 15});

      expect(results.length).to.equal(15);
      expect(results.map(country => country.cca3)).to.not.contain(first.cca3);
    });

  });

  describe('#filter(parameter)', () => {

    it('shows only the countries that have that contain the query parameter in the common or official name', () => {
      const results = Countries.filter('States');
      expect(results).to.not.be.empty();
    });

    // Reuse the #all function
    it('shows all the countries if the search parameter is empty', () => {
      expect(Countries.filter()).to.not.be.empty();
    });

    it('shows a single country when the search parameter is an exact match', () => {
      const name = 'United States of America';
      const results = Countries.filter(name);
       expect(results[0].name.official).to.equal(name);
    });

  });

  describe('#get(code)', () => {

    it('retrieves a country by their cca3 code', () => {
      expect(Countries.get('USA').name.common).to.equal('United States')
    });

    it(`throws an error when anything but a 3 character code is entered`, () => {
      expect(() => Countries.get('bogus')).to.throw();
    });

    // Look at the https://www.npmjs.com/package/common-errors project and use it to throw a https://www.npmjs.com/package/common-errors#notfound
    it(`throws an error, a NotFound error if the country code is not valid (not found)`, () => {
      expect(() => Countries.get('ZZZ')).to.throw();
    });

  });

  // Use the cca3 code for the country, or the official name (Hint: the ccaa3 code is always 3 characters long)
  describe('#touches(countryCode)', () => {

    it('finds all the countries that touch a particular country (returns the full country object instead of the country code)', () => {

      expect(Countries.touches('USA')).to.be.a('object');
    });

  });

  describe(`#findByRegion(region)`, () => {

    it(`retrieves all the countries for a particular region`, () => {
      expect(Countries.findByRegion('Americas')).to.not.be.empty();
    });

    it(`throws an error if the region is not contained in the known regions`, () => {
      expect(() => Countries.findByRegion('SuperBogus')).to.throw();
    });

  });

  describe(`#findBySubRegion(region)`, () => {

    it(`retrieves all the countries for a particular sub-region`, () => {
      expect(Countries.findBySubRegion('Northern America')).to.not.be.empty();
    });

    it(`throws an error if the region is not contained in the known sub-regions`, () => {
      expect(() => Countries.findBySubRegion('SuperBogus')).to.throw();
    });

  });

  // Use the cca3 code
  describe('#distance(startingCountryCode, endingCountryCode)', () => {

    // Use something like this to calculate: http://www.geodatasource.com/developers/javascript
    it('calculates the distance using longitude and latitude of two countries, returns a positive number', () => {
      const distance = Countries.distance('USA', 'UZB');
      expect(distance).to.be.a.number();
      expect(distance).to.be.greaterThan(0);
    });

  });

  // Use the cca3 code
  describe('#subtractArea(startingCountryCode, endingCountryCode)', () => {

    it('subtracts the area of two countries, it must return a positive number', () => {
      const differenceInArea = Countries.subtractArea('USA', 'UZB');
      expect(differenceInArea).to.be.a.number();
      expect(differenceInArea).to.be.greaterThan(0);
    });

  });

  describe('#withCurrency(currencyCode)', () => {

    it(`finds all the countries that use a particular currency, eg 'USD'`, () => {
      expect(Countries.withCurrency('USD')).to.not.be.empty();
    });

    it(`returns empty if an invalid code is entered`, () => {
      expect(Countries.withCurrency('AAA')).to.be.empty();
    });

    it(`ensures the code is at least 3 characters long`, () => {
      expect(() => Countries.withCurrency('BOGUS')).to.throw();
    });

  });

});
<commit_msg>Touches tests<commit_after>const Countries = require('../src');

describe('Countries', () => {

  describe('package.json tasks', () => {

    const pkg = require('../package') || {};

    it('installed world-countries package', () => {
      expect(pkg.dependencies).to.contain('world-countries');
    });

    it('named properly', () => {
      const projectName = 'country-utilities';
      expect(pkg.name).to.equal(projectName);
    })

  });

  describe('#all([settings])', () => {

    it(`loads all the countries by setting loadAll = true`, () => {

      const result = Countries.all({ loadAll: true });

      expect(result).to.not.be.empty();
      expect(result.length).to.be.greaterThan(15);
    });

    it(`fetches a 15 countries by default, and the first page of data`, () => {
      const result = Countries.all({ index: 0, pageSize: 15});

      expect(result.length).to.equal(15);
    });

    it(`fetches a 15 countries, and the second page of data`, () => {
      const first = Countries.all({ loadAll: true })[0];
      const results = Countries.all({ index: 1, pageSize: 15});

      expect(results.length).to.equal(15);
      expect(results.map(country => country.cca3)).to.not.contain(first.cca3);
    });

  });

  describe('#filter(parameter)', () => {

    it('shows only the countries that have that contain the query parameter in the common or official name', () => {
      const results = Countries.filter('States');
      expect(results).to.not.be.empty();
    });

    // Reuse the #all function
    it('shows all the countries if the search parameter is empty', () => {
      expect(Countries.filter()).to.not.be.empty();
    });

    it('shows a single country when the search parameter is an exact match', () => {
      const name = 'United States of America';
      const results = Countries.filter(name);
       expect(results[0].name.official).to.equal(name);
    });

  });

  describe('#get(code)', () => {

    it('retrieves a country by their cca3 code', () => {
      expect(Countries.get('USA').name.common).to.equal('United States')
    });

    it(`throws an error when anything but a 3 character code is entered`, () => {
      expect(() => Countries.get('bogus')).to.throw();
    });

    // Look at the https://www.npmjs.com/package/common-errors project and use it to throw a https://www.npmjs.com/package/common-errors#notfound
    it(`throws an error, a NotFound error if the country code is not valid (not found)`, () => {
      expect(() => Countries.get('ZZZ')).to.throw();
    });

  });

  // Use the cca3 code for the country, or the official name (Hint: the ccaa3 code is always 3 characters long)
  describe('#touches(countryCode)', () => {

    it('finds all the countries that touch a particular country (returns the full country object instead of the country code)', () => {
      const countries = Countries.touches('USA');

      expect(countries).to.be.an.array();
      expect(countries).to.not.be.empty();
      expect(countries[0]).to.be.an.object();
    });

  });

  describe(`#findByRegion(region)`, () => {

    it(`retrieves all the countries for a particular region`, () => {
      expect(Countries.findByRegion('Americas')).to.not.be.empty();
    });

    it(`throws an error if the region is not contained in the known regions`, () => {
      expect(() => Countries.findByRegion('SuperBogus')).to.throw();
    });

  });

  describe(`#findBySubRegion(region)`, () => {

    it(`retrieves all the countries for a particular sub-region`, () => {
      expect(Countries.findBySubRegion('Northern America')).to.not.be.empty();
    });

    it(`throws an error if the region is not contained in the known sub-regions`, () => {
      expect(() => Countries.findBySubRegion('SuperBogus')).to.throw();
    });

  });

  // Use the cca3 code
  describe('#distance(startingCountryCode, endingCountryCode)', () => {

    // Use something like this to calculate: http://www.geodatasource.com/developers/javascript
    it('calculates the distance using longitude and latitude of two countries, returns a positive number', () => {
      const distance = Countries.distance('USA', 'UZB');
      expect(distance).to.be.a.number();
      expect(distance).to.be.greaterThan(0);
    });

  });

  // Use the cca3 code
  describe('#subtractArea(startingCountryCode, endingCountryCode)', () => {

    it('subtracts the area of two countries, it must return a positive number', () => {
      const differenceInArea = Countries.subtractArea('USA', 'UZB');
      expect(differenceInArea).to.be.a.number();
      expect(differenceInArea).to.be.greaterThan(0);
    });

  });

  describe('#withCurrency(currencyCode)', () => {

    it(`finds all the countries that use a particular currency, eg 'USD'`, () => {
      expect(Countries.withCurrency('USD')).to.not.be.empty();
    });

    it(`returns empty if an invalid code is entered`, () => {
      expect(Countries.withCurrency('AAA')).to.be.empty();
    });

    it(`ensures the code is at least 3 characters long`, () => {
      expect(() => Countries.withCurrency('BOGUS')).to.throw();
    });

  });

});
<|endoftext|>


<commit_before>// Copyright 2014 Globo.com Player authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

const Browser = {}

const hasLocalstorage = function(){
  try {
    localStorage.setItem('clappr', 'clappr')
    localStorage.removeItem('clappr')
    return true
  } catch(e) {
    return false
  }
}

const hasFlash = function() {
  try {
    const fo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash')
    return !!fo
  } catch (e) {
    return !!(navigator.mimeTypes && navigator.mimeTypes['application/x-shockwave-flash'] !== undefined &&
        navigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin)
  }
}

const getBrowserInfo = function() {
  const ua = navigator.userAgent
  let parts = ua.match(/\b(playstation 4|nx|opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [],
    extra
  if (/trident/i.test(parts[1])) {
    extra = /\brv[ :]+(\d+)/g.exec(ua) || []
    return { name: 'IE', version: parseInt(extra[1] || '') }
  } else if (parts[1] === 'Chrome' ) {
    extra = ua.match(/\bOPR\/(\d+)/)
    if (extra != null) {
      return { name:'Opera', version: parseInt(extra[1]) }
    }
  }
  parts = parts[2] ? [parts[1], parts[2]] : [navigator.appName, navigator.appVersion, '-?']

  if ((extra = ua.match(/version\/(\d+)/i))) {
    parts.splice(1, 1, extra[1])
  }
  return { name: parts[0], version: parseInt(parts[1]) }
}

const browserInfo = getBrowserInfo()

Browser.isSafari = /safari/i.test(navigator.userAgent) && navigator.userAgent.indexOf('Chrome') === -1
Browser.isChrome = /chrome/i.test(navigator.userAgent) || /CriOS/i.test(navigator.userAgent)
Browser.isFirefox = /firefox/i.test(navigator.userAgent)
Browser.isLegacyIE = !!(window.ActiveXObject)
Browser.isIE = Browser.isLegacyIE || /trident.*rv:1\d/i.test(navigator.userAgent)
Browser.isIE11 = /trident.*rv:11/i.test(navigator.userAgent)
Browser.isChromecast = Browser.isChrome && /CrKey/i.test(navigator.userAgent)
Browser.isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone|IEMobile|Opera Mini/i.test(navigator.userAgent)
Browser.isiOS = /iPad|iPhone|iPod/i.test(navigator.userAgent)
Browser.isAndroid = /Android/i.test(navigator.userAgent)
Browser.isWindowsPhone = /Windows Phone/i.test(navigator.userAgent)
Browser.isWin8App = /MSAppHost/i.test(navigator.userAgent)
Browser.isWiiU = /WiiU/i.test(navigator.userAgent)
Browser.isPS4 = /PlayStation 4/i.test(navigator.userAgent)
Browser.hasLocalstorage = hasLocalstorage()
Browser.hasFlash = hasFlash()

Browser.name = browserInfo.name
Browser.version = browserInfo.version

export default Browser
<commit_msg>refactor(browser): simplify isChrome regex<commit_after>// Copyright 2014 Globo.com Player authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

const Browser = {}

const hasLocalstorage = function(){
  try {
    localStorage.setItem('clappr', 'clappr')
    localStorage.removeItem('clappr')
    return true
  } catch(e) {
    return false
  }
}

const hasFlash = function() {
  try {
    const fo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash')
    return !!fo
  } catch (e) {
    return !!(navigator.mimeTypes && navigator.mimeTypes['application/x-shockwave-flash'] !== undefined &&
        navigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin)
  }
}

const getBrowserInfo = function() {
  const ua = navigator.userAgent
  let parts = ua.match(/\b(playstation 4|nx|opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [],
    extra
  if (/trident/i.test(parts[1])) {
    extra = /\brv[ :]+(\d+)/g.exec(ua) || []
    return { name: 'IE', version: parseInt(extra[1] || '') }
  } else if (parts[1] === 'Chrome' ) {
    extra = ua.match(/\bOPR\/(\d+)/)
    if (extra != null) {
      return { name:'Opera', version: parseInt(extra[1]) }
    }
  }
  parts = parts[2] ? [parts[1], parts[2]] : [navigator.appName, navigator.appVersion, '-?']

  if ((extra = ua.match(/version\/(\d+)/i))) {
    parts.splice(1, 1, extra[1])
  }
  return { name: parts[0], version: parseInt(parts[1]) }
}

const browserInfo = getBrowserInfo()

Browser.isSafari = /safari/i.test(navigator.userAgent) && navigator.userAgent.indexOf('Chrome') === -1
Browser.isChrome = /chrome|CriOS/i.test(navigator.userAgent)
Browser.isFirefox = /firefox/i.test(navigator.userAgent)
Browser.isLegacyIE = !!(window.ActiveXObject)
Browser.isIE = Browser.isLegacyIE || /trident.*rv:1\d/i.test(navigator.userAgent)
Browser.isIE11 = /trident.*rv:11/i.test(navigator.userAgent)
Browser.isChromecast = Browser.isChrome && /CrKey/i.test(navigator.userAgent)
Browser.isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone|IEMobile|Opera Mini/i.test(navigator.userAgent)
Browser.isiOS = /iPad|iPhone|iPod/i.test(navigator.userAgent)
Browser.isAndroid = /Android/i.test(navigator.userAgent)
Browser.isWindowsPhone = /Windows Phone/i.test(navigator.userAgent)
Browser.isWin8App = /MSAppHost/i.test(navigator.userAgent)
Browser.isWiiU = /WiiU/i.test(navigator.userAgent)
Browser.isPS4 = /PlayStation 4/i.test(navigator.userAgent)
Browser.hasLocalstorage = hasLocalstorage()
Browser.hasFlash = hasFlash()

Browser.name = browserInfo.name
Browser.version = browserInfo.version

export default Browser
<|endoftext|>