<commit_before>'use strict';

Object.defineProperty(exports, "__esModule", {
    value: true
});

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _propTypes = require('prop-types');

var _propTypes2 = _interopRequireDefault(_propTypes);

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _reactDom = require('react-dom');

var _reactDom2 = _interopRequireDefault(_reactDom);

var _mask3 = require('./mask.js');

var _mask4 = _interopRequireDefault(_mask3);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

// IE* parseFloat polyfill
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/parseFloat#Polyfill
Number.parseFloat = parseFloat;

var CurrencyInput = function (_Component) {
    _inherits(CurrencyInput, _Component);

    function CurrencyInput(props) {
        _classCallCheck(this, CurrencyInput);

        var _this = _possibleConstructorReturn(this, (CurrencyInput.__proto__ || Object.getPrototypeOf(CurrencyInput)).call(this, props));

        _this.prepareProps = _this.prepareProps.bind(_this);
        _this.handleChange = _this.handleChange.bind(_this);
        _this.handleFocus = _this.handleFocus.bind(_this);
        _this.state = _this.prepareProps(_this.props);

        _this.inputSelectionStart = 0;
        _this.inputSelectionEnd = 0;
        return _this;
    }

    /**
     * Exposes the current masked value.
     *
     * @returns {String}
     */

    _createClass(CurrencyInput, [{
        key: 'getMaskedValue',
        value: function getMaskedValue() {
            return this.state.maskedValue;
        }

        /**
         * General function used to cleanup and define the final props used for rendering
         * @returns {{ maskedValue: {String}, value: {Number}, customProps: {Object} }}
         */

    }, {
        key: 'prepareProps',
        value: function prepareProps(props) {
            var customProps = _extends({}, props); // babeljs converts to Object.assign, then polyfills.
            delete customProps.onChange;
            delete customProps.onChangeEvent;
            delete customProps.value;
            delete customProps.decimalSeparator;
            delete customProps.thousandSeparator;
            delete customProps.precision;
            delete customProps.inputType;
            delete customProps.allowNegative;
            delete customProps.allowEmpty;
            delete customProps.prefix;
            delete customProps.suffix;

            var initialValue = props.value;
            if (initialValue === null) {
                initialValue = props.allowEmpty ? null : '';
            } else {

                if (typeof initialValue == 'string') {
                    // Some people, when confronted with a problem, think "I know, I'll use regular expressions."
                    // Now they have two problems.

                    // Strip out thousand separators, prefix, and suffix, etc.
                    if (props.thousandSeparator === ".") {
                        // special handle the . thousand separator
                        initialValue = initialValue.replace(/\./g, '');
                    }

                    if (props.decimalSeparator != ".") {
                        // fix the decimal separator
                        initialValue = initialValue.replace(new RegExp(props.decimalSeparator, 'g'), '.');
                    }

                    //Strip out anything that is not a digit, -, or decimal separator
                    initialValue = initialValue.replace(/[^0-9-.]/g, '');

                    // now we can parse.
                    initialValue = Number.parseFloat(initialValue);
                }
                initialValue = Number(initialValue).toLocaleString(undefined, {
                    style: 'decimal',
                    minimumFractionDigits: props.precision,
                    maximumFractionDigits: props.precision
                });
            }

            var _mask = (0, _mask4.default)(initialValue, props.precision, props.decimalSeparator, props.thousandSeparator, props.allowNegative, props.prefix, props.suffix),
                maskedValue = _mask.maskedValue,
                value = _mask.value;

            return { maskedValue: maskedValue, value: value, customProps: customProps };
        }

        /**
         * Component lifecycle function.
         * Invoked when a component is receiving new props. This method is not called for the initial render.
         *
         * @param nextProps
         * @see https://facebook.github.io/react/docs/component-specs.html#updating-componentwillreceiveprops
         */

    }, {
        key: 'componentWillReceiveProps',
        value: function componentWillReceiveProps(nextProps) {
            this.setState(this.prepareProps(nextProps));
        }

        /**
         * Component lifecycle function.
         * @returns {XML}
         * @see https://facebook.github.io/react/docs/react-component.html#componentdidmount
         */

    }, {
        key: 'componentDidMount',
        value: function componentDidMount() {
            var node = _reactDom2.default.findDOMNode(this.theInput);

            var selectionEnd = Math.min(node.selectionEnd, this.theInput.value.length - this.props.suffix.length);
            var selectionStart = Math.min(node.selectionStart, selectionEnd);
            //console.log("normal", selectionStart, selectionEnd);
            node.setSelectionRange(selectionStart, selectionEnd);
        }

        /**
         * Component lifecycle function
         * @returns {XML}
         * @see https://facebook.github.io/react/docs/react-component.html#componentwillupdate
         */

    }, {
        key: 'componentWillUpdate',
        value: function componentWillUpdate() {
            var node = _reactDom2.default.findDOMNode(this.theInput);
            this.inputSelectionStart = node.selectionStart;
            this.inputSelectionEnd = node.selectionEnd;
        }

        /**
         * Component lifecycle function.
         * @returns {XML}
         * @see https://facebook.github.io/react/docs/react-component.html#componentdidupdate
         */

    }, {
        key: 'componentDidUpdate',
        value: function componentDidUpdate(prevProps, prevState) {

            var node = _reactDom2.default.findDOMNode(this.theInput);
            var isNegative = (this.theInput.value.match(/-/g) || []).length % 2 === 1;
            var minPos = this.props.prefix.length + (isNegative ? 1 : 0);
            var selectionEnd = Math.max(minPos, Math.min(this.inputSelectionEnd, this.theInput.value.length - this.props.suffix.length));
            var selectionStart = Math.max(minPos, Math.min(this.inputSelectionEnd, selectionEnd));

            var regexEscapeRegex = /[-[\]{}()*+?.,\\^$|#\s]/g;
            var separatorsRegex = new RegExp(this.props.decimalSeparator.replace(regexEscapeRegex, '\\$&') + '|' + this.props.thousandSeparator.replace(regexEscapeRegex, '\\$&'), 'g');
            var currSeparatorCount = (this.state.maskedValue.match(separatorsRegex) || []).length;
            var prevSeparatorCount = (prevState.maskedValue.match(separatorsRegex) || []).length;
            var adjustment = Math.max(currSeparatorCount - prevSeparatorCount, 0);

            selectionEnd = selectionEnd + adjustment;
            selectionStart = selectionStart + adjustment;

            var baselength = this.props.suffix.length + this.props.prefix.length + this.props.decimalSeparator.length + Number(this.props.precision) + 1; // This is to account for the default '0' value that comes before the decimal separator

            if (this.state.maskedValue.length == baselength) {
                // if we are already at base length, position the cursor at the end.
                selectionEnd = this.theInput.value.length - this.props.suffix.length;
                selectionStart = selectionEnd;
            }

            node.setSelectionRange(selectionStart, selectionEnd);
            this.inputSelectionStart = selectionStart;
            this.inputSelectionEnd = selectionEnd;
        }

        /**
         * onChange Event Handler
         * @param event
         */

    }, {
        key: 'handleChange',
        value: function handleChange(event) {
            var _this2 = this;

            event.preventDefault();

            var _mask2 = (0, _mask4.default)(event.target.value, this.props.precision, this.props.decimalSeparator, this.props.thousandSeparator, this.props.allowNegative, this.props.prefix, this.props.suffix),
                maskedValue = _mask2.maskedValue,
                value = _mask2.value;

            event.persist(); // fixes issue #23

            this.setState({ maskedValue: maskedValue, value: value }, function () {
                _this2.props.onChange(maskedValue, value, event);
                _this2.props.onChangeEvent(event, maskedValue, value);
            });
        }

        /**
         * onFocus Event Handler
         * @param event
         */

    }, {
        key: 'handleFocus',
        value: function handleFocus(event) {
            //Whenever we receive focus check to see if the position is before the suffix, if not, move it.
            var selectionEnd = this.theInput.value.length - this.props.suffix.length;
            var isNegative = (this.theInput.value.match(/-/g) || []).length % 2 === 1;
            var selectionStart = this.props.prefix.length + (isNegative ? 1 : 0);
            this.props.selectAllOnFocus && event.target.setSelectionRange(selectionStart, selectionEnd);
            this.inputSelectionStart = selectionStart;
            this.inputSelectionEnd = selectionEnd;
        }
    }, {
        key: 'handleBlur',
        value: function handleBlur(event) {
            this.inputSelectionStart = 0;
            this.inputSelectionEnd = 0;
        }

        /**
         * Component lifecycle function.
         * @returns {XML}
         * @see https://facebook.github.io/react/docs/component-specs.html#render
         */

    }, {
        key: 'render',
        value: function render() {
            var _this3 = this;

            return _react2.default.createElement('input', _extends({
                ref: function ref(input) {
                    _this3.theInput = input;
                },
                type: this.props.inputType,
                value: this.state.maskedValue,
                onChange: this.handleChange,
                onFocus: this.handleFocus,
                onMouseUp: this.handleFocus
            }, this.state.customProps));
        }
    }]);

    return CurrencyInput;
}(_react.Component);

/**
 * Prop validation.
 * @see https://facebook.github.io/react/docs/component-specs.html#proptypes
 */

CurrencyInput.propTypes = {
    onChange: _propTypes2.default.func,
    value: _propTypes2.default.oneOfType([_propTypes2.default.number, _propTypes2.default.string]),
    decimalSeparator: _propTypes2.default.string,
    thousandSeparator: _propTypes2.default.string,
    precision: _propTypes2.default.oneOfType([_propTypes2.default.number, _propTypes2.default.string]),
    inputType: _propTypes2.default.string,
    allowNegative: _propTypes2.default.bool,
    allowEmpty: _propTypes2.default.bool,
    prefix: _propTypes2.default.string,
    suffix: _propTypes2.default.string,
    selectAllOnFocus: _propTypes2.default.bool
};

CurrencyInput.defaultProps = {
    onChange: function onChange(maskValue, value, event) {/*no-op*/},
    onChangeEvent: function onChangeEvent(event, maskValue, value) {/*no-op*/},
    value: '0',
    decimalSeparator: '.',
    thousandSeparator: ',',
    precision: '2',
    inputType: 'text',
    allowNegative: false,
    prefix: '',
    suffix: '',
    selectAllOnFocus: false
};

exports.default = CurrencyInput;<commit_msg>Fixes<commit_after>'use strict';

Object.defineProperty(exports, "__esModule", {
    value: true
});

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _propTypes = require('prop-types');

var _propTypes2 = _interopRequireDefault(_propTypes);

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _reactDom = require('react-dom');

var _reactDom2 = _interopRequireDefault(_reactDom);

var _mask3 = require('./mask.js');

var _mask4 = _interopRequireDefault(_mask3);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

// IE* parseFloat polyfill
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/parseFloat#Polyfill
Number.parseFloat = parseFloat;

var CurrencyInput = function (_Component) {
    _inherits(CurrencyInput, _Component);

    function CurrencyInput(props) {
        _classCallCheck(this, CurrencyInput);

        var _this = _possibleConstructorReturn(this, (CurrencyInput.__proto__ || Object.getPrototypeOf(CurrencyInput)).call(this, props));

        _this.prepareProps = _this.prepareProps.bind(_this);
        _this.handleChange = _this.handleChange.bind(_this);
        _this.handleFocus = _this.handleFocus.bind(_this);
        _this.state = _this.prepareProps(_this.props);

        _this.inputSelectionStart = 1;
        _this.inputSelectionEnd = 1;
        return _this;
    }

    /**
     * Exposes the current masked value.
     *
     * @returns {String}
     */

    _createClass(CurrencyInput, [{
        key: 'getMaskedValue',
        value: function getMaskedValue() {
            return this.state.maskedValue;
        }

        /**
         * General function used to cleanup and define the final props used for rendering
         * @returns {{ maskedValue: {String}, value: {Number}, customProps: {Object} }}
         */

    }, {
        key: 'prepareProps',
        value: function prepareProps(props) {
            var customProps = _extends({}, props); // babeljs converts to Object.assign, then polyfills.
            delete customProps.onChange;
            delete customProps.onChangeEvent;
            delete customProps.value;
            delete customProps.decimalSeparator;
            delete customProps.thousandSeparator;
            delete customProps.precision;
            delete customProps.inputType;
            delete customProps.allowNegative;
            delete customProps.allowEmpty;
            delete customProps.prefix;
            delete customProps.suffix;
            delete customProps.selectAllOnFocus;

            var initialValue = props.value;
            if (initialValue === null) {
                initialValue = props.allowEmpty ? null : '';
            } else {

                if (typeof initialValue == 'string') {
                    // Some people, when confronted with a problem, think "I know, I'll use regular expressions."
                    // Now they have two problems.

                    // Strip out thousand separators, prefix, and suffix, etc.
                    if (props.thousandSeparator === ".") {
                        // special handle the . thousand separator
                        initialValue = initialValue.replace(/\./g, '');
                    }

                    if (props.decimalSeparator != ".") {
                        // fix the decimal separator
                        initialValue = initialValue.replace(new RegExp(props.decimalSeparator, 'g'), '.');
                    }

                    //Strip out anything that is not a digit, -, or decimal separator
                    initialValue = initialValue.replace(/[^0-9-.]/g, '');

                    // now we can parse.
                    initialValue = Number.parseFloat(initialValue);
                }
                initialValue = Number(initialValue).toLocaleString(undefined, {
                    style: 'decimal',
                    minimumFractionDigits: props.precision,
                    maximumFractionDigits: props.precision
                });
            }

            var _mask = (0, _mask4.default)(initialValue, props.precision, props.decimalSeparator, props.thousandSeparator, props.allowNegative, props.prefix, props.suffix),
                maskedValue = _mask.maskedValue,
                value = _mask.value;

            return { maskedValue: maskedValue, value: value, customProps: customProps };
        }

        /**
         * Component lifecycle function.
         * Invoked when a component is receiving new props. This method is not called for the initial render.
         *
         * @param nextProps
         * @see https://facebook.github.io/react/docs/component-specs.html#updating-componentwillreceiveprops
         */

    }, {
        key: 'componentWillReceiveProps',
        value: function componentWillReceiveProps(nextProps) {
            this.setState(this.prepareProps(nextProps));
        }

        /**
         * Component lifecycle function.
         * @returns {XML}
         * @see https://facebook.github.io/react/docs/react-component.html#componentdidmount
         */

    }, {
        key: 'componentDidMount',
        value: function componentDidMount() {
            var node = _reactDom2.default.findDOMNode(this.theInput);

            var selectionEnd = Math.min(node.selectionEnd, this.theInput.value.length - this.props.suffix.length);
            var selectionStart = Math.min(node.selectionStart, selectionEnd);
            //console.log("normal", selectionStart, selectionEnd);
            node.setSelectionRange(selectionStart, selectionEnd);
        }

        /**
         * Component lifecycle function
         * @returns {XML}
         * @see https://facebook.github.io/react/docs/react-component.html#componentwillupdate
         */

    }, {
        key: 'componentWillUpdate',
        value: function componentWillUpdate() {
            var node = _reactDom2.default.findDOMNode(this.theInput);
            this.inputSelectionStart = node.selectionStart;
            this.inputSelectionEnd = node.selectionEnd;
        }

        /**
         * Component lifecycle function.
         * @returns {XML}
         * @see https://facebook.github.io/react/docs/react-component.html#componentdidupdate
         */

    }, {
        key: 'componentDidUpdate',
        value: function componentDidUpdate(prevProps, prevState) {

            var node = _reactDom2.default.findDOMNode(this.theInput);
            var isNegative = (this.theInput.value.match(/-/g) || []).length % 2 === 1;
            var minPos = this.props.prefix.length + (isNegative ? 1 : 0);
            var selectionEnd = Math.max(minPos, Math.min(this.inputSelectionEnd, this.theInput.value.length - this.props.suffix.length));
            var selectionStart = Math.max(minPos, Math.min(this.inputSelectionEnd, selectionEnd));

            var regexEscapeRegex = /[-[\]{}()*+?.,\\^$|#\s]/g;
            var separatorsRegex = new RegExp(this.props.decimalSeparator.replace(regexEscapeRegex, '\\$&') + '|' + this.props.thousandSeparator.replace(regexEscapeRegex, '\\$&'), 'g');
            var currSeparatorCount = (this.state.maskedValue.match(separatorsRegex) || []).length;
            var prevSeparatorCount = (prevState.maskedValue.match(separatorsRegex) || []).length;
            var adjustment = Math.max(currSeparatorCount - prevSeparatorCount, 0);

            selectionEnd = selectionEnd + adjustment;
            selectionStart = selectionStart + adjustment;

            var baselength = this.props.suffix.length + this.props.prefix.length + this.props.decimalSeparator.length + Number(this.props.precision) + 1; // This is to account for the default '0' value that comes before the decimal separator

            if (this.state.maskedValue.length == baselength) {
                // if we are already at base length, position the cursor at the end.
                selectionEnd = this.theInput.value.length - this.props.suffix.length;
                selectionStart = selectionEnd;
            }

            node.setSelectionRange(selectionStart, selectionEnd);
            this.inputSelectionStart = selectionStart;
            this.inputSelectionEnd = selectionEnd;
        }

        /**
         * onChange Event Handler
         * @param event
         */

    }, {
        key: 'handleChange',
        value: function handleChange(event) {
            var _this2 = this;

            event.preventDefault();

            var _mask2 = (0, _mask4.default)(event.target.value, this.props.precision, this.props.decimalSeparator, this.props.thousandSeparator, this.props.allowNegative, this.props.prefix, this.props.suffix),
                maskedValue = _mask2.maskedValue,
                value = _mask2.value;

            event.persist(); // fixes issue #23

            this.setState({ maskedValue: maskedValue, value: value }, function () {
                _this2.props.onChange(maskedValue, value, event);
                _this2.props.onChangeEvent(event, maskedValue, value);
            });
        }

        /**
         * onFocus Event Handler
         * @param event
         */

    }, {
        key: 'handleFocus',
        value: function handleFocus(event) {
            if (!this.theInput) return;

            //Whenever we receive focus check to see if the position is before the suffix, if not, move it.
            var selectionEnd = this.theInput.value.length - this.props.suffix.length;
            var isNegative = (this.theInput.value.match(/-/g) || []).length % 2 === 1;
            var selectionStart = this.props.prefix.length + (isNegative ? 1 : 0);
            this.props.selectAllOnFocus && event.target.setSelectionRange(selectionStart, selectionEnd);
            this.inputSelectionStart = selectionStart;
            this.inputSelectionEnd = selectionEnd;
        }
    }, {
        key: 'handleBlur',
        value: function handleBlur(event) {
            this.inputSelectionStart = 0;
            this.inputSelectionEnd = 0;
        }

        /**
         * Component lifecycle function.
         * @returns {XML}
         * @see https://facebook.github.io/react/docs/component-specs.html#render
         */

    }, {
        key: 'render',
        value: function render() {
            var _this3 = this;

            return _react2.default.createElement('input', _extends({
                ref: function ref(input) {
                    _this3.theInput = input;
                },
                type: this.props.inputType,
                value: this.state.maskedValue,
                onChange: this.handleChange,
                onFocus: this.handleFocus,
                onMouseUp: this.handleFocus
            }, this.state.customProps));
        }
    }]);

    return CurrencyInput;
}(_react.Component);

/**
 * Prop validation.
 * @see https://facebook.github.io/react/docs/component-specs.html#proptypes
 */

CurrencyInput.propTypes = {
    onChange: _propTypes2.default.func,
    value: _propTypes2.default.oneOfType([_propTypes2.default.number, _propTypes2.default.string]),
    decimalSeparator: _propTypes2.default.string,
    thousandSeparator: _propTypes2.default.string,
    precision: _propTypes2.default.oneOfType([_propTypes2.default.number, _propTypes2.default.string]),
    inputType: _propTypes2.default.string,
    allowNegative: _propTypes2.default.bool,
    allowEmpty: _propTypes2.default.bool,
    prefix: _propTypes2.default.string,
    suffix: _propTypes2.default.string,
    selectAllOnFocus: _propTypes2.default.bool
};

CurrencyInput.defaultProps = {
    onChange: function onChange(maskValue, value, event) {/*no-op*/},
    onChangeEvent: function onChangeEvent(event, maskValue, value) {/*no-op*/},
    value: '0',
    decimalSeparator: '.',
    thousandSeparator: ',',
    precision: '2',
    inputType: 'text',
    allowNegative: false,
    prefix: '',
    suffix: '',
    selectAllOnFocus: false
};

exports.default = CurrencyInput;<|endoftext|>


<commit_before>"use strict";

const React = require("react");
const PropTypes = require("prop-types");
const AnimatedLogo = require("@sandhose/prettier-animated-logo");
const { MarkdownBlock, Container } = require("../../core/CompLibrary.js");

const siteConfig = require(process.cwd() + "/siteConfig.js");

const ButtonGroup = (props) => (

{props.children}

);

ButtonGroup.propTypes = {
  children: PropTypes.node,
};

class Button extends React.Component {
  render() {
    return (

          {this.props.children}

    );
  }
}

Button.defaultProps = {
  target: "_self",
};

Button.propTypes = {
  href: PropTypes.string,
  target: PropTypes.string,
  children: PropTypes.any,
};

function Tidelift() {
  return (

      PRETTIER FOR ENTERPRISE

  );
}

const HomeSplash = (props) => (

    <Tidelift />

          <AnimatedLogo version="wide" />

                <Button href="/playground/">Try It Online</Button>
                <Button href={"/docs/" + props.language + "/install.html"}>
                  Install Prettier
                </Button>

);

HomeSplash.propTypes = {
  language: PropTypes.string,
};

const TldrSection = ({ language }) => (

    <Container>

What is Prettier?

An opinionated code formatter

Supports many languages

Integrates with most editors

Has few options

Why?

You press save and code is formatted

No need to discuss style in code review

Saves you time and energy

              And more

    </Container>

);

TldrSection.propTypes = {
  language: PropTypes.string,
};

const Language = ({ name, nameLink, showName, image, variants }) => (

      {showName && (

          {nameLink ? {name} : name}

      )}
      {variants.map((variant) => (

          <MarkdownBlock>{variant}</MarkdownBlock>

      ))}

);

Language.propTypes = {
  name: PropTypes.string,
  nameLink: PropTypes.string,
  showName: PropTypes.bool,
  image: PropTypes.string,
  variants: PropTypes.array,
};

const LanguagesSection = () => {
  const languageChunks = siteConfig.supportedLanguages.reduce(
    (acc, language) => {
      const last = acc[acc.length - 1];
      if (
        last &&
        last.length < 2 &&
        last.reduce((sum, lang) => sum + lang.variants.length, 0) +
          language.variants.length <
          9
      ) {
        last.push(language);
      } else {
        acc.push([language]);
      }
      return acc;
    },
    []
  );

  return (

      <Container>

Works with the Tools You Use

          {languageChunks.map((languageChunk, index) => (

              {languageChunk.map((language) => (
                <Language key={language.name} {...language} />
              ))}

          ))}

      </Container>

  );
};

const Editor = ({ content = "", image, name }) => (

{name}

      <MarkdownBlock>{content.replace(/\n/g, "  \n")}</MarkdownBlock>

);

Editor.propTypes = {
  content: PropTypes.string,
  image: PropTypes.string.isRequired,
  name: PropTypes.string.isRequired,
};

const EditorSupportSection = () => (

    <Container>

Editor Support

        {siteConfig.editors.map((editor) => (
          <Editor key={editor.name} {...editor} />
        ))}

    </Container>

      Got more?
      <a
        href={`${siteConfig.githubUrl}/edit/main/website/data/editors.yml`}
        className="button"
      >
        Send a PR

);

const UsersSection = ({ language }) => {
  const showcase = siteConfig.users
    .filter((user) => user.pinned)
    .map((user, i) => (

    ));

  return (

      <Container>

Used By People You Rely On

          {showcase}

            See Others

Established in the Ecosystem

                Regularly used by more than 70% of respondents
                to State of JS 2020

              <Button href="https://2020.stateofjs.com/en-US/other-tools/utilities">
                Go to Survey Results
              </Button>

                More than{" "}
                2.8 million{" "}
                dependent repositories on GitHub

              <Button href="https://github.com/prettier/prettier/network/dependents">
                Check Them Out
              </Button>

                More than 8000{" "}
                dependent packages on npm

              <Button href="https://www.npmjs.com/browse/depended/prettier">
                See them all
              </Button>

      </Container>

  );
};

UsersSection.propTypes = {
  language: PropTypes.string,
};

class Index extends React.Component {
  render() {
    const language = this.props.language || "en";

    return (


<commit_before>// Load modules

var Path = require('path');

// Declare internals

var internals = {
    defaults: {
        endpoint: '/docs',
        auth: false,
        indexTemplate: 'index',
        routeTemplate: 'route'
    }
};

exports.register = function (plugin, options, next) {

    var settings = plugin.hapi.utils.applyToDefaults(internals.defaults, options || {});

    plugin.views({ engines: { html: 'handlebars' }, path: './templates' });
    plugin.route({ method: 'GET', path: settings.endpoint, config: internals.docs(settings, plugin) });

    next();
};

internals.docs = function (settings, plugin) {

    return {
        auth: settings.auth,
        validate: {
            query: {
                path: plugin.hapi.types.String()
            }
        },
        handler: function (request) {

            var routes = request.server.routingTable();
            routes = routes.filter(function (item) {

                if (request.query.path &&
                    item.path !== request.query.path) {

                    return false;
                }

                return item.settings.plugins.lout !== false && item.method !== 'options';
            });

            if (!routes.length) {
                return request.reply(plugin.hapi.error.notFound());
            }

            routes.sort(function (route1, route2) {

                if (route1.path > route2.path) {
                    return 1;
                }
                if (route1.path < route2.path) {
                    return -1;
                }
                return 0;
            });

            if (request.query.path) {
                var templateData = internals.getRoutesData(routes);
                templateData.path = routes[0] ? routes[0].path : '/';

                return request.reply.view(settings.routeTemplate, templateData);
            }

            return request.reply.view(settings.indexTemplate, internals.getRoutesData(routes));
        },
        plugins: {
            lout: false
        }
    };
};

internals.getRoutesData = function (routes) {

    var routesData = [];
    routes.forEach(function (route) {

        routesData.push({
            path: route.path,
            method: route.method.toUpperCase(),
            description: route.settings.description,
            notes: route.settings.notes,
            tags: route.settings.tags,
            queryParams: internals.getParamsData(route.settings.validate && route.settings.validate.query),
            payloadParams: internals.getParamsData(route.settings.validate && route.settings.validate.payload),
            responseParams: internals.getParamsData(route.settings.validate && route.settings.validate.response && route.settings.validate.response.schema)
        });
    });

    return { routes: routesData };
};

internals.getParamsData = function (params) {

    if (params === null ||
        params === undefined ||
        (typeof params !== 'object')) {

        return [];
    }

    var paramsData = [];
    var keys = Object.keys(params);

    for (var i = 0, il = keys.length; i < il; ++i) {
        var key = keys[i];
        var param = params[key];

        paramsData.push({
            name: key,
            description: typeof param.description === 'function' ? '' : param.description,
            notes: typeof param.notes === 'function' ? '' : param.notes,
            tags: typeof param.tags === 'function' ? '' : param.tags,
            type: param.type,
            required: param.__modifiers && param.__modifiers._values ? param.__modifiers._values.some(internals.isRequiredParam) : null,
            allowedValues: param.__valids ? internals.getExistsValues(param.__valids._exists) : null,
            disallowedValues: param.__invalids ? internals.getExistsValues(param.__invalids._exists) : null
        });
    }

    return paramsData;
};

internals.getExistsValues = function (exists) {

    var values = [];

    var keys = Object.keys(exists);
    keys.forEach(function (key) {
        key = key.substring(1, key.length - 1);
        if (key !== 'ndefine' && key !== 'ul' && key.length !== 0) {
            values.push(key);
        }
    });

    return values;
};

internals.isRequiredParam = function (element) {

    return element === 'required';
};<commit_msg>adding basePath to settings, fixes #23<commit_after>// Load modules

var Path = require('path');

// Declare internals

var internals = {
    defaults: {
        endpoint: '/docs',
        auth: false,
        indexTemplate: 'index',
        routeTemplate: 'route'
    }
};

exports.register = function (plugin, options, next) {

    var settings = plugin.hapi.utils.applyToDefaults(internals.defaults, options || {});

    plugin.views({ engines: { html: 'handlebars' }, path: './templates', basePath: settings.basePath });
    plugin.route({ method: 'GET', path: settings.endpoint, config: internals.docs(settings, plugin) });

    next();
};

internals.docs = function (settings, plugin) {

    return {
        auth: settings.auth,
        validate: {
            query: {
                path: plugin.hapi.types.String()
            }
        },
        handler: function (request) {

            var routes = request.server.routingTable();
            routes = routes.filter(function (item) {

                if (request.query.path &&
                    item.path !== request.query.path) {

                    return false;
                }

                return item.settings.plugins.lout !== false && item.method !== 'options';
            });

            if (!routes.length) {
                return request.reply(plugin.hapi.error.notFound());
            }

            routes.sort(function (route1, route2) {

                if (route1.path > route2.path) {
                    return 1;
                }
                if (route1.path < route2.path) {
                    return -1;
                }
                return 0;
            });

            if (request.query.path) {
                var templateData = internals.getRoutesData(routes);
                templateData.path = routes[0] ? routes[0].path : '/';

                return request.reply.view(settings.routeTemplate, templateData);
            }

            return request.reply.view(settings.indexTemplate, internals.getRoutesData(routes));
        },
        plugins: {
            lout: false
        }
    };
};

internals.getRoutesData = function (routes) {

    var routesData = [];
    routes.forEach(function (route) {

        routesData.push({
            path: route.path,
            method: route.method.toUpperCase(),
            description: route.settings.description,
            notes: route.settings.notes,
            tags: route.settings.tags,
            queryParams: internals.getParamsData(route.settings.validate && route.settings.validate.query),
            payloadParams: internals.getParamsData(route.settings.validate && route.settings.validate.payload),
            responseParams: internals.getParamsData(route.settings.validate && route.settings.validate.response && route.settings.validate.response.schema)
        });
    });

    return { routes: routesData };
};

internals.getParamsData = function (params) {

    if (params === null ||
        params === undefined ||
        (typeof params !== 'object')) {

        return [];
    }

    var paramsData = [];
    var keys = Object.keys(params);

    for (var i = 0, il = keys.length; i < il; ++i) {
        var key = keys[i];
        var param = params[key];

        paramsData.push({
            name: key,
            description: typeof param.description === 'function' ? '' : param.description,
            notes: typeof param.notes === 'function' ? '' : param.notes,
            tags: typeof param.tags === 'function' ? '' : param.tags,
            type: param.type,
            required: param.__modifiers && param.__modifiers._values ? param.__modifiers._values.some(internals.isRequiredParam) : null,
            allowedValues: param.__valids ? internals.getExistsValues(param.__valids._exists) : null,
            disallowedValues: param.__invalids ? internals.getExistsValues(param.__invalids._exists) : null
        });
    }

    return paramsData;
};

internals.getExistsValues = function (exists) {

    var values = [];

    var keys = Object.keys(exists);
    keys.forEach(function (key) {
        key = key.substring(1, key.length - 1);
        if (key !== 'ndefine' && key !== 'ul' && key.length !== 0) {
            values.push(key);
        }
    });

    return values;
};

internals.isRequiredParam = function (element) {

    return element === 'required';
};<|endoftext|>


<commit_before>define(
  ['./platform', './util'],
  function (platform, util) {

    "use strict";

    // Namespace: webfinger
    //
    // Webfinger discovery.
    // Supports XRD, JRD and the <"resource" parameter at http://tools.ietf.org/html/draft-jones-appsawg-webfinger-06#section-5.2>
    //
    // remoteStorage.js tries the following things to discover a user's profile:
    //   * via HTTPS to /.well-known/host-meta.json
    //   * via HTTPS to /.well-known/host-meta
    //   * via HTTP to /.well-known/host-meta.json
    //   * via HTTP to /.well-known/host-meta
    //
    //   All those requests carry the "resource" query parameter.
    //
    // So in order for a discovery to work most quickly, a server should
    // respond to HTTPS requests like:
    //
    //   > /.well-known/host-meta.json?resource=acct%3Abob%40example.com
    // And return a JSON representation of the profile, such as this:
    //
    //   (start code)
    //
    //   {
    //     links:[{
    //       href: 'https://example.com/storage/bob',
    //       rel: "remoteStorage",
    //       type: "https://www.w3.org/community/rww/wiki/read-write-web-00#simple",
    //       properties: {
    //         'auth-method': "https://tools.ietf.org/html/draft-ietf-oauth-v2-26#section-4.2",
    //         'auth-endpoint': 'https://example.com/auth/bob'
    //       }
    //     }]
    //   }
    //
    //   (end code)
    //

    var logger = util.getLogger('webfinger');

      ///////////////
     // Webfinger //
    ///////////////

    // PARSE

    // parse user address
    function extractHostname(userAddress) {
      var parts = userAddress.toLowerCase().split('@');
      var error;
      if(parts.length < 2) {
        error = 'no-at';
      } else if(parts.length > 2) {
        error = 'multiple-at';
      } else {
        if(!(/^[\.0-9a-z\-\_]+$/.test(parts[0]))) {
          error = 'non-dotalphanum';
        } else if(!(/^[\.0-9a-z\-]+$/.test(parts[1]))) {
          error = 'non-dotalphanum';
        }
      }
      if(error) {
        throw error;
      }
      return parts[1];
    }

    function parseXRD(str) {
      var promise = util.getPromise();
      platform.parseXml(str, function(err, obj) {
        if(err) {
          promise.fail(err);
        } else {
          if(obj && obj.Link) {
            var links = {};
            if(obj.Link && obj.Link['@']) {//obj.Link is one element
              if(obj.Link['@'].rel) {
                links[obj.Link['@'].rel]=obj.Link['@'];
              }
            } else {//obj.Link is an array
              for(var i=0; i<obj.Link.length; i++) {
                if(obj.Link[i]['@'] && obj.Link[i]['@'].rel) {
                  links[obj.Link[i]['@'].rel]=obj.Link[i]['@'];
                }
              }
            }
            promise.fulfill(links);
          } else {
            promise.fail('invalid-xml');
          }
        }
      });
      return promise;
    }

    function parseJRD(data) {
      var object = JSON.parse(data);
      if(! object.links) {
        throw 'invalid-jrd';
      }
      var links = {};
      object.links.forEach(function(link) {
        // just take the first one of each rel:
        if(link.rel && (! links[link.rel])) {
          links[link.rel] = link;
        }
      });
      return links;
    }

    // request a single profile
    function fetchProfile(address, timeout) {
      console.log('fetch profile', address, timeout);
      return platform.ajax({
        url: address,
        timeout: timeout
      }).then(function(body, headers) {
        var mimeType = headers && headers['content-type'] && headers['content-type'].split(';')[0];
        console.log('fetched', body, mimeType);
        if(mimeType && mimeType.match(/^application\/json/)) {
          return parseJRD(body);
        } else {
          return util.makePromise(function(jrdPromise) {
            parseXRD(body).then(
              function(xrd) {
                jrdPromise.fulfill(xrd);
              }, function(error) {
                jrdPromise.fulfill(parseJRD(body));
              });
          });
        }
      });
    }

    // fetch profile from all given addresses and yield the first one that
    // succeeds.
    function fetchHostMeta(addresses, timeout) {
      console.log('fetch host meta', addresses, timeout);
      return util.asyncMap(addresses, util.rcurry(fetchProfile, timeout, true)).
        then(function(profiles, errors) {
          console.log('host meta mapped', profiles);
          for(var i=0;i<profiles.length;i++) {
            if(profiles[i]) {
              return profiles[i];
            }
          }
          throw 'requests-failed';
        });
    }

    function extractRemoteStorageLink(links) {
      console.log('extract remoteStorage link', links);
      var remoteStorageLink = links.remoteStorage || links.remotestorage;
      var lrddLink;
      if(remoteStorageLink) {
        console.log('remoteStorageLink', remoteStorageLink);
        if(remoteStorageLink.href &&
           remoteStorageLink.type &&
           remoteStorageLink.properties &&
           remoteStorageLink.properties['auth-endpoint']) {
          return remoteStorageLink;
        } else {
          throw new Error("Invalid remoteStorage link. Required properties are:" +
                          "href, type, properties, properties.auth-endpoint. " +
                          JSON.stringify(remoteStorageLink));
        }
      } else if(lrddLink = links.lrdd) {
        return fetchProfile(
          lrddLink.template.replace('{uri}', 'acct:' + userAddress)
        ).then(extractRemoteStorageLink);
      } else {
        throw 'not-supported';
      }
    }

    // method: getStorageInfo
    // Get the storage information of a given user address.
    //
    // Parameters:
    //   userAddress - a string in the form user@host
    //   options     - see below
    //   callback    - to receive the discovered storage info
    //
    // Options:
    //   timeout     - time in milliseconds, until resulting in a 'timeout' error.
    //
    // Callback parameters:
    //   err         - either an error message or null if discovery succeeded
    //   storageInfo - the format is equivalent to that of the JSON representation of the remotestorage link (see above)
    //
    function getStorageInfo(userAddress, options) {

      /*

        - validate userAddres
        - fetch host-meta
        - parse host-meta
        - (optionally) fetch lrdd
        - (optionally) parse lrdd
        - extract links

       */

      try {
        var hostname = extractHostname(userAddress)
      } catch(error) {
        if(error) {
          return util.getPromise().failLater(error);
        }
      }
      var query = '?resource=acct:' + encodeURIComponent(userAddress);
      var addresses = [
        'https://' + hostname + '/.well-known/webfinger' + query,
        'http://'  + hostname + '/.well-known/webfinger' + query,
        'https://' + hostname + '/.well-known/host-meta.json' + query,
        'https://' + hostname + '/.well-known/host-meta' + query,
        'http://'  + hostname + '/.well-known/host-meta.json' + query,
        'http://'  + hostname + '/.well-known/host-meta' + query
      ];

      return fetchHostMeta(addresses, (options && options.timeout) || 10000).
        then(extractRemoteStorageLink);
    }

    return {
      getStorageInfo: getStorageInfo
    };
});
<commit_msg>fixed parsing of webfinger XML in browser (refs #168)<commit_after>define(
  ['./platform', './util'],
  function (platform, util) {

    "use strict";

    // Namespace: webfinger
    //
    // Webfinger discovery.
    // Supports XRD, JRD and the <"resource" parameter at http://tools.ietf.org/html/draft-jones-appsawg-webfinger-06#section-5.2>
    //
    // remoteStorage.js tries the following things to discover a user's profile:
    //   * via HTTPS to /.well-known/host-meta.json
    //   * via HTTPS to /.well-known/host-meta
    //   * via HTTP to /.well-known/host-meta.json
    //   * via HTTP to /.well-known/host-meta
    //
    //   All those requests carry the "resource" query parameter.
    //
    // So in order for a discovery to work most quickly, a server should
    // respond to HTTPS requests like:
    //
    //   > /.well-known/host-meta.json?resource=acct%3Abob%40example.com
    // And return a JSON representation of the profile, such as this:
    //
    //   (start code)
    //
    //   {
    //     links:[{
    //       href: 'https://example.com/storage/bob',
    //       rel: "remoteStorage",
    //       type: "https://www.w3.org/community/rww/wiki/read-write-web-00#simple",
    //       properties: {
    //         'auth-method': "https://tools.ietf.org/html/draft-ietf-oauth-v2-26#section-4.2",
    //         'auth-endpoint': 'https://example.com/auth/bob'
    //       }
    //     }]
    //   }
    //
    //   (end code)
    //

    var logger = util.getLogger('webfinger');

      ///////////////
     // Webfinger //
    ///////////////

    // PARSE

    // parse user address
    function extractHostname(userAddress) {
      var parts = userAddress.toLowerCase().split('@');
      var error;
      if(parts.length < 2) {
        error = 'no-at';
      } else if(parts.length > 2) {
        error = 'multiple-at';
      } else {
        if(!(/^[\.0-9a-z\-\_]+$/.test(parts[0]))) {
          error = 'non-dotalphanum';
        } else if(!(/^[\.0-9a-z\-]+$/.test(parts[1]))) {
          error = 'non-dotalphanum';
        }
      }
      if(error) {
        throw error;
      }
      return parts[1];
    }

    function parseXRD(str) {
      return util.makePromise(function(promise) {
        platform.parseXml(str, function(err, obj) {
          if(err) {
            promise.fail(err);
          } else {
            if(obj && obj.Link) {
              var links = {};
              if(obj.Link && obj.Link['@']) {//obj.Link is one element
                if(obj.Link['@'].rel) {
                  links[obj.Link['@'].rel]=obj.Link['@'];
                }
              } else {//obj.Link is an array
                for(var i=0; i<obj.Link.length; i++) {
                  if(obj.Link[i]['@'] && obj.Link[i]['@'].rel) {
                    links[obj.Link[i]['@'].rel]=obj.Link[i]['@'];
                  }
                }
              }
              promise.fulfill(links);
            } else {
              promise.fail('invalid-xml');
            }
          }
        });
      });
    }

    function parseJRD(data) {
      var object = JSON.parse(data);
      if(! object.links) {
        throw 'invalid-jrd';
      }
      var links = {};
      object.links.forEach(function(link) {
        // just take the first one of each rel:
        if(link.rel && (! links[link.rel])) {
          links[link.rel] = link;
        }
      });
      return links;
    }

    // request a single profile
    function fetchProfile(address, timeout) {
      console.log('fetch profile', address, timeout);
      return platform.ajax({
        url: address,
        timeout: timeout
      }).then(function(body, headers) {
        var mimeType = headers && headers['content-type'] && headers['content-type'].split(';')[0];
        console.log('fetched', body, mimeType);
        if(mimeType && mimeType.match(/^application\/json/)) {
          return parseJRD(body);
        } else {
          return util.makePromise(function(jrdPromise) {
            parseXRD(body).then(
              function(xrd) {
                jrdPromise.fulfill(xrd);
              }, function(error) {
                jrdPromise.fulfill(parseJRD(body));
              });
          });
        }
      });
    }

    // fetch profile from all given addresses and yield the first one that
    // succeeds.
    function fetchHostMeta(addresses, timeout) {
      console.log('fetch host meta', addresses, timeout);
      return util.asyncMap(addresses, util.rcurry(fetchProfile, timeout, true)).
        then(function(profiles, errors) {
          console.log('host meta mapped', profiles);
          for(var i=0;i<profiles.length;i++) {
            if(profiles[i]) {
              return profiles[i];
            }
          }
          throw 'requests-failed';
        });
    }

    function extractRemoteStorageLink(links) {
      console.log('extract remoteStorage link', links);
      var remoteStorageLink = links.remoteStorage || links.remotestorage;
      var lrddLink;
      if(remoteStorageLink) {
        console.log('remoteStorageLink', remoteStorageLink);
        if(remoteStorageLink.href &&
           remoteStorageLink.type &&
           remoteStorageLink.properties &&
           remoteStorageLink.properties['auth-endpoint']) {
          return remoteStorageLink;
        } else {
          throw new Error("Invalid remoteStorage link. Required properties are:" +
                          "href, type, properties, properties.auth-endpoint. " +
                          JSON.stringify(remoteStorageLink));
        }
      } else if(lrddLink = links.lrdd) {
        return fetchProfile(
          lrddLink.template.replace('{uri}', 'acct:' + userAddress)
        ).then(extractRemoteStorageLink);
      } else {
        throw 'not-supported';
      }
    }

    // method: getStorageInfo
    // Get the storage information of a given user address.
    //
    // Parameters:
    //   userAddress - a string in the form user@host
    //   options     - see below
    //   callback    - to receive the discovered storage info
    //
    // Options:
    //   timeout     - time in milliseconds, until resulting in a 'timeout' error.
    //
    // Callback parameters:
    //   err         - either an error message or null if discovery succeeded
    //   storageInfo - the format is equivalent to that of the JSON representation of the remotestorage link (see above)
    //
    function getStorageInfo(userAddress, options) {

      /*

        - validate userAddres
        - fetch host-meta
        - parse host-meta
        - (optionally) fetch lrdd
        - (optionally) parse lrdd
        - extract links

       */

      try {
        var hostname = extractHostname(userAddress)
      } catch(error) {
        if(error) {
          return util.getPromise().failLater(error);
        }
      }
      var query = '?resource=acct:' + encodeURIComponent(userAddress);
      var addresses = [
        'https://' + hostname + '/.well-known/webfinger' + query,
        'http://'  + hostname + '/.well-known/webfinger' + query,
        'https://' + hostname + '/.well-known/host-meta.json' + query,
        'https://' + hostname + '/.well-known/host-meta' + query,
        'http://'  + hostname + '/.well-known/host-meta.json' + query,
        'http://'  + hostname + '/.well-known/host-meta' + query
      ];

      return fetchHostMeta(addresses, (options && options.timeout) || 10000).
        then(extractRemoteStorageLink);
    }

    return {
      getStorageInfo: getStorageInfo
    };
});
<|endoftext|>


<commit_before>/*global QUnit, module, Ember, asyncTest, ok, deepEqual, start, stop, Lawnchair*/

(function() {
  'use strict';
  QUnit.config.testTimeout = 1500;

  // Don't let RSVP eat all our errors!
  Ember.RSVP.configure('onerror', function(e) {
    throw e;
  });

  var PostModel;

  module('Ember.LawnchairAdapter', {
    setup: function() {
      stop();
      PostModel = Ember.Model.extend({
        id: Ember.attr(),
        title: Ember.attr()
      });
      PostModel.adapter = Ember.LawnchairAdapter.create();
      PostModel.url = 'posts';

      // Empty the IndexedDB:
      Lawnchair({name: PostModel.adapter.prefix + PostModel.url, adapter: PostModel.adapter.lawnchairAdapter}, function(store) {
        store.nuke(function() {
          start();
        });
      });
    },
    teardown: function() {
      PostModel = null;
    }
  });

  asyncTest('when a record is created with no ID an ID should be automatically set', function() {
    PostModel
      .create({title: 'Hello world'})
      .save().then(function(post) {
        ok(post.get('id'), 'ID is set');
        start();
      });
  });

  asyncTest('when a record is created with an ID that ID should be preserved', function() {
    var postJson = {id: 1, title: 'Hello world'};
    PostModel
      .create(postJson)
      .save().then(function(post) {
        ok(post.get('id'), 'ID is set');
        ok(post.get('id') === postJson.id, 'ID has same value as originally set.');
        start();
      });
  });

  asyncTest('when a record is created we should be able to find it by its id', function() {
    var postJson = {id: 1, title: 'Hello world'};
    PostModel.create(postJson)
      .save().then(function(savedPost) {

        var loadedPost = PostModel.find(postJson.id);
        Ember.loadPromise(loadedPost).then(function() {
          ok(loadedPost, 'a post is found');
          ok(loadedPost === savedPost, 'the loaded post is the same as the saved post');
          start();
        });
      });
  });

  asyncTest('when a record is created then deleted from the cache we should be still able to find it by its id', function() {
    var postJson = {id: 1, title: 'Hello world'};
    PostModel.create(postJson)
      .save().then(function(savedPost) {
        // Clear the cache so that ember-model is forced to load our object from the adapter.
        PostModel.clearCache();

        var loadedPost = PostModel.find(postJson.id);
        return Ember.loadPromise(loadedPost).then(function() {
          ok(loadedPost, 'a post is found');
          deepEqual(loadedPost.toJSON(), savedPost.toJSON(), 'the loaded post is the same as the saved post');
          start();
        });
      });
  });

  asyncTest('when a record is deleted it should be marked as deleted', function() {
    var postJson = {id: 1, title: 'Hello world'};
    PostModel.create(postJson)
      .save().then(function(savedPost) {
        savedPost.deleteRecord().then(function() {
          var loadedPost = PostModel.find(postJson.id);
          ok(loadedPost.isDeleted, 'The model isDeleted');
          start();
        });
      });
  });

  // The behaviour here is not what I would expect but seems to mirror other ember-model adapters
  // see https://github.com/ebryn/ember-model/issues/248
  asyncTest('when a record is deleted and cache is emptied nothing should be found', function() {
    var postJson = {id: 1, title: 'Hello world'};
    PostModel.create(postJson)
      .save().then(function(savedPost) {
        savedPost.deleteRecord().then(function() {
          PostModel.clearCache();
          var loadedPost = PostModel.find(postJson.id);
          return Ember.loadPromise(loadedPost).then(
            function() {
              // An empty record comes back which isn't what I would expect but the only thing I can think to test against
              // is that the title comes back empty
              ok(!loadedPost.get('title'), 'no title for the returned post');
              start();
            }
          );
        });
      });
  });

  asyncTest('when two records are created findAll should return both records', function() {
    PostModel.create({id:1, title:'Hello world'}).save()
      .then(function() {
        return PostModel.create({id:2, title:'Goodbye cruel world'}).save();
      }).then(function() {
        var records = PostModel.find();
        Ember.loadPromise(records).then(function(records) {
          equal(records.get('content').length, 2, 'There are two records');
          start();
        });
      });
  });
})();
<commit_msg>Added a test for finding all with a record removed from the cache<commit_after>/*global QUnit, module, Ember, asyncTest, ok, deepEqual, start, stop, Lawnchair*/

(function() {
  'use strict';
  QUnit.config.testTimeout = 1500;

  // Don't let RSVP eat all our errors!
  Ember.RSVP.configure('onerror', function(e) {
    throw e;
  });

  var PostModel;

  module('Ember.LawnchairAdapter', {
    setup: function() {
      stop();
      PostModel = Ember.Model.extend({
        id: Ember.attr(),
        title: Ember.attr()
      });
      PostModel.adapter = Ember.LawnchairAdapter.create();
      PostModel.url = 'posts';

      // Empty the IndexedDB:
      Lawnchair({name: PostModel.adapter.prefix + PostModel.url, adapter: PostModel.adapter.lawnchairAdapter}, function(store) {
        store.nuke(function() {
          start();
        });
      });
    },
    teardown: function() {
      PostModel = null;
    }
  });

  asyncTest('when a record is created with no ID an ID should be automatically set', function() {
    PostModel
      .create({title: 'Hello world'})
      .save().then(function(post) {
        ok(post.get('id'), 'ID is set');
        start();
      });
  });

  asyncTest('when a record is created with an ID that ID should be preserved', function() {
    var postJson = {id: 1, title: 'Hello world'};
    PostModel
      .create(postJson)
      .save().then(function(post) {
        ok(post.get('id'), 'ID is set');
        ok(post.get('id') === postJson.id, 'ID has same value as originally set.');
        start();
      });
  });

  asyncTest('when a record is created we should be able to find it by its id', function() {
    var postJson = {id: 1, title: 'Hello world'};
    PostModel.create(postJson)
      .save().then(function(savedPost) {

        var loadedPost = PostModel.find(postJson.id);
        Ember.loadPromise(loadedPost).then(function() {
          ok(loadedPost, 'a post is found');
          ok(loadedPost === savedPost, 'the loaded post is the same as the saved post');
          start();
        });
      });
  });

  asyncTest('when a record is created then deleted from the cache we should be still able to find it by its id', function() {
    var postJson = {id: 1, title: 'Hello world'};
    PostModel.create(postJson)
      .save().then(function(savedPost) {
        // Clear the cache so that ember-model is forced to load our object from the adapter.
        PostModel.clearCache();

        var loadedPost = PostModel.find(postJson.id);
        return Ember.loadPromise(loadedPost).then(function() {
          ok(loadedPost, 'a post is found');
          deepEqual(loadedPost.toJSON(), savedPost.toJSON(), 'the loaded post is the same as the saved post');
          start();
        });
      });
  });

  asyncTest('when a record is deleted it should be marked as deleted', function() {
    var postJson = {id: 1, title: 'Hello world'};
    PostModel.create(postJson)
      .save().then(function(savedPost) {
        savedPost.deleteRecord().then(function() {
          var loadedPost = PostModel.find(postJson.id);
          ok(loadedPost.isDeleted, 'The model isDeleted');
          start();
        });
      });
  });

  // The behaviour here is not what I would expect but seems to mirror other ember-model adapters
  // see https://github.com/ebryn/ember-model/issues/248
  asyncTest('when a record is deleted and cache is emptied nothing should be found', function() {
    var postJson = {id: 1, title: 'Hello world'};
    PostModel.create(postJson)
      .save().then(function(savedPost) {
        savedPost.deleteRecord().then(function() {
          PostModel.clearCache();
          var loadedPost = PostModel.find(postJson.id);
          return Ember.loadPromise(loadedPost).then(
            function() {
              // An empty record comes back which isn't what I would expect but the only thing I can think to test against
              // is that the title comes back empty
              ok(!loadedPost.get('title'), 'no title for the returned post');
              start();
            }
          );
        });
      });
  });

  asyncTest('when two records are created findAll should return both records', function() {
    PostModel.create({id:1, title:'Hello world'}).save()
      .then(function() {
        return PostModel.create({id:2, title:'Goodbye cruel world'}).save();
      }).then(function() {
        var records = PostModel.find();
        Ember.loadPromise(records).then(function(records) {
          equal(records.get('content').length, 2, 'There are two records');
          start();
        });
      });
  });

  asyncTest('when two records are created and one has been removed from cache findAll should return both records', function() {
    PostModel.create({id:1, title:'Hello world'}).save()
      .then(function() {
        PostModel.clearCache();
        return PostModel.create({id:2, title:'Goodbye cruel world'}).save();
      }).then(function() {
        var records = PostModel.find();
        Ember.loadPromise(records).then(function(records) {
          equal(records.get('content').length, 2, 'There are two records');
          start();
        });
      });
  });
})();
<|endoftext|>


<commit_before>'use-script';

var connectLr         = require('connect-livereload'),
    express           = require('express'),
    app               = express(),
    expressPort       = 4000,
    expressRoot       = require('path').resolve('./.tmp'),
    gulp              = require('gulp'),
    liveReloadPort    = 35729,
    lrServer          = require('tiny-lr')(),
    permitIndexReload = true,
    plugins           = require('gulp-load-plugins')(),
    publicDir         = require('path').resolve('./dist'),
    source            = require('vinyl-source-stream'),
    mainBowerFiles    = require('main-bower-files'),
    watchify          = require('watchify');

function startExpress() {
  app.use(connectLr());
  app.use(express.static(expressRoot));
  app.listen(expressPort);
}

function startLiveReload() {
  lrServer.listen(liveReloadPort, function(err) {
    if (err) {
      return console.log(err);
    }
  });
}

function notifyLivereload(fileName) {
  if (fileName !== 'index.html' || permitIndexReload) {
    lrServer.changed({ body: { files: [fileName] } });

    if (fileName === 'index.html') {
      permitIndexReload = false;
      setTimeout(function() { permitIndexReload = true; }, 5000);
    }
  }
}

function clean(relativePath, cb) {
  plugins.util.log('Cleaning: ' + plugins.util.colors.blue(relativePath));

  gulp
    .src([(publicDir + relativePath), (expressRoot + relativePath)], {read: false})
    .pipe(plugins.rimraf({force: true}))
    .on('end', cb || function() {});
}

function scripts(cb) {
  var bundler = watchify('./src/app/app.js');

  function rebundle() {
    clean('/app*.js', function() {
      plugins.util.log('Rebuilding application JS bundle');

      return bundler.bundle({ debug: true})
        .pipe(source('app.js'))
        .pipe(plugins.streamify(plugins.rev()))
        .pipe(gulp.dest(expressRoot + '/'))
        .pipe(plugins.streamify(plugins.uglify({ mangle: false })))
        .pipe(plugins.streamify(plugins.size({ showFiles: true })))
        .pipe(gulp.dest(publicDir + '/'))
        .on('end', cb || function() {})
        .on('error', plugins.util.log);
    });

  }
  bundler.on('update', rebundle);
  bundler.on('error', plugins.util.log);
  rebundle();
}

function styles(cb) {
  clean('/templates*.js', function() {
    plugins.util.log('Rebuilding templates');

    gulp.src('app/**/*.html')
      .pipe(plugins.angularTemplatecache({
        root:   'views/',
        module: 'clientApp'
      }))
      .pipe(plugins.streamify(plugins.rev()))
      .pipe(gulp.dest(expressRoot + '/'))
      .pipe(gulp.dest(publicDir + '/'))
      .on('end', cb || function() {})
      .on('error', plugins.util.log);
  });
}

function templates(cb) {
  clean('/app/templates*.js', function() {
    plugins.util.log('Rebuilding templates');

    gulp.src('app/**/*.html')
      .pipe(plugins.angularTemplatecache({
        root: 'views/',
        module: 'stories-with-friends'
      }))
      .pipe(plugins.streamify(plugins.rev()))
      .pipe(gulp.dest(expressRoot + '/'))
      .pipe(gulp.dest(publicDir + '/'))
      .on('end', cb)
      .on('error', plugins.util.log)
  });
}

function shims(cb) {
  cb();
}

function vendor(cb) {
  clean('/app/vendor*.js', function() {
    plugins.util.log('Rebuilding vendor JS bundle');

    gulp.src(mainBowerFiles())
      .pipe(plugins.concat('vendor.js'))
      .pipe(plugins.streamify(plugins.uglify({ mangle: false })))
      .pipe(plugins.streamify(plugins.rev()))
      .pipe(plugins.size({ showFiles: true }))
      .pipe(gulp.dest(expressRoot + '/'))
      .pipe(gulp.dest(publicDir + '/'))
      .on('end', cb || function() {})
      .on('error', plugins.util.log);
  });
}

function images(cb) {
  clean('/images', function() {
    plugins.util.log('Minifying images');

    gulp.src('app/images/**/*.*')
      .pipe(plugins.imagemin())
      .pipe(plugins.size({ showFiles: true }))
      .pipe(gulp.dest(expressRoot + '/images'))
      .pipe(gulp.dest(publicDir + '/images'))
      .on('end', cb || function() {})
      .on('error', plugins.util.log);
  });
}

function fonts(cb) {
  clean('/styles/fonts/icons', function() {
    plugins.util.log('Copying fonts');

    gulp.src('app/styles/fonts/icons/*.*')
      .pipe(gulp.dest(publicDir + '/styles/fonts/icons'))
      .pipe(gulp.dest(expressRoot + '/styles/fonts/icons'))
      .on('end', cb || function() {})
      .on('error', plugins.util.log);
  });
}

function indexHtml(cb) {
  plugins.util.log('Rebuilding index.html');

  function inject(glob, path, tag) {
    return plugins.inject(
      gulp.src(glob, {
        cwd: path
      }), {
        starttag: '<!-- inject:' + tag + ':{{ext}} -->'
      }
    );
  }

  function buildIndex(path, cb) {
    gulp.src('app/index.html')
      .pipe(inject('./style*.css', path, 'app-style'))
      .pipe(inject('./shim*.js', path, 'shim'))
      .pipe(inject('./vendor*.js', path, 'vendor'))
      .pipe(inject('./app*.js', path, 'app'))
      .pipe(inject('./templates*.js', path, 'templates'))
      .pipe(gulp.dest(path))
      .on('end', cb || function() {})
      .on('error', plugins.util.log);
  }

  buildIndex(expressRoot, cb || function(){});
  buildIndex(publicDir, function(){});
}

gulp.task('default', function () {
  startExpress();
  startLiveReload();
  fonts();
  images();
  styles(indexHtml);
  templates(indexHtml);
  shims(indexHtml);
  scripts(function() {
    indexHtml(function() {
      notifyLivereload('index.html');
    });
  });

  gulp.watch('bower.json', function() {
    vendor(function() {
      indexHtml(function() {
        notifyLivereload('index.html');
      });
    });
  });

  gulp.watch('src/shims.js', function() {
    shims(function() {
      indexHtml(function() {
        notifyLivereload('index.html');
      });
    });
  });

  gulp.watch(['src/styles/**/*', '!src/styles/fonts/**/*'], function() {
    styles(function() {
      indexHtml(function() {
        notifyLivereload('style.css');
      });
    });
  });

  gulp.watch('src/styles/fonts/**/*', function() {
    fonts(function() {
      styles(function() {
        indexHtml(function() {
          notifyLivereload('style.css');
        });
      });
    });
  });

  gulp.watch('src/images/**/*', function() {
    images(function() {
      indexHtml(function() {
        notifyLivereload('index.html');
      });
    });
  });

  gulp.watch('src/app/**/*.html', function() {
    templates(function() {
      indexHtml(function() {
        notifyLivereload('index.html');
      });
    });
  });

  gulp.watch('src/index.html', function() {
    indexHtml(function() {
      notifyLivereload('index.html');
    });
  });
});
<commit_msg>Build the correct index.html<commit_after>'use-script';

var connectLr         = require('connect-livereload'),
    express           = require('express'),
    app               = express(),
    expressPort       = 4000,
    expressRoot       = require('path').resolve('./.tmp'),
    gulp              = require('gulp'),
    liveReloadPort    = 35729,
    lrServer          = require('tiny-lr')(),
    permitIndexReload = true,
    plugins           = require('gulp-load-plugins')(),
    publicDir         = require('path').resolve('./dist'),
    source            = require('vinyl-source-stream'),
    mainBowerFiles    = require('main-bower-files'),
    watchify          = require('watchify');

function startExpress() {
  app.use(connectLr());
  app.use(express.static(expressRoot));
  app.listen(expressPort);
}

function startLiveReload() {
  lrServer.listen(liveReloadPort, function(err) {
    if (err) {
      return console.log(err);
    }
  });
}

function notifyLivereload(fileName) {
  if (fileName !== 'index.html' || permitIndexReload) {
    lrServer.changed({ body: { files: [fileName] } });

    if (fileName === 'index.html') {
      permitIndexReload = false;
      setTimeout(function() { permitIndexReload = true; }, 5000);
    }
  }
}

function clean(relativePath, cb) {
  plugins.util.log('Cleaning: ' + plugins.util.colors.blue(relativePath));

  gulp
    .src([(publicDir + relativePath), (expressRoot + relativePath)], {read: false})
    .pipe(plugins.rimraf({force: true}))
    .on('end', cb || function() {});
}

function scripts(cb) {
  var bundler = watchify('./src/app/app.js');

  function rebundle() {
    clean('/app*.js', function() {
      plugins.util.log('Rebuilding application JS bundle');

      return bundler.bundle({ debug: true})
        .pipe(source('app.js'))
        .pipe(plugins.streamify(plugins.rev()))
        .pipe(gulp.dest(expressRoot + '/'))
        .pipe(plugins.streamify(plugins.uglify({ mangle: false })))
        .pipe(plugins.streamify(plugins.size({ showFiles: true })))
        .pipe(gulp.dest(publicDir + '/'))
        .on('end', cb || function() {})
        .on('error', plugins.util.log);
    });

  }
  bundler.on('update', rebundle);
  bundler.on('error', plugins.util.log);
  rebundle();
}

function styles(cb) {
  clean('/templates*.js', function() {
    plugins.util.log('Rebuilding templates');

    gulp.src('app/**/*.html')
      .pipe(plugins.angularTemplatecache({
        root:   'views/',
        module: 'clientApp'
      }))
      .pipe(plugins.streamify(plugins.rev()))
      .pipe(gulp.dest(expressRoot + '/'))
      .pipe(gulp.dest(publicDir + '/'))
      .on('end', cb || function() {})
      .on('error', plugins.util.log);
  });
}

function templates(cb) {
  clean('/app/templates*.js', function() {
    plugins.util.log('Rebuilding templates');

    gulp.src('app/**/*.html')
      .pipe(plugins.angularTemplatecache({
        root: 'views/',
        module: 'stories-with-friends'
      }))
      .pipe(plugins.streamify(plugins.rev()))
      .pipe(gulp.dest(expressRoot + '/'))
      .pipe(gulp.dest(publicDir + '/'))
      .on('end', cb)
      .on('error', plugins.util.log)
  });
}

function shims(cb) {
  cb();
}

function vendor(cb) {
  clean('/app/vendor*.js', function() {
    plugins.util.log('Rebuilding vendor JS bundle');

    gulp.src(mainBowerFiles())
      .pipe(plugins.concat('vendor.js'))
      .pipe(plugins.streamify(plugins.uglify({ mangle: false })))
      .pipe(plugins.streamify(plugins.rev()))
      .pipe(plugins.size({ showFiles: true }))
      .pipe(gulp.dest(expressRoot + '/'))
      .pipe(gulp.dest(publicDir + '/'))
      .on('end', cb || function() {})
      .on('error', plugins.util.log);
  });
}

function images(cb) {
  clean('/images', function() {
    plugins.util.log('Minifying images');

    gulp.src('app/images/**/*.*')
      .pipe(plugins.imagemin())
      .pipe(plugins.size({ showFiles: true }))
      .pipe(gulp.dest(expressRoot + '/images'))
      .pipe(gulp.dest(publicDir + '/images'))
      .on('end', cb || function() {})
      .on('error', plugins.util.log);
  });
}

function fonts(cb) {
  clean('/styles/fonts/icons', function() {
    plugins.util.log('Copying fonts');

    gulp.src('app/styles/fonts/icons/*.*')
      .pipe(gulp.dest(publicDir + '/styles/fonts/icons'))
      .pipe(gulp.dest(expressRoot + '/styles/fonts/icons'))
      .on('end', cb || function() {})
      .on('error', plugins.util.log);
  });
}

function indexHtml(cb) {
  plugins.util.log('Rebuilding index.html');

  function inject(glob, path, tag) {
    return plugins.inject(
      gulp.src(glob, {
        cwd: path
      }), {
        starttag: '<!-- inject:' + tag + ':{{ext}} -->'
      }
    );
  }

  function buildIndex(path, cb) {
    gulp.src('src/index.html')
      .pipe(inject('./style*.css', path, 'app-style'))
      .pipe(inject('./shim*.js', path, 'shim'))
      .pipe(inject('./vendor*.js', path, 'vendor'))
      .pipe(inject('./app*.js', path, 'app'))
      .pipe(inject('./templates*.js', path, 'templates'))
      .pipe(gulp.dest(path))
      .on('end', cb || function() {})
      .on('error', plugins.util.log);
  }

  buildIndex(expressRoot, cb || function(){});
  buildIndex(publicDir, function(){});
}

gulp.task('default', function () {
  startExpress();
  startLiveReload();
  fonts();
  images();
  styles(indexHtml);
  templates(indexHtml);
  shims(indexHtml);
  scripts(function() {
    indexHtml(function() {
      notifyLivereload('index.html');
    });
  });

  gulp.watch('bower.json', function() {
    vendor(function() {
      indexHtml(function() {
        notifyLivereload('index.html');
      });
    });
  });

  gulp.watch('src/shims.js', function() {
    shims(function() {
      indexHtml(function() {
        notifyLivereload('index.html');
      });
    });
  });

  gulp.watch(['src/styles/**/*', '!src/styles/fonts/**/*'], function() {
    styles(function() {
      indexHtml(function() {
        notifyLivereload('style.css');
      });
    });
  });

  gulp.watch('src/styles/fonts/**/*', function() {
    fonts(function() {
      styles(function() {
        indexHtml(function() {
          notifyLivereload('style.css');
        });
      });
    });
  });

  gulp.watch('src/images/**/*', function() {
    images(function() {
      indexHtml(function() {
        notifyLivereload('index.html');
      });
    });
  });

  gulp.watch('src/app/**/*.html', function() {
    templates(function() {
      indexHtml(function() {
        notifyLivereload('index.html');
      });
    });
  });

  gulp.watch('src/index.html', function() {
    indexHtml(function() {
      notifyLivereload('index.html');
    });
  });
});
<|endoftext|>


<commit_before>const handlebars = require('handlebars');

const responses = {};
const catchers  = {
	debug: log,
	info:  log,
	warn:  log,
	error: log,
	fatal: log,
};

function logger(level) {
	return function (code, reasons, meta) {
		var err = createError(code, reasons, meta);

		propagateError(level, err);

		return err;
	};
}

function log(level, err) {
	// Pad so the codes of error/fatal line up with that of info and warn
	// TODO: print out inner errors instead of swallowing them (just verbose mode?)
	var errorString = message(level, err);

	level = level == 'fatal' ? 'error' : level;
	if (level in console) {
		console[level](errorString);
	}
	else {
		console.log(errorString);
	}
}

function message(level, err) {
	var errorString = pad(level, 5) + ": " + err.code;
	const desc = err.meta;

	if (desc)
		errorString += "\n" + JSON.stringify(desc);

	return errorString;
}

function pad(str, len) {
	while (str.length < len)
		str += " ";

	return str;
}

function description(err) {
	const response = responses[err.code];

	return typeof response === 'undefined' ? "" : response(err.meta);
}

function createError(code, reasons, meta) {
	if (!Array.isArray(reasons)) {
		meta = reasons;
		reasons = undefined;
	}

	return {
		code:       code,
		reasons:    reasons,
		meta:       meta,
	};
}

function propagateError(level, err) {
	if (!(level in catchers))
		return;

	catchers[level](level, err);
}

function addCatch(level, catcher) {
	if (typeof catcher === 'undefined') {
		catcher = level;

		if (typeof catcher !== 'function')
			throw logger('error')('register-catch-error', { catcher: catcher });

		for (var prop in catchers)
		{
			catchers[prop] = catcher;
		}

		return;
	}

	if (typeof catcher !== 'function')
		throw logger('error')('register-catch-error', { catcher: catcher });

	catchers[level] = catcher;
}

module.exports = {
	info:         logger('info'),
	warn:         logger('warn'),
	debug:        logger('debug'),
	error:        logger('error'),
	fatal:        logger('fatal'),
	handler:      addCatch,
	create:       createError
};
<commit_msg>JSHint suggested changes<commit_after>const responses = {};

const catchers  = {
	debug: log,
	info: log,
	warn: log,
	error: log,
	fatal: log,
};

function logger(level) {
	return function (code, reasons, meta) {
		var err = createError(code, reasons, meta);

		propagateError(level, err);

		return err;
	};
}

function log(level, err) {
	// Pad so the codes of error/fatal line up with that of info and warn
	// TODO: print out inner errors instead of swallowing them (just verbose mode?)
	var errorString = message(level, err);

	level = level == 'fatal' ? 'error' : level;
	if (level in console) {
		console[level](errorString);
	}
	else {
		console.log(errorString);
	}
}

function message(level, err) {
	var errorString = pad(level, 5) + ': ' + err.code;
	const desc = err.meta;

	if (desc)
		errorString += '\n' + JSON.stringify(desc);

	return errorString;
}

function pad(str, len) {
	if (str.length < len)
		str += new Array(len - str.length + 1).join(' ');

	return str;
}

function description(err) {
	const response = responses[err.code];

	if (typeof response === 'undefined')
		return '';

	return response(err.meta);
}

function createError(code, reasons, meta) {
	if (!Array.isArray(reasons)) {
		meta = reasons;
		reasons = undefined;
	}

	return {
		code:    code,
		reasons: reasons,
		meta:    meta,
	};
}

function propagateError(level, err) {
	if (!(level in catchers))
		return;

	catchers[level](level, err);
}

function addCatch(level, catcher) {
	if (typeof catcher === 'undefined') {
		catcher = level;

		if (typeof catcher !== 'function')
			throw logger('error')('register-catch-error', { catcher: catcher });

		for (var prop in catchers)
			catchers[prop] = catcher;

		return;
	}

	if (typeof catcher !== 'function')
		throw logger('error')('register-catch-error', { catcher: catcher });

	catchers[level] = catcher;
}

module.exports = {
	debug:   logger('debug'),
	info:    logger('info'),
	warn:    logger('warn'),
	error:   logger('error'),
	fatal:   logger('fatal'),
	handler: addCatch,
	create:  createError
};
<|endoftext|>


<commit_before>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var Class = require('../../../utils/Class');
var GetFastValue = require('../../../utils/object/GetFastValue');
var PointLightShaderSourceFS = require('../shaders/PointLight-frag.js');
var PointLightShaderSourceVS = require('../shaders/PointLight-vert.js');
var PostFXPipeline = require('./PostFXPipeline');
var WEBGL_CONST = require('../const');

var LightPipeline = new Class({

    Extends: PostFXPipeline,

    initialize:

    function LightPipeline (config)
    {
        config.shaders = GetFastValue(config, 'shaders', [
            {
                name: 'PointLight',
                fragShader: PointLightShaderSourceFS,
                vertShader: PointLightShaderSourceVS,
                attributes: [
                    {
                        name: 'inPosition',
                        size: 2,
                        type: WEBGL_CONST.FLOAT
                    },
                    {
                        name: 'inLightPosition',
                        size: 2,
                        type: WEBGL_CONST.FLOAT
                    },
                    {
                        name: 'inLightRadius',
                        size: 1,
                        type: WEBGL_CONST.FLOAT
                    },
                    {
                        name: 'inLightColor',
                        size: 4,
                        type: WEBGL_CONST.FLOAT
                    }
                ],
                uniforms: [
                    'uProjectionMatrix',
                    'uResolution'
                ]
            }
        ]);

        PostFXPipeline.call(this, config);
    }

});

module.exports = LightPipeline;
<commit_msg>Back to Normal Map only pipeline<commit_after>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @author       Felipe Alfonso <@bitnenfer>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var Class = require('../../../utils/Class');
var GetFastValue = require('../../../utils/object/GetFastValue');
var LightShaderSourceFS = require('../shaders/Light-frag.js');
var SinglePipeline = require('./SinglePipeline');
var TransformMatrix = require('../../../gameobjects/components/TransformMatrix');
var WebGLPipeline = require('../WebGLPipeline');

var LIGHT_COUNT = 10;

/**
 * @classdesc
 *
 * The Light Pipeline is an extension of the Multi Pipeline and uses a custom shader
 * designed to handle forward diffused rendering of 2D lights in a Scene.
 *
 * The shader works in tandem with Light Game Objects, and optionally texture normal maps,
 * to provide an ambient illumination effect.
 *
 * If you wish to provide your own shader, you can use the `%LIGHT_COUNT%` declaration in the source,
 * and it will be automatically replaced at run-time with the total number of configured lights.
 *
 * The maximum number of lights can be set in the Render Config `maxLights` property and defaults to 10.
 *
 * Prior to Phaser v3.50 this pipeline was called the `ForwardDiffuseLightPipeline`.
 *
 * The fragment shader it uses can be found in `shaders/src/Light.frag`.
 * The vertex shader it uses can be found in `shaders/src/Multi.vert`.
 *
 * The default shader attributes for this pipeline are:
 *
 * `inPosition` (vec2, offset 0)
 * `inTexCoord` (vec2, offset 8)
 * `inTexId` (float, offset 16)
 * `inTintEffect` (float, offset 20)
 * `inTint` (vec4, offset 24, normalized)
 *
 * The default shader uniforms for this pipeline are:
 *
 * `uProjectionMatrix` (mat4)
 * `uViewMatrix` (mat4)
 * `uModelMatrix` (mat4)
 * `uMainSampler` (sampler2D)
 * `uNormSampler` (sampler2D)
 * `uCamera` (vec4)
 * `uResolution` (vec2)
 * `uAmbientLightColor` (vec3)
 * `uInverseRotationMatrix` (mat3)
 * `uLights` (Light struct)
 *
 * @class LightPipeline
 * @extends Phaser.Renderer.WebGL.Pipelines.MultiPipeline
 * @memberof Phaser.Renderer.WebGL.Pipelines
 * @constructor
 * @since 3.50.0
 *
 * @param {Phaser.Types.Renderer.WebGL.WebGLPipelineConfig} config - The configuration options for this pipeline.
 */
var LightPipeline = new Class({

    Extends: SinglePipeline,

    initialize:

    function LightPipeline (config)
    {
        LIGHT_COUNT = config.game.renderer.config.maxLights;

        config.fragShader = GetFastValue(config, 'fragShader', LightShaderSourceFS).replace('%LIGHT_COUNT%', LIGHT_COUNT.toString());

        SinglePipeline.call(this, config);

        /**
         * A temporary Transform Matrix, re-used internally during batching.
         *
         * @name Phaser.Renderer.WebGL.Pipelines.MultiPipeline#tempMatrix1
         * @type {Phaser.GameObjects.Components.TransformMatrix}
         * @since 3.11.0
         */
        this.tempMatrix1 = new TransformMatrix();

        /**
         * A temporary Transform Matrix, re-used internally during batching.
         *
         * @name Phaser.Renderer.WebGL.Pipelines.MultiPipeline#tempMatrix2
         * @type {Phaser.GameObjects.Components.TransformMatrix}
         * @since 3.11.0
         */
        this.tempMatrix2 = new TransformMatrix();

        /**
         * A temporary Transform Matrix, re-used internally during batching.
         *
         * @name Phaser.Renderer.WebGL.Pipelines.MultiPipeline#tempMatrix3
         * @type {Phaser.GameObjects.Components.TransformMatrix}
         * @since 3.11.0
         */
        this.tempMatrix3 = new TransformMatrix();

        /**
         * Inverse rotation matrix for normal map rotations.
         *
         * @name Phaser.Renderer.WebGL.Pipelines.LightPipeline#inverseRotationMatrix
         * @type {Float32Array}
         * @private
         * @since 3.16.0
         */
        this.inverseRotationMatrix = new Float32Array([
            1, 0, 0,
            0, 1, 0,
            0, 0, 1
        ]);

        /**
         * Stores a default normal map, which is an object with a `glTexture` property that
         * maps to a 1x1 texture of the color #7f7fff created in the `boot` method.
         *
         * @name Phaser.Renderer.WebGL.Pipelines.LightPipeline#defaultNormalMap
         * @type {object}
         * @since 3.50.0
         */
        this.defaultNormalMap;

        /**
         * Stores the previous number of lights rendered.
         *
         * @name Phaser.Renderer.WebGL.Pipelines.LightPipeline#lightCount
         * @type {number}
         * @since 3.50.0
         */
        this.lightCount = 0;
    },

    /**
     * Called when the Game has fully booted and the Renderer has finished setting up.
     *
     * By this stage all Game level systems are now in place and you can perform any final
     * tasks that the pipeline may need that relied on game systems such as the Texture Manager.
     *
     * @method Phaser.Renderer.WebGL.Pipelines.LightPipeline#boot
     * @since 3.11.0
     */
    boot: function ()
    {
        WebGLPipeline.prototype.boot.call(this);

        var gl = this.gl;

        var tempTexture = gl.createTexture();

        gl.activeTexture(gl.TEXTURE0);

        gl.bindTexture(gl.TEXTURE_2D, tempTexture);

        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([ 127, 127, 255, 255 ]));

        this.defaultNormalMap = { glTexture: tempTexture };
    },

    /**
     * Called every time a Game Object needs to use this pipeline.
     *
     * @method Phaser.Renderer.WebGL.Pipelines.MultiPipeline#onBind
     * @since 3.0.0
     *
     * @param {Phaser.GameObjects.GameObject} [gameObject] - The Game Object that invoked this pipeline, if any.
     *
     * @return {this} This WebGLPipeline instance.
     */
    onBind: function ()
    {
        this.set1i('uMainSampler', 0);
        this.set1i('uNormSampler', 1);
        this.set2f('uResolution', this.width / 2, this.height / 2);
    },

    /**
     * This function sets all the needed resources for each camera pass.
     *
     * @method Phaser.Renderer.WebGL.Pipelines.LightPipeline#onRender
     * @ignore
     * @since 3.0.0
     *
     * @param {Phaser.Scene} scene - The Scene being rendered.
     * @param {Phaser.Cameras.Scene2D.Camera} camera - The Scene Camera being rendered with.
     *
     * @return {this} This WebGLPipeline instance.
     */
    onRender: function (scene, camera)
    {
        this.active = false;

        var lightManager = scene.sys.lights;

        if (!lightManager || lightManager.lights.length <= 0 || !lightManager.active)
        {
            //  Passthru
            return this;
        }

        var lights = lightManager.cull(camera);
        var lightCount = Math.min(lights.length, LIGHT_COUNT);

        if (lightCount === 0)
        {
            return this;
        }

        this.active = true;

        var renderer = this.renderer;
        var program = this.program;
        var cameraMatrix = camera.matrix;
        var point = {x: 0, y: 0};
        var height = renderer.height;
        var i;

        if (lightCount !== this.lightCount)
        {
            for (i = 0; i < LIGHT_COUNT; i++)
            {
                //  Reset lights
                renderer.setFloat1(program, 'uLights[' + i + '].radius', 0);
            }

            this.lightCount = lightCount;
        }

        if (camera.dirty)
        {
            renderer.setFloat4(program, 'uCamera', camera.x, camera.y, camera.rotation, camera.zoom);
        }

        //  TODO - Only if dirty! and cache the location
        renderer.setFloat3(program, 'uAmbientLightColor', lightManager.ambientColor.r, lightManager.ambientColor.g, lightManager.ambientColor.b);

        for (i = 0; i < lightCount; i++)
        {
            var light = lights[i];
            var lightName = 'uLights[' + i + '].';

            cameraMatrix.transformPoint(light.x, light.y, point);

            //  TODO - Cache the uniform locations!!!
            renderer.setFloat2(program, lightName + 'position', point.x - (camera.scrollX * light.scrollFactorX * camera.zoom), height - (point.y - (camera.scrollY * light.scrollFactorY) * camera.zoom));

            if (light.dirty)
            {
                renderer.setFloat3(program, lightName + 'color', light.r, light.g, light.b);
                renderer.setFloat1(program, lightName + 'intensity', light.intensity);
                renderer.setFloat1(program, lightName + 'radius', light.radius);
                light.dirty = false;
            }
        }

        this.currentNormalMapRotation = null;

        return this;
    },

    /**
     * Rotates the normal map vectors inversely by the given angle.
     * Only works in 2D space.
     *
     * @method Phaser.Renderer.WebGL.Pipelines.LightPipeline#setNormalMapRotation
     * @since 3.16.0
     *
     * @param {number} rotation - The angle of rotation in radians.
     */
    setNormalMapRotation: function (rotation)
    {
        if (rotation !== this.currentNormalMapRotation || this.vertexCount === 0)
        {
            if (this.vertexCount > 0)
            {
                this.flush();
            }

            var inverseRotationMatrix = this.inverseRotationMatrix;

            if (rotation)
            {
                var rot = -rotation;
                var c = Math.cos(rot);
                var s = Math.sin(rot);

                inverseRotationMatrix[1] = s;
                inverseRotationMatrix[3] = -s;
                inverseRotationMatrix[0] = inverseRotationMatrix[4] = c;
            }
            else
            {
                inverseRotationMatrix[0] = inverseRotationMatrix[4] = 1;
                inverseRotationMatrix[1] = inverseRotationMatrix[3] = 0;
            }

            this.renderer.setMatrix3(this.program, 'uInverseRotationMatrix', false, inverseRotationMatrix);

            this.currentNormalMapRotation = rotation;
        }
    },

    /**
     * Assigns a texture to the current batch. If a different texture is already set it creates a new batch object.
     *
     * @method Phaser.Renderer.WebGL.Pipelines.LightPipeline#setTexture2D
     * @ignore
     * @since 3.50.0
     *
     * @param {WebGLTexture} [texture] - WebGLTexture that will be assigned to the current batch. If not given uses blankTexture.
     * @param {Phaser.GameObjects.GameObject} [gameObject] - The Game Object being rendered or added to the batch.
     */
    setTexture2D: function (texture, gameObject)
    {
        var renderer = this.renderer;

        if (texture === undefined) { texture = renderer.tempTextures[0]; }

        var normalTexture = this.getNormalMap(gameObject);

        if (renderer.isNewNormalMap())
        {
            this.flush();

            renderer.setTextureZero(texture);
            renderer.setNormalMap(normalTexture);
        }

        var rotation = (gameObject) ? gameObject.rotation : 0;

        this.setNormalMapRotation(rotation);

        this.currentUnit = 0;

        return 0;
    },

    /**
     * Custom pipelines can use this method in order to perform any required pre-batch tasks
     * for the given Game Object. It must return the texture unit the Game Object was assigned.
     *
     * @method Phaser.Renderer.WebGL.Pipelines.LightPipeline#setGameObject
     * @ignore
     * @since 3.50.0
     *
     * @param {Phaser.GameObjects.GameObject} gameObject - The Game Object being rendered or added to the batch.
     * @param {Phaser.Textures.Frame} [frame] - Optional frame to use. Can override that of the Game Object.
     *
     * @return {number} The texture unit the Game Object has been assigned.
     */
    setGameObject: function (gameObject, frame)
    {
        if (frame === undefined) { frame = gameObject.frame; }

        var renderer = this.renderer;
        var texture = frame.glTexture;
        var normalTexture = this.getNormalMap(gameObject);

        if (renderer.isNewNormalMap())
        {
            this.flush();

            renderer.setTextureZero(texture);
            renderer.setNormalMap(normalTexture);
        }

        this.setNormalMapRotation(gameObject.rotation);

        this.currentUnit = 0;

        return 0;
    },

    /**
     * Returns the normal map WebGLTexture from the given Game Object.
     * If the Game Object doesn't have one, it returns the default normal map from this pipeline instead.
     *
     * @method Phaser.Renderer.WebGL.Pipelines.LightPipeline#getNormalMap
     * @since 3.50.0
     *
     * @param {Phaser.GameObjects.GameObject} [gameObject] - The Game Object to get the normal map from.
     *
     * @return {WebGLTexture} The normal map texture.
     */
    getNormalMap: function (gameObject)
    {
        var normalTexture;

        if (!gameObject)
        {
            normalTexture = this.defaultNormalMap;
        }
        else if (gameObject.displayTexture)
        {
            normalTexture = gameObject.displayTexture.dataSource[gameObject.displayFrame.sourceIndex];
        }
        else if (gameObject.texture)
        {
            normalTexture = gameObject.texture.dataSource[gameObject.frame.sourceIndex];
        }
        else if (gameObject.tileset)
        {
            if (Array.isArray(gameObject.tileset))
            {
                normalTexture = gameObject.tileset[0].image.dataSource[0];
            }
            else
            {
                normalTexture = gameObject.tileset.image.dataSource[0];
            }
        }

        if (!normalTexture)
        {
            normalTexture = this.defaultNormalMap;
        }

        return normalTexture.glTexture;
    }

});

LightPipeline.LIGHT_COUNT = LIGHT_COUNT;

module.exports = LightPipeline;
<|endoftext|>