<commit_before>/*!
 * Nodeunit
 * Copyright (c) 2010 Caolan McMahon
 * MIT Licensed
 */

/**
 * Module dependencies
 */

var async = require('../deps/async'),
    fs = require('fs'),
    util = require('util'),
    Script = process.binding('evals').Script || process.binding('evals').NodeScript,
    http = require('http');

/**
 * Detect if coffee-script, iced-coffeescript, or streamline are available and
 * the respective file extensions to the search filter in modulePaths if it is.
 */

var extensions = [ 'js' ];  // js is always supported: add it unconditionally
var extensionPattern;

try {
    require('coffee-script');
    extensions.push('coffee');
} catch (e) { }

try {
    require('iced-coffee-script');
    extensions.push('iced');
} catch (e) { }

try {
    require('streamline').register();
    extensions.push('_coffee');
    extensions.push('_js');
} catch (e) { }

extensionPattern = new RegExp('\\.(?:' + extensions.join('|') + ')$');

/**
 * Finds all modules at each path in an array, If a path is a directory, it
 * returns all supported file types inside it. This only reads 1 level deep in
 * the directory and does not recurse through sub-directories.
 *
 * The extension (.js, .coffee etc) is stripped from the filenames so they can
 * simply be require()'ed.
 *
 * @param {Array} paths
 * @param {Function} callback
 * @api public
 */

exports.modulePaths = function (paths, callback) {
    async.concat(paths, function (p, cb) {
        fs.stat(p, function (err, stats) {
            if (err) {
                return cb(err);
            }
            if (stats.isFile()) {
                return cb(null, [p]);
            }
            if (stats.isDirectory()) {
                fs.readdir(p, function (err, files) {
                    if (err) {
                        return cb(err);
                    }

                    // filter out any filenames with unsupported extensions
                    var modules = files.filter(function (filename) {
                        return extensionPattern.exec(filename);
                    });

                    // remove extension from module name and prepend the
                    // directory path
                    var fullpaths = modules.map(function (filename) {
                        var mod_name = filename.replace(extensionPattern, '');
                        return [p, mod_name].join('/');
                    });

                    // sort filenames here, because Array.map changes order
                    fullpaths.sort();

                    cb(null, fullpaths);
                });
            }
        });
    }, callback);
};

/**
 * Evaluates JavaScript files in a sandbox, returning the context. The first
 * argument can either be a single filename or an array of filenames. If
 * multiple filenames are given their contents are concatenated before
 * evalution. The second argument is an optional context to use for the sandbox.
 *
 * @param files
 * @param {Object} sandbox
 * @return {Object}
 * @api public
 */

exports.sandbox = function (files, /*optional*/sandbox) {
    var source, script, result;
    if (!(files instanceof Array)) {
        files = [files];
    }
    source = files.map(function (file) {
        return fs.readFileSync(file, 'utf8');
    }).join('');

    if (!sandbox) {
        sandbox = {};
    }
    script = new Script(source);
    result = script.runInNewContext(sandbox);
    return sandbox;
};

/**
 * Provides a http request, response testing environment.
 *
 * Example:
 *
 *  var httputil = require('nodeunit').utils.httputil
 *  exports.testSomething = function(test) {
 *    httputil(function (req, resp) {
 *        resp.writeHead(200, {});
 *        resp.end('test data');
 *      },
 *      function(server, client) {
 *        client.fetch('GET', '/', {}, function(resp) {
 *          test.equal('test data', resp.body);
 *          server.close();
 *          test.done();
 *        })
 *      });
 *  };
 *
 * @param {Function} cgi
 * @param {Function} envReady
 * @api public
 */
exports.httputil = function (cgi, envReady) {
    var hostname = process.env.HOSTNAME || 'localhost';
    var port = process.env.PORT || 3000;

    var server = http.createServer(cgi);
    server.listen(port, hostname);

    var client = http.createClient(port, hostname);
    client.fetch = function (method, path, headers, respReady) {
        var request = this.request(method, path, headers);
        request.end();
        request.on('response', function (response) {
            response.setEncoding('utf8');
            response.on('data', function (chunk) {
                if (response.body) {
                    response.body += chunk;
                } else {
                    response.body = chunk;
                }
            });
            response.on('end', function () {
                if (response.headers['content-type'] === 'application/json') {
                    response.bodyAsObject = JSON.parse(response.body);
                }
                respReady(response);
            });
        });
    };

    process.nextTick(function () {
        if (envReady && typeof envReady === 'function') {
            envReady(server, client);
        }
    });
};

/**
 * Improves formatting of AssertionError messages to make deepEqual etc more
 * readable.
 *
 * @param {Object} assertion
 * @return {Object}
 * @api public
 */

exports.betterErrors = function (assertion) {
    if (!assertion.error) {
        return assertion;
    }
    var e = assertion.error;
    if (e.actual && e.expected) {
        var actual = util.inspect(e.actual, false, 10).replace(/\n$/, '');
        var expected = util.inspect(e.expected, false, 10).replace(/\n$/, '');
        var multiline = (
            actual.indexOf('\n') !== -1 ||
            expected.indexOf('\n') !== -1
        );
        var spacing = (multiline ? '\n' : ' ');
        e._message = e.message;
        e.stack = (
            e.name + ':' + spacing +
            actual + spacing + e.operator + spacing +
            expected + '\n' +
            e.stack.split('\n').slice(1).join('\n')
        );
    }
    return assertion;
};
<commit_msg>utils: do not use internal Node API<commit_after>/*!
 * Nodeunit
 * Copyright (c) 2010 Caolan McMahon
 * MIT Licensed
 */

/**
 * Module dependencies
 */

var async = require('../deps/async'),
    fs = require('fs'),
    util = require('util'),
    Script = require('vm').Script,
    http = require('http');

/**
 * Detect if coffee-script, iced-coffeescript, or streamline are available and
 * the respective file extensions to the search filter in modulePaths if it is.
 */

var extensions = [ 'js' ];  // js is always supported: add it unconditionally
var extensionPattern;

try {
    require('coffee-script');
    extensions.push('coffee');
} catch (e) { }

try {
    require('iced-coffee-script');
    extensions.push('iced');
} catch (e) { }

try {
    require('streamline').register();
    extensions.push('_coffee');
    extensions.push('_js');
} catch (e) { }

extensionPattern = new RegExp('\\.(?:' + extensions.join('|') + ')$');

/**
 * Finds all modules at each path in an array, If a path is a directory, it
 * returns all supported file types inside it. This only reads 1 level deep in
 * the directory and does not recurse through sub-directories.
 *
 * The extension (.js, .coffee etc) is stripped from the filenames so they can
 * simply be require()'ed.
 *
 * @param {Array} paths
 * @param {Function} callback
 * @api public
 */

exports.modulePaths = function (paths, callback) {
    async.concat(paths, function (p, cb) {
        fs.stat(p, function (err, stats) {
            if (err) {
                return cb(err);
            }
            if (stats.isFile()) {
                return cb(null, [p]);
            }
            if (stats.isDirectory()) {
                fs.readdir(p, function (err, files) {
                    if (err) {
                        return cb(err);
                    }

                    // filter out any filenames with unsupported extensions
                    var modules = files.filter(function (filename) {
                        return extensionPattern.exec(filename);
                    });

                    // remove extension from module name and prepend the
                    // directory path
                    var fullpaths = modules.map(function (filename) {
                        var mod_name = filename.replace(extensionPattern, '');
                        return [p, mod_name].join('/');
                    });

                    // sort filenames here, because Array.map changes order
                    fullpaths.sort();

                    cb(null, fullpaths);
                });
            }
        });
    }, callback);
};

/**
 * Evaluates JavaScript files in a sandbox, returning the context. The first
 * argument can either be a single filename or an array of filenames. If
 * multiple filenames are given their contents are concatenated before
 * evalution. The second argument is an optional context to use for the sandbox.
 *
 * @param files
 * @param {Object} sandbox
 * @return {Object}
 * @api public
 */

exports.sandbox = function (files, /*optional*/sandbox) {
    var source, script, result;
    if (!(files instanceof Array)) {
        files = [files];
    }
    source = files.map(function (file) {
        return fs.readFileSync(file, 'utf8');
    }).join('');

    if (!sandbox) {
        sandbox = {};
    }
    script = new Script(source);
    result = script.runInNewContext(sandbox);
    return sandbox;
};

/**
 * Provides a http request, response testing environment.
 *
 * Example:
 *
 *  var httputil = require('nodeunit').utils.httputil
 *  exports.testSomething = function(test) {
 *    httputil(function (req, resp) {
 *        resp.writeHead(200, {});
 *        resp.end('test data');
 *      },
 *      function(server, client) {
 *        client.fetch('GET', '/', {}, function(resp) {
 *          test.equal('test data', resp.body);
 *          server.close();
 *          test.done();
 *        })
 *      });
 *  };
 *
 * @param {Function} cgi
 * @param {Function} envReady
 * @api public
 */
exports.httputil = function (cgi, envReady) {
    var hostname = process.env.HOSTNAME || 'localhost';
    var port = process.env.PORT || 3000;

    var server = http.createServer(cgi);
    server.listen(port, hostname);

    var client = http.createClient(port, hostname);
    client.fetch = function (method, path, headers, respReady) {
        var request = this.request(method, path, headers);
        request.end();
        request.on('response', function (response) {
            response.setEncoding('utf8');
            response.on('data', function (chunk) {
                if (response.body) {
                    response.body += chunk;
                } else {
                    response.body = chunk;
                }
            });
            response.on('end', function () {
                if (response.headers['content-type'] === 'application/json') {
                    response.bodyAsObject = JSON.parse(response.body);
                }
                respReady(response);
            });
        });
    };

    process.nextTick(function () {
        if (envReady && typeof envReady === 'function') {
            envReady(server, client);
        }
    });
};

/**
 * Improves formatting of AssertionError messages to make deepEqual etc more
 * readable.
 *
 * @param {Object} assertion
 * @return {Object}
 * @api public
 */

exports.betterErrors = function (assertion) {
    if (!assertion.error) {
        return assertion;
    }
    var e = assertion.error;
    if (e.actual && e.expected) {
        var actual = util.inspect(e.actual, false, 10).replace(/\n$/, '');
        var expected = util.inspect(e.expected, false, 10).replace(/\n$/, '');
        var multiline = (
            actual.indexOf('\n') !== -1 ||
            expected.indexOf('\n') !== -1
        );
        var spacing = (multiline ? '\n' : ' ');
        e._message = e.message;
        e.stack = (
            e.name + ':' + spacing +
            actual + spacing + e.operator + spacing +
            expected + '\n' +
            e.stack.split('\n').slice(1).join('\n')
        );
    }
    return assertion;
};
<|endoftext|>


<commit_before>'use strict';

/* value.js
 * Expresses CSS values.
 */

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

let Value = create(function(data, value){
  if (typeof data === 'string' && Array.isArray(value)) {
    this.type = 'function';
    this.function = this.name = data;
    this.val = value;
  } else if (typeof data === 'number') {
    this.type = 'number';
    this.unit = this.name = value || null;
    this.val = data;
  } else {
    this.type = 'keyword';
    this.val = this.keyword = this.name = data;
  }
}, {

  operation: function(otherValue, callback){
    return callback(this, otherValue);
  },

  math: function(otherValue, callback){
    if (
      otherValue.type === 'number' &&
      this.type === 'number' &&
      this.unit === otherValue.unit
    ) return new Value(this.operation(otherValue, callback), this.unit);
    else
      throw new TypeError('both values must be numbers and have the same unit');
  },

  plus: function(other){
    return this.math(other, (x, y) => x.val + y.val);
  },

  minus: function(other){
    if (!(other instanceof Value)) other = new Value(...arguments);
    return this.math(other, (x, y) => x.val - y.val);
  },

  times: function(other){
    if (!(other instanceof Value)) other = new Value(...arguments);
    return this.math(other, (x, y) => x.val * y.val);
  },

  divide: function(other){
    if (!(other instanceof Value)) other = new Value(...arguments);
    return this.math(other, (x, y) => x.val / y.val);
  },

  equals: function(other){
    if (!(other instanceof Value)) other = new Value(...arguments);
    if (this.type === 'number' && other.type === 'number' &&
        this.unit !== other.unit) return false;

    return (
      this.falsey[this.val] ? false : this.val
    ) === (
      this.falsey[other.val] ? false : other.val
    );
  },

  falsey: {'none':true, 'false':true, '0':true, '':true}

});

module.exports = exports = Value;
<commit_msg>Don't make keyword a fallback for unknown data.<commit_after>'use strict';

/* value.js
 * Expresses CSS values.
 */

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

let Value = create(function(data, value){
  if (typeof data === 'string' && Array.isArray(value)) {
    this.type = 'function';
    this.function = this.name = data;
    this.val = value;
  } else if (typeof data === 'number') {
    this.type = 'number';
    this.unit = this.name = value || null;
    this.val = data;
  } else if (typeof data === 'string' && /^[A-z]+$/.test(data)) {
    this.type = 'keyword';
    this.val = this.keyword = this.name = data;
  } else {
    this.type = 'unknown';
    this.val = value;
  }
}, {

  operation: function(otherValue, callback){
    return callback(this, otherValue);
  },

  math: function(otherValue, callback){
    if (
      otherValue.type === 'number' &&
      this.type === 'number' &&
      this.unit === otherValue.unit
    ) return new Value(this.operation(otherValue, callback), this.unit);
    else
      throw new TypeError('both values must be numbers and have the same unit');
  },

  plus: function(other){
    return this.math(other, (x, y) => x.val + y.val);
  },

  minus: function(other){
    if (!(other instanceof Value)) other = new Value(...arguments);
    return this.math(other, (x, y) => x.val - y.val);
  },

  times: function(other){
    if (!(other instanceof Value)) other = new Value(...arguments);
    return this.math(other, (x, y) => x.val * y.val);
  },

  divide: function(other){
    if (!(other instanceof Value)) other = new Value(...arguments);
    return this.math(other, (x, y) => x.val / y.val);
  },

  equals: function(other){
    if (!(other instanceof Value)) other = new Value(...arguments);
    if (this.type === 'number' && other.type === 'number' &&
        this.unit !== other.unit) return false;

    return (
      this.falsey[this.val] ? false : this.val
    ) === (
      this.falsey[other.val] ? false : other.val
    );
  },

  falsey: {'none':true, 'false':true, '0':true, '':true}

});

module.exports = exports = Value;
<|endoftext|>


<commit_before>/*jshint esversion:6, node:true*/
'use strict';

const path = require('path');
const express = require('express');
const getView = require('./getView');

const TrackFinder = require('trackfinder');

class Setup {
    constructor(app, config) {
        this.app = app;
        this.config = config;
        this.mountedApps = {};
    }

    addRoutes() {
        this.logger.info('Scanning routes...');
        //Wire routes:

        TrackFinder.register(this.app, {
            path: this.config.routesPath,
            config: this.config,
            logger: this.logger
        });
    }

    addMiddleware() {
        let app = this.app;
        let config = this.config;

        let parent = path.resolve(__dirname, '..');

        //static
        //TODO: We need to be able to configura this
        //and override on other apps.
        let publicpath = path.join(parent, 'public');

        if (config.publicPath) publicpath = config.publicPath;

        config.publicPath = publicpath;

        app.use(express.static(publicpath));

        //favicon
        const fav = require('serve-favicon');

        let favipath = path.join(parent, 'public/favicon.ico');
        if (config.faviconPath) favipath = config.faviconPath;

        app.use(fav(favipath));
    }

    addViews() {
        let app = this.app;
        let config = this.config;

        /*
         * We handle errors, which means we need
         * to be able to render views...
         */
        let viewpath = path.join(__dirname, '../views');

        if (config.viewsPath) viewpath = config.viewsPath;

        config.viewsPath = viewpath;

        app.set('views', viewpath);
        app.set('view engine', 'ejs');
    }

    mount() {
        var apps = this.config.subapps;

        if (!apps) return;

        /*
         * This pretty much should always be empty.
         * @TODO: This is awkard, very. We should not
         * store those values in config. We should store
         * in whatever property we espose to application
         * context. So we can do:
         * app.server.findSubapp('admin')
         */
        if(!this.config.mountedApps) this.config.mountedApps = {};

        var router;

        Object.keys(apps).map((route) => {
            router = apps[route];

            this.extend(router);

            this.logger.info('mount app: %s', route);
            this.app.use(route, router);
            this.config.mountedApps[router.appId] = router;
        });
    }

    extend(subapp) {
        /*
         * How can we extend express protoype?
         * Also, we need to extend both app and
         * router, since we can use them both
         */
        subapp.getRoot = function() {
            var root = this;
            //@TODO add guard here, do not while for evers.
            while (root.parent) {
                root = root.parent;
            }

            return root;
        };
    }

    addErrorHandlers() {
        let app = this.app;
        let config = this.config;

        /*
         * This ensures that the first time we
         * run the app, we can show a default
         * html page.
         *
         * TODO: we should be able to configure the
         * path to the view file.
         */
        app.use(function handleServeIndexIfNotDefined(req, res, next) {
            if (req.url === '/') {
                let root = config.publicPath;
                let defaultIndex = path.join(root, 'default-index.html');
                return res.sendFile(defaultIndex);
            }
            next();
        });

        // catch 404 and forward to error handler
        app.use(function handle404(req, res, next) {
            var err = new Error('Not Found');
            err.status = 404;
            next(err);
        });

        // error handlers

        // development error handler
        // will print stacktrace
        let self = this;
        app.use(function handleErrorFinal(err, req, res, next) {

            let error = {};
            if (app.get('env') === 'development') {
                error = err;
            }

            let status = err.status || 500;

            switch (status) {
                case 500:
                    self.logger.error('Error %s: %s', status, err.message);
                    self.logger.error('%s', err.stack);
                    break;
                case 404:
                    self.logger.warn('url: %s', req.protocol + '://' + req.get('Host') + req.url);
                    break;
                case 401:
                    self.logger.warn('Auth error url: %s', err.message);
                    break;
                default:
                    self.logger.error('Error %s: %s', status, err.message);

            }

            res.status(status);

            /**
             * res.format performs content negotiation
             * on the `Accept` HTTP header on the req
             * object when present.
             *
             * If the header is not specified the first
             * callback is invoked.
             *
             * When no match is found, it responds with
             * a 406 Not Acceptable, or invokes the
             * `default` callback.
             *
             * @type {[type]}
             */
            res.format({
                // html|text
                html: function formatHMTL() {
                    let view = getView(app, status, 'error');
                    res.render(view, {
                        message: err.message,
                        error: error,
                        stack: error.stack
                    });
                },
                json: function formatJSON() {
                    res.send({
                        success: false,
                        message: error.message
                    });
                },
                default: function formatDef() {
                    let view = getView(app, status, 'error');
                    res.render(view, {
                        message: err.message,
                        error: error,
                        stack: error.stack
                    });
                }
            });
        });
    }

    get express() {
        return this.app;
    }

    createServer(port = 3000) {
        this.app.set('port', port);

        const http = require('http');

        this.server = http.createServer(this.app);

        this.server.on('clientError', (err, socket) => {
            socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
        });

        /*
         * TODO: We might want to pass
         * the **hostname** as well.
         * If you bind
         */
        this.server.listen(port);

        return this.server;
    }
}

module.exports = Setup;
<commit_msg>Add addViewPath to subapp<commit_after>/*jshint esversion:6, node:true*/
'use strict';

const path = require('path');
const express = require('express');
const getView = require('./getView');

const TrackFinder = require('trackfinder');

class Setup {
    constructor(app, config) {
        this.app = app;
        this.config = config;
        this.mountedApps = {};
    }

    addRoutes() {
        this.logger.info('Scanning routes...');
        //Wire routes:

        TrackFinder.register(this.app, {
            path: this.config.routesPath,
            config: this.config,
            logger: this.logger
        });
    }

    addMiddleware() {
        let app = this.app;
        let config = this.config;

        let parent = path.resolve(__dirname, '..');

        //static
        //TODO: We need to be able to configura this
        //and override on other apps.
        let publicpath = path.join(parent, 'public');

        if (config.publicPath) publicpath = config.publicPath;

        config.publicPath = publicpath;

        app.use(express.static(publicpath));

        //favicon
        const fav = require('serve-favicon');

        let favipath = path.join(parent, 'public/favicon.ico');
        if (config.faviconPath) favipath = config.faviconPath;

        app.use(fav(favipath));
    }

    addViews() {
        let app = this.app;
        let config = this.config;

        /*
         * We handle errors, which means we need
         * to be able to render views...
         */
        let viewpath = path.join(__dirname, '../views');

        if (config.viewsPath) viewpath = config.viewsPath;

        config.viewsPath = viewpath;

        app.set('views', viewpath);
        app.set('view engine', 'ejs');
    }

    mount() {
        var apps = this.config.subapps;

        if (!apps) return;

        /*
         * This pretty much should always be empty.
         * @TODO: This is awkard, very. We should not
         * store those values in config. We should store
         * in whatever property we espose to application
         * context. So we can do:
         * app.server.findSubapp('admin')
         */
        if(!this.config.mountedApps) this.config.mountedApps = {};

        var router;

        Object.keys(apps).map((route) => {
            router = apps[route];

            this.extend(router);

            this.logger.info('mount app: %s', route);
            this.app.use(route, router);
            this.config.mountedApps[router.appId] = router;
        });
    }

    extend(subapp) {
        /*
         * How can we extend express protoype?
         * Also, we need to extend both app and
         * router, since we can use them both
         */
        subapp.getRoot = function() {
            var root = this;
            //@TODO add guard here, do not while for evers.
            while (root.parent) {
                root = root.parent;
            }

            return root;
        };

        /**
         * Ensure we have a view path in a given app.
         * @method ensureViewHasPath
         * @param  {Express}          app
         * @param  {String}          moduleId
         * @return {void}
         */
        subapp.addViewPath = function(path) {
            let paths = this.get('views');
            if(!Array.isArray(paths)) paths = [paths];

            /*
             * Here we basically want to ensure we
             * dont already have the view path.
             * We could have different forms of
             * the same path:
             * - ./modules/invite/views
             * - /opt/myapp/src/modules/invite/views
             */
            if(paths.indexOf(path) === -1) {
                return;
            }

            paths.push(path);
            this.set('views', paths);
        };
    }

    addErrorHandlers() {
        let app = this.app;
        let config = this.config;

        /*
         * This ensures that the first time we
         * run the app, we can show a default
         * html page.
         *
         * TODO: we should be able to configure the
         * path to the view file.
         */
        app.use(function handleServeIndexIfNotDefined(req, res, next) {
            if (req.url === '/') {
                let root = config.publicPath;
                let defaultIndex = path.join(root, 'default-index.html');
                return res.sendFile(defaultIndex);
            }
            next();
        });

        // catch 404 and forward to error handler
        app.use(function handle404(req, res, next) {
            var err = new Error('Not Found');
            err.status = 404;
            next(err);
        });

        // error handlers

        // development error handler
        // will print stacktrace
        let self = this;

        //@TODO: We should be able to attach error processors.
        //e.g. if we get a Waterline error, we should be able to parse
        //it here and send something menaingful...
        app.use(function handleErrorFinal(err, req, res, next) {

            let error = {};
            if (app.get('env') === 'development') {
                error = err;
            }

            let status = err.status || 500;

            switch (status) {
                case 500:
                    self.logger.error('Error %s: %s', status, err.message);
                    self.logger.error('%s', err.stack);
                    break;
                case 404:
                    self.logger.warn('url: %s', req.protocol + '://' + req.get('Host') + req.url);
                    break;
                case 401:
                    self.logger.warn('Auth error url: %s', err.message);
                    break;
                default:
                    self.logger.error('Error %s: %s', status, err.message);

            }

            res.status(status);

            /**
             * res.format performs content negotiation
             * on the `Accept` HTTP header on the req
             * object when present.
             *
             * If the header is not specified the first
             * callback is invoked.
             *
             * When no match is found, it responds with
             * a 406 Not Acceptable, or invokes the
             * `default` callback.
             *
             * @type {[type]}
             */
            res.format({
                // html|text
                html: function formatHMTL() {
                    let view = getView(app, status, 'error');
                    res.render(view, {
                        message: err.message,
                        error: error,
                        stack: error.stack
                    });
                },
                json: function formatJSON() {
                    res.send({
                        success: false,
                        message: error.message
                    });
                },
                default: function formatDef() {
                    let view = getView(app, status, 'error');
                    res.render(view, {
                        message: err.message,
                        error: error,
                        stack: error.stack
                    });
                }
            });
        });
    }

    get express() {
        return this.app;
    }

    createServer(port = 3000) {
        this.app.set('port', port);

        const http = require('http');

        this.server = http.createServer(this.app);

        this.server.on('clientError', (err, socket) => {
            socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
        });

        /*
         * TODO: We might want to pass
         * the **hostname** as well.
         * If you bind
         */
        this.server.listen(port);

        return this.server;
    }
}

module.exports = Setup;
<|endoftext|>


<commit_before>'use strict';

var engine = require('./engine.js');
var _ = require('lodash');
var Sync = require('./share/sync/sync.js');
var core = require('./core.js');
var Promise = require('bluebird');
var container = require('./share/sync/syncContainer.js');
var async = require('async');
var app = require('./app.js');

var CONTAINER_NAME = 'kalabox_syncthing';

var logDebug = core.log.debug;

var logInfo = core.log.info;

/*
 * Given an app return true if the app has any containers running.
 */
var isAppRunning = function(appName) {

  // Get list of app's containers.
  return new Promise(function(fulfill, reject) {
    engine.list(appName, function(err, containers) {
      if (err) {
        return reject(err);
      }
      fulfill(containers);
    });
  })
  // Map container to container's is running value.
  .map(function(container) {
    return new Promise(function(fulfill, reject) {
      engine.inspect(container.name, function(err, data) {
        if (err) {
          return reject(err);
        }
        fulfill(data.State.Running);
      });
    });
  }, {concurrency: 5})
  // Filter out falses.
  .filter(_.identity)
  // Sum trues.
  .reduce(function(count) {
    return count + 1;
  }, 0)
  // Return true if sum of trues is greater than zero.
  .then(function(count) {
    return count > 0;
  });

};

/*
 * Get list of data containers that are part of apps that are running.
 */
var getDataContainers = function() {

  // Get list of all installed containers.
  return new Promise(function(fulfill, reject) {
    engine.list(function(err, containers) {
      if (err) {
        return reject(err);
      }
      fulfill(containers);
    });
  })
  // Filter out non data containers, and containers that are part of
  // apps that are not running.
  .filter(function(container) {
    var parts = container.name.split('_');
    var isDataContainer =
      parts.length === 3 &&
      parts[0] === 'kb' &&
      parts[2] === 'data';
    if (!isDataContainer) {
      return false;
    } else {
      return isAppRunning(parts[1]);
    }
  })
  // Wait until all results are in.
  .all()
  // Return.
  .then(function(dataContainers) {
    logDebug('SHARE => Data containers with an app running.', dataContainers);
    return dataContainers;
  });

};

/*
 * Get the data container volume path.
 */
var getDataContainerVolume = function(dataContainer) {

  return new Promise(function(fulfill, reject) {
    engine.inspect(dataContainer.name, function(err, data) {
      if (err) {
        return reject(err);
      }
      var codeDir = '/' + core.deps.lookup('globalConfig').codeDir;
      if (data.Volumes[codeDir]) {
        fulfill(data.Volumes[codeDir]);
      } else {
        fulfill(null);
      }
    });
  });

};

/*
 * Get list of volumes.
 */
var getVolumes = function() {

  // Get list of data containers.
  return getDataContainers()
  // Map list to volume objects.
  .map(function(dataContainer) {
    return getDataContainerVolume(dataContainer)
    .then(function(volume) {
      if (volume) {
        return {app: dataContainer.app, volume: volume};
      } else {
        return null;
      }
    });
  })
  // Filter out nulls.
  .filter(_.negate(_.isNull));

};

/*
 * Get local sync instance.
 */
var getLocalSync = exports.getLocalSync = function() {
  return new Promise(function(fulfill) {
    fulfill(new Sync('127.0.0.1'));
  });
};

/*
 * Get remote sync instance.
 */
var getRemoteSync = exports.getRemoteSync = function() {
  return new Promise(function(fulfill, reject) {
    // Get ip of VM.
    engine.provider.engineConfig(function(err, engineConfig) {
      if (err) {
        return reject(err);
      }
      fulfill(new Sync(engineConfig.host));
    });
  });
};

/*
 * Get a map function of app names to code roots.
 */
var getCodeRootMap = function() {

  return new Promise(function(fulfill, reject) {

    // Get list of apps.
    app.list(function(err, apps) {

      // Report errors.
      if (err) {
        return reject(err);
      }

      // Build map of app name to code root.
      var map = {};
      _.each(apps, function(app) {
        map[app.name] = app.config.codeRoot;
      });

      // Build map function.
      var fn = function(name) {
        if (!map[name]) {
          throw new Error('App code root not found: ' + name);
        }
        return map[name];
      };

      // Return.
      fulfill(fn);

    });

  });

};

/*
 * Stop the remote sync container.
 */
var stopContainer = function(remoteSync) {

  // Check if container is installed.
  return container.isInstalled()
  .then(function(isInstalled) {
    if (isInstalled) {
      // Check if container is running.
      return container.isRunning()
      .then(function(isRunning) {
        if (isRunning) {
          // Stop container.
          return container.stop();
        }
      })
      .then(function() {
        // Remove the container.
        return container.remove();
      });
    }
  });

};

/*
 * Create the remote sync container.
 */
var createContainer = function(volumes) {
  var binds = _.map(volumes, function(x) {
    return [x.volume, '/' + x.app].join(':');
  });
  return container.create(binds);
};

/*
 * Start the remote sync container.
 */
var startContainer = function() {
  return container.start();
};

/*
 * Restart the sync instances.
 */
var restart = exports.restart = function(cb, retries) {

  // Defaults.
  if (!retries) {
    retries = 2;
  }

  // Have we tried enough times.
  if (retries < 0) {
    return cb(new Error('Could not establish syncthing connections.'));
  }

  // Get volumes.
  var volumes = getVolumes();

  // Get local sync instance.
  var localSync = getLocalSync()
    .then(function(localSync) {
      // Check if sync is running.
      return localSync.isUp()
      .then(function(isUp) {
        if (isUp) {
          // If sync is running, clear it and then shut it down.
          return localSync.clear()
          .then(function() {
            return localSync.shutdown()
            // Wait for 5 seconds after shutting down.
            .delay(5 * 1000);
          });
        }
      })
      // Return reference to local sync instance.
      .then(function() {
        return localSync;
      });
    });

  // Get remote sync instance.
  var remoteSync = getRemoteSync()
    .then(function(remoteSync) {
      // Stop sync container.
      return stopContainer()
      // Return reference to remote sync instance.
      .then(function() {
        return remoteSync;
      });
    });

  // Get a map between app names and app code roots.
  var codeRootMap = getCodeRootMap();

  // Wait for previous promises to finish.
  Promise.all([volumes, localSync, remoteSync, codeRootMap])
  .spread(function(volumes, localSync, remoteSync, codeRootMap) {

    // Start local sync instance.
    var startLocal = localSync.start();

    // Start remote sync instance.
    var startRemote = createContainer(volumes)
      .then(function() {
        return startContainer()
        .then(function() {
          return remoteSync.wait();
        });
      });

    // Get configs and deviceIds for sync instances.
    return Promise.all([startLocal, startRemote])
    .then(function() {

      return Promise.all([
        localSync.getConfig(),
        localSync.getDeviceId(),
        remoteSync.getConfig(),
        remoteSync.getDeviceId()
      ]);

    })
    // Edit configs.
    .spread(function(localConfig, localId, remoteConfig, remoteId) {

      // Add devices to configs.
      localSync.addDevice(localConfig, remoteId, remoteSync.ip);
      remoteSync.addDevice(remoteConfig, localId, localSync.ip);

      // Add each volume to configs.
      _.each(volumes, function(volume) {
        var app = volume.app;
        var codeRoot = codeRootMap(app);
        localSync.addFolder(localConfig, app, codeRoot);
        remoteSync.addFolder(remoteConfig, app, '/' + app);
      });

      return Promise.all([
        localConfig,
        remoteConfig
      ]);

    })
    // Set configs.
    .spread(function(localConfig, remoteConfig) {

      return Promise.all([
        localSync.setConfig(localConfig),
        remoteSync.setConfig(remoteConfig)
      ]);

    })
    // Restart sync instances.
    .then(function() {

      return Promise.all([
        localSync.restartWait(),
        remoteSync.restartWait()
      ]);

    })
    // Make sure local and remote instances are connected.
    .then(function() {

      return new Promise(function(fulfill, reject) {

        var count = 30;

        // Loop.
        async.forever(function(next) {

          // Have we tried enough times?
          count -= 1;
          if (count < 0) {
            // Try the entire restart process over again.
            return restart(cb, retries - 1);
          }

          // Query local sync for connection data.
          localSync.connections()
          .then(function(data) {

            // Success!
            if (_.keys(data.connections).length > 0) {
              return fulfill();
            }
            // Wait and try again.
            setTimeout(function() {
              next();
            }, 1 * 1000);

          })
          .catch(next);

        }, reject);

      });

    })
    // Return.
    .return();

  })
  .nodeify(cb);

};
<commit_msg>Good sized refactoring of lib/share.js.<commit_after>'use strict';

var engine = require('./engine.js');
var _ = require('lodash');
var Sync = require('./share/sync/sync.js');
var core = require('./core.js');
var Promise = require('./promise.js');
var container = require('./share/sync/syncContainer.js');
var async = require('async');
var app = require('./app.js');

var CONTAINER_NAME = 'kalabox_syncthing';

var logDebug = core.log.debug;

var logInfo = core.log.info;

/*
 * Given an app return true if the app has any containers running.
 */
var isAppRunning = function(appName) {

  // Get list of app's containers.
  return engine.list(appName)
  // Map container to container's is running value.
  .map(function(container) {
    return engine.inspect(container.name)
    .then(function(data) {
      return data.State.Running;
    });
  }, {concurrency: 5})
  // Filter out falses.
  .filter(_.identity)
  // Sum trues.
  .reduce(function(count) {
    return count + 1;
  }, 0)
  // Return true if sum of trues is greater than zero.
  .then(function(count) {
    return count > 0;
  });

};

/*
 * Get list of data containers that are part of apps that are running.
 */
var getDataContainers = function() {

  // Get list of all installed containers.
  return engine.list(null)
  // Filter out non data containers, and containers that are part of
  // apps that are not running.
  .filter(function(container) {
    var parts = container.name.split('_');
    var isDataContainer =
      parts.length === 3 &&
      parts[0] === 'kb' &&
      parts[2] === 'data';
    if (!isDataContainer) {
      return false;
    } else {
      return isAppRunning(parts[1]);
    }
  })
  // Wait until all results are in.
  .all()
  // Return.
  .tap(function(dataContainers) {
    logDebug('SHARE => Data containers with an app running.', dataContainers);
  });

};

/*
 * Get the data container volume path.
 */
var getDataContainerVolume = function(dataContainer) {

  // Inspect data container.
  return engine.inspect(dataContainer.name)
  // Return the data containres data volume.
  .then(function(data) {
    var codeDir = '/' + core.deps.lookup('globalConfig').codeDir;
    return data.Volumes[codeDir];
  });

};

/*
 * Get list of volumes.
 */
var getVolumes = function() {

  // Get list of data containers.
  return getDataContainers()
  // Map list to volume objects.
  .map(function(dataContainer) {
    return getDataContainerVolume(dataContainer)
    .then(function(volume) {
      if (volume) {
        return {app: dataContainer.app, volume: volume};
      } else {
        return null;
      }
    });
  })
  // Filter out nulls.
  .filter(_.identity);

};

/*
 * Get local sync instance.
 */
var getLocalSync = exports.getLocalSync = function() {
  return Promise.resolve(new Sync('127.0.0.1'));
};

/*
 * Get remote sync instance.
 */
var getRemoteSync = exports.getRemoteSync = function() {
  // Get provider's engine config.
  return engine.provider.engineConfig()
  // Return syncthing instance with engine config's host IP.
  .then(function(engineConfig) {
    return new Sync(engineConfig.host);
  });
};

/*
 * Get a map function of app names to code roots.
 */
var getCodeRootMap = function() {

  // Get list of apps.
  return app.list()
  // Return a function that maps an app name to a code root.
  .then(function(apps) {

    // Build map of app name to code root.
    var codeRootMap = {};
    _.each(apps, function(app) {
      codeRootMap[app.name] = app.config.codeRoot;
    });

    // Build map function.
    var fn = function(name) {
      if (!codeRootMap[name]) {
        throw new Error('App code root not found: ' + name);
      }
      return codeRootMap[name];
    };

    // Return map function.
    return fn;

  });

};

/*
 * Stop the remote sync container.
 */
var stopContainer = function(remoteSync) {

  // Check if container is installed.
  return container.isInstalled()
  .then(function(isInstalled) {
    if (isInstalled) {
      // Check if container is running.
      return container.isRunning()
      .then(function(isRunning) {
        if (isRunning) {
          // Stop container.
          return container.stop();
        }
      })
      .then(function() {
        // Remove the container.
        return container.remove();
      });
    }
  });

};

/*
 * Create the remote sync container.
 */
var createContainer = function(volumes) {
  var binds = _.map(volumes, function(x) {
    return [x.volume, '/' + x.app].join(':');
  });
  return container.create(binds);
};

/*
 * Start the remote sync container.
 */
var startContainer = function() {
  return container.start();
};

/*
 * Restart the sync instances.
 */
// @todo: bcauldwell - Maybe cb and retries should swap places?
var restart = exports.restart = function(cb, retries) {

  // Defaults.
  if (!retries) {
    retries = 2;
  }

  // Have we tried enough times.
  // @todo: bcauldwell - This needs to be moved inside of a promise to have
  // this workflow be 100% correct.
  if (retries < 0) {
    return cb(new Error('Could not establish syncthing connections.'));
  }

  // Get volumes.
  var volumes = getVolumes();

  // Get local sync instance.
  var localSync = getLocalSync()
    .then(function(localSync) {
      // Check if sync is running.
      return localSync.isUp()
      .then(function(isUp) {
        if (isUp) {
          // If sync is running, clear it and then shut it down.
          return localSync.clear()
          .then(function() {
            return localSync.shutdown()
            // Wait for 5 seconds after shutting down.
            .delay(5 * 1000);
          });
        }
      })
      // Return reference to local sync instance.
      .return(localSync);
    });

  // Get remote sync instance.
  var remoteSync = getRemoteSync()
    .then(function(remoteSync) {
      // Stop sync container.
      return stopContainer()
      // Return reference to remote sync instance.
      .return(remoteSync);
    });

  // Get a map between app names and app code roots.
  var codeRootMap = getCodeRootMap();

  // Wait for previous promises to finish.
  Promise.all([volumes, localSync, remoteSync, codeRootMap])
  .spread(function(volumes, localSync, remoteSync, codeRootMap) {

    // Start local sync instance.
    var startLocal = localSync.start();

    // Start remote sync instance.
    var startRemote = createContainer(volumes)
      .then(function() {
        return startContainer()
        .then(function() {
          return remoteSync.wait();
        });
      });

    // Get configs and deviceIds for sync instances.
    return Promise.all([startLocal, startRemote])
    .then(function() {

      return Promise.all([
        localSync.getConfig(),
        localSync.getDeviceId(),
        remoteSync.getConfig(),
        remoteSync.getDeviceId()
      ]);

    })
    // Edit configs.
    .spread(function(localConfig, localId, remoteConfig, remoteId) {

      // Add devices to configs.
      localSync.addDevice(localConfig, remoteId, remoteSync.ip);
      remoteSync.addDevice(remoteConfig, localId, localSync.ip);

      // Add each volume to configs.
      _.each(volumes, function(volume) {
        var app = volume.app;
        var codeRoot = codeRootMap(app);
        localSync.addFolder(localConfig, app, codeRoot);
        remoteSync.addFolder(remoteConfig, app, '/' + app);
      });

      return Promise.all([
        localConfig,
        remoteConfig
      ]);

    })
    // Set configs.
    .spread(function(localConfig, remoteConfig) {

      return Promise.all([
        localSync.setConfig(localConfig),
        remoteSync.setConfig(remoteConfig)
      ]);

    })
    // Restart sync instances.
    .then(function() {

      return Promise.all([
        localSync.restartWait(),
        remoteSync.restartWait()
      ]);

    })
    // Make sure local and remote instances are connected.
    .then(function() {

      // Recursive function for checking connection state.
      var rec = function(counter) {

        // Query local syncthing instance's connections info.
        return localSync.connections()
        // Check connection state and retry a reasonable amount of times.
        .then(function(data) {
          // Not in a good state.
          if (_.keys(data.connections).length === 0) {
            if (counter > 0) {
              // Wait 2 seconds then try again.
              return Promise.delay(2 * 1000)
              .then(function() {
                return rec(counter - 1);
              });
            } else {
              // Try entire restart again.
              return restart(cb, retries - 1);
            }
          }
        });

      };

      // Init recursive function with 15 tries.
      return rec(15);

    });

  })
  // Return.
  .nodeify(cb);

};
<|endoftext|>


<commit_before>/*jshint esversion: 6 */
var fs = require('fs');
var chokidar = require('chokidar');

var Watch = function(options) {
  this.logger = options.logger;
  this.events = {};
};

Watch.prototype.start = function() {
  var embarkConfig = JSON.parse(fs.readFileSync("embark.json"));

  var appConfig = embarkConfig.app;
  var filesToWatch = [];

  for(var targetFile in appConfig) {
    filesToWatch.push(appConfig[targetFile]);
  }

  // TODO: add callback to ready
  this.logger.trace(filesToWatch);
  var assetWatcher = chokidar.watch(filesToWatch, {
    ignored: /[\/\\]\./, persistent: true, ignoreInitial: true, followSymlinks: true
  });
  assetWatcher
  .on('add',    path => {
    this.logger.info(`File ${path} has been added`)
    this.trigger('rebuildAssets', path);
  })
  .on('change', path => {
    this.logger.info(`File ${path} has been changed`)
    this.trigger('rebuildAssets', path);
  })
  .on('unlink', path => {
    this.logger.info(`File ${path} has been removed`)
    this.trigger('rebuildAssets', path);
  })
  .on('ready', () => this.logger.info('ready to watch changes'));

  var contractsToWatch = [];
  contractsToWatch.push(embarkConfig.contracts);
  this.logger.trace(contractsToWatch);
  var contractWatcher = chokidar.watch(contractsToWatch, {
    ignored: /[\/\\]\./, persistent: true, ignoreInitial: true, followSymlinks: true
  });
  contractWatcher
  .on('add',    path => {
    this.logger.info(`File ${path} has been added`)
    this.trigger('redeploy', path);
  })
  .on('change', path => {
      this.logger.info(`File ${path} has been changed`);
      this.trigger('redeploy', path);
  })
  .on('unlink', path => this.logger.info(`File ${path} has been removed`))
  .on('ready', () => this.logger.info('ready to watch changes'));

  this.logger.info("done!");
};

Watch.prototype.on = function(eventName, callback) {
  this.events[eventName] = callback;
};

Watch.prototype.trigger = function(eventName, values) {
  this.events[eventName](values);
};

module.exports = Watch;
<commit_msg>watch for config file changes and redeploy<commit_after>/*jshint esversion: 6 */
var fs = require('fs');
var chokidar = require('chokidar');

var Watch = function(options) {
  this.logger = options.logger;
  this.events = {};
};

Watch.prototype.start = function() {
  var embarkConfig = JSON.parse(fs.readFileSync("embark.json"));

  var appConfig = embarkConfig.app;
  var filesToWatch = [];

  for(var targetFile in appConfig) {
    filesToWatch.push(appConfig[targetFile]);
  }

  // TODO: add callback to ready
  this.logger.trace(filesToWatch);
  var assetWatcher = chokidar.watch(filesToWatch, {
    ignored: /[\/\\]\./, persistent: true, ignoreInitial: true, followSymlinks: true
  });
  assetWatcher
  .on('add',    path => {
    this.logger.info(`File ${path} has been added`)
    this.trigger('rebuildAssets', path);
  })
  .on('change', path => {
    this.logger.info(`File ${path} has been changed`)
    this.trigger('rebuildAssets', path);
  })
  .on('unlink', path => {
    this.logger.info(`File ${path} has been removed`)
    this.trigger('rebuildAssets', path);
  })
  .on('ready', () => this.logger.info('ready to watch changes'));

  var contractsToWatch = [];
  contractsToWatch.push(embarkConfig.contracts);
  this.logger.trace(contractsToWatch);
  var contractWatcher = chokidar.watch(contractsToWatch, {
    ignored: /[\/\\]\./, persistent: true, ignoreInitial: true, followSymlinks: true
  });
  contractWatcher
  .on('add',    path => {
    this.logger.info(`File ${path} has been added`)
    this.trigger('redeploy', path);
  })
  .on('change', path => {
      this.logger.info(`File ${path} has been changed`);
      this.trigger('redeploy', path);
  })
  .on('unlink', path => this.logger.info(`File ${path} has been removed`))
  .on('ready', () => this.logger.info('ready to watch changes'));

  var configWatcher = chokidar.watch("config/**/contracts.json", {
    ignored: /[\/\\]\./, persistent: true, ignoreInitial: true, followSymlinks: true
  });
  configWatcher
  .on('add',    path => {
    this.logger.info(`File ${path} has been added`)
    this.trigger('redeploy', path);
  })
  .on('change', path => {
    this.logger.info(`File ${path} has been changed`)
    this.trigger('redeploy', path);
  })
  .on('unlink', path => {
    this.logger.info(`File ${path} has been removed`)
    this.trigger('redeploy', path);
  })
  .on('ready', () => this.logger.info('ready to watch changes'));

  this.logger.info("done!");
};

Watch.prototype.on = function(eventName, callback) {
  this.events[eventName] = callback;
};

Watch.prototype.trigger = function(eventName, values) {
  this.events[eventName](values);
};

module.exports = Watch;
<|endoftext|>


<commit_before>'use strict';

var sharp = require('sharp');
var gutil = require('gulp-util');
var path = require('path');
var rename = require('rename');
var size = require('./size');
var format = require('./format');

var PLUGIN_NAME = require('../package.json').name;

module.exports = function(file, config, options, cb) {
  var errPrefix = 'File `' + file.relative + '`: ';
  var image = sharp(file.contents);

  image.metadata(function(err, metadata) {
    if (err) {
      return cb(new gutil.PluginError(PLUGIN_NAME, errPrefix + err.message));
    }

    var width, height, extract, toFormat;

    var filePath = file.path;
    if (config.rename) {
      filePath = path.join(file.base, rename(file.relative, config.rename));
    }

    if (config.format) {
      toFormat = config.format;
    } else {
      toFormat = format(filePath);
    }

    try {
      width = size(config.width, metadata.width);
      height = size(config.height, metadata.height);
    } catch  (err){
      return cb(new gutil.PluginError(PLUGIN_NAME, errPrefix + err.message));
    }

    if (width || height) {
      if (config.withoutEnlargement && (width > metadata.width || height > metadata.height)) {
        var message = errPrefix + 'Image enlargement is detected';
        if (width) {
          message += '\n  real width: ' + metadata.width + 'px, required width: ' + width + 'px';
        }
        if (height) {
          message += '\n  real height: ' + metadata.height + 'px, required height: ' + height + 'px';
        }
        if (options.errorOnEnlargement) {
          return cb(new gutil.PluginError(PLUGIN_NAME, message));
        } else if (config.skipOnEnlargement) {
          if (!options.silent){
            gutil.log(PLUGIN_NAME + ': (skip for processing)', gutil.colors.red(message));
          }
          // passing a null file to the callback stops a new image being added to the pipeline for this config
          return cb(null, null);
        }
        if (!options.silent){
          gutil.log(PLUGIN_NAME + ': (skip for enlargement)', gutil.colors.yellow(message));
        }
      }
    }

    try {
      if (config.extractBeforeResize) {
        extract = config.extractBeforeResize;
        image.extract(extract.top, extract.left, extract.width, extract.height);
      }

      image.resize(width, height);

      if (config.extractAfterResize) {
        extract = config.extractAfterResize;
        image.extract(extract.top, extract.left, extract.width, extract.height);
      }

      if (config.crop !== false) {
        image.crop(config.crop);
      }

      if (config.embed) {
        image.embed();
      }

      if (config.max) {
        image.max();
      }

      if (config.min) {
        image.min();
      }

      if (config.ignoreAspectRatio) {
        image.ignoreAspectRatio();
      }

      image.withoutEnlargement(config.withoutEnlargement);
      image.interpolateWith(config.interpolation);
      image.background(config.background);
      image.flatten(config.flatten);
      image.negate(config.negate);

      if (config.rotate !== false) {
        if (typeof config.rotate === 'boolean') {
          image.rotate();
        } else {
          image.rotate(config.rotate);
        }
      }

      image.flip(config.flip);
      image.flop(config.flop);
      image.blur(config.blur);

      if (typeof config.sharpen === 'boolean') {
        image.sharpen(config.sharpen);
      } else {
        image.sharpen(config.sharpen.sigma, config.sharpen.flat, config.sharpen.jagged);
      }

      image.threshold(config.threshold);

      if (config.gamma !== false) {
        if (typeof config.gamma === 'boolean') {
          image.gamma();
        } else {
          image.gamma(config.gamma);
        }
      }

      image.grayscale(config.grayscale);
      image.normalize(config.normalize);
      image.quality(config.quality);
      image.progressive(config.progressive);
      image.withMetadata(config.withMetadata);
      image.tile(config.tile);
      image.withoutChromaSubsampling(config.withoutChromaSubsampling);
      image.compressionLevel(config.compressionLevel);

      image.toFormat(toFormat);

    } catch (err) {
      err.message = errPrefix + err.message;
      return cb(new gutil.PluginError(PLUGIN_NAME, err, {showStack: true}));
    }

    image.toBuffer(function(err, buf) {
      if (err) {
        err.message = errPrefix + err.message;
        return cb(new gutil.PluginError(PLUGIN_NAME, err, {showStack: true}));
      }

      var newFile = new gutil.File({
        cwd: file.cwd,
        base: file.base,
        path: filePath,
        contents: buf
      });

      if (!options.silent){
        gutil.log(PLUGIN_NAME + ':', gutil.colors.green(file.relative + ' -> ' + newFile.relative));
      }

      cb(null, newFile);
    });
  });
};
<commit_msg>change interpolator usage<commit_after>'use strict';

var sharp = require('sharp');
var gutil = require('gulp-util');
var path = require('path');
var rename = require('rename');
var size = require('./size');
var format = require('./format');

var PLUGIN_NAME = require('../package.json').name;

module.exports = function(file, config, options, cb) {
  var errPrefix = 'File `' + file.relative + '`: ';
  var image = sharp(file.contents);

  image.metadata(function(err, metadata) {
    if (err) {
      return cb(new gutil.PluginError(PLUGIN_NAME, errPrefix + err.message));
    }

    var width, height, extract, toFormat;

    var filePath = file.path;
    if (config.rename) {
      filePath = path.join(file.base, rename(file.relative, config.rename));
    }

    if (config.format) {
      toFormat = config.format;
    } else {
      toFormat = format(filePath);
    }

    try {
      width = size(config.width, metadata.width);
      height = size(config.height, metadata.height);
    } catch  (err){
      return cb(new gutil.PluginError(PLUGIN_NAME, errPrefix + err.message));
    }

    if (width || height) {
      if (config.withoutEnlargement && (width > metadata.width || height > metadata.height)) {
        var message = errPrefix + 'Image enlargement is detected';
        if (width) {
          message += '\n  real width: ' + metadata.width + 'px, required width: ' + width + 'px';
        }
        if (height) {
          message += '\n  real height: ' + metadata.height + 'px, required height: ' + height + 'px';
        }
        if (options.errorOnEnlargement) {
          return cb(new gutil.PluginError(PLUGIN_NAME, message));
        } else if (config.skipOnEnlargement) {
          if (!options.silent){
            gutil.log(PLUGIN_NAME + ': (skip for processing)', gutil.colors.red(message));
          }
          // passing a null file to the callback stops a new image being added to the pipeline for this config
          return cb(null, null);
        }
        if (!options.silent){
          gutil.log(PLUGIN_NAME + ': (skip for enlargement)', gutil.colors.yellow(message));
        }
      }
    }

    try {
      if (config.extractBeforeResize) {
        extract = config.extractBeforeResize;
        image.extract(extract.top, extract.left, extract.width, extract.height);
      }

      image.resize(width, height, { interpolator: config.interpolation });

      if (config.extractAfterResize) {
        extract = config.extractAfterResize;
        image.extract(extract.top, extract.left, extract.width, extract.height);
      }

      if (config.crop !== false) {
        image.crop(config.crop);
      }

      if (config.embed) {
        image.embed();
      }

      if (config.max) {
        image.max();
      }

      if (config.min) {
        image.min();
      }

      if (config.ignoreAspectRatio) {
        image.ignoreAspectRatio();
      }

      image.withoutEnlargement(config.withoutEnlargement);
      image.background(config.background);
      image.flatten(config.flatten);
      image.negate(config.negate);

      if (config.rotate !== false) {
        if (typeof config.rotate === 'boolean') {
          image.rotate();
        } else {
          image.rotate(config.rotate);
        }
      }

      image.flip(config.flip);
      image.flop(config.flop);
      image.blur(config.blur);

      if (typeof config.sharpen === 'boolean') {
        image.sharpen(config.sharpen);
      } else {
        image.sharpen(config.sharpen.sigma, config.sharpen.flat, config.sharpen.jagged);
      }

      image.threshold(config.threshold);

      if (config.gamma !== false) {
        if (typeof config.gamma === 'boolean') {
          image.gamma();
        } else {
          image.gamma(config.gamma);
        }
      }

      image.grayscale(config.grayscale);
      image.normalize(config.normalize);
      image.quality(config.quality);
      image.progressive(config.progressive);
      image.withMetadata(config.withMetadata);
      image.tile(config.tile);
      image.withoutChromaSubsampling(config.withoutChromaSubsampling);
      image.compressionLevel(config.compressionLevel);

      image.toFormat(toFormat);

    } catch (err) {
      err.message = errPrefix + err.message;
      return cb(new gutil.PluginError(PLUGIN_NAME, err, {showStack: true}));
    }

    image.toBuffer(function(err, buf) {
      if (err) {
        err.message = errPrefix + err.message;
        return cb(new gutil.PluginError(PLUGIN_NAME, err, {showStack: true}));
      }

      var newFile = new gutil.File({
        cwd: file.cwd,
        base: file.base,
        path: filePath,
        contents: buf
      });

      if (!options.silent){
        gutil.log(PLUGIN_NAME + ':', gutil.colors.green(file.relative + ' -> ' + newFile.relative));
      }

      cb(null, newFile);
    });
  });
};
<|endoftext|>


<commit_before>const commander = require('commander'),
      Command   = commander.Command,
      fs        = require('fs');

function Commodore(name) {
  Command.call(this, name);
}

/**
 * Inherit from `Command.prototype`
 */
Commodore.prototype.__proto__ = Command.prototype;

module.exports = new Commodore();

/**
 * Mark a field as loadable.
 *
 * @param {String} optionName
 * @api public
 */
Commodore.prototype.loadable = function(optionName) {
  var option = this.optionFor(optionName);
  if (!option) {
    this.invalidLoadableOption(optionName);
  }

  option.loadable = true;
  option.description = option.description + " (loadable)";

  return this;
};

/**
 * Load options from a configuration file.
 *
 * @param {String} configPath
 * @api public
 */
Commodore.prototype.load = function(configPath) {
  var data;
  try {
    data = fs.readFileSync(configPath, 'utf8');
  } catch(e) {
    if (e.code === "ENOENT") {
      // config file does not exist.
      data = "{}";
    } else {
      throw e;
    }
  }

  try {
    this.loadedData = JSON.parse(data);
    this.configPath = configPath;
  } catch(e) {
    this.invalidJSON(configPath, String(e));
  }

  return this;
};

/**
 * Demand an option `optionName`.
 *
 * @param {String} optionName
 * @api public
 */

Commodore.prototype.demand = function(optionName) {
  var option = this.optionFor(optionName);
  if (!option) {
    this.invalidDemandedOption(optionName);
  }

  option.description = '[required] ' + option.description;
  option.demand = true;

  return this;
};

/**
 * Demand that the value of `optionName` be one of `choices`.
 *
 * @param {String} optionName
 * @param {Array} choices
 * @api public
 */

Commodore.prototype.oneof = function(optionName, choices) {
  var option = this.optionFor(optionName);
  if (!option) {
    this.invalidOneOfOption(optionName);
  }

  option.description = option.description + " [" + choices.join(", ") + "]";

  var self=this;
  this.on(optionName, function(val) {
    if (choices.indexOf(val) === -1) {
      self.invalidOneOfChoice(optionName, val, choices);
    }
  });
  return this;
};

Commodore.prototype.importLoadedData = function() {
  // copy loaded data to this.
  for (var optionName in this.loadedData) {
    var option = this.optionFor(optionName);
    if (option.loadable && !(optionName in this)) {
      this[optionName] = this.loadedData[optionName];
    }
  }
};

Commodore.prototype.checkDemanded = function() {
  // check required options.
  var self = this;
  this.options.forEach(function(option) {
    if (option.demand && !(option.name() in self)) {
      self.missingDemandedOption(option.flags);
    }
  });
};

Commodore.prototype.command = function(name, desc) {
  var args = name.split(/ +/);
  var cmd = new Commodore(args.shift());
  if (desc) cmd.description(desc);
  if (desc) this.executables = true;
  this.commands.push(cmd);
  cmd.parseExpectedArgs(args);
  cmd.parent = this;
  if (desc) return this;
  return cmd;
};

Commodore.prototype.parse = function(argv) {
  Command.prototype.parse.call(this, argv);

  this.importLoadedData();
  this.checkDemanded();

  return this;
};

Commodore.prototype.helpInformation = function() {
  var helpInfo = Command.prototype.helpInformation.call(this);

  if (this.description()) {
    helpInfo = "\n  Description: " + this.description() + "\n" + helpInfo;
  }

  if (this.configPath) {
    helpInfo += "\n  Config file: " + this.configPath + "\n\n";
  }

  return helpInfo;
};

/**
 * Return an option matching `arg` if any.
 *
 * @param {String} arg
 * @return {Option}
 * @api private
 */

Commodore.prototype.optionFor = function(arg) {
  if (/-/.test(arg)) {
    return Command.prototype.optionFor.call(this, arg);
  }

  // arg does not have a -, search both short and long codes.
  for (var i = 0, option; option = this.options[i]; ++i) {
    if (option.is("-" + arg) || option.is("--" + arg)) {
      return option;
    }
  }
};

/**
 * Invalid JSON in `config` file
 *
 * @param {String} configPath
 * @param {Error} err
 * @api private
 */

Commodore.prototype.invalidJSON = function(configPath, err) {
  console.error();
  console.error("  invalid JSON in %s", configPath);
  console.error(err);
  console.error();
  process.exit(1);
};

/**
 * Option `optionName` not defined, cannot be loadable.
 *
 * @param {optionName}
 * @api private
 */

Commodore.prototype.invalidLoadableOption = function(optionName) {
  console.error();
  console.error("  invalid loadable option `%s`", optionName);
  console.error();
  process.exit(1);
}

/**
 * Option `optionName` not defined, cannot be required.
 *
 * @param {optionName}
 * @api private
 */

Commodore.prototype.invalidDemandedOption = function(optionName) {
  console.error();
  console.error("  invalid required option `%s`", optionName);
  console.error();
  process.exit(1);
};

/**
 * Option `optionName` not entered.
 *
 * @param {optionName}
 * @api private
 */

Commodore.prototype.missingDemandedOption = function(optionName) {
  console.error();
  console.error("  option `%s` missing", optionName);
  console.error();
  process.exit(1);
};

/**
 * Option `optionName` not defined, cannot be required.
 *
 * @param {optionName}
 * @api private
 */

Commodore.prototype.invalidOneOfOption = function(optionName) {
  console.error();
  console.error("  invalid oneof option `%s`", optionName);
  console.error();
  process.exit(1);
};

/**
 * Invalid choice for option `optionName`
 *
 * @param {optionName}
 * @api private
 */

Commodore.prototype.invalidOneOfChoice = function(optionName, val, options) {
  console.error();
  console.error("  `%s` must be one of: %s", optionName, options.join(', '));
  console.error();
  process.exit(1);
};

<commit_msg>Add a generic displayErrorAndExit function to reduce the amount of error display code.<commit_after>const commander = require('commander'),
      Command   = commander.Command,
      fs        = require('fs');

function Commodore(name) {
  Command.call(this, name);
}

/**
 * Inherit from `Command.prototype`
 */
Commodore.prototype.__proto__ = Command.prototype;

module.exports = new Commodore();

/**
 * Mark a field as loadable.
 *
 * @param {String} optionName
 * @api public
 */
Commodore.prototype.loadable = function(optionName) {
  var option = this.optionFor(optionName);
  if (!option) {
    this.invalidLoadableOption(optionName);
  }

  option.loadable = true;
  option.description = option.description + " (loadable)";

  return this;
};

/**
 * Load options from a configuration file.
 *
 * @param {String} configPath
 * @api public
 */
Commodore.prototype.load = function(configPath) {
  var data;
  try {
    data = fs.readFileSync(configPath, 'utf8');
  } catch(e) {
    if (e.code === "ENOENT") {
      // config file does not exist.
      data = "{}";
    } else {
      throw e;
    }
  }

  try {
    this.loadedData = JSON.parse(data);
    this.configPath = configPath;
  } catch(e) {
    this.invalidJSON(configPath, String(e));
  }

  return this;
};

/**
 * Demand an option `optionName`.
 *
 * @param {String} optionName
 * @api public
 */

Commodore.prototype.demand = function(optionName) {
  var option = this.optionFor(optionName);
  if (!option) {
    this.invalidDemandedOption(optionName);
  }

  option.description = '[required] ' + option.description;
  option.demand = true;

  return this;
};

/**
 * Demand that the value of `optionName` be one of `choices`.
 *
 * @param {String} optionName
 * @param {Array} choices
 * @api public
 */

Commodore.prototype.oneof = function(optionName, choices) {
  var option = this.optionFor(optionName);
  if (!option) {
    this.invalidOneOfOption(optionName);
  }

  option.description = option.description + " [" + choices.join(", ") + "]";

  var self=this;
  this.on(optionName, function(val) {
    if (choices.indexOf(val) === -1) {
      self.invalidOneOfChoice(optionName, val, choices);
    }
  });
  return this;
};

Commodore.prototype.importLoadedData = function() {
  // copy loaded data to this.
  for (var optionName in this.loadedData) {
    var option = this.optionFor(optionName);
    if (option.loadable && !(optionName in this)) {
      this[optionName] = this.loadedData[optionName];
    }
  }
};

Commodore.prototype.checkDemanded = function() {
  // check required options.
  var self = this;
  this.options.forEach(function(option) {
    if (option.demand && !(option.name() in self)) {
      self.missingDemandedOption(option.flags);
    }
  });
};

Commodore.prototype.command = function(name, desc) {
  var args = name.split(/ +/);
  var cmd = new Commodore(args.shift());
  if (desc) cmd.description(desc);
  if (desc) this.executables = true;
  this.commands.push(cmd);
  cmd.parseExpectedArgs(args);
  cmd.parent = this;
  if (desc) return this;
  return cmd;
};

Commodore.prototype.parse = function(argv) {
  Command.prototype.parse.call(this, argv);

  this.importLoadedData();
  this.checkDemanded();

  return this;
};

Commodore.prototype.helpInformation = function() {
  var helpInfo = Command.prototype.helpInformation.call(this);

  if (this.description()) {
    helpInfo = "\n  Description: " + this.description() + "\n" + helpInfo;
  }

  if (this.configPath) {
    helpInfo += "\n  Config file: " + this.configPath + "\n\n";
  }

  return helpInfo;
};

/**
 * Return an option matching `arg` if any.
 *
 * @param {String} arg
 * @return {Option}
 * @api private
 */

Commodore.prototype.optionFor = function(arg) {
  if (/-/.test(arg)) {
    return Command.prototype.optionFor.call(this, arg);
  }

  // arg does not have a -, search both short and long codes.
  for (var i = 0, option; option = this.options[i]; ++i) {
    if (option.is("-" + arg) || option.is("--" + arg)) {
      return option;
    }
  }
};

/**
 * Invalid JSON in `config` file
 *
 * @param {String} configPath
 * @param {Error} err
 * @api private
 */

Commodore.prototype.invalidJSON = function(configPath, err) {
  displayErrorAndExit("  invalid JSON in %s", configPath, "\n", err);
};

/**
 * Option `optionName` not defined, cannot be loadable.
 *
 * @param {optionName}
 * @api private
 */

Commodore.prototype.invalidLoadableOption = function(optionName) {
  displayErrorAndExit("  invalid loadable option `%s`", optionName);
}

/**
 * Option `optionName` not defined, cannot be required.
 *
 * @param {optionName}
 * @api private
 */

Commodore.prototype.invalidDemandedOption = function(optionName) {
  displayErrorAndExit("  invalid required option `%s`", optionName);
};

/**
 * Option `optionName` not entered.
 *
 * @param {optionName}
 * @api private
 */

Commodore.prototype.missingDemandedOption = function(optionName) {
  this.outputHelp();
  displayErrorAndExit("  option `%s` missing", optionName);
};

/**
 * Option `optionName` not defined, cannot be required.
 *
 * @param {optionName}
 * @api private
 */

Commodore.prototype.invalidOneOfOption = function(optionName) {
  displayErrorAndExit("  invalid oneof option `%s`", optionName);
};

/**
 * Invalid choice for option `optionName`
 *
 * @param {optionName}
 * @api private
 */

Commodore.prototype.invalidOneOfChoice = function(optionName, val, options) {
  displayErrorAndExit("  `%s` must be one of: %s", optionName, options.join(', '));
};

function displayErrorAndExit() {
  var args = [].slice.call(arguments, 0);

  console.error();
  console.error.apply(console, args);
  console.error();
  process.exit(1);
}

<|endoftext|>


<commit_before>// node-xconf: xconf.js
// (c) 2013 by Matthias Lienau <matthias@mlienau.de>
// Freely distributable under the MIT license.

var _ = require('underscore')
  , fs = require('fs');

var XConf = {

  load: function() {

    // Parse args
    var arg
      , args = []
      , _i
      , _len
      , options = {
          useDefaultSection: true
      };

    for (_i = 0, _len = arguments.length; _i < _len; _i++) {
      arg = arguments[_i];

      switch (typeof arg) {

        case 'string':
          args.push(arg);
          break;

        case 'object':
          options = _.defaults(options,arg);
          break;
      }
    }

    // Read configuration and filter/aggregate desired sections

    var file
      , ext
      , section
      , fullconfig = null
      , defaults = {};

    // File is either found relatively to dir where calling script resided
    // or - in case of require() - relatively to this modules directory
    file = (args.length >= 1) ? args[ 0 ] : '../../config.json';

    // Default section name is node environment name or 'development' as standard fallback
    section = (args.length >= 2) ? args[ 1 ] : process.env.NODE_ENV || 'development';

    ext = file.substr(file.lastIndexOf('.') + 1);

    if (ext == 'js' || ext == 'json' || ext == '') {
      // "native" formats supported by require()
      fullconfig = require(file);
    } else {

      // other formats need file consumption first
      var fconts = fs.readFileSync(file,'utf8');

      switch (ext.toLowerCase()) {

        case 'json':
          fullconfig = JSON.parse(fconts);
          break;

        case 'yml':
        case 'yaml':
          fullconfig = require('yaml').eval(fconts);
          break;

        case 'ini':
          fullconfig = require('ini').parseString(fconts);
          break;

        default:
          break;
      }
    }

    if (fullconfig[ 'default' ] !== undefined && options.useDefaultSection) {
      defaults = fullconfig[ 'default' ];
    }

    return _.defaults(fullconfig[ section ],defaults);
  }
};

module.exports.load = exports.load = XConf.load;
<commit_msg>Cleanup.<commit_after>// node-xconf: xconf.js
// (c) 2013 by Matthias Lienau <matthias@mlienau.de>
// Freely distributable under the MIT license.

var _ = require('underscore')
  , fs = require('fs');

var XConf = {

  load: function() {

    // Parse args
    var arg
      , args = []
      , _i
      , _len
      , options = {
          useDefaultSection: true
      };

    for (_i = 0, _len = arguments.length; _i < _len; _i++) {
      arg = arguments[_i];

      switch (typeof arg) {

        case 'string':
          args.push(arg);
          break;

        case 'object':
          options = _.defaults(options,arg);
          break;
      }
    }

    // Read configuration and filter/aggregate desired sections
    var file
      , ext
      , section
      , fullconfig = null
      , defaults = {};

    // File is either found relatively to dir where calling script resided
    // or - in case of require() - relatively to this modules directory
    file = (args.length >= 1) ? args[ 0 ] : '../../config.json';

    // Default section name is node environment name or 'development' as standard fallback
    section = (args.length >= 2) ? args[ 1 ] : process.env.NODE_ENV || 'development';

    ext = file.substr(file.lastIndexOf('.') + 1);

    if (ext == 'js' || ext == 'json' || ext == '') {
      // "native" formats supported by require()
      fullconfig = require(file);
    } else {

      // other formats need file consumption first
      var fconts = fs.readFileSync(file,'utf8');

      switch (ext.toLowerCase()) {

        case 'json':
          fullconfig = JSON.parse(fconts);
          break;

        case 'yml':
        case 'yaml':
          fullconfig = require('yaml').eval(fconts);
          break;

        case 'ini':
          fullconfig = require('ini').parseString(fconts);
          break;

        default:
          break;
      }
    }

    if (fullconfig[ 'default' ] !== undefined && options.useDefaultSection) {
      defaults = fullconfig[ 'default' ];
    }

    return _.defaults(fullconfig[ section ],defaults);
  }
};

module.exports.load = exports.load = XConf.load;
<|endoftext|>


<commit_before>var orm = require('orm');
var queue = require('queue-async');
var LFU = require('lfu-cache');

module.exports = function(raja, opts, cb) {
	var store = new Store(raja, opts);
	orm.connect(opts.store, function(err, db) {
		if (err) return cb(err);
		store.init(db, cb);
	});
};

function Store(raja, opts) {
	this.raja = raja;
	this.lfu = new LFU(opts.cacheSize || 500, opts.cacheDecay || 60000);
	this.lfu.on('eviction', function(key, obj) {
		this.Resource.one(obj.url, function(err, res) {
			if (err) return raja.error(err);
			if (!res) res = new (this.Resource)();
			// alter obj since it is evicted anyway
			var resources = obj.resources;
			if (resources) delete obj.resources;
			var parents = obj.parents;
			if (parents) delete obj.parents;
			// delete obj.itime ? in general, delete keys not in schema ?
			res.save(obj, function(err) {
				if (err) return raja.error(err);
				var q = queue(2);
				if (resources) q.defer(saveResource.bind(this), res, resources, true);
				if (parents) q.defer(saveParents.bind(this), res, parents, false);
				q.awaitAll(function(err) {
					if (err) raja.error(err);
				});
			}.bind(this));
		}.bind(this));
	});
}

Store.prototype.init = function(db, cb) {
	var Resource = this.Resource = db.define('Resource', {
		url: { type: 'text', index: true },
		mtime: { type: 'date', time: true, index: true },
		maxage: { type: 'integer' },
		headers: { type: 'object' },
		valid: { type: 'boolean', defaultValue: true },
		data: { type: 'binary' },
		code: { type: 'integer', defaultValue: 200 }
	}, {
		table: "raja_cached_resources",
		cache: false,
		hooks: {
			beforeSave: beforeSaveResource
		},
	});
	Resource.hasMany("children", Resource, {}, {
		reverse : "parents",
		key: true
	});
	var store = this;
	Resource.drop(function(err) {
		if (err) console.error(err);
		Resource.sync(function(err) {
			cb(err, store);
		});
	});
};

function beforeSaveResource() {
	if (typeof this.data == "string") {
		this.data = new Buffer(this.data);
	}
	if (this.valid == null && this.data != null) {
		this.valid = true;
	} else if (this.valid != null && this.data == null) {
		this.valid = false;
	}
	if (!this.headers) this.headers = {};
	this.mtime = new Date();
}

Store.prototype.get = function(url, cb) {
	var lfuObj = this.lfu.get(url);
	if (lfuObj) {
		if (lfuObj.valid) return cb(null, lfuObj);
		else return cb();
	}
	this.Resource.one({url: url}, function(err, obj) {
		if (obj) {
			var lfuObj = this.raja.shallow(obj);
			queue(2)
			.defer(getRelations, obj, lfuObj, true)
			.defer(getRelations, obj, lfuObj, false)
			.awaitAll(function(err) {
				if (err) return cb(err);
				this.lfu.set(url, lfuObj);
				cb(err, lfuObj);
			}.bind(this));
		} else {
			cb(err, obj);
		}
	}.bind(this));
};

Store.prototype.del = function(url, cb) {
	this.lfu.remove(url);
	this.Resource.find({url: url}).remove(cb);
};

Store.prototype.invalidate = function(url, cb) {
	// what happens if it does not find any resource ?
	var lfuObj = this.lfu.get(url);
	if (lfuObj) {
		lfuObj.valid = false;
	}
	this.Resource.find({url: url}, function(err, rows) {
		if (err) return cb(err);
		if (rows.length > 1) return cb(new Error("invalidate expects only one resource at " + url));
		else if (rows.length == 0) return cb();
		rows[0].valid = false;
		rows[0].save(cb);
	});
};

Store.prototype.invalidateParents = function(msg, cb) {
	var raja = this.raja;
	var url = msg.parents.slice(-1).pop() || msg.url;
	var lfu = this.lfu;
	var lfuObj = lfu.get(url);
	var lfuParents = lfuObj && lfuObj.parents;
	var onlyCache = true;
	var sentMsg = {};
	if (lfuParents) for (var rurl in lfuParents) {
		var robj = lfu.get(rurl);
		if (robj) {
			robj.valid = false; // robj is a pointer to the object in lfu, no need to lfu.set
			var cmsg = raja.shallow(msg);
			cmsg.parents = msg.parents.slice();
			cmsg.parents.push(rurl);
			sentMsg[rurl] = true;
			raja.send(cmsg);
		} else {
			onlyCache = false;
		}
	} else {
		onlyCache = false;
		lfuParents = {};
	}

	if (onlyCache) return cb();

	this.Resource.find({url: url}, function(err, rows) {
		if (err) return cb(err);
		if (rows.length > 1) return cb(new Error("invalidateParents expects only one resource at " + url));
		else if (rows.length == 0) return cb();
		var res = rows[0];
		res.getParents().each(function(par) {
			if (sentMsg[par.url]) return; // already dealt with
			var lfuObj = lfu.get(par.url);
			if (lfuObj) lfuObj.valid = false;
			par.valid = false;
			var cmsg = raja.shallow(msg);
			cmsg.parents = msg.parents.slice();
			cmsg.parents.push(par.url);
			raja.send(cmsg);
		}).save(cb);
	});
};

Store.prototype.set = function(url, obj, cb) {
	if (!cb && typeof obj == "function") {
		cb = obj;
		obj = null;
	}
	if (!obj) obj = {};
	if (!obj.url) obj.url = url;
	var lfu = this.lfu;
	var lfuObj = lfu.get(url);
	// first remove previous associations
	if (obj.resources && lfuObj && lfuObj.resources) for (var rurl in lfuObj.resources) {
		var robj = lfu.get(rurl);
		if (robj && robj.parents) delete robj.parents[url];
	}
	lfuObj = this.raja.shallow(obj, lfuObj || {});
	// then add new associations
	if (obj.resources && lfuObj.resources) for (var rurl in lfuObj.resources) {
		var robj = lfu.get(rurl);
		if (!robj) {
			robj = {url: rurl};
			beforeSaveResource.call(robj);
			lfu.set(rurl, robj);
		}
		if (!robj.parents) {
			robj.parents = {};
		}
		robj.parents[url] = true;
	}
	beforeSaveResource.call(lfuObj);
	this.lfu.set(url, lfuObj);
	// this api should not be async
	cb(null, lfuObj);
};

function saveRelations(inst, hash, isChildren, cb) {
	var self = this;
	this.Resources.find({url: Object.keys(hash)}).run(function(err, rows) {
		if (err) return cb(err);
		var notfound = self.raja.shallow(hash);
		rows.forEach(function(row) {
			delete notfound[row.url];
		});
		var q = queue(3);
		for (var rurl in notfound) {
			q.defer(function(rurl, cb) {
				(new self.Resource({url: rurl})).save(cb);
			}, rurl);
		}
		q.awaitAll(function(err, savedRows) {
			var total = rows.concat(savedRows);
			if (isChildren) inst.setChildren(total, cb);
			else inst.setParents(total, cb);
		});
	});
}

function getRelations(inst, lfuObj, isChildren, cb) {
	var hash, method;
	if (isChildren) {
		hash = lfuObj.resources = {};
		method = obj.getChildren;
	} else {
		hash = lfuObj.parents = {};
		method = obj.getParents;
	}
	method.call(obj, function(err, rows) {
		if (err) return cb(err);
		rows.forEach(function(row) {
			hash[row.url] = true;
		});
		cb();
	});
}

<commit_msg>Use q here<commit_after>var orm = require('orm');
var queue = require('queue-async');
var LFU = require('lfu-cache');

module.exports = function(raja, opts, cb) {
	var store = new Store(raja, opts);
	orm.connect(opts.store, function(err, db) {
		if (err) return cb(err);
		store.init(db, cb);
	});
};

function Store(raja, opts) {
	this.raja = raja;
	this.lfu = new LFU(opts.cacheSize || 500, opts.cacheDecay || 60000);
	this.lfu.on('eviction', function(key, obj) {
		this.Resource.one(obj.url, function(err, res) {
			if (err) return raja.error(err);
			if (!res) res = new (this.Resource)();
			// alter obj since it is evicted anyway
			var resources = obj.resources;
			if (resources) delete obj.resources;
			var parents = obj.parents;
			if (parents) delete obj.parents;
			// delete obj.itime ? in general, delete keys not in schema ?
			res.save(obj, function(err) {
				if (err) return raja.error(err);
				var q = queue(2);
				if (resources) q.defer(saveResource.bind(this), res, resources, true);
				if (parents) q.defer(saveParents.bind(this), res, parents, false);
				q.awaitAll(function(err) {
					if (err) raja.error(err);
				});
			}.bind(this));
		}.bind(this));
	});
}

Store.prototype.init = function(db, cb) {
	var Resource = this.Resource = db.define('Resource', {
		url: { type: 'text', index: true },
		mtime: { type: 'date', time: true, index: true },
		maxage: { type: 'integer' },
		headers: { type: 'object' },
		valid: { type: 'boolean', defaultValue: true },
		data: { type: 'binary' },
		code: { type: 'integer', defaultValue: 200 }
	}, {
		table: "raja_cached_resources",
		cache: false,
		hooks: {
			beforeSave: beforeSaveResource
		},
	});

	Resource.hasMany("children", Resource, {}, {
		reverse : "parents",
		key: true
	});

	var store = this;

	queue(1)
	.defer(Resource.drop)
	.defer(Resource.sync)
	.awaitAll(function(err) {
		cb(err, store);
	});
};

function beforeSaveResource() {
	if (typeof this.data == "string") {
		this.data = new Buffer(this.data);
	}
	if (this.valid == null && this.data != null) {
		this.valid = true;
	} else if (this.valid != null && this.data == null) {
		this.valid = false;
	}
	if (!this.headers) this.headers = {};
	this.mtime = new Date();
}

Store.prototype.get = function(url, cb) {
	var lfuObj = this.lfu.get(url);
	if (lfuObj) {
		if (lfuObj.valid) return cb(null, lfuObj);
		else return cb();
	}
	this.Resource.one({url: url}, function(err, obj) {
		if (obj) {
			var lfuObj = this.raja.shallow(obj);
			queue(2)
			.defer(getRelations, obj, lfuObj, true)
			.defer(getRelations, obj, lfuObj, false)
			.awaitAll(function(err) {
				if (err) return cb(err);
				this.lfu.set(url, lfuObj);
				cb(err, lfuObj);
			}.bind(this));
		} else {
			cb(err, obj);
		}
	}.bind(this));
};

Store.prototype.del = function(url, cb) {
	this.lfu.remove(url);
	this.Resource.find({url: url}).remove(cb);
};

Store.prototype.invalidate = function(url, cb) {
	// what happens if it does not find any resource ?
	var lfuObj = this.lfu.get(url);
	if (lfuObj) {
		lfuObj.valid = false;
	}
	this.Resource.find({url: url}, function(err, rows) {
		if (err) return cb(err);
		if (rows.length > 1) return cb(new Error("invalidate expects only one resource at " + url));
		else if (rows.length == 0) return cb();
		rows[0].valid = false;
		rows[0].save(cb);
	});
};

Store.prototype.invalidateParents = function(msg, cb) {
	var raja = this.raja;
	var url = msg.parents.slice(-1).pop() || msg.url;
	var lfu = this.lfu;
	var lfuObj = lfu.get(url);
	var lfuParents = lfuObj && lfuObj.parents;
	var onlyCache = true;
	var sentMsg = {};
	if (lfuParents) for (var rurl in lfuParents) {
		var robj = lfu.get(rurl);
		if (robj) {
			robj.valid = false; // robj is a pointer to the object in lfu, no need to lfu.set
			var cmsg = raja.shallow(msg);
			cmsg.parents = msg.parents.slice();
			cmsg.parents.push(rurl);
			sentMsg[rurl] = true;
			raja.send(cmsg);
		} else {
			onlyCache = false;
		}
	} else {
		onlyCache = false;
		lfuParents = {};
	}

	if (onlyCache) return cb();

	this.Resource.find({url: url}, function(err, rows) {
		if (err) return cb(err);
		if (rows.length > 1) return cb(new Error("invalidateParents expects only one resource at " + url));
		else if (rows.length == 0) return cb();
		var res = rows[0];
		res.getParents().each(function(par) {
			if (sentMsg[par.url]) return; // already dealt with
			var lfuObj = lfu.get(par.url);
			if (lfuObj) lfuObj.valid = false;
			par.valid = false;
			var cmsg = raja.shallow(msg);
			cmsg.parents = msg.parents.slice();
			cmsg.parents.push(par.url);
			raja.send(cmsg);
		}).save(cb);
	});
};

Store.prototype.set = function(url, obj, cb) {
	if (!cb && typeof obj == "function") {
		cb = obj;
		obj = null;
	}
	if (!obj) obj = {};
	if (!obj.url) obj.url = url;
	var lfu = this.lfu;
	var lfuObj = lfu.get(url);
	// first remove previous associations
	if (obj.resources && lfuObj && lfuObj.resources) for (var rurl in lfuObj.resources) {
		var robj = lfu.get(rurl);
		if (robj && robj.parents) delete robj.parents[url];
	}
	lfuObj = this.raja.shallow(obj, lfuObj || {});
	// then add new associations
	if (obj.resources && lfuObj.resources) for (var rurl in lfuObj.resources) {
		var robj = lfu.get(rurl);
		if (!robj) {
			robj = {url: rurl};
			beforeSaveResource.call(robj);
			lfu.set(rurl, robj);
		}
		if (!robj.parents) {
			robj.parents = {};
		}
		robj.parents[url] = true;
	}
	beforeSaveResource.call(lfuObj);
	this.lfu.set(url, lfuObj);
	// this api should not be async
	cb(null, lfuObj);
};

function saveRelations(inst, hash, isChildren, cb) {
	var self = this;
	this.Resources.find({url: Object.keys(hash)}).run(function(err, rows) {
		if (err) return cb(err);
		var notfound = self.raja.shallow(hash);
		rows.forEach(function(row) {
			delete notfound[row.url];
		});
		var q = queue(3);
		for (var rurl in notfound) {
			q.defer(function(rurl, cb) {
				(new self.Resource({url: rurl})).save(cb);
			}, rurl);
		}
		q.awaitAll(function(err, savedRows) {
			var total = rows.concat(savedRows);
			if (isChildren) inst.setChildren(total, cb);
			else inst.setParents(total, cb);
		});
	});
}

function getRelations(inst, lfuObj, isChildren, cb) {
	var hash, method;
	if (isChildren) {
		hash = lfuObj.resources = {};
		method = obj.getChildren;
	} else {
		hash = lfuObj.parents = {};
		method = obj.getParents;
	}
	method.call(obj, function(err, rows) {
		if (err) return cb(err);
		rows.forEach(function(row) {
			hash[row.url] = true;
		});
		cb();
	});
}

<|endoftext|>


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

module.exports = function(teoria) {
  var Pitch = teoria.Pitch;
  var Chord = teoria.Chord;
  var Scale = teoria.Scale;

  Pitch.prototype.chord = function(chord) {
    chord = (chord in knowledge.chordShort) ? knowledge.chordShort[chord] : chord;

    return new Chord(this, chord);
  }

  Pitch.prototype.scale = function(scale) {
    return new Scale(this, scale);
  }
}
<commit_msg>Number.semitones, Number.octaves<commit_after>var knowledge = require('./knowledge');

module.exports = function(teoria) {
  var Pitch = teoria.Pitch;
  var Chord = teoria.Chord;
  var Scale = teoria.Scale;

  Pitch.prototype.chord = function(chord) {
    chord = (chord in knowledge.chordShort) ? knowledge.chordShort[chord] : chord;

    return new Chord(this, chord);
  }

  Pitch.prototype.scale = function(scale) {
    return new Scale(this, scale);
  }
}

// NB: for these to work in the node REPL, it must be started with {useGlobal: true}

Object.defineProperty(Number.prototype, 'semitones', {
  get: function() { return [0, this.valueOf()]; },
  enumerable: false,
  configurable: false
});

Object.defineProperty(Number.prototype, 'octaves', {
  get: function() { return [7 * this.valueOf(), 12 * this.valueOf()]; },
  enumerable: false,
  configurable: false
});
<|endoftext|>


<commit_before>var mysql = require('mysql'),
    when = require('when');

function getMysqlConnection(key, pool) {
    var d = when.defer();
    pool.getConnection(function(err, connection) {
        //TODO store the connections by key
        //TODO what to do if connection aborded ??? we need to release some how ???
        //TODO This should be probably done at the appending to the request

        if (err) {
            d.reject(err);
        }
        if (!connection) {
            d.reject("no connection received");
        }
        //TODO this should not happen we need to test this at the assigning
        //     and release if connection is closed (request is finished)

        d.resolve({
            key: key,
            connection: connection
        });
    });

    return d.promise;
}

function setup(options) {

    var pools = [];

    for (var key in options.dbs) {
        if (options.dbs.hasOwnProperty(key)) {

            //TODO check the engine !!!!!
            pools.push({
                key: key,
                pool: mysql.createPool(options.dbs[key]),
                cb: getMysqlConnection
            });
        }
    }

    function getConnections() {
        var connections = [];

        pools.forEach(function(pool) {
            connections.push(pool.cb(pool.key, pool.pool));
        });

        return when.all(connections);
    }

    function releaseDbs() {
        if (this._dbs) {
            for (var key in this._dbs) {
                if (this._dbs.hasOwnProperty(key)) {
                    this._dbs[key].release();
                }
            }
            this._dbs = undefined;
        }
    }

    function db(key) {
        return this._dbs[key];
    }

    return function(req, res, next) {
        var end = res.end;

        when(getConnections()).then(function(dbs) {
            req._dbs = {};

            //TODO check if request is alive and response was not send !!!!
            dbs.forEach(function(value) {
                req._dbs[value.key] = value.connection;
            });
            next();

        }, function() {
            next(new Error("connections could not be opened"));
        });

        req.db = db;

        res.on("close", function() {
            releaseDbs.call(req);
        });

        res.end = function(chunk, encoding) {
            releaseDbs.call(req);
            end.apply(res, arguments);
        };

    };
}<commit_msg>added export for setup<commit_after>var mysql = require('mysql'),
    when = require('when');

function getMysqlConnection(key, pool) {
    var d = when.defer();
    pool.getConnection(function(err, connection) {
        //TODO store the connections by key
        //TODO what to do if connection aborded ??? we need to release some how ???
        //TODO This should be probably done at the appending to the request

        if (err) {
            d.reject(err);
        }
        if (!connection) {
            d.reject("no connection received");
        }
        //TODO this should not happen we need to test this at the assigning
        //     and release if connection is closed (request is finished)

        d.resolve({
            key: key,
            connection: connection
        });
    });

    return d.promise;
}

function setup(options) {

    var pools = [];

    for (var key in options.dbs) {
        if (options.dbs.hasOwnProperty(key)) {

            //TODO check the engine !!!!!
            pools.push({
                key: key,
                pool: mysql.createPool(options.dbs[key]),
                cb: getMysqlConnection
            });
        }
    }

    function getConnections() {
        var connections = [];

        pools.forEach(function(pool) {
            connections.push(pool.cb(pool.key, pool.pool));
        });

        return when.all(connections);
    }

    function releaseDbs() {
        if (this._dbs) {
            for (var key in this._dbs) {
                if (this._dbs.hasOwnProperty(key)) {
                    this._dbs[key].release();
                }
            }
            this._dbs = undefined;
        }
    }

    function db(key) {
        return this._dbs[key];
    }

    return function(req, res, next) {
        var end = res.end;

        when(getConnections()).then(function(dbs) {
            req._dbs = {};

            //TODO check if request is alive and response was not send !!!!
            dbs.forEach(function(value) {
                req._dbs[value.key] = value.connection;
            });
            next();

        }, function() {
            next(new Error("connections could not be opened"));
        });

        req.db = db;

        res.on("close", function() {
            releaseDbs.call(req);
        });

        res.end = function(chunk, encoding) {
            releaseDbs.call(req);
            end.apply(res, arguments);
        };

    };
}

exports.setup = setup;<|endoftext|>