<commit_before>import React, { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom';
import Pane from './Pane';
import Resizer from './Resizer';

class SplitPane extends Component {
    constructor(...args) {
        super(...args);

        this.onMouseDown = this.onMouseDown.bind(this);
        this.onTouchStart = this.onTouchStart.bind(this);
        this.onMouseMove = this.onMouseMove.bind(this);
        this.onTouchMove = this.onTouchMove.bind(this);
        this.onMouseUp = this.onMouseUp.bind(this);

        this.state = {
            active: false,
            resized: false,
        };
    }

    componentDidMount() {
        this.setSize(this.props, this.state);
        document.addEventListener('mouseup', this.onMouseUp);
        document.addEventListener('mousemove', this.onMouseMove);
        document.addEventListener('touchmove', this.onTouchMove);
    }

    componentWillReceiveProps(props) {
        this.setSize(props, this.state);
    }

    componentWillUnmount() {
        document.removeEventListener('mouseup', this.onMouseUp);
        document.removeEventListener('touchend', this.onMouseUp);
        document.removeEventListener('mousemove', this.onMouseMove);
        document.removeEventListener('touchmove', this.onTouchMove);
    }

    onMouseDown(event) {
        event.touches = [{clientX: event.clientX, clientY: event.clientY}];
        this.onTouchStart(event);
    }

    onTouchStart(event) {
        console.log('here');
        if (this.props.allowResize && !this.props.size) {
            this.unFocus();
            const position = this.props.split === 'vertical' ? event.touches[0].clientX : event.touches[0].clientY;
            if (typeof this.props.onDragStarted === 'function') {
                this.props.onDragStarted();
            }
            this.setState({
                active: true,
                position,
            });
        }
    }

    onMouseMove(event) {
        event.touches = [{clientX: event.clientX, clientY: event.clientY}];
        this.onTouchMove(event);
    }

    onTouchMove(event) {
        if (this.props.allowResize && !this.props.size) {
            if (this.state.active) {
                this.unFocus();
                const isPrimaryFirst = this.props.primary === 'first';
                const ref = isPrimaryFirst ? this.pane1 : this.pane2;
                if (ref) {
                    const node = ReactDOM.findDOMNode(ref);

                    if (node.getBoundingClientRect) {
                        const width = node.getBoundingClientRect().width;
                        const height = node.getBoundingClientRect().height;
                        const current = this.props.split === 'vertical' ? event.touches[0].clientX : event.touches[0].clientY;
                        const size = this.props.split === 'vertical' ? width : height;
                        const position = this.state.position;
                        const newPosition = isPrimaryFirst ? (position - current) : (current - position);

                        let maxSize = this.props.maxSize;
                        if ((this.props.maxSize !== undefined) && (this.props.maxSize <= 0)) {
                            const splPane = this.splitPane;
                            if (this.props.split === 'vertical') {
                                maxSize = splPane.getBoundingClientRect().width + this.props.maxSize;
                            } else {
                                maxSize = splPane.getBoundingClientRect().height + this.props.maxSize;
                            }
                        }

                        let newSize = size - newPosition;

                        if (newSize < this.props.minSize) {
                            newSize = this.props.minSize;
                        } else if ((this.props.maxSize !== undefined) && (newSize > maxSize)) {
                            newSize = maxSize;
                        } else {
                            this.setState({
                                position: current,
                                resized: true,
                            });
                        }

                        if (this.props.onChange) {
                            this.props.onChange(newSize);
                        }
                        this.setState({
                            draggedSize: newSize,
                        });
                        ref.setState({
                            size: newSize,
                        });
                    }
                }
            }
        }
    }

    onMouseUp() {
        if (this.props.allowResize && !this.props.size) {
            if (this.state.active) {
                if (typeof this.props.onDragFinished === 'function') {
                    this.props.onDragFinished();
                }
                this.setState({
                    active: false,
                });
            }
        }
    }

    setSize(props, state) {
        const ref = this.props.primary === 'first' ? this.pane1 : this.pane2;
        let newSize;
        if (ref) {
            newSize = props.size || (state && state.draggedSize) || props.defaultSize || props.minSize;
            ref.setState({
                size: newSize,
            });
        }
    }

    unFocus() {
        if (document.selection) {
            document.selection.empty();
        } else {
            window.getSelection().removeAllRanges();
        }
    }

    render() {
        const { split, allowResize } = this.props;
        const disabledClass = allowResize ? '' : 'disabled';

        const style = Object.assign({},
            this.props.style || {}, {
                display: 'flex',
                flex: 1,
                position: 'relative',
                outline: 'none',
                overflow: 'hidden',
                MozUserSelect: 'text',
                WebkitUserSelect: 'text',
                msUserSelect: 'text',
                userSelect: 'text',
            });

        if (split === 'vertical') {
            Object.assign(style, {
                flexDirection: 'row',
                height: '100%',
                position: 'absolute',
                left: 0,
                right: 0,
            });
        } else {
            Object.assign(style, {
                flexDirection: 'column',
                height: '100%',
                minHeight: '100%',
                position: 'absolute',
                top: 0,
                bottom: 0,
                width: '100%',
            });
        }

        const children = this.props.children;
        const classes = ['SplitPane', this.props.className, split, disabledClass];

        const pane1Style = Object.assign({}, this.props.paneStyle || {}, this.props.pane1Style || {});
        const pane2Style = Object.assign({}, this.props.paneStyle || {}, this.props.pane2Style || {});

        return (

 { this.splitPane = node; }}>

                <Pane
                    ref={node => { this.pane1 = node; }}
                    key="pane1" className="Pane1"
                    style={pane1Style}
                    split={split}
                >
                    {children[0]}
                </Pane>
                <Resizer
                    ref={node => { this.resizer = node; }}
                    key="resizer"
                    className={disabledClass}
                    onMouseDown={this.onMouseDown}
                    onTouchStart={this.onTouchStart}
                    style={this.props.resizerStyle || {}}
                    split={split}
                />
                <Pane
                    ref={node => { this.pane2 = node; }}
                    key="pane2"
                    className="Pane2"
                    style={pane2Style}
                    split={split}
                >
                    {children[1]}
                </Pane>

        );
    }
}

SplitPane.propTypes = {
    primary: PropTypes.oneOf(['first', 'second']),
    minSize: PropTypes.oneOfType([
        React.PropTypes.string,
        React.PropTypes.number,
    ]),
    maxSize: PropTypes.oneOfType([
        React.PropTypes.string,
        React.PropTypes.number,
    ]),
    defaultSize: PropTypes.oneOfType([
        React.PropTypes.string,
        React.PropTypes.number,
    ]),
    size: PropTypes.oneOfType([
        React.PropTypes.string,
        React.PropTypes.number,
    ]),
    allowResize: PropTypes.bool,
    split: PropTypes.oneOf(['vertical', 'horizontal']),
    onDragStarted: PropTypes.func,
    onDragFinished: PropTypes.func,
    onChange: PropTypes.func,
    style: PropTypes.object,
    resizerStyle: PropTypes.object,
    paneStyle: PropTypes.object,
    pane1Style: PropTypes.object,
    pane2Style: PropTypes.object,
    className: PropTypes.string,
    children: PropTypes.arrayOf(PropTypes.node).isRequired,
};

SplitPane.defaultProps = {
    split: 'vertical',
    minSize: 50,
    allowResize: true,
    primary: 'first',
};

export default SplitPane;
<commit_msg>removed console.log<commit_after>import React, { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom';
import Pane from './Pane';
import Resizer from './Resizer';

class SplitPane extends Component {
    constructor(...args) {
        super(...args);

        this.onMouseDown = this.onMouseDown.bind(this);
        this.onTouchStart = this.onTouchStart.bind(this);
        this.onMouseMove = this.onMouseMove.bind(this);
        this.onTouchMove = this.onTouchMove.bind(this);
        this.onMouseUp = this.onMouseUp.bind(this);

        this.state = {
            active: false,
            resized: false,
        };
    }

    componentDidMount() {
        this.setSize(this.props, this.state);
        document.addEventListener('mouseup', this.onMouseUp);
        document.addEventListener('mousemove', this.onMouseMove);
        document.addEventListener('touchmove', this.onTouchMove);
    }

    componentWillReceiveProps(props) {
        this.setSize(props, this.state);
    }

    componentWillUnmount() {
        document.removeEventListener('mouseup', this.onMouseUp);
        document.removeEventListener('touchend', this.onMouseUp);
        document.removeEventListener('mousemove', this.onMouseMove);
        document.removeEventListener('touchmove', this.onTouchMove);
    }

    onMouseDown(event) {
        event.touches = [{clientX: event.clientX, clientY: event.clientY}];
        this.onTouchStart(event);
    }

    onTouchStart(event) {
        if (this.props.allowResize && !this.props.size) {
            this.unFocus();
            const position = this.props.split === 'vertical' ? event.touches[0].clientX : event.touches[0].clientY;
            if (typeof this.props.onDragStarted === 'function') {
                this.props.onDragStarted();
            }
            this.setState({
                active: true,
                position,
            });
        }
    }

    onMouseMove(event) {
        event.touches = [{clientX: event.clientX, clientY: event.clientY}];
        this.onTouchMove(event);
    }

    onTouchMove(event) {
        if (this.props.allowResize && !this.props.size) {
            if (this.state.active) {
                this.unFocus();
                const isPrimaryFirst = this.props.primary === 'first';
                const ref = isPrimaryFirst ? this.pane1 : this.pane2;
                if (ref) {
                    const node = ReactDOM.findDOMNode(ref);

                    if (node.getBoundingClientRect) {
                        const width = node.getBoundingClientRect().width;
                        const height = node.getBoundingClientRect().height;
                        const current = this.props.split === 'vertical' ? event.touches[0].clientX : event.touches[0].clientY;
                        const size = this.props.split === 'vertical' ? width : height;
                        const position = this.state.position;
                        const newPosition = isPrimaryFirst ? (position - current) : (current - position);

                        let maxSize = this.props.maxSize;
                        if ((this.props.maxSize !== undefined) && (this.props.maxSize <= 0)) {
                            const splPane = this.splitPane;
                            if (this.props.split === 'vertical') {
                                maxSize = splPane.getBoundingClientRect().width + this.props.maxSize;
                            } else {
                                maxSize = splPane.getBoundingClientRect().height + this.props.maxSize;
                            }
                        }

                        let newSize = size - newPosition;

                        if (newSize < this.props.minSize) {
                            newSize = this.props.minSize;
                        } else if ((this.props.maxSize !== undefined) && (newSize > maxSize)) {
                            newSize = maxSize;
                        } else {
                            this.setState({
                                position: current,
                                resized: true,
                            });
                        }

                        if (this.props.onChange) {
                            this.props.onChange(newSize);
                        }
                        this.setState({
                            draggedSize: newSize,
                        });
                        ref.setState({
                            size: newSize,
                        });
                    }
                }
            }
        }
    }

    onMouseUp() {
        if (this.props.allowResize && !this.props.size) {
            if (this.state.active) {
                if (typeof this.props.onDragFinished === 'function') {
                    this.props.onDragFinished();
                }
                this.setState({
                    active: false,
                });
            }
        }
    }

    setSize(props, state) {
        const ref = this.props.primary === 'first' ? this.pane1 : this.pane2;
        let newSize;
        if (ref) {
            newSize = props.size || (state && state.draggedSize) || props.defaultSize || props.minSize;
            ref.setState({
                size: newSize,
            });
        }
    }

    unFocus() {
        if (document.selection) {
            document.selection.empty();
        } else {
            window.getSelection().removeAllRanges();
        }
    }

    render() {
        const { split, allowResize } = this.props;
        const disabledClass = allowResize ? '' : 'disabled';

        const style = Object.assign({},
            this.props.style || {}, {
                display: 'flex',
                flex: 1,
                position: 'relative',
                outline: 'none',
                overflow: 'hidden',
                MozUserSelect: 'text',
                WebkitUserSelect: 'text',
                msUserSelect: 'text',
                userSelect: 'text',
            });

        if (split === 'vertical') {
            Object.assign(style, {
                flexDirection: 'row',
                height: '100%',
                position: 'absolute',
                left: 0,
                right: 0,
            });
        } else {
            Object.assign(style, {
                flexDirection: 'column',
                height: '100%',
                minHeight: '100%',
                position: 'absolute',
                top: 0,
                bottom: 0,
                width: '100%',
            });
        }

        const children = this.props.children;
        const classes = ['SplitPane', this.props.className, split, disabledClass];

        const pane1Style = Object.assign({}, this.props.paneStyle || {}, this.props.pane1Style || {});
        const pane2Style = Object.assign({}, this.props.paneStyle || {}, this.props.pane2Style || {});

        return (

 { this.splitPane = node; }}>

                <Pane
                    ref={node => { this.pane1 = node; }}
                    key="pane1" className="Pane1"
                    style={pane1Style}
                    split={split}
                >
                    {children[0]}
                </Pane>
                <Resizer
                    ref={node => { this.resizer = node; }}
                    key="resizer"
                    className={disabledClass}
                    onMouseDown={this.onMouseDown}
                    onTouchStart={this.onTouchStart}
                    style={this.props.resizerStyle || {}}
                    split={split}
                />
                <Pane
                    ref={node => { this.pane2 = node; }}
                    key="pane2"
                    className="Pane2"
                    style={pane2Style}
                    split={split}
                >
                    {children[1]}
                </Pane>

        );
    }
}

SplitPane.propTypes = {
    primary: PropTypes.oneOf(['first', 'second']),
    minSize: PropTypes.oneOfType([
        React.PropTypes.string,
        React.PropTypes.number,
    ]),
    maxSize: PropTypes.oneOfType([
        React.PropTypes.string,
        React.PropTypes.number,
    ]),
    defaultSize: PropTypes.oneOfType([
        React.PropTypes.string,
        React.PropTypes.number,
    ]),
    size: PropTypes.oneOfType([
        React.PropTypes.string,
        React.PropTypes.number,
    ]),
    allowResize: PropTypes.bool,
    split: PropTypes.oneOf(['vertical', 'horizontal']),
    onDragStarted: PropTypes.func,
    onDragFinished: PropTypes.func,
    onChange: PropTypes.func,
    style: PropTypes.object,
    resizerStyle: PropTypes.object,
    paneStyle: PropTypes.object,
    pane1Style: PropTypes.object,
    pane2Style: PropTypes.object,
    className: PropTypes.string,
    children: PropTypes.arrayOf(PropTypes.node).isRequired,
};

SplitPane.defaultProps = {
    split: 'vertical',
    minSize: 50,
    allowResize: true,
    primary: 'first',
};

export default SplitPane;
<|endoftext|>


<commit_before>module.exports = {
  'plugins': [
    'jsx-a11y',
    'react'
  ],
  'ecmaFeatures': {
    'jsx': true
  },
  // View link below for react rules documentation
  // https://github.com/yannickcr/eslint-plugin-react#list-of-supported-rules
  'rules': {
    // Prevent use of `accessKey`
    // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-access-key.md
    'jsx-a11y/no-access-key': 2,

    // Require <img> to have a non-empty `alt` prop, or role="presentation"
    // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/img-uses-alt.md
    'jsx-a11y/img-uses-alt': 2,

    // Prevent img alt text from containing redundant words like "image", "picture", or "photo"
    // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/redundant-alt.md
    'jsx-a11y/redundant-alt': 2,

    // Require ARIA roles to be valid and non-abstract
    // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/valid-aria-role.md
    'jsx-a11y/valid-aria-role': 2,

    // Prevent missing displayName in a React component definition
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/display-name.md
    'react/display-name': [0, { 'ignoreTranspilerName': false }],
    // Forbid certain propTypes (any, array, object)
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/forbid-prop-types.md
    'react/forbid-prop-types': [0, { 'forbid': ['any', 'array', 'object'] }],
    // Enforce boolean attributes notation in JSX
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md
    'react/jsx-boolean-value': [2, 'never'],
    // Validate closing bracket location in JSX
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md
    'react/jsx-closing-bracket-location': [2, 'line-aligned'],
    // Enforce or disallow spaces inside of curly braces in JSX attributes
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-curly-spacing.md
    'react/jsx-curly-spacing': [0, 'never', { 'allowMultiline': true }],
    // Enforce event handler naming conventions in JSX
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-handler-names.md
    'react/jsx-handler-names': [0, {
      'eventHandlerPrefix': 'handle',
      'eventHandlerPropPrefix': 'on',
    }],
    // Validate props indentation in JSX
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-indent-props.md
    'react/jsx-indent-props': [2, 2],
    // Validate JSX has key prop when in array or iterator
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-key.md
    'react/jsx-key': 0,
    // Limit maximum of props on a single line in JSX
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-max-props-per-line.md
    'react/jsx-max-props-per-line': [0, { 'maximum': 1 }],
    // Prevent usage of .bind() and arrow functions in JSX props
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md
    'react/jsx-no-bind': [2, {
      'ignoreRefs': true,
      'allowArrowFunctions': true,
      'allowBind': false,
    }],
    // Prevent duplicate props in JSX
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-duplicate-props.md
    'react/jsx-no-duplicate-props': [0, { 'ignoreCase': false }],
    // Prevent usage of unwrapped JSX strings
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-literals.md
    'react/jsx-no-literals': 0,
    // Disallow undeclared variables in JSX
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-undef.md
    'react/jsx-no-undef': 2,
    // Enforce PascalCase for user-defined JSX components
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md
    'react/jsx-pascal-case': 0,
    // Enforce propTypes declarations alphabetical sorting
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-prop-types.md
    'react/sort-prop-types': [0, {
      'ignoreCase': false,
      'callbacksLast': false,
    }],
    // Enforce props alphabetical sorting
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-sort-props.md
    'react/jsx-sort-props': [0, {
      'ignoreCase': false,
      'callbacksLast': false,
    }],
    // Prevent React to be incorrectly marked as unused
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-uses-react.md
    'react/jsx-uses-react': [2, { 'pragma': 'React' }],
    // Prevent variables used in JSX to be incorrectly marked as unused
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-uses-vars.md
    'react/jsx-uses-vars': 2,
    // Prevent usage of dangerous JSX properties
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-danger.md
    'react/no-danger': 0,
    // Prevent usage of deprecated methods
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-deprecated.md
    'react/no-deprecated': [1, { 'react': '0.14.0' }],
    // Prevent usage of setState in componentDidMount
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-mount-set-state.md
    'react/no-did-mount-set-state': [2, 'allow-in-func'],
    // Prevent usage of setState in componentDidUpdate
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-update-set-state.md
    'react/no-did-update-set-state': [2, 'allow-in-func'],
    // Prevent direct mutation of this.state
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-direct-mutation-state.md
    'react/no-direct-mutation-state': 0,
    // Prevent usage of isMounted
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-is-mounted.md
    'react/no-is-mounted': 2,
    // Prevent multiple component definition per file
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-multi-comp.md
    'react/no-multi-comp': [2, { 'ignoreStateless': true }],
    // Prevent usage of setState
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-set-state.md
    'react/no-set-state': 0,
    // Prevent using string references
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-string-refs.md
    'react/no-string-refs': 0,
    // Prevent usage of unknown DOM property
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-unknown-property.md
    'react/no-unknown-property': 2,
    // Require ES6 class declarations over React.createClass
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md
    'react/prefer-es6-class': [2, 'always'],
    // Require stateless functions when not using lifecycle methods, setState or ref
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-stateless-function.md
    'react/prefer-stateless-function': 2,
    // Prevent missing props validation in a React component definition
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prop-types.md
    'react/prop-types': [2, { 'ignore': [], 'customValidators': [] }],
    // Prevent missing React when using JSX
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/react-in-jsx-scope.md
    'react/react-in-jsx-scope': 2,
    // Restrict file extensions that may be required
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/require-extension.md
    'react/require-extension': [0, { 'extensions': ['.jsx'] }],
    // Prevent extra closing tags for components without children
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md
    'react/self-closing-comp': 2,
    // Enforce spaces before the closing bracket of self-closing JSX elements
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-space-before-closing.md
    'react/jsx-space-before-closing': [2, 'always'],
    // Enforce component methods order
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-comp.md
    'react/sort-comp': [2, {
      'order': [
        'static-methods',
        'lifecycle',
        '/^on.+$/',
        '/^(get|set)(?!(InitialState$|DefaultProps$|ChildContext$)).+$/',
        'everything-else',
        '/^render.+$/',
        'render'
      ]
    }],
    // Prevent missing parentheses around multilines JSX
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/wrap-multilines.md
    'react/wrap-multilines': [2, {
      declaration: true,
      assignment: true,
      return: true
    }],
  }
};
<commit_msg>[eslint config] [semver-minor] enable `jsx-pascal-case` rule.<commit_after>module.exports = {
  'plugins': [
    'jsx-a11y',
    'react'
  ],
  'ecmaFeatures': {
    'jsx': true
  },
  // View link below for react rules documentation
  // https://github.com/yannickcr/eslint-plugin-react#list-of-supported-rules
  'rules': {
    // Prevent use of `accessKey`
    // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-access-key.md
    'jsx-a11y/no-access-key': 2,

    // Require <img> to have a non-empty `alt` prop, or role="presentation"
    // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/img-uses-alt.md
    'jsx-a11y/img-uses-alt': 2,

    // Prevent img alt text from containing redundant words like "image", "picture", or "photo"
    // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/redundant-alt.md
    'jsx-a11y/redundant-alt': 2,

    // Require ARIA roles to be valid and non-abstract
    // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/valid-aria-role.md
    'jsx-a11y/valid-aria-role': 2,

    // Prevent missing displayName in a React component definition
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/display-name.md
    'react/display-name': [0, { 'ignoreTranspilerName': false }],
    // Forbid certain propTypes (any, array, object)
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/forbid-prop-types.md
    'react/forbid-prop-types': [0, { 'forbid': ['any', 'array', 'object'] }],
    // Enforce boolean attributes notation in JSX
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md
    'react/jsx-boolean-value': [2, 'never'],
    // Validate closing bracket location in JSX
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md
    'react/jsx-closing-bracket-location': [2, 'line-aligned'],
    // Enforce or disallow spaces inside of curly braces in JSX attributes
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-curly-spacing.md
    'react/jsx-curly-spacing': [0, 'never', { 'allowMultiline': true }],
    // Enforce event handler naming conventions in JSX
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-handler-names.md
    'react/jsx-handler-names': [0, {
      'eventHandlerPrefix': 'handle',
      'eventHandlerPropPrefix': 'on',
    }],
    // Validate props indentation in JSX
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-indent-props.md
    'react/jsx-indent-props': [2, 2],
    // Validate JSX has key prop when in array or iterator
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-key.md
    'react/jsx-key': 0,
    // Limit maximum of props on a single line in JSX
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-max-props-per-line.md
    'react/jsx-max-props-per-line': [0, { 'maximum': 1 }],
    // Prevent usage of .bind() and arrow functions in JSX props
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md
    'react/jsx-no-bind': [2, {
      'ignoreRefs': true,
      'allowArrowFunctions': true,
      'allowBind': false,
    }],
    // Prevent duplicate props in JSX
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-duplicate-props.md
    'react/jsx-no-duplicate-props': [0, { 'ignoreCase': false }],
    // Prevent usage of unwrapped JSX strings
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-literals.md
    'react/jsx-no-literals': 0,
    // Disallow undeclared variables in JSX
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-undef.md
    'react/jsx-no-undef': 2,
    // Enforce PascalCase for user-defined JSX components
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md
    'react/jsx-pascal-case': 2,
    // Enforce propTypes declarations alphabetical sorting
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-prop-types.md
    'react/sort-prop-types': [0, {
      'ignoreCase': false,
      'callbacksLast': false,
    }],
    // Enforce props alphabetical sorting
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-sort-props.md
    'react/jsx-sort-props': [0, {
      'ignoreCase': false,
      'callbacksLast': false,
    }],
    // Prevent React to be incorrectly marked as unused
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-uses-react.md
    'react/jsx-uses-react': [2, { 'pragma': 'React' }],
    // Prevent variables used in JSX to be incorrectly marked as unused
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-uses-vars.md
    'react/jsx-uses-vars': 2,
    // Prevent usage of dangerous JSX properties
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-danger.md
    'react/no-danger': 0,
    // Prevent usage of deprecated methods
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-deprecated.md
    'react/no-deprecated': [1, { 'react': '0.14.0' }],
    // Prevent usage of setState in componentDidMount
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-mount-set-state.md
    'react/no-did-mount-set-state': [2, 'allow-in-func'],
    // Prevent usage of setState in componentDidUpdate
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-update-set-state.md
    'react/no-did-update-set-state': [2, 'allow-in-func'],
    // Prevent direct mutation of this.state
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-direct-mutation-state.md
    'react/no-direct-mutation-state': 0,
    // Prevent usage of isMounted
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-is-mounted.md
    'react/no-is-mounted': 2,
    // Prevent multiple component definition per file
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-multi-comp.md
    'react/no-multi-comp': [2, { 'ignoreStateless': true }],
    // Prevent usage of setState
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-set-state.md
    'react/no-set-state': 0,
    // Prevent using string references
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-string-refs.md
    'react/no-string-refs': 0,
    // Prevent usage of unknown DOM property
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-unknown-property.md
    'react/no-unknown-property': 2,
    // Require ES6 class declarations over React.createClass
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md
    'react/prefer-es6-class': [2, 'always'],
    // Require stateless functions when not using lifecycle methods, setState or ref
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-stateless-function.md
    'react/prefer-stateless-function': 2,
    // Prevent missing props validation in a React component definition
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prop-types.md
    'react/prop-types': [2, { 'ignore': [], 'customValidators': [] }],
    // Prevent missing React when using JSX
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/react-in-jsx-scope.md
    'react/react-in-jsx-scope': 2,
    // Restrict file extensions that may be required
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/require-extension.md
    'react/require-extension': [0, { 'extensions': ['.jsx'] }],
    // Prevent extra closing tags for components without children
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md
    'react/self-closing-comp': 2,
    // Enforce spaces before the closing bracket of self-closing JSX elements
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-space-before-closing.md
    'react/jsx-space-before-closing': [2, 'always'],
    // Enforce component methods order
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-comp.md
    'react/sort-comp': [2, {
      'order': [
        'static-methods',
        'lifecycle',
        '/^on.+$/',
        '/^(get|set)(?!(InitialState$|DefaultProps$|ChildContext$)).+$/',
        'everything-else',
        '/^render.+$/',
        'render'
      ]
    }],
    // Prevent missing parentheses around multilines JSX
    // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/wrap-multilines.md
    'react/wrap-multilines': [2, {
      declaration: true,
      assignment: true,
      return: true
    }],
  }
};
<|endoftext|>


<commit_before>const templata = require('../index')
const mocha = require('mocha')
const chai = require('chai')
const expect = chai.expect

function run() {
    describe('Templata.Template', function () {
        describe('Templata.Template#Interpolation',
            function () {
                it('Interpolation should insert the given value to output buffer (external source)',
                    function () {
                        const template = '{{= local.value =}}'

                        expect(templata.template(template)({ value: 'example' })).to.equal('example')
                    }
                )

                it('Interpolation should insert the given value to output buffer (hard coded)',
                    function () {
                        const template = '{{= "example" =}}'

                        expect(templata.template(template)()).to.equal('example')
                    }
                )

                it('Interpolation should insert the given value to output buffer (internal source)',
                    function () {
                        const template = '{{= example =}}'

                        expect(templata.template(template, { example: 'example' })()).to.equal('example')
                    }
                )

                it('Interpolation should insert the given value to output buffer with given filter (lowercase)',
                    function () {
                        const template = '{{= "ExAmPle" | lowercase =}}'

                        expect(templata.template(template)()).to.equal('example')
                    }
                )

                it('Interpolation should insert the given value to output buffer with given filter (uppercase)',
                    function () {
                        const template = '{{= "ExAmPle" | uppercase =}}'

                        expect(templata.template(template)()).to.equal('EXAMPLE')
                    }
                )

                it('Interpolation should insert the given value to output buffer with given filter (currency using comma)',
                    function () {
                        const template = '{{= "00,99000" | currency =}}'

                        expect(templata.template(template)()).to.equal('0.99')
                    }
                )

                it('Interpolation should insert the given value to output buffer with given filter (currency using dot)',
                    function () {
                        const template = '{{= "00.99000" | currency =}}'

                        expect(templata.template(template)()).to.equal('0.99')
                    }
                )
            }
        )

        describe('Templata.Template#Conditional',
            function () {
                it('Conditional "if" should return given value',
                    function () {
                        const template = '{{? true ?}}if{{/?}}'

                        expect(templata.template(template)()).to.equal('if')
                    }
                )

                it('Conditional "if"-"else" should return given value',
                    function () {
                        const template = '{{? false ?}}if{{? ?}}else{{/?}}'

                        expect(templata.template(template)()).to.equal('else')
                    }
                )

                it('Conditional "elseif" should return given value',
                    function () {
                        const template = '{{? false ?}}if{{?? true ??}}elseif{{? ?}}else{{/?}}'

                        expect(templata.template(template)()).to.equal('elseif')
                    }
                )
            }
        )

        describe('Templata.Template#Iteration',
            function () {
                it('Iteration should iterate trough given array (print value)',
                    function () {
                        const template = '{{~ local.arr :value: ~}}{{= value =}}{{/~}}'

                        expect(templata.template(template)({ arr: [1, 2, 3, 4] })).to.equal('1234')
                    }
                )

                it('Iteration should iterate trough given array (print index)',
                    function () {
                        const template = '{{~ local.arr :value,key: ~}}{{= key =}}{{/~}}'

                        expect(templata.template(template)({ arr: [1, 2, 3, 4] })).to.equal('0123')
                    }
                )

                it('Iteration should iterate trough given object (print value)',
                    function () {
                        const template = '{{~ local.obj :value: ~}}{{= value =}}{{/~}}'

                        expect(templata.template(template)({ obj: { item_1: '#1', item_2: '#2', item_3: '#3' } }))
                            .to.equal('#1#2#3')
                    }
                )

                it('Iteration should iterate trough given object (print key)',
                    function () {
                        const template = '{{~ local.obj :value,key: ~}}{{= key =}}{{/~}}'

                        expect(templata.template(template)({ obj: { item_1: '#1', item_2: '#2', item_3: '#3' } }))
                            .to.equal('item_1item_2item_3')
                    }
                )
            }
        )

        describe('Templata.Template#JavaScript',
            function () {
                it('JavaScript should work with pure JavaScript (varible definition)',
                    function () {
                        const template = '{{- var varible = "var"; -}}{{= varible =}}'

                        expect(templata.template(template)())
                            .to.equal('var')
                    }
                )

                it('JavaScript should work with pure JavaScript (function definition)',
                    function () {
                        const template = '{{- function print(){ return "var"; } -}}{{= print() =}}'

                        expect(templata.template(template)())
                            .to.equal('var')
                    }
                )
            }
        )

        describe('Templata.Template#Comment',
            function () {
                it('Comment should not print value inside block (but everything around it)',
                    function () {
                        const template = 'outside{{* should not render *}}block'

                        expect(templata.template(template)())
                            .to.equal('outsideblock')
                    }
                )
            }
        )
    })
}

module.exports = run
<commit_msg>added Templata.Template#HTMLEncode spec<commit_after>const templata = require('../index')
const mocha = require('mocha')
const chai = require('chai')
const expect = chai.expect

function run() {
    describe('Templata.Template', function () {
        describe('Templata.Template#Interpolation',
            function () {
                it('Interpolation should insert the given value to output buffer (external source)',
                    function () {
                        const template = '{{= local.value =}}'

                        expect(templata.template(template)({ value: 'example' })).to.equal('example')
                    }
                )

                it('Interpolation should insert the given value to output buffer (hard coded)',
                    function () {
                        const template = '{{= "example" =}}'

                        expect(templata.template(template)()).to.equal('example')
                    }
                )

                it('Interpolation should insert the given value to output buffer (internal source)',
                    function () {
                        const template = '{{= example =}}'

                        expect(templata.template(template, { example: 'example' })()).to.equal('example')
                    }
                )

                it('Interpolation should insert the given value to output buffer with given filter (lowercase)',
                    function () {
                        const template = '{{= "ExAmPle" | lowercase =}}'

                        expect(templata.template(template)()).to.equal('example')
                    }
                )

                it('Interpolation should insert the given value to output buffer with given filter (uppercase)',
                    function () {
                        const template = '{{= "ExAmPle" | uppercase =}}'

                        expect(templata.template(template)()).to.equal('EXAMPLE')
                    }
                )

                it('Interpolation should insert the given value to output buffer with given filter (currency using comma)',
                    function () {
                        const template = '{{= "00,99000" | currency =}}'

                        expect(templata.template(template)()).to.equal('0.99')
                    }
                )

                it('Interpolation should insert the given value to output buffer with given filter (currency using dot)',
                    function () {
                        const template = '{{= "00.99000" | currency =}}'

                        expect(templata.template(template)()).to.equal('0.99')
                    }
                )
            }
        )

        describe('Templata.Template#Conditional',
            function () {
                it('Conditional "if" should return given value',
                    function () {
                        const template = '{{? true ?}}if{{/?}}'

                        expect(templata.template(template)()).to.equal('if')
                    }
                )

                it('Conditional "if"-"else" should return given value',
                    function () {
                        const template = '{{? false ?}}if{{? ?}}else{{/?}}'

                        expect(templata.template(template)()).to.equal('else')
                    }
                )

                it('Conditional "elseif" should return given value',
                    function () {
                        const template = '{{? false ?}}if{{?? true ??}}elseif{{? ?}}else{{/?}}'

                        expect(templata.template(template)()).to.equal('elseif')
                    }
                )
            }
        )

        describe('Templata.Template#Iteration',
            function () {
                it('Iteration should iterate trough given array (print value)',
                    function () {
                        const template = '{{~ local.arr :value: ~}}{{= value =}}{{/~}}'

                        expect(templata.template(template)({ arr: [1, 2, 3, 4] })).to.equal('1234')
                    }
                )

                it('Iteration should iterate trough given array (print index)',
                    function () {
                        const template = '{{~ local.arr :value,key: ~}}{{= key =}}{{/~}}'

                        expect(templata.template(template)({ arr: [1, 2, 3, 4] })).to.equal('0123')
                    }
                )

                it('Iteration should iterate trough given object (print value)',
                    function () {
                        const template = '{{~ local.obj :value: ~}}{{= value =}}{{/~}}'

                        expect(templata.template(template)({ obj: { item_1: '#1', item_2: '#2', item_3: '#3' } }))
                            .to.equal('#1#2#3')
                    }
                )

                it('Iteration should iterate trough given object (print key)',
                    function () {
                        const template = '{{~ local.obj :value,key: ~}}{{= key =}}{{/~}}'

                        expect(templata.template(template)({ obj: { item_1: '#1', item_2: '#2', item_3: '#3' } }))
                            .to.equal('item_1item_2item_3')
                    }
                )
            }
        )

        describe('Templata.Template#JavaScript',
            function () {
                it('JavaScript should work with pure JavaScript (varible definition)',
                    function () {
                        const template = '{{- var varible = "var"; -}}{{= varible =}}'

                        expect(templata.template(template)())
                            .to.equal('var')
                    }
                )

                it('JavaScript should work with pure JavaScript (function definition)',
                    function () {
                        const template = '{{- function print(){ return "var"; } -}}{{= print() =}}'

                        expect(templata.template(template)())
                            .to.equal('var')
                    }
                )
            }
        )

        describe('Templata.Template#Comment',
            function () {
                it('Comment should not print value inside block (but everything around it)',
                    function () {
                        const template = 'outside{{* should not render *}}block'

                        expect(templata.template(template)())
                            .to.equal('outsideblock')
                    }
                )
            }
        )

        describe('Templata.Template#HTMLEncode',
            function () {
                it('Should encode HTML String',
                    function () {
                        const template = '{{! "John White" !}}'

                        expect(templata.template(template)())
                            .to.equal('<span class='name'>John White</span>')
                    }
                )
            }
        )
    })
}

module.exports = run
<|endoftext|>


<commit_before>"use strict";

var crypto = require("crypto"),
    path = require("path"),
    url = require("url"),
    util = require("util");

var abaculus = require("abaculus"),
    cachecache = require("cachecache"),
    clone = require("clone"),
    debug = require("debug"),
    express = require("express"),
    handlebars = require("handlebars"),
    mercator = new (require("sphericalmercator"))();

var tessera = require("./index");

debug = debug("tessera");

var FLOAT_PATTERN = "[+-]?(?:\\d+|\\d+\.?\\d+)";
var SCALE_PATTERN = "@[23]x";

// TODO a more complete implementation of this exists...somewhere
var getExtension = function(format) {
  // trim PNG variant info
  switch ((format || "").replace(/^(png).*/, "$1")) {
  case "png":
    return "png";

  default:
    return format;
  }
};

var getScale = function(scale) {
  return (scale || "@1x").slice(1, 2) | 0;
};

var normalizeHeaders = function(headers) {
  var _headers = {};

  Object.keys(headers).forEach(function(x) {
    _headers[x.toLowerCase()] = headers[x];
  });

  return _headers;
};

var md5sum = function(data) {
  var hash = crypto.createHash("md5");
  hash.update(data);
  return hash.digest();
};

module.exports = function(tilelive, options) {
  var app = express().disable("x-powered-by").enable("trust proxy"),
      templates = {},
      uri = options,
      tilePath = "/{z}/{x}/{y}.{format}",
      sourceMaxZoom = null,
      tilePattern;

  app.use(cachecache());

  if (typeof options === "object") {
    uri = options.source;
    tilePath = options.tilePath || tilePath;

    if (options.sourceMaxZoom) {
      sourceMaxZoom = parseInt(options.sourceMaxZoom);
    }

    Object.keys(options.headers || {}).forEach(function(name) {
      templates[name] = handlebars.compile(options.headers[name]);

      // attempt to parse so we can fail fast
      try {
        templates[name]();
      } catch (e) {
        console.error("'%s' header is invalid:", name);
        console.error(e.message);
        process.exit(1);
      }
    });
  }

  if (typeof uri === "string") {
    uri = url.parse(uri, true);
  } else {
    uri = clone(uri);
  }

  tilePattern = tilePath
    .replace(/\.(?!.*\.)/, ":scale(" + SCALE_PATTERN + ")?.")
    .replace(/\./g, "\.")
    .replace("{z}", ":z(\\d+)")
    .replace("{x}", ":x(\\d+)")
    .replace("{y}", ":y(\\d+)")
    .replace("{format}", ":format([\\w\\.]+)");

  var populateHeaders = function(headers, params, extras) {
    Object.keys(extras || {}).forEach(function(k) {
      params[k] = extras[k];
    });

    Object.keys(templates).forEach(function(name) {
      var val = templates[name](params);

      if (val) {
        headers[name.toLowerCase()] = val;
      }
    });

    return headers;
  };

  // warm the cache
  tilelive.load(uri);

  var sourceURIs = {
    1: uri
  };

  [2, 3].forEach(function(scale) {
    var retinaURI = clone(uri);

    retinaURI.query.scale = scale;
    // explicitly tell tilelive-mapnik to use larger tiles
    retinaURI.query.tileSize = scale * 256;

    sourceURIs[scale] = retinaURI;
  });

  var getTile = function(z, x, y, scale, format, callback) {
    var sourceURI = sourceURIs[scale],
        params = {
          tile: {
            zoom: z,
            x: x,
            y: y,
            format: format,
            retina: scale > 1,
            scale: scale
          }
        };

    // Additional params for vector tile based sources
    if (sourceMaxZoom != null) {
      params.tile.sourceZoom = z;
      params.tile.sourceX = x;
      params.tile.sourceY = y;

      while (params.tile.sourceZoom > sourceMaxZoom) {
        params.tile.sourceZoom--;
        params.tile.sourceX = Math.floor(params.tile.sourceX / 2);
        params.tile.sourceY = Math.floor(params.tile.sourceY / 2);
      }
    }

    return tilelive.load(sourceURI, function(err, source) {
      if (err) {
        return callback(err);
      }

      return tessera.getInfo(source, function(err, info) {
        if (err) {
          return callback(err);
        }

        // validate format / extension
        var ext = getExtension(info.format);

        if (ext !== format) {
          debug("Invalid format '%s', expected '%s'", format, ext);
          return callback(null, null, populateHeaders({}, params, { 404: true, invalidFormat: true }));
        }

        // validate zoom
        if (z < info.minzoom || z > info.maxzoom) {
          debug("Invalid zoom:", z);
          return callback(null, null, populateHeaders({}, params, { 404: true, invalidZoom: true }));
        }

        // validate coords against bounds
        var xyz = mercator.xyz(info.bounds, z);

        if (x < xyz.minX ||
            x > xyz.maxX ||
            y < xyz.minY ||
            y > xyz.maxY) {
          debug("Invalid coordinates: %d,%d relative to bounds:", x, y, xyz);
          return callback(null, null, populateHeaders({}, params, { 404: true, invalidCoordinates: true }));
        }

        return source.getTile(z, x, y, function(err, data, headers) {
          headers = normalizeHeaders(headers || {});

          if (err) {
            if (err.message.match(/(Tile|Grid) does not exist/)) {
              return callback(null, null, populateHeaders(headers, params, { 404: true }));
            }

            return callback(err);
          }

          if (data === null || data === undefined) {
            return callback(null, null, populateHeaders(headers, params, { 404: true }));
          }

          if (!headers["content-md5"]) {
            headers["content-md5"] = md5sum(data).toString("base64");
          }

          // work-around for PBF MBTiles that don't contain appropriate headers
          if (ext === "pbf") {
            headers["content-type"] = headers["content-type"] || "application/x-protobuf";
            headers["content-encoding"] = headers["content-encoding"] || "gzip";
          }

          return callback(null, data, populateHeaders(headers, params, { 200: true }));
        });
      });
    });
  };

  app.get(tilePattern, function(req, res, next) {
    var z = req.params.z | 0,
        x = req.params.x | 0,
        y = req.params.y | 0,
        scale = getScale(req.params.scale),
        format = req.params.format;
    return getTile(z, x, y, scale, format, function(err, data, headers) {
        if (err) {
          return next(err);
        }
        if (data == null && format !== "pbf") {
          return res.status(404).send("Not found");
        } else {
          res.set(headers);
          return res.status(200).send(data);
        }
    }, res, next);
  });

  var processStaticMap = function(areaParams, req, res, next) {
    var scale = getScale(req.params.scale),
        format = req.params.format,
        params = {
          zoom: req.params.z | 0,
          scale: scale,
          bbox: areaParams.bbox,
          center: areaParams.center,
          format: format,
          getTile: function(z, x, y, callback) {
            return getTile(z, x, y, scale, format, function(err, data, headers) {
              if (!err && data == null) {
                err = new Error("Not found");
                err.status = 404;
              }
              callback(err, data, headers);
            });
          }
        };
    return abaculus(params, function(err, data, headers) {
      if (err && !err.status) {
        return next(err);
      }
      res.set(headers);
      res.status((err && err.status) || 200);
      return res.send((err && err.message) || data);
    });
  };

  var staticPattern = "/static/%s:scale(" + SCALE_PATTERN + ")?\.:format([\\w\\.]+)";

  var centerPattern = util.format(':lon(%s),:lat(%s),:z(\\d+)/:width(\\d+)x:height(\\d+)',
                                  FLOAT_PATTERN, FLOAT_PATTERN);

  app.get(util.format(staticPattern, centerPattern), function(req, res, next) {
    return processStaticMap({
      center: {
        x: +req.params.lon,
        y: +req.params.lat,
        w: req.params.width | 0,
        h: req.params.height | 0
      }
    }, req, res, next);
  });

  var boundsPattern = util.format(':minx(%s),:miny(%s),:maxx(%s),:maxy(%s)/:z(\\d+)',
                                  FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN);

  app.get(util.format(staticPattern, boundsPattern), function(req, res, next) {
    return processStaticMap({
      bbox: [
        +req.params.minx,
        +req.params.miny,
        +req.params.maxx,
        +req.params.maxy
      ]
    }, req, res, next);
  });

  app.get("/index.json", function(req, res, next) {
    var params = {
      tileJSON: true
    };

    return tilelive.load(uri, function(err, source) {
      if (err) {
        return next(err);
      }

      return tessera.getInfo(source, function(err, info) {
        if (err) {
          return next(err);
        }

        var protocol = req.headers['x-forwarded-proto'] || req.protocol;
        var uri = protocol + "://" + req.headers.host +
          (path.dirname(req.originalUrl) +
                         tilePath.replace("{format}",
                                          getExtension(info.format))).replace(/\/+/g, "/");

        info.tiles = [uri];
        info.tilejson = "2.0.0";

        res.set(populateHeaders({}, params, { 200: true }));
        return res.send(info);
      });
    });
  });

  return app;
};
<commit_msg>Use X-Forwarded-Host header, if provided<commit_after>"use strict";

var crypto = require("crypto"),
    path = require("path"),
    url = require("url"),
    util = require("util");

var abaculus = require("abaculus"),
    cachecache = require("cachecache"),
    clone = require("clone"),
    debug = require("debug"),
    express = require("express"),
    handlebars = require("handlebars"),
    mercator = new (require("sphericalmercator"))();

var tessera = require("./index");

debug = debug("tessera");

var FLOAT_PATTERN = "[+-]?(?:\\d+|\\d+\.?\\d+)";
var SCALE_PATTERN = "@[23]x";

// TODO a more complete implementation of this exists...somewhere
var getExtension = function(format) {
  // trim PNG variant info
  switch ((format || "").replace(/^(png).*/, "$1")) {
  case "png":
    return "png";

  default:
    return format;
  }
};

var getScale = function(scale) {
  return (scale || "@1x").slice(1, 2) | 0;
};

var normalizeHeaders = function(headers) {
  var _headers = {};

  Object.keys(headers).forEach(function(x) {
    _headers[x.toLowerCase()] = headers[x];
  });

  return _headers;
};

var md5sum = function(data) {
  var hash = crypto.createHash("md5");
  hash.update(data);
  return hash.digest();
};

module.exports = function(tilelive, options) {
  var app = express().disable("x-powered-by").enable("trust proxy"),
      templates = {},
      uri = options,
      tilePath = "/{z}/{x}/{y}.{format}",
      sourceMaxZoom = null,
      tilePattern;

  app.use(cachecache());

  if (typeof options === "object") {
    uri = options.source;
    tilePath = options.tilePath || tilePath;

    if (options.sourceMaxZoom) {
      sourceMaxZoom = parseInt(options.sourceMaxZoom);
    }

    Object.keys(options.headers || {}).forEach(function(name) {
      templates[name] = handlebars.compile(options.headers[name]);

      // attempt to parse so we can fail fast
      try {
        templates[name]();
      } catch (e) {
        console.error("'%s' header is invalid:", name);
        console.error(e.message);
        process.exit(1);
      }
    });
  }

  if (typeof uri === "string") {
    uri = url.parse(uri, true);
  } else {
    uri = clone(uri);
  }

  tilePattern = tilePath
    .replace(/\.(?!.*\.)/, ":scale(" + SCALE_PATTERN + ")?.")
    .replace(/\./g, "\.")
    .replace("{z}", ":z(\\d+)")
    .replace("{x}", ":x(\\d+)")
    .replace("{y}", ":y(\\d+)")
    .replace("{format}", ":format([\\w\\.]+)");

  var populateHeaders = function(headers, params, extras) {
    Object.keys(extras || {}).forEach(function(k) {
      params[k] = extras[k];
    });

    Object.keys(templates).forEach(function(name) {
      var val = templates[name](params);

      if (val) {
        headers[name.toLowerCase()] = val;
      }
    });

    return headers;
  };

  // warm the cache
  tilelive.load(uri);

  var sourceURIs = {
    1: uri
  };

  [2, 3].forEach(function(scale) {
    var retinaURI = clone(uri);

    retinaURI.query.scale = scale;
    // explicitly tell tilelive-mapnik to use larger tiles
    retinaURI.query.tileSize = scale * 256;

    sourceURIs[scale] = retinaURI;
  });

  var getTile = function(z, x, y, scale, format, callback) {
    var sourceURI = sourceURIs[scale],
        params = {
          tile: {
            zoom: z,
            x: x,
            y: y,
            format: format,
            retina: scale > 1,
            scale: scale
          }
        };

    // Additional params for vector tile based sources
    if (sourceMaxZoom != null) {
      params.tile.sourceZoom = z;
      params.tile.sourceX = x;
      params.tile.sourceY = y;

      while (params.tile.sourceZoom > sourceMaxZoom) {
        params.tile.sourceZoom--;
        params.tile.sourceX = Math.floor(params.tile.sourceX / 2);
        params.tile.sourceY = Math.floor(params.tile.sourceY / 2);
      }
    }

    return tilelive.load(sourceURI, function(err, source) {
      if (err) {
        return callback(err);
      }

      return tessera.getInfo(source, function(err, info) {
        if (err) {
          return callback(err);
        }

        // validate format / extension
        var ext = getExtension(info.format);

        if (ext !== format) {
          debug("Invalid format '%s', expected '%s'", format, ext);
          return callback(null, null, populateHeaders({}, params, { 404: true, invalidFormat: true }));
        }

        // validate zoom
        if (z < info.minzoom || z > info.maxzoom) {
          debug("Invalid zoom:", z);
          return callback(null, null, populateHeaders({}, params, { 404: true, invalidZoom: true }));
        }

        // validate coords against bounds
        var xyz = mercator.xyz(info.bounds, z);

        if (x < xyz.minX ||
            x > xyz.maxX ||
            y < xyz.minY ||
            y > xyz.maxY) {
          debug("Invalid coordinates: %d,%d relative to bounds:", x, y, xyz);
          return callback(null, null, populateHeaders({}, params, { 404: true, invalidCoordinates: true }));
        }

        return source.getTile(z, x, y, function(err, data, headers) {
          headers = normalizeHeaders(headers || {});

          if (err) {
            if (err.message.match(/(Tile|Grid) does not exist/)) {
              return callback(null, null, populateHeaders(headers, params, { 404: true }));
            }

            return callback(err);
          }

          if (data === null || data === undefined) {
            return callback(null, null, populateHeaders(headers, params, { 404: true }));
          }

          if (!headers["content-md5"]) {
            headers["content-md5"] = md5sum(data).toString("base64");
          }

          // work-around for PBF MBTiles that don't contain appropriate headers
          if (ext === "pbf") {
            headers["content-type"] = headers["content-type"] || "application/x-protobuf";
            headers["content-encoding"] = headers["content-encoding"] || "gzip";
          }

          return callback(null, data, populateHeaders(headers, params, { 200: true }));
        });
      });
    });
  };

  app.get(tilePattern, function(req, res, next) {
    var z = req.params.z | 0,
        x = req.params.x | 0,
        y = req.params.y | 0,
        scale = getScale(req.params.scale),
        format = req.params.format;
    return getTile(z, x, y, scale, format, function(err, data, headers) {
        if (err) {
          return next(err);
        }
        if (data == null && format !== "pbf") {
          return res.status(404).send("Not found");
        } else {
          res.set(headers);
          return res.status(200).send(data);
        }
    }, res, next);
  });

  var processStaticMap = function(areaParams, req, res, next) {
    var scale = getScale(req.params.scale),
        format = req.params.format,
        params = {
          zoom: req.params.z | 0,
          scale: scale,
          bbox: areaParams.bbox,
          center: areaParams.center,
          format: format,
          getTile: function(z, x, y, callback) {
            return getTile(z, x, y, scale, format, function(err, data, headers) {
              if (!err && data == null) {
                err = new Error("Not found");
                err.status = 404;
              }
              callback(err, data, headers);
            });
          }
        };
    return abaculus(params, function(err, data, headers) {
      if (err && !err.status) {
        return next(err);
      }
      res.set(headers);
      res.status((err && err.status) || 200);
      return res.send((err && err.message) || data);
    });
  };

  var staticPattern = "/static/%s:scale(" + SCALE_PATTERN + ")?\.:format([\\w\\.]+)";

  var centerPattern = util.format(':lon(%s),:lat(%s),:z(\\d+)/:width(\\d+)x:height(\\d+)',
                                  FLOAT_PATTERN, FLOAT_PATTERN);

  app.get(util.format(staticPattern, centerPattern), function(req, res, next) {
    return processStaticMap({
      center: {
        x: +req.params.lon,
        y: +req.params.lat,
        w: req.params.width | 0,
        h: req.params.height | 0
      }
    }, req, res, next);
  });

  var boundsPattern = util.format(':minx(%s),:miny(%s),:maxx(%s),:maxy(%s)/:z(\\d+)',
                                  FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN, FLOAT_PATTERN);

  app.get(util.format(staticPattern, boundsPattern), function(req, res, next) {
    return processStaticMap({
      bbox: [
        +req.params.minx,
        +req.params.miny,
        +req.params.maxx,
        +req.params.maxy
      ]
    }, req, res, next);
  });

  app.get("/index.json", function(req, res, next) {
    var params = {
      tileJSON: true
    };

    return tilelive.load(uri, function(err, source) {
      if (err) {
        return next(err);
      }

      return tessera.getInfo(source, function(err, info) {
        if (err) {
          return next(err);
        }

        var protocol = req.headers['x-forwarded-proto'] || req.protocol;
        var host = req.headers['x-forwarded-host'] || req.headers.host;
        var uri = protocol + "://" + host +
          (path.dirname(req.originalUrl) +
                         tilePath.replace("{format}",
                                          getExtension(info.format))).replace(/\/+/g, "/");

        info.tiles = [uri];
        info.tilejson = "2.0.0";

        res.set(populateHeaders({}, params, { 200: true }));
        return res.send(info);
      });
    });
  });

  return app;
};
<|endoftext|>


<commit_before>var json = require("json");
var geom = require("geoscript/geom");
var proj = require("geoscript/proj");
var geotools = Packages.org.geotools;
var jts = Packages.com.vividsolutions.jts;
var GeometryDescriptor = Packages.org.opengis.feature.type.GeometryDescriptor;
var SimpleFeatureBuilder = geotools.feature.simple.SimpleFeatureBuilder;
var SimpleFeatureTypeBuilder = geotools.feature.simple.SimpleFeatureTypeBuilder;
var crs = geotools.referencing.CRS;
var NameImpl = geotools.feature.NameImpl;
var CoordinateReferenceSystem = Packages.org.opengis.referencing.crs.CoordinateReferenceSystem;

var types = {};

// map type names to java types
var javaTypeNames = ["String", "Integer", "Short", "Float", "Long", "Double"];
javaTypeNames.forEach(function(str) {
    var type = java.lang[str];
    types[str] = type;
    types[type] = type;
});
// map type names to jts geometry types
var jtsTypeNames = ["Geometry", "Point", "LineString", "Polygon", "MultiPoint", "MultiLineString", "MultiPolygon"];
jtsTypeNames.forEach(function(str) {
    var type = jts.geom[str];
    types[str] = type;
    types[type] = type;
});

var getTypeName = function(type) {
    var name;
    for (var str in types) {
        if (types[str] === type) {
            name = str;
            break;
        };
    }
    return str;
};

var FeatureType = function(config) {
    config = config || {};
    this.ft = config.ft;
    if (config.name && config.atts) {
        // generate gt feature type from attributes
        var tb = new SimpleFeatureTypeBuilder();
        tb.setName(new NameImpl(config.name));
        config.atts.forEach(function(att) {
            var name = att[0],
                typeName = att[1];
            if (geom[typeName]) {
                if (att.length > 2) {
                    var xrs = att[2];
                    if (xrs instanceof CoordinateReferenceSystem) {
                        tb.crs(xrs);
                    } else {
                        tb.srs(xrs);
                    }
                }
            }
            tb.add(name, types[typeName]);
        });
        this.ft = tb.buildFeatureType();
    }
    this.name = this.ft.name.localPart;

    // geom property
    var gd = this.ft.geometryDescriptor;
    if (gd) {
        this.geom = [
            gd.localName,
            getTypeName(gd.type.binding)
        ];
        if (gd.coordinateReferenceSystem) {
            this.geom[2] = gd.coordinateReferenceSystem;
        }
    }

    // atts property
    this.atts = this.ft.attributeDescriptors.toArray().map(function(ad) {
        return [ad.localName, getTypeName(ad.type.binding)];
    });

    // attNames property
    this.attNames = this.ft.attributeDescriptors.toArray().map(function(ad) {
        return ad.localName;
    });

};

FeatureType.prototype = {
    feature: function(atts, id) {
        return new Feture({
            ftype: this,
            atts: atts,
            id: id
        });
    }
};

var Feature = function(config) {
    config = config || {};

    this.id = config.id;
    if (!config.id) {
        // TODO: generate a unique id
    }

    if (config.ftype) {
        this.ftype = config.ftype;
    } else {
        // TODO: generate feature type from attributes
    }

    if (config.feature) {
        this._feature = config.feature;
        if (this.ftype) {
            for (var name in this.ftype.atts) {
                if (ftype.geom && name === ftype.geom.name) {
                    this.geom = this._feature.getAttribute(name);
                } else {
                    this.atts[name] = this._feature.getAttribute(name);
                }
            }
        }
    }

    this.atts = {};
    for (var name in config.atts) {
        this.atts[name] = config.atts[name];
    }

    this.geom = config.geom;

};

Feature.prototype = {

    toString: function() {
        return json.encode(this.atts) + "; " + this.geom;
    },

    set: function(name, value) {
        this.atts[name] = value;
    },

    get: function(name) {
        return this.atts[name];
    },

    _sync: function() {
        if (!this._feature) {
            var builder = new SimpleFeatureBuilder(this.ftype._ft);
            this._feature = builder.buildFeature(null, []);
        }
        for (var name in this.atts) {
            this._feature.setAttribute(name, this.atts[name]);
        }
        if (this.geom) {
            this._feature.setDefaultGeometry(this.geom);
        }
    }

};

exports.FeatureType = FeatureType;
exports.Feature = Feature;
<commit_msg>Private ft.  Default name.  Convenience method to create from GT ft.<commit_after>var json = require("json");
var geom = require("geoscript/geom");
var proj = require("geoscript/proj");
var geotools = Packages.org.geotools;
var jts = Packages.com.vividsolutions.jts;
var GeometryDescriptor = Packages.org.opengis.feature.type.GeometryDescriptor;
var SimpleFeatureBuilder = geotools.feature.simple.SimpleFeatureBuilder;
var SimpleFeatureTypeBuilder = geotools.feature.simple.SimpleFeatureTypeBuilder;
var crs = geotools.referencing.CRS;
var NameImpl = geotools.feature.NameImpl;
var CoordinateReferenceSystem = Packages.org.opengis.referencing.crs.CoordinateReferenceSystem;

var types = {};

// map type names to java types
var javaTypeNames = ["String", "Integer", "Short", "Float", "Long", "Double"];
javaTypeNames.forEach(function(str) {
    var type = java.lang[str];
    types[str] = type;
    types[type] = type;
});
// map type names to jts geometry types
var jtsTypeNames = ["Geometry", "Point", "LineString", "Polygon", "MultiPoint", "MultiLineString", "MultiPolygon"];
jtsTypeNames.forEach(function(str) {
    var type = jts.geom[str];
    types[str] = type;
    types[type] = type;
});

var getTypeName = function(type) {
    var name;
    for (var str in types) {
        if (types[str] === type) {
            name = str;
            break;
        };
    }
    return str;
};

var FeatureType = function(config) {
    config = config || {};
    config.name = config.name || "feature";
    this._ft = config.ft;
    if (config.atts) {
        // generate gt feature type from attributes
        var tb = new SimpleFeatureTypeBuilder();
        tb.setName(new NameImpl(config.name));
        config.atts.forEach(function(att) {
            var name = att[0],
                typeName = att[1];
            if (geom[typeName]) {
                if (att.length > 2) {
                    var xrs = att[2];
                    if (xrs instanceof CoordinateReferenceSystem) {
                        tb.crs(xrs);
                    } else {
                        tb.srs(xrs);
                    }
                }
            }
            tb.add(name, types[typeName]);
        });
        this._ft = tb.buildFeatureType();
    }
    this.name = this._ft.name.localPart;

    // geom property
    var gd = this._ft.geometryDescriptor;
    if (gd) {
        this.geom = [
            gd.localName,
            getTypeName(gd.type.binding)
        ];
        if (gd.coordinateReferenceSystem) {
            this.geom[2] = gd.coordinateReferenceSystem;
        }
    }

    // atts property
    this.atts = this._ft.attributeDescriptors.toArray().map(function(ad) {
        return [ad.localName, getTypeName(ad.type.binding)];
    });

    // attNames property
    this.attNames = this._ft.attributeDescriptors.toArray().map(function(ad) {
        return ad.localName;
    });

};

FeatureType.prototype = {
    feature: function(atts, id) {
        return new Feture({
            ftype: this,
            atts: atts,
            id: id
        });
    }
};

FeatureType.fromGT = function(ft) {
    return new FeatureType({ft: ft});
};

var Feature = function(config) {
    config = config || {};

    this.id = config.id;
    if (!config.id) {
        // TODO: generate a unique id
    }

    if (config.ftype) {
        this.ftype = config.ftype;
    } else {
        // TODO: generate feature type from attributes
    }

    if (config.feature) {
        this._feature = config.feature;
        if (this.ftype) {
            for (var name in this.ftype.atts) {
                if (ftype.geom && name === ftype.geom.name) {
                    this.geom = this._feature.getAttribute(name);
                } else {
                    this.atts[name] = this._feature.getAttribute(name);
                }
            }
        }
    }

    this.atts = {};
    for (var name in config.atts) {
        this.atts[name] = config.atts[name];
    }

    this.geom = config.geom;

};

Feature.prototype = {

    toString: function() {
        return json.encode(this.atts) + "; " + this.geom;
    },

    set: function(name, value) {
        this.atts[name] = value;
    },

    get: function(name) {
        return this.atts[name];
    },

    _sync: function() {
        if (!this._feature) {
            var builder = new SimpleFeatureBuilder(this.ftype._ft);
            this._feature = builder.buildFeature(null, []);
        }
        for (var name in this.atts) {
            this._feature.setAttribute(name, this.atts[name]);
        }
        if (this.geom) {
            this._feature.setDefaultGeometry(this.geom);
        }
    }

};

exports.FeatureType = FeatureType;
exports.Feature = Feature;
<|endoftext|>


<commit_before>if(typeof browser === 'undefined') {
  window.browser = window.chrome;
}

const STORE_NAME = 'pptw_settings';
const SETTINGS_LIST = [
  {
    id: 'update_check',
    value: 'checked',
  },
  {
    id: 'update_check_interval',
    value: 'value',
  },
  {
    id: 'mute_by_key',
    value: 'checked',
  },
  {
    id: 'block_by_key',
    value: 'checked',
  },
];

const configUI = {

  extractSettings : () => {
    const ret = [];
    SETTINGS_LIST.forEach((setting) => {
      const inpElm = document.getElementById(setting.id);
      ret.push({
        id: setting.id,
        value: setting.id === 'update_check_interval' ? parseInt(inpElm[setting.value]) : inpElm[setting.value],
      });
    });
    console.log(`${JSON.stringify(ret)}`);
    return ret;
  },

  restoreEntries : () => {
    browser.storage.local.get(STORE_NAME, (store_obj) => {
      const result = store_obj[STORE_NAME];
      if(!result || !Array.isArray(result) || result.length === 0) {
        console.log('nothing');
        return;
      }
      console.log(`restore ${JSON.stringify(result)}`);
      result.forEach((setting) => {
        const inpElm = document.getElementById(setting.id);
        if(typeof setting.value === 'boolean') {
          inpElm.checked = setting.value;
        }
        else {
          inpElm.value = setting.value;
        }
      });
    });
  },

  saveEntries : () => {
    browser.storage.local.set({
      [STORE_NAME]: configUI.extractSettings(),
    });
  }

};

document.addEventListener('DOMContentLoaded', configUI.restoreEntries);
document.getElementById('save').addEventListener('click', configUI.saveEntries);

document.getElementById('update_check_interval').addEventListener("input", (e) => {
  if (e.target.validity.valid) {
    document.getElementById('save').disabled = false;
  } else {
    document.getElementById('save').disabled = true;
  }
});

// vim:expandtab ff=dos fenc=utf-8 sw=2
<commit_msg>refactor: settings page<commit_after>if(typeof browser === 'undefined') {
  window.browser = window.chrome;
}

const STORE_NAME = 'pptw_settings';
const SETTINGS_LIST = [
  {
    id: 'update_check',
    value: 'checked',
  },
  {
    id: 'update_check_interval',
    value: 'value',
  },
  {
    id: 'mute_by_key',
    value: 'checked',
  },
  {
    id: 'block_by_key',
    value: 'checked',
  },
];

const configUI = {

  extractSettings : () => {
    const ret = [];
    SETTINGS_LIST.forEach((setting) => {
      const inpElm = document.getElementById(setting.id);
      ret.push({
        id: setting.id,
        value: setting.id === 'update_check_interval' ? parseInt(inpElm[setting.value]) : inpElm[setting.value],
      });
    });
    return ret;
  },

  restoreEntries : () => {
    browser.storage.local.get(STORE_NAME, (store_obj) => {
      const result = store_obj[STORE_NAME];
      if(!result || !Array.isArray(result) || result.length === 0) {
        return;
      }
      result.forEach((setting) => {
        const inpElm = document.getElementById(setting.id);
        if(typeof setting.value === 'boolean') {
          inpElm.checked = setting.value;
        }
        else {
          inpElm.value = setting.value;
        }
      });
    });
  },

  saveEntries : () => {
    browser.storage.local.set({
      [STORE_NAME]: configUI.extractSettings(),
    });
  }

};

document.addEventListener('DOMContentLoaded', configUI.restoreEntries);
document.getElementById('save').addEventListener('click', configUI.saveEntries);

document.getElementById('update_check_interval').addEventListener('input', (e) => {
  const saveButton = document.getElementById('save');
  if (e.target.validity.valid) {
    saveButton.disabled = false;
  } else {
    saveButton.disabled = true;
  }
});

// vim:expandtab ff=dos fenc=utf-8 sw=2
<|endoftext|>