<commit_before>'use strict';

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

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; }; }(); /*
                                                                                MIT License

                                                                                Copyright (c) 2016 Martin Snyder

                                                                                Permission is hereby granted, free of charge, to any person obtaining a copy
                                                                                of this software and associated documentation files (the "Software"), to deal
                                                                                in the Software without restriction, including without limitation the rights
                                                                                to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                                                                                copies of the Software, and to permit persons to whom the Software is
                                                                                furnished to do so, subject to the following conditions:

                                                                                The above copyright notice and this permission notice shall be included in all
                                                                                copies or substantial portions of the Software.

                                                                                THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                                                                                IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                                                                                FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
                                                                                AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                                                                                LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                                                                                OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
                                                                                SOFTWARE.
                                                                                */

var _seamlessImmutable = require('seamless-immutable');

var _seamlessImmutable2 = _interopRequireDefault(_seamlessImmutable);

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

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; }

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

/*
 * Cursor data that is private to the class/module.
 *
 * Instances of this class manage MUTABLE data associated with a cursor. This includes:
 * - The current generation of the immutable state object
 * - The current list of change listeners
 *
 * Because this class is private to the module and never returned to an outside caller,
 * its usage is known to us. It can ONLY be constructed by a root cursor and is shared
 * between the root cursor and any child cursors 'refined' from there.
 */
var PrivateData = function () {
    function PrivateData(initialData) {
        _classCallCheck(this, PrivateData);

        this.currentData = initialData;
        this.changeListeners = [];
    }

    /*
     * Updates the portion of this.currentData referenced by 'path' with the 'newValue'
     */

    _createClass(PrivateData, [{
        key: 'update',
        value: function update(path, newValue) {
            // this.currentData is about to become the "previous generation"
            var prevData = this.currentData;

            // Apply the update to produce the next generation. Because this.currentData has
            // been processed by seamless-immutable, nextData will automatically be immutable as well.
            this.currentData = this.currentData.setIn(path, newValue);

            // Notify all change listeners
            var _iteratorNormalCompletion = true;
            var _didIteratorError = false;
            var _iteratorError = undefined;

            try {
                for (var _iterator = this.changeListeners[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
                    var changeListener = _step.value;

                    // Pass nextData first because many listeners will ONLY care about that.
                    changeListener(this.currentData, prevData, path);
                }
            } catch (err) {
                _didIteratorError = true;
                _iteratorError = err;
            } finally {
                try {
                    if (!_iteratorNormalCompletion && _iterator.return) {
                        _iterator.return();
                    }
                } finally {
                    if (_didIteratorError) {
                        throw _iteratorError;
                    }
                }
            }
        }

        /*
         * Adds a new change listener to this managed data with the following signature:
         *      function changeListener(nextRoot, prevRoot, pathUpdated)
         *
         * Where the parameters pass to this function have the following data types
         *      nextRoot - Next generation of the JSON-style immutable data being managed by a cursor
         *      prevRoot - Previous generation of the JSON-style immutable data being managed by a cursor
         *      pathUpdated - Array of String indicating the keys used to navigate a nested/hierarchical
         *                    structure to the point where the update occurred.
         */

    }, {
        key: 'addListener',
        value: function addListener(changeListener) {
            this.changeListeners.push(changeListener);
        }
    }]);

    return PrivateData;
}();

/*
 * ES6 classes don't have a direct provision for private data, but we can associate data
 * with a class via a WeakMap and hide that WeakMap within the module.
 *
 * This WeakMap is of mapping of Cursor->PrivateData
 */

var privateDataMap = new WeakMap();

/*
 * Implementation of a cursor referencing an evolving immutable data structure.
 *
 * Note that callers of this module CAN receive instances of this class through
 * the normal usage pattern of constructing a 'RootCursor' object and then
 * calling 'refine', but they cannot construct them on their own.
 */

var Cursor = function () {
    /*
     * This class is private to the module, so its constructor is impossible to
     * invoke externally. This is good since the "privateData" parameter of the
     * constructor is not something we want external callers to attempt to provide.
     */
    function Cursor(privateData, path) {
        _classCallCheck(this, Cursor);

        // Keep our private data hidden. This data is 'owned' by a RootCursor and
        // shared with all cursors 'refined' from that root (or 'refined' from a
        // child cursor of that root)
        privateDataMap.set(this, privateData);

        // Path will have already been locked by seamless-immutable
        this.path = path;

        // Freeze ourselves so that callers cannot re-assign the path post-construction
        Object.freeze(this);
    }

    /*
     * Property getter for 'data' property of a cursor. This returns the section of the
     * current generation of immutable data referred to by the path of the cursor.
     *
     * Calling this getter over time may return different results, but the data returned
     * is an immutable object that can be safely referenced without copy.
     *
     * This getter returns undefined in the case where the path specified by the cursor
     * does not exist in the current generation of the managed data.
     */

    _createClass(Cursor, [{
        key: 'refine',

        /*
         * Create a new child cursor from this cursor with the subPath appended to our current path
         */
        value: function refine(subPath) {
            if (subPath.length === 0) {
                return this;
            } else {
                // Because this.path is already immutable, this.path.concat returns
                // a new immutable array.
                return new Cursor(privateDataMap.get(this), this.path.concat(subPath));
            }
        }
    }, {
        key: 'data',
        get: function get() {
            // I didn't see a 'getIn' method in seamless-immutable that was publicly accessible
            // So I rolled my own
            var pointer = privateDataMap.get(this).currentData;
            var _iteratorNormalCompletion2 = true;
            var _didIteratorError2 = false;
            var _iteratorError2 = undefined;

            try {
                for (var _iterator2 = this.path[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
                    var el = _step2.value;

                    pointer = pointer ? pointer[el] : undefined;
                }
            } catch (err) {
                _didIteratorError2 = true;
                _iteratorError2 = err;
            } finally {
                try {
                    if (!_iteratorNormalCompletion2 && _iterator2.return) {
                        _iterator2.return();
                    }
                } finally {
                    if (_didIteratorError2) {
                        throw _iteratorError2;
                    }
                }
            }

            return pointer;
        }

        /*
         * Property setter for 'data' property of a cursor. This creates a new generation
         * of the managed data object with the provided 'newValue' replacing whatever
         * exists in the 'path' of the current generation
         *
         * No attempt is made to address issues such as stale writes. Concurrency issues
         * are the responsibility of caller.
         */
        ,
        set: function set(newValue) {
            privateDataMap.get(this).update(this.path, newValue);
        }
    }]);

    return Cursor;
}();

/*
 * Public entry into this module.
 *
 * RootCursor objects are the same as regular cursor objects except that:
 * 1. The 'root' cursor can be constructed by external callers
 * 2. The 'root' cursor can register changeListeners
 */

var RootCursor = function (_Cursor) {
    _inherits(RootCursor, _Cursor);

    function RootCursor() {
        var initialRoot = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

        _classCallCheck(this, RootCursor);

        // Use seamless-immutable to constrain the initial data. This is the only
        // place where we invoke seamless-immutable because once we do this, our
        // interactions with these objects will only spawn other immutable objects
        return _possibleConstructorReturn(this, (RootCursor.__proto__ || Object.getPrototypeOf(RootCursor)).call(this, new PrivateData((0, _seamlessImmutable2.default)(initialRoot)), (0, _seamlessImmutable2.default)([])));
    }

    /*
     * Adds a new change listener to this cursor with the following signature:
     *      function changeListener(nextRoot, prevRoot, pathUpdated)
     *
     * Where the parameters pass to this function have the following data types
     *      nextRoot - Next generation of the JSON-style immutable data being managed by a cursor
     *      prevRoot - Previous generation of the JSON-style immutable data being managed by a cursor
     *      pathUpdated - Array of String indicating the keys used to navigate a nested/hierarchical
     *                    structure to the point where the update occurred.
     */

    _createClass(RootCursor, [{
        key: 'onChange',
        value: function onChange(changeListener) {
            privateDataMap.get(this).addListener(changeListener);
        }
    }]);

    return RootCursor;
}(Cursor);

exports.default = RootCursor;<commit_msg>Ran prepublish<commit_after>'use strict';

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

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; }; }(); /*
                                                                                MIT License

                                                                                Copyright (c) 2016 Martin Snyder

                                                                                Permission is hereby granted, free of charge, to any person obtaining a copy
                                                                                of this software and associated documentation files (the "Software"), to deal
                                                                                in the Software without restriction, including without limitation the rights
                                                                                to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                                                                                copies of the Software, and to permit persons to whom the Software is
                                                                                furnished to do so, subject to the following conditions:

                                                                                The above copyright notice and this permission notice shall be included in all
                                                                                copies or substantial portions of the Software.

                                                                                THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                                                                                IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                                                                                FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
                                                                                AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                                                                                LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                                                                                OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
                                                                                SOFTWARE.
                                                                                */

var _seamlessImmutable = require('seamless-immutable');

var _seamlessImmutable2 = _interopRequireDefault(_seamlessImmutable);

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

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; }

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

/*
 * Custom getIn function
 *
 * Using custom getIn because Seamless Immutable's getIn function does not default to
 * the original object when path is empty.
 */
function getIn(obj, path) {
    var pointer = obj;
    var _iteratorNormalCompletion = true;
    var _didIteratorError = false;
    var _iteratorError = undefined;

    try {
        for (var _iterator = path[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
            var el = _step.value;

            pointer = pointer ? pointer[el] : undefined;
        }
    } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
    } finally {
        try {
            if (!_iteratorNormalCompletion && _iterator.return) {
                _iterator.return();
            }
        } finally {
            if (_didIteratorError) {
                throw _iteratorError;
            }
        }
    }

    return pointer;
}

/*
 * Cursor data that is private to the class/module.
 *
 * Instances of this class manage MUTABLE data associated with a cursor. This includes:
 * - The current generation of the immutable state object
 * - The current list of change listeners
 *
 * Because this class is private to the module and never returned to an outside caller,
 * its usage is known to us. It can ONLY be constructed by a root cursor and is shared
 * between the root cursor and any child cursors 'refined' from there.
 */

var PrivateData = function () {
    function PrivateData(initialData) {
        _classCallCheck(this, PrivateData);

        this.currentData = initialData;
        this.changeListeners = [];
    }

    /*
     * Updates the portion of this.currentData referenced by 'path' with the 'newValue'
     */

    _createClass(PrivateData, [{
        key: 'update',
        value: function update(path, newValue) {
            // this.currentData is about to become the "previous generation"
            var prevData = this.currentData;

            if (path.length === 0) {
                // Replace the data entirely. We must manually force its immutability when we do this.
                this.currentData = (0, _seamlessImmutable2.default)(newValue);
            } else {
                // Apply the update to produce the next generation. Because this.currentData has
                // been processed by seamless-immutable, nextData will automatically be immutable as well.
                this.currentData = this.currentData.setIn(path, newValue);
            }

            // Notify all change listeners
            var _iteratorNormalCompletion2 = true;
            var _didIteratorError2 = false;
            var _iteratorError2 = undefined;

            try {
                for (var _iterator2 = this.changeListeners[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
                    var changeListener = _step2.value;

                    var shouldUpdate = true;
                    var shorterPathLength = Math.min(path.length, changeListener.path.length);

                    // Only update if the change listener path is a sub-path of the update path (or vice versa)
                    for (var i = 1; i < shorterPathLength; i++) {
                        shouldUpdate = shouldUpdate && path[i] === changeListener.path[i];
                    }

                    if (shouldUpdate) {
                        // Only call change listener if associated path data has changed
                        if (getIn(this.currentData, changeListener.path) !== getIn(prevData, changeListener.path)) {
                            // Pass nextData first because many listeners will ONLY care about that.
                            changeListener(this.currentData, prevData, path);
                        }
                    }
                }
            } catch (err) {
                _didIteratorError2 = true;
                _iteratorError2 = err;
            } finally {
                try {
                    if (!_iteratorNormalCompletion2 && _iterator2.return) {
                        _iterator2.return();
                    }
                } finally {
                    if (_didIteratorError2) {
                        throw _iteratorError2;
                    }
                }
            }
        }

        /*
         * Adds a new change listener to this managed data with the following signature:
         *      function changeListener(nextRoot, prevRoot, pathUpdated)
         *
         * Where the parameters pass to this function have the following data types
         *      nextRoot - Next generation of the JSON-style immutable data being managed by a cursor
         *      prevRoot - Previous generation of the JSON-style immutable data being managed by a cursor
         *      pathUpdated - Array of String indicating the keys used to navigate a nested/hierarchical
         *                    structure to the point where the update occurred.
         */

    }, {
        key: 'addListener',
        value: function addListener(changeListener) {
            this.changeListeners.push(changeListener);
        }

        /*
         * Removes change listener
         */

    }, {
        key: 'removeListener',
        value: function removeListener(changeListener) {
            this.changeListeners.splice(this.changeListeners.indexOf(changeListener), 1);
        }
    }]);

    return PrivateData;
}();

/*
 * ES6 classes don't have a direct provision for private data, but we can associate data
 * with a class via a WeakMap and hide that WeakMap within the module.
 *
 * This WeakMap is of mapping of Cursor->PrivateData
 */

var privateDataMap = new WeakMap();

/*
 * Implementation of a cursor referencing an evolving immutable data structure.
 *
 * Note that callers of this module CAN receive instances of this class through
 * the normal usage pattern of constructing a 'RootCursor' object and then
 * calling 'refine', but they cannot construct them on their own.
 */

var Cursor = function () {
    /*
     * This class is private to the module, so its constructor is impossible to
     * invoke externally. This is good since the "privateData" parameter of the
     * constructor is not something we want external callers to attempt to provide.
     */
    function Cursor(privateData, path) {
        _classCallCheck(this, Cursor);

        // Keep our private data hidden. This data is 'owned' by a RootCursor and
        // shared with all cursors 'refined' from that root (or 'refined' from a
        // child cursor of that root)
        privateDataMap.set(this, privateData);

        // Path will have already been locked by seamless-immutable
        this.path = path;

        // Freeze ourselves so that callers cannot re-assign the path post-construction
        Object.freeze(this);
    }

    /*
     * Property getter for 'data' property of a cursor. This returns the section of the
     * current generation of immutable data referred to by the path of the cursor.
     *
     * Calling this getter over time may return different results, but the data returned
     * is an immutable object that can be safely referenced without copy.
     *
     * This getter returns undefined in the case where the path specified by the cursor
     * does not exist in the current generation of the managed data.
     */

    _createClass(Cursor, [{
        key: 'refine',

        /*
         * Create a new child cursor from this cursor with the subPath appended to our current path
         */
        value: function refine(subPath) {
            if (subPath.length === 0) {
                return this;
            } else {
                // Because this.path is already immutable, this.path.concat returns
                // a new immutable array.
                return new Cursor(privateDataMap.get(this), this.path.concat(subPath));
            }
        }

        /*
         * Adds a new change listener to this cursor with the following signature:
         *      function changeListener(nextRoot, prevRoot, pathUpdated)
         *
         * Where the parameters pass to this function have the following data types
         *      nextRoot - Next generation of the JSON-style immutable data being managed by a cursor
         *      prevRoot - Previous generation of the JSON-style immutable data being managed by a cursor
         *      pathUpdated - Array of String indicating the keys used to navigate a nested/hierarchical
         *                    structure to the point where the update occurred.
         */

    }, {
        key: 'onChange',
        value: function onChange(changeListener) {
            changeListener.path = this.path;
            privateDataMap.get(this).addListener(changeListener, this.path);
        }

        /*
         * Removes change listener
         */

    }, {
        key: 'removeListener',
        value: function removeListener(changeListener) {
            privateDataMap.get(this).removeListener(changeListener);
        }
    }, {
        key: 'data',
        get: function get() {
            return getIn(privateDataMap.get(this).currentData, this.path);
        }

        /*
         * Property setter for 'data' property of a cursor. This creates a new generation
         * of the managed data object with the provided 'newValue' replacing whatever
         * exists in the 'path' of the current generation
         *
         * No attempt is made to address issues such as stale writes. Concurrency issues
         * are the responsibility of caller.
         */
        ,
        set: function set(newValue) {
            privateDataMap.get(this).update(this.path, newValue);
        }
    }]);

    return Cursor;
}();

/*
 * Public entry into this module.
 *
 * RootCursor objects are the same as regular cursor objects except that:
 * 1. The 'root' cursor can be constructed by external callers
 * 2. The 'root' cursor can register changeListeners
 */

var RootCursor = function (_Cursor) {
    _inherits(RootCursor, _Cursor);

    function RootCursor() {
        var initialRoot = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

        _classCallCheck(this, RootCursor);

        // Use seamless-immutable to constrain the initial data. This is the only
        // place where we invoke seamless-immutable because once we do this, our
        // interactions with these objects will only spawn other immutable objects
        return _possibleConstructorReturn(this, (RootCursor.__proto__ || Object.getPrototypeOf(RootCursor)).call(this, new PrivateData((0, _seamlessImmutable2.default)(initialRoot)), (0, _seamlessImmutable2.default)([])));
    }

    return RootCursor;
}(Cursor);

exports.default = RootCursor;<|endoftext|>


<commit_before>// Deps =========================================
const Joi = require('joi');
const Hoek = require('hoek');
const Fs = require('fs-extra');
const Os = require('os');
const Chalk = require('chalk');
const Useragent = require('useragent');
const prettyjson = require('prettyjson');
const stringify = require('fast-safe-stringify');
const pkg = require('../package.json');

// Internals Scope ==============================
const internals = { };

// Validation Shemas ============================
internals.schemas = {
    plugin: Joi.object().keys({
        path: Joi.string().default('./logs'),
        stopTimeoutMsec: Joi.number().default(15 * 1000),
        silent: Joi.boolean().default(false),
        signals: Joi.boolean().default(true),
        exceptions: Joi.boolean().default(true),
        timestampKey: Joi.string().default('@timestamp'),
        unixStamp: Joi.boolean().default(false)
    }),
    write: Joi.object().required().keys({
        async: Joi.boolean().default(true),
        request: Joi.object().default(null),
        entry: Joi.object().required().keys({
            message: Joi.string().required(),
            error: Joi.object(),
            tags: Joi.array().required().items(
                Joi.string().required().valid(['info', 'error', 'warning', 'request', 'plugin']),
                Joi.string()
            )
        })
    })
};

// Write to file ================================
internals.write = (options, callback) => {

    const done = callback || Hoek.ignore; // Done callback
    const result = Joi.validate(options, internals.schemas.write, { allowUnknown: true }); // Validate and merge options

    try {
        //== Check if schema validation had an error
        if (result.error !== null) {
            internals.console(result.error, 'error');

            return done(result.error);
        }

        const { path, silent, timestampKey, unixStamp } = internals.settings;
        const { entry, request, async } = result.value;
        const now = unixStamp ? Date.now() : new Date().toISOString();
        const type = entry.tags.shift();
        const filePath = `${ path }/${ type }.log`;
        const log = Object.assign({}, entry, {
            type,
            [timestampKey]: now,
            host: Os.hostname()
        });

        //== Has request?
        if (request) {
            // Create data from request
            const scoot = Useragent.lookup(request.headers['user-agent']);
            const { method, info, route } = request;
            const req = {
                method,
                remoteIP: info.remoteAddress,
                routePath: route.path,
                referrer: info.referrer,
                received: request.info.received,
                elapsed: Date.now() - request.info.received,
                userAgent: {
                    browser: `${scoot.family} v${scoot.major}.${scoot.minor}.${scoot.patch}`,
                    device: `${scoot.device.family} v${scoot.device.major}.${scoot.device.minor}.${scoot.device.patch}`,
                    os: `${scoot.os.family} v${scoot.os.major}.${scoot.os.minor}.${scoot.os.patch}`
                }
            };

            // Add auth data
            if (request.auth.credentials) {
                req.auth = {
                    isAuthenticated: request.auth.isAuthenticated,
                    credentials: request.auth.credentials
                };
            }

            // Add request vars to log object
            Object.assign(log, { request: req });
        }

        //== Has Error?
        if (entry.error) {
            log.error = entry.error;
        }

        //== Write to file Sync
        if (!async) {
            Fs.outputJsonSync(filePath, log, { flag: 'a' });
            internals.console(log, type);

            return done();
        }

        //== Write to file Async
        Fs.outputJson(filePath, log, { flag: 'a' });

        //== Log to console if not silent
        if (!silent) {
            if (type === 'error') {
                internals.console(log, type);
            } else {
                console.log(stringify(log));
            }
        }

        //== All done
        return done();
    } catch (up) {
        console.log('There was an error:', up);

        throw up; // haha!
    }
};

// Write to console =============================
internals.console = (data = {}, type = 'info', callback) => {

    let bg;
    const done = callback || Hoek.ignore;

    switch (type.toLowerCase()) {
        case 'error':
            bg = 'bgRed';
            break;
        case 'info':
            bg = 'bgBlue';
            break;
        case 'warn':
            bg = 'bgYellow';
            break;
        default:
            bg = 'bgGreen';
            break;
    }

    // Log to console
    if (!internals.settings.silent) {
        console.log(Chalk[bg].bold.white(`\n// ${ type } =====`));
        console.log(`${ prettyjson.render(data) }\n`);
    }

    return done();
};

// Normalize error data =========================
internals.formatError = event => {

    const errInstance = event instanceof Error;

    if (!('error' in event) && errInstance === false) {
        return event;
    }

    let error = {};
    let message = errInstance ? event.message : null;
    let stack = null;
    const err = errInstance ? event : event.error;

    if (err.isJoi) {
        message = err.details.message;
    }

    if (err.isBoom) {
        message = err.message;
    }

    stack = err.stack;
    error = { message, stack };

    return { error };
};

// Process signals logging ======================
internals.signals = (server) => {

    const shutdown = (signal) => {

        return () => {

            const async = false;
            const entry = {
                tags: ['info', 'app', 'signal', signal.toLowerCase()],
                message: `Server shutdown on signal: ${ signal }`
            };

            internals.write({ entry, async });
            server.root.stop({ timeout: internals.settings.stopTimeoutMsec }, process.exit);
        };
    };

    process.once('SIGTERM', shutdown('SIGTERM'));
    process.once('SIGINT', shutdown('SIGINT'));
};

// Exceptions handling ==========================
internals.exceptions = () => {

    const uncaught = (err, promise) => {

        const { error } = internals.formatError(err);
        const result = {
            error,
            message: err.message
        };

        if (promise) {
            result.promise = promise;
        }

        return result;
    };

    process.on('uncaughtException', err => {

        const write = {
            entry: Object.assign(uncaught(err), { tags: ['error', 'uncaught'] }),
            async: false
        };

        return internals.write(write, () => process.exit(1));
    });
    process.on('unhandledRejection', (reason, promise) => {

        const write = {
            entry: Object.assign(uncaught(reason, promise), { tags: ['error', 'uncaught', 'promise'] }),
            async: false
        };

        internals.write(write);
    });
};

// Subscribe to server events ===================
internals.events = (server) => {

    const { write } = internals;
    const formatEvent = evt => {

        const _entry = internals.formatError(evt);
        const result = typeof evt.data === 'string'
            ? Object.assign({}, internals.formatError(evt), { message: evt.data })
            : Object.assign({}, internals.formatError(evt), evt.data);

        // Removing Unneeded fields
        delete result.data;
        delete result.timestamp;
        delete result.internal;

        return result;
    };

    // Server extensions
    server.ext('onPostStop', (srv, nextEvt) => {

        const uptime = Date.now() - srv.info.created;
        const entry = {
            tags: ['info', 'app', 'stop'],
            message: 'Server onPostStop - connection listeners are stopped',
            data: { uptime }
        };

        process.removeAllListeners('SIGTERM');
        process.removeAllListeners('SIGINT');

        return write({ entry }, nextEvt);
    });

    // Server events
    server.on('log', (event) => {

        const entry = formatEvent(event);

        return write({ entry });
    });
    server.on('request', (request, event) => {

        const code = request.raw.res.statusCode;
        const state = Object.keys(request.state)[0];
        const entry = formatEvent(event);

        // If Client or Server errors
        if (code >= 400) {
            entry.error = (entry.error) ? entry.error : {};
            entry.error = Object.assign(entry.error, request.response.source);
        }

        // Check if session is available
        if (state && request[state].id) {
            entry.session = request[state].id;
        }

        // If request tag is not presetn, add it
        if (entry.tags.indexOf('request') === -1) {
            entry.tags = ['request', request.route.path, ...entry.tags];
        }

        return write({ entry, request });
    });
    server.on('request-error', (request, err) => {

        const entry = internals.formatError({ error: err });

        entry.message = 'Request error';
        entry.tags = ['error', 'request', request.route.path];

        return write({ entry, request });
    });
};

// Exposing Routes ==============================
exports.register = (plugin, options, next) => {

    // Validate and merge options
    const opts = Joi.validate(options, internals.schemas.plugin);

    // Check if schema validation had an error
    if (opts.error !== null) {
        return next(opts.error.message);
    }

    // Settings to be available in internals
    const { signals, exceptions } = internals.settings = opts.value;
    const server = plugin.root;

    // Should we handle process signals?
    if (signals) {
        internals.signals(server);
    }

    // Should we handle exceptions?
    if (exceptions) {
        internals.exceptions(server);
    }

    // Handle server events
    internals.events(server);

    // Exposing methods
    plugin.expose('write', internals.write);
    plugin.expose('console', internals.console);

    // Move along
    return next();
};

// Exposing Plugin Attributes ===================
exports.register.attributes = { pkg };
<commit_msg>- [Update] fix lint warning<commit_after>// Deps =========================================
const Joi = require('joi');
const Hoek = require('hoek');
const Fs = require('fs-extra');
const Os = require('os');
const Chalk = require('chalk');
const Useragent = require('useragent');
const prettyjson = require('prettyjson');
const stringify = require('fast-safe-stringify');
const pkg = require('../package.json');

// Internals Scope ==============================
const internals = { };

// Validation Shemas ============================
internals.schemas = {
    plugin: Joi.object().keys({
        path: Joi.string().default('./logs'),
        stopTimeoutMsec: Joi.number().default(15 * 1000),
        silent: Joi.boolean().default(false),
        signals: Joi.boolean().default(true),
        exceptions: Joi.boolean().default(true),
        timestampKey: Joi.string().default('@timestamp'),
        unixStamp: Joi.boolean().default(false)
    }),
    write: Joi.object().required().keys({
        async: Joi.boolean().default(true),
        request: Joi.object().default(null),
        entry: Joi.object().required().keys({
            message: Joi.string().required(),
            error: Joi.object(),
            tags: Joi.array().required().items(
                Joi.string().required().valid(['info', 'error', 'warning', 'request', 'plugin']),
                Joi.string()
            )
        })
    })
};

// Write to file ================================
internals.write = (options, callback) => {

    const done = callback || Hoek.ignore; // Done callback
    const result = Joi.validate(options, internals.schemas.write, { allowUnknown: true }); // Validate and merge options

    try {
        //== Check if schema validation had an error
        if (result.error !== null) {
            internals.console(result.error, 'error');

            return done(result.error);
        }

        const { path, silent, timestampKey, unixStamp } = internals.settings;
        const { entry, request, async } = result.value;
        const now = unixStamp ? Date.now() : new Date().toISOString();
        const type = entry.tags.shift();
        const filePath = `${ path }/${ type }.log`;
        const log = Object.assign({}, entry, {
            type,
            [timestampKey]: now,
            host: Os.hostname()
        });

        //== Has request?
        if (request) {
            // Create data from request
            const scoot = Useragent.lookup(request.headers['user-agent']);
            const { method, info, route } = request;
            const req = {
                method,
                remoteIP: info.remoteAddress,
                routePath: route.path,
                referrer: info.referrer,
                received: request.info.received,
                elapsed: Date.now() - request.info.received,
                userAgent: {
                    browser: `${scoot.family} v${scoot.major}.${scoot.minor}.${scoot.patch}`,
                    device: `${scoot.device.family} v${scoot.device.major}.${scoot.device.minor}.${scoot.device.patch}`,
                    os: `${scoot.os.family} v${scoot.os.major}.${scoot.os.minor}.${scoot.os.patch}`
                }
            };

            // Add auth data
            if (request.auth.credentials) {
                req.auth = {
                    isAuthenticated: request.auth.isAuthenticated,
                    credentials: request.auth.credentials
                };
            }

            // Add request vars to log object
            Object.assign(log, { request: req });
        }

        //== Has Error?
        if (entry.error) {
            log.error = entry.error;
        }

        //== Write to file Sync
        if (!async) {
            Fs.outputJsonSync(filePath, log, { flag: 'a' });
            internals.console(log, type);

            return done();
        }

        //== Write to file Async
        Fs.outputJson(filePath, log, { flag: 'a' });

        //== Log to console if not silent
        if (!silent) {
            if (type === 'error') {
                internals.console(log, type);
            } else {
                console.log(stringify(log));
            }
        }

        //== All done
        return done();
    } catch (up) {
        console.log('There was an error:', up);

        throw up; // haha!
    }
};

// Write to console =============================
internals.console = (data = {}, type = 'info', callback) => {

    let bg;
    const done = callback || Hoek.ignore;

    switch (type.toLowerCase()) {
        case 'error':
            bg = 'bgRed';
            break;
        case 'info':
            bg = 'bgBlue';
            break;
        case 'warn':
            bg = 'bgYellow';
            break;
        default:
            bg = 'bgGreen';
            break;
    }

    // Log to console
    if (!internals.settings.silent) {
        console.log(Chalk[bg].bold.white(`\n// ${ type } =====`));
        console.log(`${ prettyjson.render(data) }\n`);
    }

    return done();
};

// Normalize error data =========================
internals.formatError = event => {

    const errInstance = event instanceof Error;

    if (!('error' in event) && errInstance === false) {
        return event;
    }

    let error = {};
    let message = errInstance ? event.message : null;
    let stack = null;
    const err = errInstance ? event : event.error;

    if (err.isJoi) {
        message = err.details.message;
    }

    if (err.isBoom) {
        message = err.message;
    }

    stack = err.stack;
    error = { message, stack };

    return { error };
};

// Process signals logging ======================
internals.signals = (server) => {

    const shutdown = (signal) => {

        return () => {

            const async = false;
            const entry = {
                tags: ['info', 'app', 'signal', signal.toLowerCase()],
                message: `Server shutdown on signal: ${ signal }`
            };

            internals.write({ entry, async });
            server.root.stop({ timeout: internals.settings.stopTimeoutMsec }, process.exit);
        };
    };

    process.once('SIGTERM', shutdown('SIGTERM'));
    process.once('SIGINT', shutdown('SIGINT'));
};

// Exceptions handling ==========================
internals.exceptions = () => {

    const uncaught = (err, promise) => {

        const { error } = internals.formatError(err);
        const result = {
            error,
            message: err.message
        };

        if (promise) {
            result.promise = promise;
        }

        return result;
    };

    process.on('uncaughtException', err => {

        const write = {
            entry: Object.assign(uncaught(err), { tags: ['error', 'uncaught'] }),
            async: false
        };

        return internals.write(write, () => process.exit(1));
    });
    process.on('unhandledRejection', (reason, promise) => {

        const write = {
            entry: Object.assign(uncaught(reason, promise), { tags: ['error', 'uncaught', 'promise'] }),
            async: false
        };

        internals.write(write);
    });
};

// Subscribe to server events ===================
internals.events = (server) => {

    const { write } = internals;
    const formatEvent = evt => {

        const _entry = internals.formatError(evt);
        const result = typeof evt.data === 'string'
            ? Object.assign({}, _entry, { message: evt.data })
            : Object.assign({}, _entry, evt.data);

        // Removing Unneeded fields
        delete result.data;
        delete result.timestamp;
        delete result.internal;

        return result;
    };

    // Server extensions
    server.ext('onPostStop', (srv, nextEvt) => {

        const uptime = Date.now() - srv.info.created;
        const entry = {
            tags: ['info', 'app', 'stop'],
            message: 'Server onPostStop - connection listeners are stopped',
            data: { uptime }
        };

        process.removeAllListeners('SIGTERM');
        process.removeAllListeners('SIGINT');

        return write({ entry }, nextEvt);
    });

    // Server events
    server.on('log', (event) => {

        const entry = formatEvent(event);

        return write({ entry });
    });
    server.on('request', (request, event) => {

        const code = request.raw.res.statusCode;
        const state = Object.keys(request.state)[0];
        const entry = formatEvent(event);

        // If Client or Server errors
        if (code >= 400) {
            entry.error = (entry.error) ? entry.error : {};
            entry.error = Object.assign(entry.error, request.response.source);
        }

        // Check if session is available
        if (state && request[state].id) {
            entry.session = request[state].id;
        }

        // If request tag is not presetn, add it
        if (entry.tags.indexOf('request') === -1) {
            entry.tags = ['request', request.route.path, ...entry.tags];
        }

        return write({ entry, request });
    });
    server.on('request-error', (request, err) => {

        const entry = internals.formatError({ error: err });

        entry.message = 'Request error';
        entry.tags = ['error', 'request', request.route.path];

        return write({ entry, request });
    });
};

// Exposing Routes ==============================
exports.register = (plugin, options, next) => {

    // Validate and merge options
    const opts = Joi.validate(options, internals.schemas.plugin);

    // Check if schema validation had an error
    if (opts.error !== null) {
        return next(opts.error.message);
    }

    // Settings to be available in internals
    const { signals, exceptions } = internals.settings = opts.value;
    const server = plugin.root;

    // Should we handle process signals?
    if (signals) {
        internals.signals(server);
    }

    // Should we handle exceptions?
    if (exceptions) {
        internals.exceptions(server);
    }

    // Handle server events
    internals.events(server);

    // Exposing methods
    plugin.expose('write', internals.write);
    plugin.expose('console', internals.console);

    // Move along
    return next();
};

// Exposing Plugin Attributes ===================
exports.register.attributes = { pkg };
<|endoftext|>


<commit_before>// Uncomment for local environment or start the server using "heroku local"
// require('dotenv').config();

require('./config/db');
require('./config/passport');

const allowCORS = require('./config/cors');
const passport = require('passport');
const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');
const usersRouter = require('./users/router');
const itemsRouter = require('./items/router');
const movieInfoController = require('./info/movieController');

const server = express();

server.use(express.static(path.join(__dirname, 'public')));
server.use(bodyParser.json())
server.use(bodyParser.urlencoded({ extended: true }));

if(process.env.ALLOW_CORS === 'yes') {
    allowCORS(server);
}

server.use(passport.initialize());

/*
 * An artificial delay for debug purpose
 */
// server.use((req, res, next) => {
//   setTimeout(() => next(), 1000);
// });

server.use('/api/users', usersRouter);
server.use('/api/books', itemsRouter.personal('Book'));
server.use('/api/movies', itemsRouter.personal('Movie'));
server.use('/api/shared/books', itemsRouter.shared('Book'));
server.use('/api/shared/movies', itemsRouter.shared('Movie'));
// Get info by movie id (qs=imdbId)
server.get('/api/get-movie', movieInfoController.get);
// Get info by movie title (qs=title)
server.get('/api/search-movie', movieInfoController.search);

server.route('/*').get(function(req, res) {
    return res.sendFile(path.join(__dirname, 'public/index.html'));
});

server.listen(process.env.PORT || 3000);
<commit_msg>back-end: extra content (commented)<commit_after>// Uncomment for local environment or start the server using "heroku local"
// require('dotenv').config()

require('./config/db')
require('./config/passport')

const allowCORS = require('./config/cors')
const passport = require('passport')
const path = require('path')
const express = require('express')
const bodyParser = require('body-parser')
const usersRouter = require('./users/router')
const itemsRouter = require('./items/router')
const movieInfoController = require('./info/movieController')

const server = express()

server.use(express.static(path.join(__dirname, 'public')))
server.use(bodyParser.json())
server.use(bodyParser.urlencoded({ extended: true }))

if(process.env.ALLOW_CORS === 'yes') {
    allowCORS(server)
}

server.use(passport.initialize())

// An artificial delay for debug purpose
//
// server.use((req, res, next) => {
//   setTimeout(() => next(), 1000)
// })

server.use('/api/users', usersRouter)
server.use('/api/books', itemsRouter.personal('Book'))
server.use('/api/movies', itemsRouter.personal('Movie'))
server.use('/api/shared/books', itemsRouter.shared('Book'))
server.use('/api/shared/movies', itemsRouter.shared('Movie'))
// Get info by movie id (qs=imdbId)
server.get('/api/get-movie', movieInfoController.get)
// Get info by movie title (qs=title)
server.get('/api/search-movie', movieInfoController.search)

// Get extra content
//
// const fs = require("fs")
// server.route(`/${process.env.EXTRA_CONTENT}/:file`)
// .get((req, res, next) => {
//   const file = path.join(__dirname, `extra/${req.params.file}`)
//   fs.exists(file, exists => {
//     if (exists) res.sendFile(file)
//     else next()
//   })
// })

server.route('/*').get(function(req, res) {
  return res.sendFile(path.join(__dirname, 'public/index.html'))
})

server.listen(process.env.PORT || 3000)
<|endoftext|>


<commit_before>'use strict';

var jsDAVFile = require("../../jsDAV/lib/DAV/file");
var jsDAVCollection = require("../../jsDAV/lib/DAV/collection");

exports.File = jsDAVFile.extend({
    get: function(callback) {
        if (this.getAsync) {
            this.getAsync().then(function(buffer) {
                callback(null, buffer);
            }).catch(function(err) {
                callback(err);
            });
        } else {
            jsDAVFile.get.apply(this, arguments);
        }
    },

    put: function(data, type, callback) {
        if (this.putAsync) {
            this.putAsync(data, type).then(function(etag) {
                callback(null, etag);
            }).catch(function(err) {
                callback(err);
            });
        } else {
            jsDAVFile.put.apply(this, arguments);
        }
    },

    delete: function(callback) {
        if (this.deleteAsync) {
            this.deleteAsync().then(function() {
                callback(null);
            }).catch(function(err) {
                callback(err);
            });
        } else {
            jsDAVFile.delete.apply(this, arguments);
        }
    },

    getSize: function(callback) {
        if (this.getSizeAsync) {
            this.getSizeAsync().then(function(size) {
                callback(null, size);
            }).catch(function(err) {
                callback(err);
            });
        } else {
            jsDAVFile.getSize.apply(this, arguments);
        }
    },

    getETag: function(callback) {
        if (this.getETagAsync) {
            this.getETagAsync().then(function(etag) {
                callback(null, etag);
            }).catch(function(err) {
                callback(err);
            });
        } else {
            jsDAVFile.getETag.apply(this, arguments);
        }
    },

    getContentType: function(callback) {
        if (this.getContentTypeAsync) {
            this.getContentTypeAsync().then(function(type) {
                callback(null, type);
            }).catch(function(err) {
                callback(err);
            });
        } else {
            jsDAVFile.getContentType.apply(this, arguments);
        }
    },

    getLastModified: function(callback) {
        if (this.getLastModifiedAsync) {
            this.getLastModifiedAsync().then(function(date) {
                callback(null, date);
            }).catch(function(err) {
                callback(err);
            });
        } else {
            jsDAVFile.getLastModified.apply(this, arguments);
        }
    },
});

exports.Collection = jsDAVCollection.extend(
{
    getChildren: function(callback) {
        if (this.getChildrenAsync) {
            this.getChildrenAsync().then(function(list) {
                callback(null, list);
            }).catch(function(err) {
                callback(err);
            });
        } else {
            jsDAVCollection.getChildren.apply(this, arguments);
        }
    },

    getChild: function(name, callback) {
        if (this.getChildAsync) {
            this.getChildAsync(name).then(function(child) {
                callback(null, child);
            }).catch(function(err) {
                callback(err);
            });
        } else {
            jsDAVCollection.getChild.apply(this, arguments);
        }
    },

    childExists: function(name, callback) {
        if (this.childExistsAsync) {
            this.childExistsAsync(name).then(function(state) {
                callback(null, state);
            }).catch(function(err) {
                callback(err);
            });
        } else {
            jsDAVCollection.childExists.apply(this, arguments);
        }
    },

    createFile: function(name, data, type, callback) {
        if (this.createFileAsync) {
            this.createFileAsync(name, data, type).then(function(state) {
                callback(null, state);
            }).catch(function(err) {
                callback(err);
            });
        } else {
            jsDAVCollection.createFile.apply(this, arguments);
        }
    }
});
<commit_msg>Made definition of getChild() and childExists() optional<commit_after>'use strict';

var JsDAVFile = require("../../jsDAV/lib/DAV/file");
var JsDAVCollection = require("../../jsDAV/lib/DAV/collection");
var JsDAVExceptions = require("jsDAV/lib/shared/exceptions");

function verifyResult(object) {
    if (object == null) {
        throw new jsExceptions.FileNotFound("No such file or directory");
    }
}

exports.File = JsDAVFile.extend({
    get: function(callback) {
        if (this.getAsync) {
            this.getAsync().then(function(buffer) {
                verifyResult(buffer);
                callback(null, buffer);
            }).catch(function(err) {
                callback(err);
            });
        } else {
            JsDAVFile.get.apply(this, arguments);
        }
    },

    put: function(data, type, callback) {
        if (this.putAsync) {
            this.putAsync(data, type).then(function(etag) {
                verifyResult(etag);
                callback(null, etag);
            }).catch(function(err) {
                callback(err);
            });
        } else {
            JsDAVFile.put.apply(this, arguments);
        }
    },

    delete: function(callback) {
        if (this.deleteAsync) {
            this.deleteAsync().then(function(state) {
                verifyResult(state);
                callback(null);
            }).catch(function(err) {
                callback(err);
            });
        } else {
            JsDAVFile.delete.apply(this, arguments);
        }
    },

    getSize: function(callback) {
        if (this.getSizeAsync) {
            this.getSizeAsync().then(function(size) {
                verifyResult(size);
                callback(null, size);
            }).catch(function(err) {
                callback(err);
            });
        } else {
            JsDAVFile.getSize.apply(this, arguments);
        }
    },

    getETag: function(callback) {
        if (this.getETagAsync) {
            this.getETagAsync().then(function(etag) {
                verifyResult(etag);
                callback(null, etag);
            }).catch(function(err) {
                callback(err);
            });
        } else {
            JsDAVFile.getETag.apply(this, arguments);
        }
    },

    getContentType: function(callback) {
        if (this.getContentTypeAsync) {
            this.getContentTypeAsync().then(function(type) {
                verifyResult(type);
                callback(null, type);
            }).catch(function(err) {
                callback(err);
            });
        } else {
            JsDAVFile.getContentType.apply(this, arguments);
        }
    },

    getLastModified: function(callback) {
        if (this.getLastModifiedAsync) {
            this.getLastModifiedAsync().then(function(date) {
                verifyResult(date);
                callback(null, date);
            }).catch(function(err) {
                callback(err);
            });
        } else {
            JsDAVFile.getLastModified.apply(this, arguments);
        }
    },
});

exports.Collection = JsDAVCollection.extend(
{
    getChildren: function(callback) {
        if (this.getChildrenAsync) {
            this.getChildrenAsync().then(function(list) {
                verifyResult(list);
                callback(null, list);
            }).catch(function(err) {
                callback(err);
            });
        } else {
            JsDAVCollection.getChildren.apply(this, arguments);
        }
    },

    getChild: function(name, callback) {
        if (this.getChildAsync) {
            this.getChildAsync(name).then(function(child) {
                verifyResult(child);
                callback(null, child);
            }).catch(function(err) {
                callback(err);
            });
        } else if (this.getChildrenAsync) {
            this.getChildrenAsync(name).then(function(children) {
                var child = null;
                for (var i = 0; children && i < children.length; i++) {
                    if (children[i].getName() === name) {
                        child = children[i];
                        break;
                    }
                }
                verifyResult(child);
                callback(null, child);
            }).catch(function(err) {
                callback(err);
            });
        } else {
            JsDAVCollection.getChild.apply(this, arguments);
        }
    },

    childExists: function(name, callback) {
        if (this.childExistsAsync) {
            this.childExistsAsync(name).then(function(state) {
                callback(null, state);
            }).catch(function(err) {
                callback(err);
            });
        } else if (this.getChildAsync) {
            this.getChildAsync(name).then(function(child) {
                callback(null, child != null);
            }).catch(function(err) {
                callback(null, false);
            });
        } else if (this.getChildrenAsync) {
            this.getChildrenAsync(name).then(function(children) {
                var found = false;
                for (var i = 0; children && i < children.length; i++) {
                    if (children[i].getName() === name) {
                        found = true;
                        break;
                    }
                }
                callback(null, found);
            }).catch(function(err) {
                callback(null, false);
            });
        } else {
            JsDAVCollection.childExists.apply(this, arguments);
        }
    },

    createDirectory: function(name, callback) {
        if (this.createDirectoryAsync) {
            this.createDirectoryAsync(name).then(function() {
                callback(null, state);
            }).catch(function(err) {
                callback(err);
            });
        } else {
            JsDAVCollection.createFile.apply(this, arguments);
        }
    },

    createFile: function(name, data, type, callback) {
        if (this.createFileAsync) {
            this.createFileAsync(name, data, type).then(function(state) {
                verifyResult(state);
                callback(null, state);
            }).catch(function(err) {
                callback(err);
            });
        } else {
            JsDAVCollection.createFile.apply(this, arguments);
        }
    }
});
<|endoftext|>


<commit_before>// Copyright 2022, University of Colorado Boulder
/* eslint-disable bad-typescript-text */

/**
 * Lint detector for invalid text, expected only to be checked against typescript files.
 * Lint is disabled for this file so the bad texts aren't themselves flagged.
 *
 * @author Michael Kauzmann (PhET Interactive Simulations)
 */

module.exports = function( context ) {

  const getBadTextTester = require( './getBadTextTester' );

  // see getBadTextTester for schema.
  const forbiddenTextObjects = [

    // Don't lie to yourself.
    'JavaScript is much, much better than TypeScript.',

    // Typescript handles this for us, please refrain from providing visibility annotations via jsdoc (unless you have
    // to, disabling this rule).
    '@public',
    '@protected',
    '@private',

    // 'options = merge', // TODO: 54 failures, https://github.com/phetsims/chipper/issues/1226

    // To convert javascript files to typescript, you do not need to include a nocheck directive, just commit locally
    // before converting to preserve history, see https://github.com/phetsims/sun/issues/732#issuecomment-995330513
    '@ts-nocheck',

    // combineOptions should always specify the type parameter like combineOptions<...>.
    'combineOptions(',

    // The type parameters should be inferred rather than specified
    '.multilink<',
    '.lazyMultilink<',
    'new DerivedProperty<',

    'const simOptions = {',

    // Typescript files should not use jsdoc for parameters
    '@param {',

    // Don't export SelfOptions, https://github.com/phetsims/chipper/issues/1263
    'export type SelfOptions',

    {
      id: '@returns with type and/or without extra doc',
      regex: /(@returns \{)|(@returns *$)/
    }
  ];

  return {
    Program: getBadTextTester( 'bad-typescript-text', forbiddenTextObjects, context )
  };
};

module.exports.schema = [
  // JSON Schema for rule options goes here
];<commit_msg>Enable options = merge check, see https://github.com/phetsims/chipper/issues/1224<commit_after>// Copyright 2022, University of Colorado Boulder
/* eslint-disable bad-typescript-text */

/**
 * Lint detector for invalid text, expected only to be checked against typescript files.
 * Lint is disabled for this file so the bad texts aren't themselves flagged.
 *
 * @author Michael Kauzmann (PhET Interactive Simulations)
 */

module.exports = function( context ) {

  const getBadTextTester = require( './getBadTextTester' );

  // see getBadTextTester for schema.
  const forbiddenTextObjects = [

    // Don't lie to yourself.
    'JavaScript is much, much better than TypeScript.',

    // Typescript handles this for us, please refrain from providing visibility annotations via jsdoc (unless you have
    // to, disabling this rule).
    '@public',
    '@protected',
    '@private',

    'options = merge',

    // To convert javascript files to typescript, you do not need to include a nocheck directive, just commit locally
    // before converting to preserve history, see https://github.com/phetsims/sun/issues/732#issuecomment-995330513
    '@ts-nocheck',

    // combineOptions should always specify the type parameter like combineOptions<...>.
    'combineOptions(',

    // The type parameters should be inferred rather than specified
    '.multilink<',
    '.lazyMultilink<',
    'new DerivedProperty<',

    'const simOptions = {',

    // Typescript files should not use jsdoc for parameters
    '@param {',

    // Don't export SelfOptions, https://github.com/phetsims/chipper/issues/1263
    'export type SelfOptions',

    {
      id: '@returns with type and/or without extra doc',
      regex: /(@returns \{)|(@returns *$)/
    }
  ];

  return {
    Program: getBadTextTester( 'bad-typescript-text', forbiddenTextObjects, context )
  };
};

module.exports.schema = [
  // JSON Schema for rule options goes here
];<|endoftext|>


<commit_before>/**
 * Define the methods of the GCB rich text editor here.
 */
function getGcbRteDefs(env, Dom, Editor) {
  return {
    setOptions: function(options) {
      GcbRteField.superclass.setOptions.call(this, options);
      this.options.opts = options.opts || {};
      this.options.supportCustomTags = options.supportCustomTags || false;
    },

    renderComponent: function() {
      // Make a unique id for the field
      if (!GcbRteField.idCounter) {
        GcbRteField.idCounter = 0;
      }
      this.id = "gcbRteField-" + GcbRteField.idCounter;
      GcbRteField.idCounter += 1;

      // Insert the text area for plain text editing
      this.el = document.createElement('textarea');
      this.el.setAttribute('id', this.id);
      if(this.options.name) {
        this.el.setAttribute('name', this.options.name);
      }

      this.fieldContainer.appendChild(this.el);

      // Make a button to toggle between plain text and rich text
      var showRteText = "Rich Text";
      var hideRteText = "";
      var showRteFlag = false;
      var toggle = document.createElement("div");
      var toggleText = document.createTextNode(showRteText);
      toggle.appendChild(toggleText);
      toggle.className = "rte-control inputEx-Button";

      var self = this;
      toggle.onclick = function() {
        showRteFlag = !showRteFlag;
        if (showRteFlag) {
          if (self.editor) {
            self.showExistingRte();
          } else {
            self.showNewRte();
          }
          toggleText.nodeValue = hideRteText;
        } else {
          self.hideRte();
          toggleText.nodeValue = showRteText;
        }
      };
      this.divEl.appendChild(toggle);
    },

    _getEditorWindow: function() {
      return document.getElementById(this.id + '_editor').contentWindow;
    },

    _insertMarkerTags: function(editorWin) {
      var editorDoc = editorWin.document;
      var that = this;
      for (var k = 0; k < env.custom_rte_tag_icons.length; k++) {
        var tag = env.custom_rte_tag_icons[k];
        var elts = editorDoc.getElementsByTagName(tag.name);
        for (var i = elts.length - 1; i >= 0; i--) {
          var elt = elts[i];
          var img = editorDoc.createElement('img');
          img.src = tag.iconUrl;
          img.className = 'gcbMarker';
          img.style.cursor = 'pointer';
          img.ondblclick = (function(_elt, _img) {
            // Create a new scope with its own pointer to the current element
            return function(event) {
              var event = event || editorWin.event;
              if (event.stopPropagation) {
                event.stopPropagation();
              } else { // IE 8 & 9
                event.cancelBubble = true;
              }
              that._editCustomTag(_elt, _img);
            };
          })(elt, img);
          img.onmousedown = function(event) {
            var event = event || editorWin.event;
            if (event.preventDefault && event.stopPropagation) {
              event.preventDefault();
              event.stopPropagation();
            } else { // IE 8 & 9
              event.returnValue = false;
              event.cancelBubble = false;
            }
          };
          img.gcbTag = elt;
          that._styleMarkerTag(img);
          elt.parentNode.replaceChild(img, elt);
        }
      }
    },

    _styleMarkerTag: function(img) {
      img.style.borderRadius = '5px';
      img.style.borderColor = '#ccc';
      img.style.borderWidth = '3px';
      img.style.borderStyle = 'ridge';
      img.style.width = '48px';
      img.style.height = '48px';
    },

    /**
     * When a custom tag is double-clicked, open up a sub-editor in a lightbox.
     */
    _editCustomTag: function(node, img) {
      var value = {};
      for (var i = 0; i < node.attributes.length; i++) {
        value[node.attributes[i].name] = node.attributes[i].value;
      }
      if (window.frameProxy) {
        window.frameProxy.close();
      }
      window.frameProxy = new FrameProxy(
        'modal-editor',
        getEditCustomTagUrl(env, node.tagName.toLowerCase()),
        value,
        function(value) { // on submit
          for (var name in value) {
            if (value.hasOwnProperty(name)) {
              node.setAttribute(name, value[name]);
            }
          }
        },
        function () { /* on cancel */ }
      );
      window.frameProxy.open();
    },

    _addCustomTag: function() {
      var that = this;
      this._insertInsertionPointTag();

      if (window.frameProxy) {
        window.frameProxy.close();
      }
      window.frameProxy = new FrameProxy(
        'modal-editor',
        getAddCustomTagUrl(env),
        null,
        function(value) { // on submit
          that._insertCustomTag(value);
        },
        function () { // on cancel
          that._removeInsertionPointTag(that._getEditorWindow());
        }
      );
      window.frameProxy.open();
    },

    _insertCustomTag: function(value) {
      var el = document.createElement(value.type.tag);
      for (var name in value.attributes) {
        if (value.attributes.hasOwnProperty(name)) {
          el.setAttribute(name, value.attributes[name]);
        }
      }
      var editorWin = this._getEditorWindow();
      var insertionPoint = editorWin.document.querySelector('.gcbInsertionPoint');
      insertionPoint.parentNode.replaceChild(el, insertionPoint);

      this._removeMarkerTags(editorWin);
      this._insertMarkerTags(editorWin);
    },

    _insertInsertionPointTag: function() {
      this.editor.execCommand('inserthtml',
          '');
    },

    _removeInsertionPointTag: function(win) {
      this._removeTagsByClass(win, 'gcbInsertionPoint');
    },

    _removeMarkerTags: function(win) {
      var elts = win.document.querySelectorAll('.gcbMarker');
      for (var i = 0; i < elts.length; i++) {
        var img = elts[i];
        img.parentNode.replaceChild(img.gcbTag, img);
      }
    },

    _removeTagsByClass: function(win, clazz) {
      var elts = win.document.querySelectorAll('.' + clazz);
      for (var i = 0; i < elts.length; i++) {
        var e = elts[i];
        e.parentNode.removeChild(e);
      }
    },

    showNewRte: function() {
      var that = this;
      var options = this.options;
      var _def = {
        height: '350px',
        width: '510px',
        dompath: true,
      };
      // Merge options.opts into the default options
      var opts = options.opts;
      for (var i in opts) {
        if (opts.hasOwnProperty(i)) {
          _def[i] = opts[i];
        }
      }

      var editor = new Editor(this.id, _def);

      // Disable any HTML cleaning done by the editor.
      editor.cleanHTML = function(html) {
        if (!html) {
            html = this.getEditorHTML();
        }
        this.fireEvent('cleanHTML',
            {type: 'cleanHTML', target: this, html: html});
        return html;
      };
      editor._cleanIncomingHTML = function(html) {
        return html;
      };
      editor._fixNodes = function() {};

      // Set up a button to add custom tags
      if (options.supportCustomTags) {
        editor.on('toolbarLoaded', function() {
          var button = {
            type: 'push',
            label: 'Insert Google Course Builder component',
            value: 'insertcustomtag',
            disabled: false
          };
          editor.toolbar.addButtonToGroup(button, 'insertitem');
          editor.toolbar.on('insertcustomtagClick', that._addCustomTag, that, true);
        });
      }

      this.editor = editor;
      this.editor.render();

      // Poll until the editor iframe has loaded
      (function() {
        var ed = document.getElementById(that.id + '_editor');
        if (ed && ed.contentWindow && ed.contentWindow.document &&
            ed.contentWindow.document.readyState == 'complete') {
          if (options.supportCustomTags) {
            that._insertMarkerTags(that._getEditorWindow());
          }
        } else {
          setTimeout(arguments.callee, 100);
        }
      })();
    },

    showExistingRte: function() {
      var editor = this.editor,
          textArea = this.el;
          rteDiv = textArea.previousSibling;

      if (this._cbGetValue) {
        this.getValue = this._cbGetValue;
      }

      Dom.setStyle(rteDiv, 'position', 'static');
      Dom.setStyle(rteDiv, 'top', '0');
      Dom.setStyle(rteDiv, 'left', '0');
      Dom.setStyle(textArea, 'visibility', 'hidden');
      Dom.setStyle(textArea, 'top', '-9999px');
      Dom.setStyle(textArea, 'left', '-9999px');
      Dom.setStyle(textArea, 'position', 'absolute');
      editor.get('element_cont').addClass('yui-editor-container');
      editor._setDesignMode('on');
      editor.setEditorHTML(textArea.value);
      if (this.options.supportCustomTags) {
        this._insertMarkerTags(this._getEditorWindow());
      }
    },

    hideRte: function() {
      var editor = this.editor,
          textArea = this.el;
          rteDiv = textArea.previousSibling;

      this._removeMarkerTags(this._getEditorWindow());
      editor.saveHTML();

      this._cbGetValue = this.getValue;
      this.getValue = function() {
        return textArea.value;
      };

      Dom.setStyle(rteDiv, 'position', 'absolute');
      Dom.setStyle(rteDiv, 'top', '-9999px');
      Dom.setStyle(rteDiv, 'left', '-9999px');
      editor.get('element_cont').removeClass('yui-editor-container');
      Dom.setStyle(textArea, 'visibility', 'visible');
      Dom.setStyle(textArea, 'top', '');
      Dom.setStyle(textArea, 'left', '');
      Dom.setStyle(textArea, 'position', 'static');
      Dom.addClass(textArea, 'raw-text-editor');
    },

    setValue: function(value, sendUpdatedEvt) {
      this.el.value = value;
      if(sendUpdatedEvt !== false) {
        this.fireUpdatedEvt();
      }
    },

    getValue: function() {
      if (this.editor) {
        var editorDoc = this._getEditorWindow();
        // Clean the editor text before saving, and then restore markers
        this._removeMarkerTags(editorDoc);
        var value = this.editor.saveHTML();
        this._insertMarkerTags(editorDoc);
        return value;
      } else {
        return this.el.value;
      }
    }
  };
};
<commit_msg>Fix copy&paste in the RTE, so that pasting a component icon doesn't break the editor (although the componext will not be copied over). 	Change on 2013/05/06 by jorr <jorr@google.com> ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=46254632<commit_after>/**
 * Define the methods of the GCB rich text editor here.
 */
function getGcbRteDefs(env, Dom, Editor) {
  return {
    setOptions: function(options) {
      GcbRteField.superclass.setOptions.call(this, options);
      this.options.opts = options.opts || {};
      this.options.supportCustomTags = options.supportCustomTags || false;
    },

    renderComponent: function() {
      // Make a unique id for the field
      if (!GcbRteField.idCounter) {
        GcbRteField.idCounter = 0;
      }
      this.id = "gcbRteField-" + GcbRteField.idCounter;
      GcbRteField.idCounter += 1;

      // Insert the text area for plain text editing
      this.el = document.createElement('textarea');
      this.el.setAttribute('id', this.id);
      if(this.options.name) {
        this.el.setAttribute('name', this.options.name);
      }

      this.fieldContainer.appendChild(this.el);

      // Make a button to toggle between plain text and rich text
      var showRteText = "Rich Text";
      var hideRteText = "";
      var showRteFlag = false;
      var toggle = document.createElement("div");
      var toggleText = document.createTextNode(showRteText);
      toggle.appendChild(toggleText);
      toggle.className = "rte-control inputEx-Button";

      var self = this;
      toggle.onclick = function() {
        showRteFlag = !showRteFlag;
        if (showRteFlag) {
          if (self.editor) {
            self.showExistingRte();
          } else {
            self.showNewRte();
          }
          toggleText.nodeValue = hideRteText;
        } else {
          self.hideRte();
          toggleText.nodeValue = showRteText;
        }
      };
      this.divEl.appendChild(toggle);
    },

    _getEditorWindow: function() {
      return document.getElementById(this.id + '_editor').contentWindow;
    },

    _insertMarkerTags: function(editorWin) {
      var editorDoc = editorWin.document;
      var that = this;
      for (var k = 0; k < env.custom_rte_tag_icons.length; k++) {
        var tag = env.custom_rte_tag_icons[k];
        var elts = editorDoc.getElementsByTagName(tag.name);
        for (var i = elts.length - 1; i >= 0; i--) {
          var elt = elts[i];
          var img = editorDoc.createElement('img');
          img.src = tag.iconUrl;
          img.className = 'gcbMarker';
          img.style.cursor = 'pointer';
          img.ondblclick = (function(_elt, _img) {
            // Create a new scope with its own pointer to the current element
            return function(event) {
              var event = event || editorWin.event;
              if (event.stopPropagation) {
                event.stopPropagation();
              } else { // IE 8 & 9
                event.cancelBubble = true;
              }
              that._editCustomTag(_elt, _img);
            };
          })(elt, img);
          img.onmousedown = function(event) {
            var event = event || editorWin.event;
            if (event.preventDefault && event.stopPropagation) {
              event.preventDefault();
              event.stopPropagation();
            } else { // IE 8 & 9
              event.returnValue = false;
              event.cancelBubble = false;
            }
          };
          img.gcbTag = elt;
          that._styleMarkerTag(img);
          elt.parentNode.replaceChild(img, elt);
        }
      }
    },

    _styleMarkerTag: function(img) {
      img.style.borderRadius = '5px';
      img.style.borderColor = '#ccc';
      img.style.borderWidth = '3px';
      img.style.borderStyle = 'ridge';
      img.style.width = '48px';
      img.style.height = '48px';
    },

    /**
     * When a custom tag is double-clicked, open up a sub-editor in a lightbox.
     */
    _editCustomTag: function(node, img) {
      var value = {};
      for (var i = 0; i < node.attributes.length; i++) {
        value[node.attributes[i].name] = node.attributes[i].value;
      }
      if (window.frameProxy) {
        window.frameProxy.close();
      }
      window.frameProxy = new FrameProxy(
        'modal-editor',
        getEditCustomTagUrl(env, node.tagName.toLowerCase()),
        value,
        function(value) { // on submit
          for (var name in value) {
            if (value.hasOwnProperty(name)) {
              node.setAttribute(name, value[name]);
            }
          }
        },
        function () { /* on cancel */ }
      );
      window.frameProxy.open();
    },

    _addCustomTag: function() {
      var that = this;
      this._insertInsertionPointTag();

      if (window.frameProxy) {
        window.frameProxy.close();
      }
      window.frameProxy = new FrameProxy(
        'modal-editor',
        getAddCustomTagUrl(env),
        null,
        function(value) { // on submit
          that._insertCustomTag(value);
        },
        function () { // on cancel
          that._removeInsertionPointTag(that._getEditorWindow());
        }
      );
      window.frameProxy.open();
    },

    _insertCustomTag: function(value) {
      var el = document.createElement(value.type.tag);
      for (var name in value.attributes) {
        if (value.attributes.hasOwnProperty(name)) {
          el.setAttribute(name, value.attributes[name]);
        }
      }
      var editorWin = this._getEditorWindow();
      var insertionPoint = editorWin.document.querySelector('.gcbInsertionPoint');
      insertionPoint.parentNode.replaceChild(el, insertionPoint);

      this._refreshMarkerTags()
    },

    _insertInsertionPointTag: function() {
      this.editor.execCommand('inserthtml',
          '');
    },

    _removeInsertionPointTag: function(win) {
      this._removeTagsByClass(win, 'gcbInsertionPoint');
    },

    _removeMarkerTags: function(win) {
      var elts = win.document.querySelectorAll('.gcbMarker');
      for (var i = 0; i < elts.length; i++) {
        var img = elts[i];
        if (img.gcbTag) {
          img.parentNode.replaceChild(img.gcbTag, img);
        } else {
          img.parentNode.removeChild(img);
        }
      }
    },

    _removeTagsByClass: function(win, clazz) {
      var elts = win.document.querySelectorAll('.' + clazz);
      for (var i = 0; i < elts.length; i++) {
        var e = elts[i];
        e.parentNode.removeChild(e);
      }
    },

    showNewRte: function() {
      var that = this;
      var options = this.options;
      var _def = {
        height: '350px',
        width: '510px',
        dompath: true,
      };
      // Merge options.opts into the default options
      var opts = options.opts;
      for (var i in opts) {
        if (opts.hasOwnProperty(i)) {
          _def[i] = opts[i];
        }
      }

      var editor = new Editor(this.id, _def);

      // Disable any HTML cleaning done by the editor.
      editor.cleanHTML = function(html) {
        if (!html) {
            html = this.getEditorHTML();
        }
        this.fireEvent('cleanHTML',
            {type: 'cleanHTML', target: this, html: html});
        return html;
      };
      editor._cleanIncomingHTML = function(html) {
        return html;
      };
      editor._fixNodes = function() {};

      // Set up a button to add custom tags
      if (options.supportCustomTags) {
        editor.on('toolbarLoaded', function() {
          var button = {
            type: 'push',
            label: 'Insert Google Course Builder component',
            value: 'insertcustomtag',
            disabled: false
          };
          editor.toolbar.addButtonToGroup(button, 'insertitem');
          editor.toolbar.on('insertcustomtagClick', that._addCustomTag, that, true);
        });
      }

      this.editor = editor;
      this.editor.render();

      // Poll until the editor iframe has loaded
      (function() {
        var ed = document.getElementById(that.id + '_editor');
        if (ed && ed.contentWindow && ed.contentWindow.document &&
            ed.contentWindow.document.readyState == 'complete') {
          that._onEditorIframeLoaded();
        } else {
          setTimeout(arguments.callee, 100);
        }
      })();
    },

    _onEditorIframeLoaded: function() {
      var that = this;
      if (this.options.supportCustomTags) {
        this._insertMarkerTags(this._getEditorWindow());
      }

      // Refresh the marker images after a paste
      this._getEditorWindow().document.body.onpaste = function(e) {
        setTimeout(function() {
          that._refreshMarkerTags();
        }, 10);
      };
    },

    _refreshMarkerTags: function() {
      var editorWin= this._getEditorWindow();
      this._removeMarkerTags(editorWin);
      this._insertMarkerTags(editorWin);
    },

    showExistingRte: function() {
      var editor = this.editor,
          textArea = this.el;
          rteDiv = textArea.previousSibling;

      if (this._cbGetValue) {
        this.getValue = this._cbGetValue;
      }

      Dom.setStyle(rteDiv, 'position', 'static');
      Dom.setStyle(rteDiv, 'top', '0');
      Dom.setStyle(rteDiv, 'left', '0');
      Dom.setStyle(textArea, 'visibility', 'hidden');
      Dom.setStyle(textArea, 'top', '-9999px');
      Dom.setStyle(textArea, 'left', '-9999px');
      Dom.setStyle(textArea, 'position', 'absolute');
      editor.get('element_cont').addClass('yui-editor-container');
      editor._setDesignMode('on');
      editor.setEditorHTML(textArea.value);
      if (this.options.supportCustomTags) {
        this._insertMarkerTags(this._getEditorWindow());
      }
    },

    hideRte: function() {
      var editor = this.editor,
          textArea = this.el;
          rteDiv = textArea.previousSibling;

      this._removeMarkerTags(this._getEditorWindow());
      editor.saveHTML();

      this._cbGetValue = this.getValue;
      this.getValue = function() {
        return textArea.value;
      };

      Dom.setStyle(rteDiv, 'position', 'absolute');
      Dom.setStyle(rteDiv, 'top', '-9999px');
      Dom.setStyle(rteDiv, 'left', '-9999px');
      editor.get('element_cont').removeClass('yui-editor-container');
      Dom.setStyle(textArea, 'visibility', 'visible');
      Dom.setStyle(textArea, 'top', '');
      Dom.setStyle(textArea, 'left', '');
      Dom.setStyle(textArea, 'position', 'static');
      Dom.addClass(textArea, 'raw-text-editor');
    },

    setValue: function(value, sendUpdatedEvt) {
      this.el.value = value;
      if(sendUpdatedEvt !== false) {
        this.fireUpdatedEvt();
      }
    },

    getValue: function() {
      if (this.editor) {
        var editorDoc = this._getEditorWindow();
        // Clean the editor text before saving, and then restore markers
        this._removeMarkerTags(editorDoc);
        var value = this.editor.saveHTML();
        this._insertMarkerTags(editorDoc);
        return value;
      } else {
        return this.el.value;
      }
    }
  };
};
<|endoftext|>


<commit_before>export default {

    browserPort: 5000,
    UIPort: 3001,
    testPort: 3002,

    sourceDir: './app/',
    buildDir: './build/',

    styles: {
        src: 'app/styles/main.scss',
        srcAll: 'app/styles/**/*.scss',
        ignore: '!app/styles/**/my_flat_style_tweaks.scss',
        dest: 'build/css',
        prodSourcemap: false,
        sassIncludePaths: []
    },

    scripts: {
        src: 'app/js/**/*.js',
        dest: 'build/js',
        test: 'test/**/*.js',
        gulp: 'gulp/**/*.js',
        server: 'server/**/*.js'
    },

    images: {
        src: 'app/images/**/*',
        dest: 'build/images'
    },

    fonts: {
        src: ['app/fonts/**/*'],
        dest: 'build/fonts'
    },

    assetExtensions: [
        'js',
        'css',
        'png',
        'jpe?g',
        'gif',
        'svg',
        'eot',
        'otf',
        'ttc',
        'ttf',
        'woff2?'
    ],

    views: {
        index: 'app/index.html',
        src: 'app/views/**/*.html',
        dest: 'app/js'
    },

    gzip: {
        src: 'build/**/*.{html,xml,json,css,js,js.map,css.map}',
        dest: 'build/',
        options: {}
    },

    browserify: {
        bundleName: 'main.js',
        prodSourcemap: false
    },

    test: {
        karma: 'test/karma.conf.js',
        protractor: 'test/protractor.conf.js'
    },

    BROWSER_SYNC_RELOAD_DELAY: 500,

    server: {
        path: 'server/',
        // tests: 'test/server_unit/**/*spec.js',
        // tests: 'test/server_unit/**/update_event_generators_next_event_spec.js',
        tests: 'test/server_unit/**/send_event_reminders_spec.js',
        file: 'server/index.js', // from top directory
        files: 'server/**/*.js',
        testTemp: 'test_tmp/'
    },

    lambdas: {
        path: 'lambdas/'
    },

    init: function() {
        this.views.watch = [
            this.views.index,
            this.views.src
        ];

        return this;
    }

}.init();
<commit_msg>going to try and run reminder test<commit_after>export default {

    browserPort: 5000,
    UIPort: 3001,
    testPort: 3002,

    sourceDir: './app/',
    buildDir: './build/',

    styles: {
        src: 'app/styles/main.scss',
        srcAll: 'app/styles/**/*.scss',
        ignore: '!app/styles/**/my_flat_style_tweaks.scss',
        dest: 'build/css',
        prodSourcemap: false,
        sassIncludePaths: []
    },

    scripts: {
        src: 'app/js/**/*.js',
        dest: 'build/js',
        test: 'test/**/*.js',
        gulp: 'gulp/**/*.js',
        server: 'server/**/*.js'
    },

    images: {
        src: 'app/images/**/*',
        dest: 'build/images'
    },

    fonts: {
        src: ['app/fonts/**/*'],
        dest: 'build/fonts'
    },

    assetExtensions: [
        'js',
        'css',
        'png',
        'jpe?g',
        'gif',
        'svg',
        'eot',
        'otf',
        'ttc',
        'ttf',
        'woff2?'
    ],

    views: {
        index: 'app/index.html',
        src: 'app/views/**/*.html',
        dest: 'app/js'
    },

    gzip: {
        src: 'build/**/*.{html,xml,json,css,js,js.map,css.map}',
        dest: 'build/',
        options: {}
    },

    browserify: {
        bundleName: 'main.js',
        prodSourcemap: false
    },

    test: {
        karma: 'test/karma.conf.js',
        protractor: 'test/protractor.conf.js'
    },

    BROWSER_SYNC_RELOAD_DELAY: 500,

    server: {
        path: 'server/',
        tests: 'test/server_unit/**/*spec.js',
        // tests: 'test/server_unit/**/update_event_generators_next_event_spec.js',
        // tests: 'test/server_unit/**/send_event_reminders_spec.js',
        file: 'server/index.js', // from top directory
        files: 'server/**/*.js',
        testTemp: 'test_tmp/'
    },

    lambdas: {
        path: 'lambdas/'
    },

    init: function() {
        this.views.watch = [
            this.views.index,
            this.views.src
        ];

        return this;
    }

}.init();
<|endoftext|>


<commit_before>'use babel';
/* @flow */

import { CompositeDisposable } from 'atom';
import path from 'path';

import handleData from './message.js';
import { check } from './helpers';

import type { LinterMessage } from './message';

type BufferType = {
  cachedText: string;
  getText(): string;
}

type TextEditorType = {
  getPath(): string;
  buffer: BufferType;
  isModified(): boolean;
}

type Linter = {
  grammarScopes: Array<string>;
  scope: 'file' | 'project';
  name?: string;
  lintOnFly: boolean;
  lint(TextEditor: TextEditorType): Array<LinterMessage> | Promise<Array<LinterMessage>>;
};

export default {
  config: {
    executablePath: {
      type: 'string',
      default: 'flow',
      description: 'Absolute path to the Flow executable on your system.',
    },
  },

  activate(): void {
    require('atom-package-deps').install('linter-flow');

    this.subscriptions = new CompositeDisposable();
    this.subscriptions.add(atom.config.observe('linter-flow.executablePath', (pathToFlow) => {
      this.pathToFlow = pathToFlow;
    }));
  },

  deactivate(): void {
    const helpers = require('atom-linter');
    console.log('deactivating... linter-flow');
    helpers.exec(this.pathToFlow, ['stop'], {}).catch(() => null);
    this.subscriptions.dispose();
  },

  provideLinter(): Linter {
    const helpers = require('atom-linter');

    return {
      grammarScopes: [
        'source.js',
        'source.js.jsx',
        'source.babel',
        'source.js-semantic',
        'source.es6',
      ],
      scope: 'project',
      name: 'Flow',
      lintOnFly: true,
      lint: (TextEditor) => {
        const filePath = TextEditor.getPath();
        const fileText = TextEditor.buffer.cachedText;

        // Is flow enabled for current file ?
        if (!fileText || fileText.indexOf('@flow') === -1) {
          return Promise.resolve([]);
        }

        // Check if .flowconfig file is present
        const flowConfig = helpers.find(filePath, '.flowconfig');
        if (!flowConfig) {
          atom.notifications.addWarning('[Linter-Flow] Missing .flowconfig file.', {
            detail: 'To get started with Flow, run `flow init`.',
            dismissable: true,
          });
          return Promise.resolve([]);
        }

        let args;
        let options;

        // Use `check-contents` for unsaved files. and `status` for saved files.
        if (TextEditor.isModified()) {
          args = ['check-contents', '--json', filePath];
          options = { cwd: path.dirname(filePath), stdin: fileText };
        } else {
          args = ['status', '--json', filePath];
          options = { cwd: path.dirname(filePath) };
        }

        return check(this.pathToFlow, args, options)
          .then(JSON.parse)
          .then(handleData);
      },
    };
  },
};
<commit_msg>feat(atom-warnings): Throttle .flowconfig errors to once every 5 minutes<commit_after>'use babel';
/* @flow */

import { CompositeDisposable } from 'atom';
import path from 'path';

import handleData from './message.js';
import { check } from './helpers';

import type { LinterMessage } from './message';

type BufferType = {
  cachedText: string;
  getText(): string;
}

type TextEditorType = {
  getPath(): string;
  buffer: BufferType;
  isModified(): boolean;
}

type Linter = {
  grammarScopes: Array<string>;
  scope: 'file' | 'project';
  name?: string;
  lintOnFly: boolean;
  lint(TextEditor: TextEditorType): Array<LinterMessage> | Promise<Array<LinterMessage>>;
};

export default {
  config: {
    executablePath: {
      type: 'string',
      default: 'flow',
      description: 'Absolute path to the Flow executable on your system.',
    },
  },

  activate(): void {
    require('atom-package-deps').install('linter-flow');

    this.subscriptions = new CompositeDisposable();
    this.subscriptions.add(atom.config.observe('linter-flow.executablePath', (pathToFlow) => {
      this.pathToFlow = pathToFlow;
    }));
  },

  deactivate(): void {
    const helpers = require('atom-linter');
    console.log('deactivating... linter-flow');
    helpers.exec(this.pathToFlow, ['stop'], {}).catch(() => null);
    this.subscriptions.dispose();
  },

  provideLinter(): Linter {
    const helpers = require('atom-linter');

    return {
      grammarScopes: [
        'source.js',
        'source.js.jsx',
        'source.babel',
        'source.js-semantic',
        'source.es6',
      ],
      scope: 'project',
      name: 'Flow',
      lintOnFly: true,
      lint: (TextEditor) => {
        const filePath = TextEditor.getPath();
        const fileText = TextEditor.buffer.cachedText;

        // Is flow enabled for current file ?
        if (!fileText || fileText.indexOf('@flow') === -1) {
          return Promise.resolve([]);
        }

        // Check if .flowconfig file is present
        const flowConfig = helpers.find(filePath, '.flowconfig');
        if (!flowConfig) {
          if (!this.lastConfigError || this.lastConfigError + 5 * 60 * 1000 < Date.now()) {
            atom.notifications.addWarning('[Linter-Flow] Missing .flowconfig file.', {
              detail: 'To get started with Flow, run `flow init`.',
              dismissable: true,
            });
            this.lastConfigError = Date.now();
          }
          return Promise.resolve([]);
        }

        let args;
        let options;

        // Use `check-contents` for unsaved files. and `status` for saved files.
        if (TextEditor.isModified()) {
          args = ['check-contents', '--json', filePath];
          options = { cwd: path.dirname(filePath), stdin: fileText };
        } else {
          args = ['status', '--json', filePath];
          options = { cwd: path.dirname(filePath) };
        }

        return check(this.pathToFlow, args, options)
          .then(JSON.parse)
          .then(handleData);
      },
    };
  },
};
<|endoftext|>


<commit_before>import React from 'react';
// import history modal

class HistoryModal extends React.Component {
	render() {
	    const post = this.props.details['post'];
	    const signup = this.props.details['post']['signup'];
        const campaign = this.props.details['campaign'];

		return (

				×

Change Quantity

Old Quantity

{signup['quantity']} {campaign['reportback_info']['noun']} {campaign['reportback_info']['verb']}

New Quantity

							<input type="text" className="text-field" placeholder="Enter # here"></input>

Reportback History

table of all the history goes here 📖

				Save

		);
	}
}

export default HistoryModal;
<commit_msg>Remove outdated comment<commit_after>import React from 'react';

class HistoryModal extends React.Component {
	render() {
	    const post = this.props.details['post'];
	    const signup = this.props.details['post']['signup'];
        const campaign = this.props.details['campaign'];

		return (

				×

Change Quantity

Old Quantity

{signup['quantity']} {campaign['reportback_info']['noun']} {campaign['reportback_info']['verb']}

New Quantity

							<input type="text" className="text-field" placeholder="Enter # here"></input>

Reportback History

table of all the history goes here 📖

				Save

		);
	}
}

export default HistoryModal;
<|endoftext|>