<commit_before>"use strict";

var Point = require("./point");

module.exports = Point3;
function Point3(x, y, z) {
    this.x = x;
    this.y = y;
    this.z = z;
}

Point3.prototype = Object.create(Point.prototype);
Point3.prototype.constructor = Point3;

Point3.zero = new Point3();
Point3.one = new Point3(1, 1, 1);

Point3.prototype.addThis = function (that) {
    this.x = this.x + that.x;
    this.y = this.y + that.y;
    this.z = this.z + that.z;
    return this;
};

Point3.prototype.subThis = function (that) {
    this.x = this.x - that.x;
    this.y = this.y - that.y;
    this.z = this.z - that.z;
    return this;
};

Point3.prototype.mulThis = function (that) {
    this.x = this.x * that.x;
    this.y = this.y * that.y;
    this.z = this.z * that.z;
    return this;
};

Point3.prototype.scaleThis = function (n) {
    this.x = this.x * n;
    this.y = this.y * n;
    this.z = this.z * n;
    return this;
};

Point2.prototype.bitwiseAndThis = function (n) {
    this.x = this.x & n;
    this.y = this.y & n;
    this.z = this.z & n;
    return this;
};

Point2.prototype.bitwiseOrThis = function (n) {
    this.x = this.x | n;
    this.y = this.y | n;
    this.z = this.z | n;
    return this;
};

Point3.prototype.roundThis = function () {
    this.x = Math.round(this.x);
    this.y = Math.round(this.y);
    this.z = Math.round(this.z);
};

Point3.prototype.floorThis = function () {
    this.x = Math.floor(this.x);
    this.y = Math.floor(this.y);
    this.z = Math.floor(this.z);
};

Point3.prototype.ceilThis = function () {
    this.x = Math.ceil(this.x);
    this.y = Math.ceil(this.y);
    this.z = Math.ceil(this.z);
};

Point3.prototype.absThis = function () {
    this.x = Math.abs(this.x);
    this.y = Math.abs(this.y);
    this.z = Math.abs(this.z);
};

Point2.prototype.minThis = function (that) {
    this.x = Math.min(this.x, that.x);
    this.y = Math.min(this.y, that.y);
    this.z = Math.min(this.z, that.z);
};

Point2.prototype.maxThis = function (that) {
    this.x = Math.max(this.x, that.x);
    this.y = Math.max(this.y, that.y);
    this.z = Math.max(this.z, that.z);
};

Point3.prototype.clone = function () {
    return new Point3(this.x, this.y, this.z);
};

Point3.prototype.copyFrom = function (that) {
    this.x = that.x;
    this.y = that.y;
    this.z = that.z;
    return this;
};

// TODO deprecated for copyFrom
Point3.prototype.become = function (that) {
    this.x = that.x;
    this.y = that.y;
    this.z = that.z;
    return this;
};

Point3.prototype.copyFromXY = function (that) {
    this.x = that.x;
    this.y = that.y;
    return this;
};

// TODO deprecated for copyFromXY
Point3.prototype.becomeXY = function (that) {
    this.x = that.x;
    this.y = that.y;
    return this;
};

Point3.prototype.toString = function () {
    return "[x=" + this.x + " y=" + this.y + " z=" + this.z + "]";
};

Point3.prototype.hash = function () {
    return this.x + "," + this.y + "," + this.z;
};

Point3.prototype.equals = function (that) {
    return this.x === that.x && this.y === that.y && this.z === that.z;
};

<commit_msg>Fix glaring point3 bugs<commit_after>"use strict";

var Point = require("./point");

module.exports = Point3;
function Point3(x, y, z) {
    this.x = x;
    this.y = y;
    this.z = z;
}

Point3.prototype = Object.create(Point.prototype);
Point3.prototype.constructor = Point3;

Point3.zero = new Point3();
Point3.one = new Point3(1, 1, 1);

Point3.prototype.addThis = function (that) {
    this.x = this.x + that.x;
    this.y = this.y + that.y;
    this.z = this.z + that.z;
    return this;
};

Point3.prototype.subThis = function (that) {
    this.x = this.x - that.x;
    this.y = this.y - that.y;
    this.z = this.z - that.z;
    return this;
};

Point3.prototype.mulThis = function (that) {
    this.x = this.x * that.x;
    this.y = this.y * that.y;
    this.z = this.z * that.z;
    return this;
};

Point3.prototype.scaleThis = function (n) {
    this.x = this.x * n;
    this.y = this.y * n;
    this.z = this.z * n;
    return this;
};

Point3.prototype.bitwiseAndThis = function (n) {
    this.x = this.x & n;
    this.y = this.y & n;
    this.z = this.z & n;
    return this;
};

Point3.prototype.bitwiseOrThis = function (n) {
    this.x = this.x | n;
    this.y = this.y | n;
    this.z = this.z | n;
    return this;
};

Point3.prototype.roundThis = function () {
    this.x = Math.round(this.x);
    this.y = Math.round(this.y);
    this.z = Math.round(this.z);
};

Point3.prototype.floorThis = function () {
    this.x = Math.floor(this.x);
    this.y = Math.floor(this.y);
    this.z = Math.floor(this.z);
};

Point3.prototype.ceilThis = function () {
    this.x = Math.ceil(this.x);
    this.y = Math.ceil(this.y);
    this.z = Math.ceil(this.z);
};

Point3.prototype.absThis = function () {
    this.x = Math.abs(this.x);
    this.y = Math.abs(this.y);
    this.z = Math.abs(this.z);
};

Point3.prototype.minThis = function (that) {
    this.x = Math.min(this.x, that.x);
    this.y = Math.min(this.y, that.y);
    this.z = Math.min(this.z, that.z);
};

Point3.prototype.maxThis = function (that) {
    this.x = Math.max(this.x, that.x);
    this.y = Math.max(this.y, that.y);
    this.z = Math.max(this.z, that.z);
};

Point3.prototype.clone = function () {
    return new Point3(this.x, this.y, this.z);
};

Point3.prototype.copyFrom = function (that) {
    this.x = that.x;
    this.y = that.y;
    this.z = that.z;
    return this;
};

// TODO deprecated for copyFrom
Point3.prototype.become = function (that) {
    this.x = that.x;
    this.y = that.y;
    this.z = that.z;
    return this;
};

Point3.prototype.copyFromXY = function (that) {
    this.x = that.x;
    this.y = that.y;
    return this;
};

// TODO deprecated for copyFromXY
Point3.prototype.becomeXY = function (that) {
    this.x = that.x;
    this.y = that.y;
    return this;
};

Point3.prototype.toString = function () {
    return "[x=" + this.x + " y=" + this.y + " z=" + this.z + "]";
};

Point3.prototype.hash = function () {
    return this.x + "," + this.y + "," + this.z;
};

Point3.prototype.equals = function (that) {
    return this.x === that.x && this.y === that.y && this.z === that.z;
};

<|endoftext|>


<commit_before>// dialects/http.js
// Provide service endpoints for pushing to services in qb

// builtin
var url = require('url');

// vendor
var _ = require('underscore'),
  express = require('express'),
  request = require('request');

module.exports = {
  name: 'http',
  type: 'rpc',
  startup: startup,
}

function HttpDialect(qb, options) {
  this.qb = qb;
  this.options = options;
  this.auth = options.auth;
  this.retry = options.retry === undefined ? 0 : options.retry * 1;
  this.types = {};
  this.app = create_app(qb, options, this.types);
  this.ended = false;

  if (!options.app && options.port) {
    qb.log.info('Starting http qb api server at :%d%s', options.port, options.base||'')
    this.server = this.app.listen(options.port)
  } else {
    qb.log.info('http qb api server not started but ready to go at %s', options.base||'')
  }
}

HttpDialect.prototype.can = function() {
  var newtypes = Array.prototype.slice.call(arguments),
    types = this.types;

  _.each(newtypes, function (type) {
    types[type] = true;
  });
}

HttpDialect.prototype.push = function (endpoint, type, task, callback) {
  if (this.ended)
    return callback(new Error('qb ended'))
  make_request(endpoint, type, task, this.retry, this.auth, callback);
}

HttpDialect.prototype.end = function (cb) {
  this.ended = true;
  if (this.server) {
    this.server.close(cb)
  }
  else
    cb();
}

function startup(qb, options) {
  return new HttpDialect(qb, options);
}

function create_app(qb, options, types) {
  var base = options.base || '',
    app = options.app || express()
      .use(logger(qb))
      .use(express.query())
      .use(express.json())
      .use(express.urlencoded()),
    hasApp = Boolean(options.app);

  if (options.auth) {
    qb.log.info('Using basic auth in http.')
    app.use(base, express.basicAuth(options.auth.user, options.auth.pass));
  }

  app
    .use(base + '/test', testEndpoint)
    .use(base, getTypeCallback(base, types))
    .use(base, pushEndpoint(qb));

  if (qb._options.allow_defer) {
    app.use(base, deleteEndpoint(qb));
  }

  app.use(base, error404);

  return app
}

function make_request(endpoint, type, task, nretries, auth, callback) {
  // Here's a good way to do
  request({
    method: 'POST',
    uri: endpoint + '/' + type,
    json: task,
    auth: auth
  }, function (err, resp) {
    if (err && nretries > 0) {
      return make_request(endpoint, type, task, nretries - 1, callback);
    } else if (!resp || resp.statusCode !== 200) {
      err = new Error(JSON.stringify(resp ? resp.body : 'no response'));
    }
    callback(err, resp);
  });
}

function verifyBaseUrl(base) {
  return function (req, res, next) {
    // Set the base url
    if (req.path.slice(0, base.length) === base) {
      return next();
    }
    res.send(404, {error: 'all routes begin with ' + base});
  }
}

// Figures out if this is an available path
function getTypeCallback(base, types) {

  return function (req, res, next) {
    var regex = new RegExp('^/(' + Object.keys(types).join('|') + ')(?:/(.*))?$')

    var m = req.url.match(regex)
      , type = m && m[1]

    if (!type) {
      return res.send(404, {error: 'url not understood'})
    } else if (!types[type]) {
      return res.send(404, {error: 'this service cannot perform tasks of type ' + type});
    }

    req.type = type
    req.rest = m && m[2]
    next()
  }
}

function pushEndpoint(qb) {
  return function (req, res, next) {
    if (req.method !== 'POST') {
      return next()
    }

    var type = req.type
      , body = _.isArray(req.body) ? req.body : [req.body];

    _.each(body, function (task) {
      qb.push(type, task, function (err) {
        if (err) {
          res.send(500, {error: err.message, stack: err.stack});
        } else {
          res.send({ok:true, type:type});
        }
      });
    })
  }
}

function deleteEndpoint(qb) {
  return function (req, res, next) {
    if (req.method !== 'DELETE') {
      return next()
    }

    var type = req.type
      , id = req.rest;

    qb.queue(type).undefer_remove(id, function (err) {
      if (err) {
        res.send(500, {error: err.message, stack: err.stack});
      } else {
        res.send({ok:true, type:type});
      }
    });
  }
}

function testEndpoint(req, res) {
  res.send(200)
}

function error404(req, res) {
  res.send(404, {error: 'not found'})
}

function logger(qb) {
  return function (req, res, next) {
    req._startTime = new Date()
    var url = req.url
    var end = res.end
    res.end = function () {
      res.end = end
      res.end.apply(res, arguments)

      log()
    }

    function log() {
      out = []
      out.push('[' + new Date().toString() + ']')
      out.push(res.statusCode)
      out.push(req.method.toUpperCase())
      out.push(url)
      out.push('(' + (new Date() - req._startTime))
      out.push('ms)')
      qb.log.debug(out.join(' '))
    }
    next()
  }
}<commit_msg>Fix bug where option wasn't gotten from pfrom proper place<commit_after>// dialects/http.js
// Provide service endpoints for pushing to services in qb

// builtin
var url = require('url');

// vendor
var _ = require('underscore'),
  express = require('express'),
  request = require('request');

module.exports = {
  name: 'http',
  type: 'rpc',
  startup: startup,
}

function HttpDialect(qb, options) {
  this.qb = qb;
  this.options = options;
  this.auth = options.auth;
  this.retry = options.retry === undefined ? 0 : options.retry * 1;
  this.types = {};
  this.app = create_app(qb, options, this.types);
  this.ended = false;

  if (!options.app && options.port) {
    qb.log.info('Starting http qb api server at :%d%s', options.port, options.base||'')
    this.server = this.app.listen(options.port)
  } else {
    qb.log.info('http qb api server not started but ready to go at %s', options.base||'')
  }
}

HttpDialect.prototype.can = function() {
  var newtypes = Array.prototype.slice.call(arguments),
    types = this.types;

  _.each(newtypes, function (type) {
    types[type] = true;
  });
}

HttpDialect.prototype.push = function (endpoint, type, task, callback) {
  if (this.ended)
    return callback(new Error('qb ended'))
  make_request(endpoint, type, task, this.retry, this.auth, callback);
}

HttpDialect.prototype.end = function (cb) {
  this.ended = true;
  if (this.server) {
    this.server.close(cb)
  }
  else
    cb();
}

function startup(qb, options) {
  return new HttpDialect(qb, options);
}

function create_app(qb, options, types) {
  var base = options.base || '',
    app = options.app || express()
      .use(logger(qb))
      .use(express.query())
      .use(express.json())
      .use(express.urlencoded()),
    hasApp = Boolean(options.app);

  if (options.auth) {
    qb.log.info('Using basic auth in http.')
    app.use(base, express.basicAuth(options.auth.user, options.auth.pass));
  }

  app
    .use(base + '/test', testEndpoint)
    .use(base, getTypeCallback(base, types))
    .use(base, pushEndpoint(qb));

  if (options.allow_defer) {
    app.use(base, deleteEndpoint(qb));
  }

  app.use(base, error404);

  return app
}

function make_request(endpoint, type, task, nretries, auth, callback) {
  // Here's a good way to do
  request({
    method: 'POST',
    uri: endpoint + '/' + type,
    json: task,
    auth: auth
  }, function (err, resp) {
    if (err && nretries > 0) {
      return make_request(endpoint, type, task, nretries - 1, callback);
    } else if (!resp || resp.statusCode !== 200) {
      err = new Error(JSON.stringify(resp ? resp.body : 'no response'));
    }
    callback(err, resp);
  });
}

function verifyBaseUrl(base) {
  return function (req, res, next) {
    // Set the base url
    if (req.path.slice(0, base.length) === base) {
      return next();
    }
    res.send(404, {error: 'all routes begin with ' + base});
  }
}

// Figures out if this is an available path
function getTypeCallback(base, types) {

  return function (req, res, next) {
    var regex = new RegExp('^/(' + Object.keys(types).join('|') + ')(?:/(.*))?$')

    var m = req.url.match(regex)
      , type = m && m[1]

    if (!type) {
      return res.send(404, {error: 'url not understood'})
    } else if (!types[type]) {
      return res.send(404, {error: 'this service cannot perform tasks of type ' + type});
    }

    req.type = type
    req.rest = m && m[2]
    next()
  }
}

function pushEndpoint(qb) {
  return function (req, res, next) {
    if (req.method !== 'POST') {
      return next()
    }

    var type = req.type
      , body = _.isArray(req.body) ? req.body : [req.body];

    _.each(body, function (task) {
      qb.push(type, task, function (err) {
        if (err) {
          res.send(500, {error: err.message, stack: err.stack});
        } else {
          res.send({ok:true, type:type});
        }
      });
    })
  }
}

function deleteEndpoint(qb) {
  return function (req, res, next) {
    if (req.method !== 'DELETE') {
      return next()
    }

    var type = req.type
      , id = req.rest;

    qb.queue(type).undefer_remove(id, function (err) {
      if (err) {
        res.send(500, {error: err.message, stack: err.stack});
      } else {
        res.send({ok:true, type:type});
      }
    });
  }
}

function testEndpoint(req, res) {
  res.send(200)
}

function error404(req, res) {
  res.send(404, {error: 'not found'})
}

function logger(qb) {
  return function (req, res, next) {
    req._startTime = new Date()
    var url = req.url
    var end = res.end
    res.end = function () {
      res.end = end
      res.end.apply(res, arguments)

      log()
    }

    function log() {
      out = []
      out.push('[' + new Date().toString() + ']')
      out.push(res.statusCode)
      out.push(req.method.toUpperCase())
      out.push(url)
      out.push('(' + (new Date() - req._startTime))
      out.push('ms)')
      qb.log.debug(out.join(' '))
    }
    next()
  }
}<|endoftext|>


<commit_before>var BigNumber = require('bignumber.js');
/*
    json_parse.js
    2012-06-20

    Public Domain.

    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.

    This file creates a json_parse function.
    During create you can (optionally) specify some behavioural switches

        require('json-bigint')(options)

            The optional options parameter holds switches that drive certain
            aspects of the parsing process:
            * options.strict = true will warn about duplicate-key usage in the json.
              The default (strict = false) will silently ignore those and overwrite
              values for keys that are in duplicate use.

    The resulting function follows this signature:
        json_parse(text, reviver)
            This method parses a JSON text to produce an object or array.
            It can throw a SyntaxError exception.

            The optional reviver parameter is a function that can filter and
            transform the results. It receives each of the keys and values,
            and its return value is used instead of the original value.
            If it returns what it received, then the structure is not modified.
            If it returns undefined then the member is deleted.

            Example:

            // Parse the text. Values that look like ISO date strings will
            // be converted to Date objects.

            myData = json_parse(text, function (key, value) {
                var a;
                if (typeof value === 'string') {
                    a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
                    if (a) {
                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
                            +a[5], +a[6]));
                    }
                }
                return value;
            });

    This is a reference implementation. You are free to copy, modify, or
    redistribute.

    This code should be minified before deployment.
    See http://javascript.crockford.com/jsmin.html

    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
    NOT CONTROL.
*/

/*members "", "\"", "\/", "\\", at, b, call, charAt, f, fromCharCode,
    hasOwnProperty, message, n, name, prototype, push, r, t, text
*/

var json_parse = function (options) {
    "use strict";

// This is a function that can parse a JSON text, producing a JavaScript
// data structure. It is a simple, recursive descent parser. It does not use
// eval or regular expressions, so it can be used as a model for implementing
// a JSON parser in other languages.

// We are defining the function inside of another function to avoid creating
// global variables.

// Default options one can override by passing options to the parse()
    var _options = {
        "strict": false  // not being strict means do not generate syntax errors for "duplicate key"
    };

// If there are options, then use them to override the default _options
    if (options !== undefined && options !== null) {
        if (options.strict === true) {
            _options.strict = true;
        }
    }

    var at,     // The index of the current character
        ch,     // The current character
        escapee = {
            '"':  '"',
            '\\': '\\',
            '/':  '/',
            b:    '\b',
            f:    '\f',
            n:    '\n',
            r:    '\r',
            t:    '\t'
        },
        text,

        error = function (m) {

// Call error when something is wrong.

            throw {
                name:    'SyntaxError',
                message: m,
                at:      at,
                text:    text
            };
        },

        next = function (c) {

// If a c parameter is provided, verify that it matches the current character.

            if (c && c !== ch) {
                error("Expected '" + c + "' instead of '" + ch + "'");
            }

// Get the next character. When there are no more characters,
// return the empty string.

            ch = text.charAt(at);
            at += 1;
            return ch;
        },

        number = function () {
// Parse a number value.

            var number,
                string = '';

            if (ch === '-') {
                string = '-';
                next('-');
            }
            while (ch >= '0' && ch <= '9') {
                string += ch;
                next();
            }
            if (ch === '.') {
                string += '.';
                while (next() && ch >= '0' && ch <= '9') {
                    string += ch;
                }
            }
            if (ch === 'e' || ch === 'E') {
                string += ch;
                next();
                if (ch === '-' || ch === '+') {
                    string += ch;
                    next();
                }
                while (ch >= '0' && ch <= '9') {
                    string += ch;
                    next();
                }
            }
            number = +string;
            if (!isFinite(number)) {
                error("Bad number");
            } else {
                //if (number > 9007199254740992 || number < -9007199254740992)
                // Bignumber has stricter check: everything with length > 15 digits disallowed
                if (string.length > 15)
                   return new BigNumber(string);
                return number;
            }
        },

        string = function () {

// Parse a string value.

            var hex,
                i,
                string = '',
                uffff;

// When parsing for string values, we must look for " and \ characters.

            if (ch === '"') {
                while (next()) {
                    if (ch === '"') {
                        next();
                        return string;
                    }
                    if (ch === '\\') {
                        next();
                        if (ch === 'u') {
                            uffff = 0;
                            for (i = 0; i < 4; i += 1) {
                                hex = parseInt(next(), 16);
                                if (!isFinite(hex)) {
                                    break;
                                }
                                uffff = uffff * 16 + hex;
                            }
                            string += String.fromCharCode(uffff);
                        } else if (typeof escapee[ch] === 'string') {
                            string += escapee[ch];
                        } else {
                            break;
                        }
                    } else {
                        string += ch;
                    }
                }
            }
            error("Bad string");
        },

        white = function () {

// Skip whitespace.

            while (ch && ch <= ' ') {
                next();
            }
        },

        word = function () {

// true, false, or null.

            switch (ch) {
            case 't':
                next('t');
                next('r');
                next('u');
                next('e');
                return true;
            case 'f':
                next('f');
                next('a');
                next('l');
                next('s');
                next('e');
                return false;
            case 'n':
                next('n');
                next('u');
                next('l');
                next('l');
                return null;
            }
            error("Unexpected '" + ch + "'");
        },

        value,  // Place holder for the value function.

        array = function () {

// Parse an array value.

            var array = [];

            if (ch === '[') {
                next('[');
                white();
                if (ch === ']') {
                    next(']');
                    return array;   // empty array
                }
                while (ch) {
                    array.push(value());
                    white();
                    if (ch === ']') {
                        next(']');
                        return array;
                    }
                    next(',');
                    white();
                }
            }
            error("Bad array");
        },

        object = function () {

// Parse an object value.

            var key,
                object = {};

            if (ch === '{') {
                next('{');
                white();
                if (ch === '}') {
                    next('}');
                    return object;   // empty object
                }
                while (ch) {
                    key = string();
                    white();
                    next(':');
                    if (_options.strict === true && Object.hasOwnProperty.call(object, key)) {
                        error('Duplicate key "' + key + '"');
                    }
                    object[key] = value();
                    white();
                    if (ch === '}') {
                        next('}');
                        return object;
                    }
                    next(',');
                    white();
                }
            }
            error("Bad object");
        };

    value = function () {

// Parse a JSON value. It could be an object, an array, a string, a number,
// or a word.

        white();
        switch (ch) {
        case '{':
            return object();
        case '[':
            return array();
        case '"':
            return string();
        case '-':
            return number();
        default:
            return ch >= '0' && ch <= '9' ? number() : word();
        }
    };

// Return the json_parse function. It will have access to all of the above
// functions and variables.

    return function (source, options, reviver) {
        var result;

        text = source;
        at = 0;
        ch = ' ';
        result = value();
        white();
        if (ch) {
            error("Syntax error");
        }

// If there is a reviver function, we recursively walk the new structure,
// passing each name/value pair to the reviver function for possible
// transformation, starting with a temporary root object that holds the result
// in an empty key. If there is not a reviver function, we simply return the
// result.

        return typeof reviver === 'function'
            ? (function walk(holder, key) {
                var k, v, value = holder[key];
                if (value && typeof value === 'object') {
                    for (k in value) {
                        if (Object.prototype.hasOwnProperty.call(value, k)) {
                            v = walk(value, k);
                            if (v !== undefined) {
                                value[k] = v;
                            } else {
                                delete value[k];
                            }
                        }
                    }
                }
                return reviver.call(holder, key, value);
            }({'': result}, ''))
            : result;
    };
}

json_stringify = require('./stringify.js').stringify;

module.exports = function(options) {
    return  {
        parse: json_parse(options),
        stringify: json_stringify
    }
};
//create the default method members with no options applied for backwards compatibility
module.exports.parse = json_parse();
module.exports.stringify = json_stringify();
<commit_msg>important backwards-compat change: this remnant of earlier sollutions must be removed<commit_after>var BigNumber = require('bignumber.js');
/*
    json_parse.js
    2012-06-20

    Public Domain.

    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.

    This file creates a json_parse function.
    During create you can (optionally) specify some behavioural switches

        require('json-bigint')(options)

            The optional options parameter holds switches that drive certain
            aspects of the parsing process:
            * options.strict = true will warn about duplicate-key usage in the json.
              The default (strict = false) will silently ignore those and overwrite
              values for keys that are in duplicate use.

    The resulting function follows this signature:
        json_parse(text, reviver)
            This method parses a JSON text to produce an object or array.
            It can throw a SyntaxError exception.

            The optional reviver parameter is a function that can filter and
            transform the results. It receives each of the keys and values,
            and its return value is used instead of the original value.
            If it returns what it received, then the structure is not modified.
            If it returns undefined then the member is deleted.

            Example:

            // Parse the text. Values that look like ISO date strings will
            // be converted to Date objects.

            myData = json_parse(text, function (key, value) {
                var a;
                if (typeof value === 'string') {
                    a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
                    if (a) {
                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
                            +a[5], +a[6]));
                    }
                }
                return value;
            });

    This is a reference implementation. You are free to copy, modify, or
    redistribute.

    This code should be minified before deployment.
    See http://javascript.crockford.com/jsmin.html

    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
    NOT CONTROL.
*/

/*members "", "\"", "\/", "\\", at, b, call, charAt, f, fromCharCode,
    hasOwnProperty, message, n, name, prototype, push, r, t, text
*/

var json_parse = function (options) {
    "use strict";

// This is a function that can parse a JSON text, producing a JavaScript
// data structure. It is a simple, recursive descent parser. It does not use
// eval or regular expressions, so it can be used as a model for implementing
// a JSON parser in other languages.

// We are defining the function inside of another function to avoid creating
// global variables.

// Default options one can override by passing options to the parse()
    var _options = {
        "strict": false  // not being strict means do not generate syntax errors for "duplicate key"
    };

// If there are options, then use them to override the default _options
    if (options !== undefined && options !== null) {
        if (options.strict === true) {
            _options.strict = true;
        }
    }

    var at,     // The index of the current character
        ch,     // The current character
        escapee = {
            '"':  '"',
            '\\': '\\',
            '/':  '/',
            b:    '\b',
            f:    '\f',
            n:    '\n',
            r:    '\r',
            t:    '\t'
        },
        text,

        error = function (m) {

// Call error when something is wrong.

            throw {
                name:    'SyntaxError',
                message: m,
                at:      at,
                text:    text
            };
        },

        next = function (c) {

// If a c parameter is provided, verify that it matches the current character.

            if (c && c !== ch) {
                error("Expected '" + c + "' instead of '" + ch + "'");
            }

// Get the next character. When there are no more characters,
// return the empty string.

            ch = text.charAt(at);
            at += 1;
            return ch;
        },

        number = function () {
// Parse a number value.

            var number,
                string = '';

            if (ch === '-') {
                string = '-';
                next('-');
            }
            while (ch >= '0' && ch <= '9') {
                string += ch;
                next();
            }
            if (ch === '.') {
                string += '.';
                while (next() && ch >= '0' && ch <= '9') {
                    string += ch;
                }
            }
            if (ch === 'e' || ch === 'E') {
                string += ch;
                next();
                if (ch === '-' || ch === '+') {
                    string += ch;
                    next();
                }
                while (ch >= '0' && ch <= '9') {
                    string += ch;
                    next();
                }
            }
            number = +string;
            if (!isFinite(number)) {
                error("Bad number");
            } else {
                //if (number > 9007199254740992 || number < -9007199254740992)
                // Bignumber has stricter check: everything with length > 15 digits disallowed
                if (string.length > 15)
                   return new BigNumber(string);
                return number;
            }
        },

        string = function () {

// Parse a string value.

            var hex,
                i,
                string = '',
                uffff;

// When parsing for string values, we must look for " and \ characters.

            if (ch === '"') {
                while (next()) {
                    if (ch === '"') {
                        next();
                        return string;
                    }
                    if (ch === '\\') {
                        next();
                        if (ch === 'u') {
                            uffff = 0;
                            for (i = 0; i < 4; i += 1) {
                                hex = parseInt(next(), 16);
                                if (!isFinite(hex)) {
                                    break;
                                }
                                uffff = uffff * 16 + hex;
                            }
                            string += String.fromCharCode(uffff);
                        } else if (typeof escapee[ch] === 'string') {
                            string += escapee[ch];
                        } else {
                            break;
                        }
                    } else {
                        string += ch;
                    }
                }
            }
            error("Bad string");
        },

        white = function () {

// Skip whitespace.

            while (ch && ch <= ' ') {
                next();
            }
        },

        word = function () {

// true, false, or null.

            switch (ch) {
            case 't':
                next('t');
                next('r');
                next('u');
                next('e');
                return true;
            case 'f':
                next('f');
                next('a');
                next('l');
                next('s');
                next('e');
                return false;
            case 'n':
                next('n');
                next('u');
                next('l');
                next('l');
                return null;
            }
            error("Unexpected '" + ch + "'");
        },

        value,  // Place holder for the value function.

        array = function () {

// Parse an array value.

            var array = [];

            if (ch === '[') {
                next('[');
                white();
                if (ch === ']') {
                    next(']');
                    return array;   // empty array
                }
                while (ch) {
                    array.push(value());
                    white();
                    if (ch === ']') {
                        next(']');
                        return array;
                    }
                    next(',');
                    white();
                }
            }
            error("Bad array");
        },

        object = function () {

// Parse an object value.

            var key,
                object = {};

            if (ch === '{') {
                next('{');
                white();
                if (ch === '}') {
                    next('}');
                    return object;   // empty object
                }
                while (ch) {
                    key = string();
                    white();
                    next(':');
                    if (_options.strict === true && Object.hasOwnProperty.call(object, key)) {
                        error('Duplicate key "' + key + '"');
                    }
                    object[key] = value();
                    white();
                    if (ch === '}') {
                        next('}');
                        return object;
                    }
                    next(',');
                    white();
                }
            }
            error("Bad object");
        };

    value = function () {

// Parse a JSON value. It could be an object, an array, a string, a number,
// or a word.

        white();
        switch (ch) {
        case '{':
            return object();
        case '[':
            return array();
        case '"':
            return string();
        case '-':
            return number();
        default:
            return ch >= '0' && ch <= '9' ? number() : word();
        }
    };

// Return the json_parse function. It will have access to all of the above
// functions and variables.

    return function (source, reviver) {
        var result;

        text = source;
        at = 0;
        ch = ' ';
        result = value();
        white();
        if (ch) {
            error("Syntax error");
        }

// If there is a reviver function, we recursively walk the new structure,
// passing each name/value pair to the reviver function for possible
// transformation, starting with a temporary root object that holds the result
// in an empty key. If there is not a reviver function, we simply return the
// result.

        return typeof reviver === 'function'
            ? (function walk(holder, key) {
                var k, v, value = holder[key];
                if (value && typeof value === 'object') {
                    for (k in value) {
                        if (Object.prototype.hasOwnProperty.call(value, k)) {
                            v = walk(value, k);
                            if (v !== undefined) {
                                value[k] = v;
                            } else {
                                delete value[k];
                            }
                        }
                    }
                }
                return reviver.call(holder, key, value);
            }({'': result}, ''))
            : result;
    };
}

json_stringify = require('./stringify.js').stringify;

module.exports = function(options) {
    return  {
        parse: json_parse(options),
        stringify: json_stringify
    }
};
//create the default method members with no options applied for backwards compatibility
module.exports.parse = json_parse();
module.exports.stringify = json_stringify();
<|endoftext|>


<commit_before>'use strict';

const config = require('./config');
const Hapi = require('hapi');
const chalk = require('chalk');

function CdnServer(opts) {
  opts = opts || {};
  this._src = opts.src;
  this._port = opts.port || config.get('port');
  this._internalCacheExpiresIn = opts.internalCacheExpiresIn || 1;
}

CdnServer.prototype.start = function() {
  return new Promise((resolve, reject) => {
    let server = new Hapi.Server({
      /*cache: [
        {
          name: 'redisCache',
          engine: require('catbox-redis'),
          host: '127.0.0.1',
          partition: 'cache'
        }
      ]*/
    });
    server.connection({ port: this._port });

    server.register([
      {
        register: require('./app/plugins/registry'),
        options: {
          mongoURI: config.get('mongodbUrl'),
        },
      },
      {
        register: require('./app/plugins/file-max-age'),
        options: {
          maxAge: config.get('maxAge')
        }
      },
      {
        register: require('./app/plugins/bundle-service'),
        options: {
          overridePath: this._src
        }
      },
      {
        register: require('./app/web/bundle'),
        options: {
          resourcesHost: config.get('host') ||
            config.get('ip') + ':' + this._port,
          internalCacheExpiresIn: this._internalCacheExpiresIn
        }
      },
      { register: require('./app/web/raw') }
    ], function(err) {
      if (err) reject(err);

      server.start(function() {
        console.log('--------------------------------------');
        console.log('');
        console.log('  ' + chalk.blue('foso cdn') + ' server started');
        console.log('  Hosted on ' + chalk.magenta(server.info.uri));
        console.log('  Press Ctrl+C to stop the server');
        console.log('');
        console.log('--------------------------------------');
      });

      resolve();
    });
  });
};

exports.Server = CdnServer;
<commit_msg>Listen possibly unhandled exceptions.<commit_after>'use strict';

process.on('unhandledRejection', function(reason, p) {
  console.log('Possibly Unhandled Rejection at: Promise ', p, ' reason: ', reason);
});

const config = require('./config');
const Hapi = require('hapi');
const chalk = require('chalk');

function CdnServer(opts) {
  opts = opts || {};
  this._src = opts.src;
  this._port = opts.port || config.get('port');
  this._internalCacheExpiresIn = opts.internalCacheExpiresIn || 1;
}

CdnServer.prototype.start = function() {
  return new Promise((resolve, reject) => {
    let server = new Hapi.Server({
      /*cache: [
        {
          name: 'redisCache',
          engine: require('catbox-redis'),
          host: '127.0.0.1',
          partition: 'cache'
        }
      ]*/
    });
    server.connection({ port: this._port });

    server.register([
      {
        register: require('./app/plugins/registry'),
        options: {
          mongoURI: config.get('mongodbUrl'),
        },
      },
      {
        register: require('./app/plugins/file-max-age'),
        options: {
          maxAge: config.get('maxAge')
        }
      },
      {
        register: require('./app/plugins/bundle-service'),
        options: {
          overridePath: this._src
        }
      },
      {
        register: require('./app/web/bundle'),
        options: {
          resourcesHost: config.get('host') ||
            config.get('ip') + ':' + this._port,
          internalCacheExpiresIn: this._internalCacheExpiresIn
        }
      },
      { register: require('./app/web/raw') }
    ], function(err) {
      if (err) reject(err);

      server.start(function() {
        console.log('--------------------------------------');
        console.log('');
        console.log('  ' + chalk.blue('foso cdn') + ' server started');
        console.log('  Hosted on ' + chalk.magenta(server.info.uri));
        console.log('  Press Ctrl+C to stop the server');
        console.log('');
        console.log('--------------------------------------');
      });

      resolve();
    });
  });
};

exports.Server = CdnServer;
<|endoftext|>


<commit_before>'use strict';

const test = require('tape')
    , fs = require('fs')
    , path = require('path')
    , proxyquire =  require('proxyquire')
    , spies = []
    , messages = []
    , Machine = proxyquire('../', {
        child_process: createMock(spies),
        deprecate() {
          messages.push.apply(messages, arguments)
        }
      })

test('name defaults to DOCKER_MACHINE_NAME or "default"', function (t) {
  t.plan(6)

  process.env.DOCKER_MACHINE_NAME = 'beep'

  t.is(new Machine().name, 'beep', 'DOCKER_MACHINE_NAME')
  t.is(new Machine('agent').name, 'agent', 'as string')
  t.is(new Machine({ name: 'agent' }).name, 'agent', 'as option')

  process.env.DOCKER_MACHINE_NAME = ''

  t.is(new Machine().name, 'default', 'default')
  t.is(new Machine('agent').name, 'agent', 'as string')
  t.is(new Machine({ name: 'agent' }).name, 'agent', 'as option')
})

test('cwd defaults to DOCKER_TOOLBOX_INSTALL_PATH or cwd', function (t) {
  t.plan(6)

  process.env.DOCKER_TOOLBOX_INSTALL_PATH = '/docker'

  const s1 = spy({ result: 'fake1' })
  const s2 = spy({ result: 'fake2' })

  Machine.command('anything1', (err, res) => {
    t.is(res, 'fake1')
    t.same(s1.args, ['anything1'])
    t.is(s1.opts.cwd, '/docker', 'DOCKER_TOOLBOX_INSTALL_PATH')
  })

  process.env.DOCKER_TOOLBOX_INSTALL_PATH = ''

  Machine.command('anything2', (err, res) => {
    t.is(res, 'fake2')
    t.same(s2.args, ['anything2'])
    t.is(s2.opts.cwd, '.', 'cwd')
  })
})

test('status', function (t) {
  t.plan(6)

  const s1 = spy({ result: ' running\n' })
  const s2 = spy({ result: 'Stopped' })

  Machine.status('beep', (err, status) => {
    t.ifError(err, 'no status error')
    t.is(status, 'running', 'trimmed')
    t.same(s1.args, ['status', 'beep'])
  })

  new Machine().status((err, status) => {
    t.ifError(err, 'no status error')
    t.is(status, 'stopped', 'lowercased')
    t.same(s2.args, ['status', 'default'])
  })
})

test('isRunning', function (t) {
  t.plan(6)

  const s1 = spy({ result: ' running\n' })
  const s2 = spy({ result: 'Stopped' })

  Machine.isRunning('beep', (err, running) => {
    t.ifError(err, 'no isRunning error')
    t.is(running, true, 'running')
    t.same(s1.args, ['status', 'beep'])
  })

  new Machine().isRunning((err, running) => {
    t.ifError(err, 'no isRunning error')
    t.is(running, false, 'not running')
    t.same(s2.args, ['status', 'default'])
  })
})

test('start', function (t) {
  t.plan(10)

  const s1 = spy({})
  const s2 = spy({})
  const s3 = spy({ error: new Error('\nhost does not exist abc') })
  const s4 = spy({ error: new Error('\nalready running abc') })
  const s5 = spy({ error: new Error('other error') })

  Machine.start('beep', (err) => {
    t.ifError(err, 'no start error')
    t.same(s1.args, ['start', 'beep'])
  })

  new Machine().start(err => {
    t.ifError(err, 'no start error')
    t.same(s2.args, ['start', 'default'])
  })

  Machine.start('boop', (err) => {
    t.is(err.message, 'Docker host "boop" does not exist', 'non existent error')
    t.same(s3.args, ['start', 'boop'])
  })

  new Machine().start(err => {
    t.ifError(err, 'no start error if already started')
    t.same(s4.args, ['start', 'default'])
  })

  Machine.start('four', (err) => {
    t.is(err.message, 'other error', 'passthrough other error')
    t.same(s5.args, ['start', 'four'])
  })
})

test('stop', function (t) {
  t.plan(10)

  const s1 = spy({})
  const s2 = spy({})
  const s3 = spy({ error: new Error('\nhost does not exist abc') })
  const s4 = spy({ error: new Error('\nalready stopped abc') })
  const s5 = spy({ error: new Error('other error') })

  Machine.stop('beep', (err) => {
    t.ifError(err, 'no stop error')
    t.same(s1.args, ['stop', 'beep'])
  })

  new Machine().stop(err => {
    t.ifError(err, 'no stop error')
    t.same(s2.args, ['stop', 'default'])
  })

  Machine.stop('boop', (err) => {
    t.is(err.message, 'Docker host "boop" does not exist', 'non existent error')
    t.same(s3.args, ['stop', 'boop'])
  })

  new Machine().stop(err => {
    t.ifError(err, 'no stop error if already stopped')
    t.same(s4.args, ['stop', 'default'])
  })

  Machine.stop('four', (err) => {
    t.is(err.message, 'other error', 'passthrough other error')
    t.same(s5.args, ['stop', 'four'])
  })
})

test('kill', function (t) {
  t.plan(10)

  const s1 = spy({})
  const s2 = spy({})
  const s3 = spy({ error: new Error('\nhost does not exist abc') })
  const s4 = spy({ error: new Error('\nalready stopped abc') })
  const s5 = spy({ error: new Error('other error') })

  Machine.kill('beep', (err) => {
    t.ifError(err, 'no stop error')
    t.same(s1.args, ['stop', 'beep'])
  })

  new Machine().kill(err => {
    t.ifError(err, 'no stop error')
    t.same(s2.args, ['stop', 'default'])
  })

  Machine.kill('boop', (err) => {
    t.is(err.message, 'Docker host "boop" does not exist', 'non existent error')
    t.same(s3.args, ['stop', 'boop'])
  })

  new Machine().kill(err => {
    t.ifError(err, 'no stop error if already stopped')
    t.same(s4.args, ['stop', 'default'])
  })

  Machine.kill('four', (err) => {
    t.is(err.message, 'other error', 'passthrough other error')
    t.same(s5.args, ['stop', 'four'])
  })
})

test('env', function (t) {
  t.plan(6)

  const s1 = spy({ result: fixture('env-windows.txt') })
  const s2 = spy({ result: fixture('env-bash.txt') })

  Machine.env('beep', (err, result) => {
    t.ifError(err, 'no env error')
    t.is(result, s1.result)
    t.same(s1.args, ['env', 'beep'])
  })

  new Machine().env((err, result) => {
    t.ifError(err, 'no env error')
    t.is(result, s2.result)
    t.same(s2.args, ['env', 'default'])
  })
})

test('env as plain object', function (t) {
  t.plan(6)

  const s1 = spy({ result: fixture('env-bash.txt') })
  const s2 = spy({ result: fixture('env-bash.txt') })

  Machine.env('beep', { parse: true }, (err, result) => {
    t.ifError(err, 'no env error')
    t.same(result, {
      DOCKER_TLS_VERIFY: '1',
      DOCKER_HOST: 'tcp://<ip>:<port>',
      DOCKER_CERT_PATH: '<home>/.docker/machine/machines/<name>',
      DOCKER_MACHINE_NAME: '<name>'
    })
    t.same(s1.args, ['env', '--shell', 'bash', 'beep'])
  })

  new Machine().env({ parse: true }, (err, result) => {
    t.ifError(err, 'no env error')
    t.same(result, {
      DOCKER_TLS_VERIFY: '1',
      DOCKER_HOST: 'tcp://<ip>:<port>',
      DOCKER_CERT_PATH: '<home>/.docker/machine/machines/<name>',
      DOCKER_MACHINE_NAME: '<name>'
    })
    t.same(s2.args, ['env', '--shell', 'bash', 'default'])
  })
})

test('env with json option is deprecated', function (t) {
  t.plan(4)

  const s1 = spy({ result: fixture('env-bash.txt') })

  Machine.env('beep', { json: true }, (err, result) => {
    t.ifError(err, 'no env error')
    t.same(result, {
      DOCKER_TLS_VERIFY: '1',
      DOCKER_HOST: 'tcp://<ip>:<port>',
      DOCKER_CERT_PATH: '<home>/.docker/machine/machines/<name>',
      DOCKER_MACHINE_NAME: '<name>'
    })
    t.same(s1.args, ['env', '--shell', 'bash', 'beep'])
    t.same(messages.splice(0), [
      'The "json" option has been renamed to "parse" and',
      'will be removed in node-docker-machine v3.x.x.'
    ], 'deprecated')
  })
})

test('env with custom shell', function (t) {
  t.plan(2)

  const s1 = spy({ result: '' })

  Machine.env('beep', { shell: 'fish' }, (err, result) => {
    t.ifError(err, 'no env error')
    t.same(s1.args, ['env', '--shell', 'fish', 'beep'])
  })
})

test('env as plain object overrides custom shell', function (t) {
  t.plan(3)

  const s1 = spy({ result: fixture('env-bash.txt') })

  Machine.env('beep', { parse: true, shell: 'fish' }, (err, result) => {
    t.ifError(err, 'no env error')
    t.same(s1.args, ['env', '--shell', 'bash', 'beep'])
    t.same(result, {
      DOCKER_TLS_VERIFY: '1',
      DOCKER_HOST: 'tcp://<ip>:<port>',
      DOCKER_CERT_PATH: '<home>/.docker/machine/machines/<name>',
      DOCKER_MACHINE_NAME: '<name>'
    })
  })
})

test('ssh', function (t) {
  t.plan(8)

  const s1 = spy({ result: ' beep ' })
  const s2 = spy({ result: ' boop ' })

  Machine.ssh('beep', 'cmd', (err, result) => {
    t.ifError(err, 'no ssh error')
    t.is(result, s1.result, 'does not trim')
    t.same(s1.args, ['ssh', 'beep', 'cmd'])
  })

  new Machine().ssh('cmd', (err, result) => {
    t.ifError(err, 'no ssh error')
    t.is(result, s2.result, 'does not trim')
    t.same(s2.args, ['ssh', 'default', 'cmd'])
  })

  t.throws(() => {
    Machine.ssh('beep', null, () => t.fail('Should not be called'))
  }, 'command cannot be null')

  t.throws(() => {
    Machine.ssh('beep', '  ', () => t.fail('Should not be called'))
  }, 'command cannot be empty')
})

test('ssh with command as array', function (t) {
  t.plan(5)

  const s1 = spy({ })
  const s2 = spy({ })

  Machine.ssh('beep', ['cmd', '--flag'], (err, result) => {
    t.ifError(err, 'no ssh error')
    t.same(s1.args, ['ssh', 'beep', 'cmd --flag'])
  })

  new Machine().ssh(['cmd', '--flag'], (err, result) => {
    t.ifError(err, 'no ssh error')
    t.same(s2.args, ['ssh', 'default', 'cmd --flag'])
  })

  t.throws(() => {
    Machine.ssh('beep', ['', ''], () => t.fail('Should not be called'))
  }, 'command cannot be empty')
})

test('inspect', function (t) {
  t.plan(9)

  const s1 = spy({ result: JSON.stringify({ name: 'beep' }) + '\r\n' })
  const s2 = spy({ result: JSON.stringify({ Other_Field: 'boop' }) })
  const s3 = spy({ result: 'invalid json' })

  Machine.inspect('beep', (err, result) => {
    t.ifError(err, 'no inspect error')
    t.same(result, { name: 'beep' }, 'parses trimmed JSON')
    t.same(s1.args, ['inspect', 'beep'])
  })

  new Machine().inspect((err, result) => {
    t.ifError(err, 'no inspect error')
    t.same(result, { otherField: 'boop' }, 'camelcased')
    t.same(s2.args, ['inspect', 'default'])
  })

  new Machine().inspect((err, result) => {
    t.ok(err, 'catches JSON parse error')
    t.is(result, undefined, 'no result')
    t.same(s2.args, ['inspect', 'default'])
  })
})

test('list', function (t) {
  t.plan(4)

  const s1 = spy({ result: fixture('list.txt') })

  t.is(Machine.prototype.list, undefined, 'static-only method')

  Machine.list((err, result) => {
    t.ifError(err, 'no inspect error')
    t.same(result, [
      { active: '*'
      , activeHost: true
      , activeSwarm: false
      , dockerVersion: 'v1.11.2'
      , driverName: 'virtualbox'
      , error: null
      , name: 'default'
      , responseTime: 290
      , state: 'running'
      , swarm: null
      , url: 'tcp://192.168.99.100:2376' },
      { active: '-'
      , activeHost: false
      , activeSwarm: false
      , dockerVersion: null
      , driverName: 'virtualbox'
      , error: null
      , name: 'host-1'
      , responseTime: 327
      , state: 'stopped'
      , swarm: null
      , url: 'tcp://192.168.99.101:2376' },
      { active: '* (swarm)'
      , activeHost: true
      , activeSwarm: true
      , dockerVersion: 'v1.11.0'
      , driverName: 'virtualbox'
      , error: null
      , name: 'host-2'
      , responseTime: 405
      , state: 'running'
      , swarm: null
      , url: 'tcp://192.168.99.102:2376' }
    ])
    t.same(s1.args, ['ls', '-f', fixture('template.txt')])
  })
})

test('list with inspect', function (t) {
  t.plan(9)

  const s1 = spy({ result: fixture('list.txt') })

  const s2 = spy({ result: JSON.stringify({ Extra: { Options: { a: true, b: '' } } }) })
  const s3 = spy({ result: JSON.stringify({ SOME_PROPERTY: 'hello' }) })
  const s4 = spy({ result: JSON.stringify({ other: 5 }) })

  Machine.list({ inspect: true }, (err, result) => {
    t.ifError(err, 'no inspect error')

    t.same(s1.args, ['ls', '-f', fixture('template.txt')])

    t.same(s2.args, ['inspect', 'default'], 'inspect default')
    t.same(s3.args, ['inspect', 'host-1'], 'inspect host-1')
    t.same(s4.args, ['inspect', 'host-2'], 'inspect host-2')

    t.is(result.length, 3, '3 hosts')

    t.same(result[0].extra, { options: { a: true, b: '' }})
    t.same(result[1].someProperty, 'hello')
    t.same(result[2].other, 5)
  })
})

test('list with timeout', function (t) {
  t.plan(2)

  const s1 = spy({ result: '' })

  Machine.list({ timeout: 5 }, (err, result) => {
    t.ifError(err, 'no inspect error')
    t.same(s1.args, ['ls', '-f', fixture('template.txt'), '-t', '5'])
  })
})

function spy(state) {
  spies.push(state)
  return state
}

function createMock(spies) {
  return {
    execFile(cmd, args, opts, done) {
      const state = spies.shift()

      state.cmd = cmd
      state.args = args
      state.opts = opts

      process.nextTick(done, state.error || null, state.result)
    }
  }
}

function fixture(name) {
  const file = path.join(__dirname, 'fixture', name)
  return fs.readFileSync(file, 'utf8').trim()
}<commit_msg>add the kill method<commit_after>'use strict';

const path = require('path')
    , fs = require('fs')
    , env = process.env
    , cp = require('child_process')
    , camelCase = require('camel-case')
    , parallel = require('run-parallel-limit')
    , xtend = require('xtend')
    , deprecate = require('deprecate')

const HOST_NON_EXISTENT = /host does not exist/i
    , ALREADY_RUNNING = /already running/i
    , ALREADY_STOPPED = /already stopped/
    , NEWLINE = /\r?\n/
    , LIST_COLUMNS_SEP = ','

const LIST_COLUMNS
  = [ 'Name'
    , 'Active'
    , 'ActiveHost'
    , 'ActiveSwarm'
    , 'DriverName'
    , 'State'
    , 'URL'
    , 'Swarm'
    , 'Error'
    , 'DockerVersion'
    , 'ResponseTime' ]

class Machine {
  constructor(opts) {
    opts = Machine.options(opts)
    this.name = opts.name || env.DOCKER_MACHINE_NAME || 'default'
  }

  static options(opts) {
    if (typeof opts === 'string') return { name: opts }
    else return opts || {}
  }

  static command(args, done) {
    cp.execFile('docker-machine', [].concat(args), {
      cwd: env.DOCKER_TOOLBOX_INSTALL_PATH || '.',
      encoding: 'utf8'
    }, done)
  }

  static status(name, done) {
    Machine.command(['status', name], (err, stdout) => {
      if (err) done(err)
      else done(null, stdout.trim().toLowerCase())
    })
  }

  static isRunning(name, done) {
    Machine.status(name, (err, status) => {
      done(err, status === 'running')
    })
  }

  static start(name, done) {
    Machine.command(['start', name], (err) => {
      if (HOST_NON_EXISTENT.test(err)) {
        done(new Error(`Docker host "${name}" does not exist`))
      } else if (ALREADY_RUNNING.test(err)) {
        done()
      } else {
        done(err)
      }
    })
  }

  static stop(name, done) {
    Machine.command(['stop', name], (err) => {
      if (HOST_NON_EXISTENT.test(err)) {
        done(new Error(`Docker host "${name}" does not exist`))
      } else if (ALREADY_STOPPED.test(err)) {
        done()
      } else {
        done(err)
      }
    })
  }

  static kill(name, done) {
    Machine.command(['kill', name], (err) => {
      if (HOST_NON_EXISTENT.test(err)) {
        done(new Error(`Docker host "${name}" does not exist`))
      } else if (ALREADY_STOPPED.test(err)) {
        done()
      } else {
        done(err)
      }
    })
  }

  static env(name, opts, done) {
    if (typeof opts === 'function') done = opts, opts = {}

    const args = ['env']

    if (opts.json) {
      deprecate(
        'The "json" option has been renamed to "parse" and',
        'will be removed in node-docker-machine v3.x.x.'
      )

      opts = xtend(opts, { parse: true })
    }

    if (opts.parse) args.push('--shell', 'bash')
    else if (opts.shell) args.push('--shell', opts.shell)

    args.push(name)

    Machine.command(args, function (err, stdout) {
      if (err) return done(err)
      if (!opts.parse) return done(null, stdout.trim())

      const res = {}

      stdout.split(/\n+/).forEach(line => {
        const m = /^export (.+)="([^"]+)/i.exec(line)
        if (m) res[m[1]] = m[2]
      })

      done(null, res)
    })
  }

  static ssh(name, cmd, done) {
    if (Array.isArray(cmd)) {
      cmd = cmd.join(' ')
    } else if (typeof cmd !== 'string') {
      throw new TypeError('Command must be an array or string')
    }

    cmd = cmd.trim()
    if (!cmd) throw new TypeError('Command may not be empty')

    Machine.command(['ssh', name, cmd], done)
  }

  static inspect(name, done) {
    Machine.command(['inspect', name], (err, stdout) => {
      if (err) return done(err)

      try {
        var data = JSON.parse(stdout.trim())
      } catch (err) {
        return done(err)
      }

      done(null, merge({}, data))
    })
  }

  static list(opts, done) {
    if (typeof opts === 'function') done = opts, opts = {}

    // Build template, escape values with URL encoding
    const template = LIST_COLUMNS.map(name => {
      if (name === 'ResponseTime') {
        return `{{ .${name} | printf "%d" }}`
      } else {
        return `{{ .${name} | urlquery }}`
      }
    }).join(LIST_COLUMNS_SEP)

    const args = ['ls', '-f', template]

    // Optionally add a timeout (in seconds)
    // to deal with docker/machine#1696.
    if (opts.timeout) args.push('-t', String(opts.timeout))

    Machine.command(args, (err, stdout) => {
      if (err) return done(err)

      const machines = stdout.split(NEWLINE).filter(Boolean).map(line => {
        const values = line.split(LIST_COLUMNS_SEP)
            , machine = {}

        LIST_COLUMNS.forEach((name, i) => {
          const key = camelCase(name)
          const val = values[i]

          machine[key] = val === '' ? null : decodeURIComponent(val)
        })

        // ResponseTime is in nanoseconds
        machine.responseTime = parseInt(machine.responseTime) / 1e6
        machine.state = machine.state.toLowerCase()
        machine.activeHost = machine.activeHost === 'true'
        machine.activeSwarm = machine.activeSwarm === 'true'

        if (machine.dockerVersion === 'Unknown') {
          machine.dockerVersion = null
        }

        return machine
      })

      if (!opts.inspect) return done(null, machines)

      // Add additional metadata from `docker-machine inspect <name>`
      parallel(machines.map(machine => next => {
        Machine.inspect(machine.name, (err, data) => {
          if (err) next(err)
          else next(null, xtend(machine, data))
        })
      }), 4, done)
    })
  }
}

;['status', 'isRunning', 'start', 'stop', 'kill' ,'env', 'ssh', 'inspect'].forEach(method => {
  Machine.prototype[method] = function () {
    const args = Array.from(arguments)
    args.unshift(this.name)
    Machine[method].apply(null, args)
  }
})

module.exports = Machine

function merge(node, data) {
  for(let key in data) {
    const val = data[key]
    node[camelCase(key)] = isObject(val) ? merge({}, val) : val
  }

  return node
}

function isObject(obj) {
  return typeof obj === 'object' && obj !== null
}<|endoftext|>


<commit_before>/**
 * angular-segment - AngularJS module for Segment
 * (C) 2016 Wong Yong Jie
 */

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as anonymous module
    define(['angular'], function (angular) {
      return factory(root, angular);
    });
  } else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
    // CommonJS
    module.exports = factory({}, require('angular'));
  } else if (angular) {
    factory(root, root.angular);
  }
}(this, function (global, angular) {
  angular.module('ngSegment', [])
    /**
     * @ngdoc service
     * @module ngSegment
     * @name SegmentProvider
     */
    .provider('Segment', function SegmentProvider() {
      var writeKey = null;

      /**
       * @ngdoc method
       * @methodOf SegmentProvider
       * @name setWriteKey
       * @param {String} key The write key to be used
       * @description
       * Sets the write key to be used with Segment. See Segment's documentation
       * for more information:
       * https://segment.com/docs/libraries/analytics.js/quickstart/
       */
      this.setWriteKey = function setWriteKey(key) {
        writeKey = key;
      };

      /**
       * @ngdoc service
       * @module ngSegment
       * @name Segment
       * See Segment's Analytics.js documentation for more info:
       * https://segment.com/docs/libraries/analytics.js/
       */
      this.$get = function SegmentFactory($window) {
        var analytics = $window.analytics = $window.analytics || [];

        analytics.methods = [
          'trackSubmit', 'trackClick', 'trackLink', 'trackForm', 'pageview',
          'identify', 'reset', 'group', 'track', 'ready', 'alias', 'page', 'once',
          'off', 'on'
        ];

        analytics.factory = function (t) {
          return function () {
            var e = Array.prototype.slice.call(arguments);
            e.unshift(t);
            analytics.push(e);
            return analytics;
          };
        };

        for (var t = 0; t < analytics.methods.length; t++) {
          var e = analytics.methods[t];
          analytics[e] = analytics.factory(e);
        }

        analytics.load = function (t) {
          var e = $window.document.createElement('script');
          e.type = 'text/javascript';
          e.async = true;
          e.src = '//cdn.segment.com/analytics.js/v1/' + t +'/analytics.min.js';
          var n = $window.document.getElementsByTagName('script')[0];
          n.parentNode.insertBefore(e, n);
        };

        analytics.SNIPPET_VERSION = '3.1.0';
        analytics.load(writeKey);

        return analytics;
      };
    });
}));
<commit_msg>Fixed events not being processed and added new tracking directive.<commit_after>/**
 * angular-segment - AngularJS module for Segment
 * (C) 2016 Wong Yong Jie
 */

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as anonymous module
    define(['angular'], function (angular) {
      return factory(root, angular);
    });
  } else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
    // CommonJS
    module.exports = factory({}, require('angular'));
  } else if (angular) {
    factory(root, root.angular);
  }
}(this, function (global, angular) {
  angular.module('ngSegment', [])
    /**
     * @ngdoc service
     * @module ngSegment
     * @name SegmentProvider
     */
    .provider('Segment', function SegmentProvider() {
      var writeKey = null;

      /**
       * @ngdoc method
       * @methodOf SegmentProvider
       * @name setWriteKey
       * @param {String} key The write key to be used
       * @description
       * Sets the write key to be used with Segment. See Segment's documentation
       * for more information:
       * https://segment.com/docs/libraries/analytics.js/quickstart/
       */
      this.setWriteKey = function setWriteKey(key) {
        writeKey = key;
      };

      /**
       * @ngdoc service
       * @module ngSegment
       * @name Segment
       * See Segment's Analytics.js documentation for more info:
       * https://segment.com/docs/libraries/analytics.js/
       */
      this.$get = function SegmentFactory($window) {
        var analytics = $window.analytics = $window.analytics || [];

        analytics.methods = [
          'trackSubmit', 'trackClick', 'trackLink', 'trackForm', 'pageview',
          'identify', 'reset', 'group', 'track', 'ready', 'alias', 'page', 'once',
          'off', 'on'
        ];

        analytics.factory = function (method) {
          return function () {
            var args = Array.prototype.slice.call(arguments);
            args.unshift(method);
            analytics.push(args);
            return analytics;
          };
        };

        for (var i = 0; i < analytics.methods.length; i++) {
          var key = analytics.methods[i];
          analytics[key] = analytics.factory(key);
        }

        analytics.load = function (key) {
          var script = $window.document.createElement('script');
          script.type = 'text/javascript';
          script.async = true;
          script.src = '//cdn.segment.com/analytics.js/v1/' + key +'/analytics.min.js';
          script.onload = function () {
            angular.copy($window.analytics, analytics);
          };

          var first = $window.document.getElementsByTagName('script')[0];
          first.parentNode.insertBefore(script, first);
        };

        analytics.SNIPPET_VERSION = '3.1.0';
        analytics.load(writeKey);

        return analytics;
      };
    })
    /**
     * @ngdoc directive
     * @restrict A
     */
    .directive('segmentTrack', function (Segment) {
      return {
        restrict: 'A',
        scope: {
          event: '@segmentTrack',
          options: '<?segmentTrackOptions'
        },
        link: function link(scope, elem) {
          elem.click(function () {
            Segment.track(scope.event, scope.options);
          });
        }
      };
    });
}));
<|endoftext|>


<commit_before>/*jslint indent: 2 */
/*global console: true, require: true, exports */
var EventEmitter = require('events').EventEmitter;
var GoogleClientLogin = require('googleclientlogin').GoogleClientLogin;
var util = require('util');

var GoogleContacts = function (conf) {
  var contacts = this;
  this.conf = conf || {};
  this.googleAuth = new GoogleClientLogin(this.conf);
  this.googleAuth.on('error', function () {
    console.error('an error occured on auth');
  });
  this.googleAuth.on('login', function () {
    contacts.loggedIn = true;
  });
  this.client = require('https');
  this.googleAuth.login();
};
GoogleContacts.prototype = {};
util.inherits(GoogleContacts, EventEmitter);
GoogleContacts.prototype.getContacts = function () {
  var contacts = this;
  if (!contacts.loggedIn) {
    this.googleAuth.on('login', function () {
      contacts._getContacts();
    });
    this.googleAuth.on('loginFailed', function () {
      console.log('login failed', this.conf);
    });
  } else {
    contacts._getContacts();
  }
};
GoogleContacts.prototype._onContactsReceived = function (response, data) {
  if (response.statusCode >= 200 && response.statusCode < 300) {
    this.contacts = JSON.parse(data);
    this.emit('contactsReceived');
  } else {
    console.error('data: ', data);
  }
};
GoogleContacts.prototype._getContacts = function () {
  var contacts = this, request;

  request = this.client.request(
    {
      host: 'www.google.com',
      port: 443,
      path: '/m8/feeds/contacts/default/full?max-results=3000&alt=json',
      method: 'GET',
      headers: {
        'Authorization': 'GoogleLogin auth=' + this.googleAuth.getAuthId(),
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    },
    function (response) {
      var data = '';

      response.on('data', function (chunk) {
        data += chunk;
      });

      response.on('error', function (e) {
        console.error('an error occured getting contacts', e);
      });

      response.on('end', function () {
        this._onContactsReceived(response, data);
      }.bind(this));
    }.bind(this)
  );
  request.end();
};
exports.GoogleContacts = GoogleContacts;
<commit_msg>add method to get contact groups<commit_after>/*jslint indent: 2 */
/*global console: true, require: true, exports */
var EventEmitter = require('events').EventEmitter;
var GoogleClientLogin = require('googleclientlogin').GoogleClientLogin;
var util = require('util');
var querystring = require('querystring');

const contactsUrl = '/m8/feeds/contacts/',
      contactGroupsUrl = '/m8/feeds/groups/';

var GoogleContacts = function (conf) {
  var contacts = this;
  this.conf = conf || {};
  this.conf.service = 'contacts';
  this.googleAuth = new GoogleClientLogin(this.conf);
  this.googleAuth.on('error', function () {
    console.error('an error occured on auth');
  });
  this.googleAuth.on('login', function () {
    contacts.loggedIn = true;
  });
  this.client = require('https');
  this.googleAuth.login();
};
GoogleContacts.prototype = {};
util.inherits(GoogleContacts, EventEmitter);
GoogleContacts.prototype.getContacts = function (projection, limit) {
  var contacts = this;
  if (!contacts.loggedIn) {
    this.googleAuth.on('login', function () {
      contacts._getContacts(projection, limit);
    });
    this.googleAuth.on('loginFailed', function () {
      console.log('login failed', this.conf);
    });
  } else {
    contacts._getContacts(projection, limit);
  }
};
GoogleContacts.prototype._onContactsReceived = function (response, data) {
    this.contacts = JSON.parse(data);
    this.emit('contactsReceived');
};
GoogleContacts.prototype._onContactGroupsReceived = function (response, data) {
    this.contacts = JSON.parse(data);
    this.emit('contactGroupsReceived');
};
GoogleContacts.prototype._onResponse = function (request, response) {
  var data = '';

  response.on('data', function (chunk) {
    data += chunk;
  });

  response.on('error', function (e) {
    this.emit('error', e);
  }.bind(this));

  response.on('end', function () {
    if (response.statusCode >= 200 && response.statusCode < 300) {
      if (request.path.indexOf(contactsUrl) === 0) {
        this._onContactsReceived(response, data);
      } else if (request.path.indexOf(contactGroupsUrl) === 0) {
        this._onContactGroupsReceived(response, data);
      }
    } else {
      this.emit('error', 'Bad response status');
    }
  }.bind(this));
};
GoogleContacts.prototype._get = function (type, projection, limit) {
  var path, params, request;
  params = {alt: 'json'};
  limit = parseInt(limit, 10);
  if (!isNaN(limit, 10)) {
    params['max-results'] = limit;
  }

  path = type === 'groups' ? contactGroupsUrl : contactsUrl;
  path += this.conf.email + '/' + projection + '?' + querystring.stringify(params);
  request = this.client.request(
    {
      host: 'www.google.com',
      port: 443,
      path: path,
      method: 'GET',
      headers: {
        'Authorization': 'GoogleLogin auth=' + this.googleAuth.getAuthId(),
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    },
    function (response) {
      this._onResponse(request, response);
    }.bind(this)
  );
  request.end();
};
GoogleContacts.prototype._getContacts = function (projection, limit) {
  this._get('contacts', projection, limit);
};
GoogleContacts.prototype._getContactGroups = function (projection, limit) {
  this._get('groups', projection, limit);
};
exports.GoogleContacts = GoogleContacts;
<|endoftext|>


<commit_before>const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const dotenv = require('dotenv');
const passport = require('passport');
const cors = require('cors');
const BearerStrategy = require('passport-http-bearer').Strategy;
const GoogleStrategy = require('passport-google-oauth20').Strategy;

const Messages = require('./models/messages');
const User = require('./models/user');

dotenv.config();

const frontendUrl = process.env.FRONTEND_URL;

mongoose.Promise = global.Promise;

// Prepend timestamp to all `logs`
const log = (...args) => console.log(new Date().toISOString(), ...args);

log(`Server running in ${process.env.NODE_ENV} mode`);

const app = express();
app.use(cors());
app.use(bodyParser.json());

// ===== AUTH =====

passport.use(new BearerStrategy(
  (accessToken, done) => {
    if (!accessToken) {
      throw new Error({ message: 'Invalid or missing accessToken' });
    }
    User.findOne({ accessToken })
    .then((user) => {
      log(`userId: ${user._id}`);
      done(null, user, { scope: 'read' });
    })
    .catch((err) => {
      log(`Passport bearer error: ${err}`);
      done(err, null);
    });
  }
));

passport.use(new GoogleStrategy({
  clientID: process.env.CLIENTID,
  clientSecret: process.env.CLIENTSECRET,
  callbackURL: `${process.env.BACKEND_URL}/auth/google/callback`
}, (accessToken, refreshToken, profile, done) => {
  log(`accessToken: ${accessToken}`);
  User.findOneAndUpdate({
    googleId: profile.id
  }, {
    $set: {
      googleId: profile.id,
      nickname: profile.name.givenName || '',
      userName: profile.displayName || '',
      email: profile.emails[0].value || '',
      avatar: profile.photos[0].value || '',
      accessToken
    }
  }, {
    upsert: true, new: true, setDefaultsOnInsert: true
  })
  .then((user) => {
    log(`userId: ${user._id}`);
    done(null, user);
  })
  .catch((err) => {
    log(err);
  });
}));

app.get('/auth/google',
  passport.authenticate('google', { scope: ['profile', 'email'] })
);

app.get('/auth/google/callback',
  passport.authenticate('google',
    { failureRedirect: frontendUrl, session: false }
  ), ({ user }, res) => {
    log(`userId: ${user._id}`);
    res.redirect(`${frontendUrl}/#/app?token=${user.accessToken}`);
  }
);

app.get('/auth/logout', (req, res) => {
  req.logout();
  res.redirect(frontendUrl);
});

// ===== MESSAGES =====

app.get('/messages',
  passport.authenticate('bearer', { session: false }),

  ({ user }, res) => {
    log('GET /messages/');

    Messages.find().sort({ date: -1 })
    .then(messages =>
      res.json({
        currentUser: user._id,
        currentAvatar: user.avatar,
        currentNickname: user.nickname,
        messages: messages.map(message =>
          Object.assign(message, {
            comments: message.comments
              .filter(comment =>
                user._id.equals(comment.from) || user._id.equals(comment.to)
              )
              .sort((x, y) => new Date(x.date) - new Date(y.date))
          })
        ),
      })
    );
  }
);

app.post('/messages',
  passport.authenticate('bearer', { session: false }),
  ({ user, body }, res) => {
    log(`POST /messages, body: ${body}`);

    Messages.create(Object.assign(body, { userId: user._id }))
    .then(({ _id }) => {
      res.status(201).json({ _id });
    })
    .catch((err) => {
      log(`Err: ${err}`);
      res.sendStatus(404);
    });
  }
);

app.delete('/messages/:messageId',
  passport.authenticate('bearer', { session: false }),

  ({ user, params: { messageId } }, res) => {
    log(`DELETE /messages/${messageId}`);

    Messages.findOne({ _id: messageId, userId: user._id })
      .then((result) => {
        if (result) {
          result.remove();
          res.sendStatus(200);
        } else {
          res.sendStatus(404);
        }
      })
      .catch((err) => {
        console.error(err);
        res.sendStatus(404);
      });
  }
);

// ===== MEMBERS =====

app.get('/members', passport.authenticate('bearer', { session: false }),
  (req, res) => {
    log('GET /members');

    // When multiple families implemented, limit find to current family
    User.find({}, { accessToken: 0, __v: 0, googleId: 0 })

    .then(users => res.json(users))

    .catch((err) => {
      console.error(err);
      res.sendStatus(400);
    });
  }
);

// ===== CURRENT USER =====
// limited functionality now; to be used for multiple families functionality

app.get('/user', passport.authenticate('bearer', { session: false }),
  ({ user }, res) =>
    res.json({
      currentUser: {
        id: user._id,
        avatar: user.avatar,
        nickname: user.nickname,
        fullname: user.userName,
      }
    })
);

// ===== COMMENTS =====

app.post('/comments', passport.authenticate('bearer', { session: false }),
  ({ body, user }, res) => {
    log(`POST /comments/:${body.messageId}`);

    Messages.update(
      { _id: body.messageId },
      { $push: { comments: {
        from: user._id,
        to: body.to,
        text: body.text,
      } } }
    )

    .then((data) => {
      if (data.nModified > 0) {
        res.sendStatus(200);
      } else {
        res.sendStatus(404);
      }
    })

    .catch((err) => {
      console.error(err);
      res.sendStatus(404);
    });
  }
);

app.delete('/comments/:messageId/:commentId',
  passport.authenticate('bearer', { session: false }),
  ({ user, params: { messageId, commentId } }, res) => {
    log(`DELETE /comments/:${messageId}/:${commentId}`);

    Messages.update(
      { _id: messageId },
      { $pull: { comments: { _id: commentId, from: user._id } } }
    )
    .then((status) => {
      if (status.nModified > 0) {
        res.sendStatus(202);
      } else {
        res.sendStatus(404);
      }
    })
    .catch((err) => {
      console.error(err.message);
      return res.sendStatus(404);
    });
  }
);

// ===== SERVER =====

let server;

function runServer(callback) {
  return new Promise((resolve, reject) => {
    mongoose.connect(process.env.DATABASE_URL, (err) => {
      if (err && callback) {
        log(err);
        return callback(err);
      }
      return null;
    });
    server = app.listen(process.env.PORT, process.env.HOST, () => {
      log(`Your app is listening on port ${process.env.PORT}`);
      if (callback) {
        callback();
      }
      resolve(server);
    }).on('error', (err) => {
      reject(err);
    });
  });
}

function closeServer() {
  return new Promise((resolve, reject) => {
    log('Closing server');
    server.close((err) => {
      if (err) {
        reject(err);
        return;
      }
      resolve();
    });
  });
}

if (require.main === module) {
  runServer();
}

module.exports = { app, runServer, closeServer };
<commit_msg>remove currentUser, currentUserAvatar, and currentUserNickname from message object on GET messages route (#36)<commit_after>const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const dotenv = require('dotenv');
const passport = require('passport');
const cors = require('cors');
const BearerStrategy = require('passport-http-bearer').Strategy;
const GoogleStrategy = require('passport-google-oauth20').Strategy;

const Messages = require('./models/messages');
const User = require('./models/user');

dotenv.config();

const frontendUrl = process.env.FRONTEND_URL;

mongoose.Promise = global.Promise;

// Prepend timestamp to all `logs`
const log = (...args) => console.log(new Date().toISOString(), ...args);

log(`Server running in ${process.env.NODE_ENV} mode`);

const app = express();
app.use(cors());
app.use(bodyParser.json());

// ===== AUTH =====

passport.use(new BearerStrategy(
  (accessToken, done) => {
    if (!accessToken) {
      throw new Error({ message: 'Invalid or missing accessToken' });
    }
    User.findOne({ accessToken })
    .then((user) => {
      log(`userId: ${user._id}`);
      done(null, user, { scope: 'read' });
    })
    .catch((err) => {
      log(`Passport bearer error: ${err}`);
      done(err, null);
    });
  }
));

passport.use(new GoogleStrategy({
  clientID: process.env.CLIENTID,
  clientSecret: process.env.CLIENTSECRET,
  callbackURL: `${process.env.BACKEND_URL}/auth/google/callback`
}, (accessToken, refreshToken, profile, done) => {
  log(`accessToken: ${accessToken}`);
  User.findOneAndUpdate({
    googleId: profile.id
  }, {
    $set: {
      googleId: profile.id,
      nickname: profile.name.givenName || '',
      userName: profile.displayName || '',
      email: profile.emails[0].value || '',
      avatar: profile.photos[0].value || '',
      accessToken
    }
  }, {
    upsert: true, new: true, setDefaultsOnInsert: true
  })
  .then((user) => {
    log(`userId: ${user._id}`);
    done(null, user);
  })
  .catch((err) => {
    log(err);
  });
}));

app.get('/auth/google',
  passport.authenticate('google', { scope: ['profile', 'email'] })
);

app.get('/auth/google/callback',
  passport.authenticate('google',
    { failureRedirect: frontendUrl, session: false }
  ), ({ user }, res) => {
    log(`userId: ${user._id}`);
    res.redirect(`${frontendUrl}/#/app?token=${user.accessToken}`);
  }
);

app.get('/auth/logout', (req, res) => {
  req.logout();
  res.redirect(frontendUrl);
});

// ===== MESSAGES =====

app.get('/messages',
  passport.authenticate('bearer', { session: false }),

  ({ user }, res) => {
    log('GET /messages/');

    Messages.find().sort({ date: -1 })
    .then(messages =>
      res.json({
        messages: messages.map(message =>
          Object.assign(message, {
            comments: message.comments
              .filter(comment =>
                user._id.equals(comment.from) || user._id.equals(comment.to)
              )
              .sort((x, y) => new Date(x.date) - new Date(y.date))
          })
        ),
      })
    );
  }
);

app.post('/messages',
  passport.authenticate('bearer', { session: false }),
  ({ user, body }, res) => {
    log(`POST /messages, body: ${body}`);

    Messages.create(Object.assign(body, { userId: user._id }))
    .then(({ _id }) => {
      res.status(201).json({ _id });
    })
    .catch((err) => {
      log(`Err: ${err}`);
      res.sendStatus(404);
    });
  }
);

app.delete('/messages/:messageId',
  passport.authenticate('bearer', { session: false }),

  ({ user, params: { messageId } }, res) => {
    log(`DELETE /messages/${messageId}`);

    Messages.findOne({ _id: messageId, userId: user._id })
      .then((result) => {
        if (result) {
          result.remove();
          res.sendStatus(200);
        } else {
          res.sendStatus(404);
        }
      })
      .catch((err) => {
        console.error(err);
        res.sendStatus(404);
      });
  }
);

// ===== MEMBERS =====

app.get('/members', passport.authenticate('bearer', { session: false }),
  (req, res) => {
    log('GET /members');

    // When multiple families implemented, limit find to current family
    User.find({}, { accessToken: 0, __v: 0, googleId: 0 })

    .then(users => res.json(users))

    .catch((err) => {
      console.error(err);
      res.sendStatus(400);
    });
  }
);

// ===== CURRENT USER =====
// limited functionality now; to be used for multiple families functionality

app.get('/user', passport.authenticate('bearer', { session: false }),
  ({ user }, res) =>
    res.json({
      currentUser: {
        id: user._id,
        avatar: user.avatar,
        nickname: user.nickname,
        fullname: user.userName,
      }
    })
);

// ===== COMMENTS =====

app.post('/comments', passport.authenticate('bearer', { session: false }),
  ({ body, user }, res) => {
    log(`POST /comments/:${body.messageId}`);

    Messages.update(
      { _id: body.messageId },
      { $push: { comments: {
        from: user._id,
        to: body.to,
        text: body.text,
      } } }
    )

    .then((data) => {
      if (data.nModified > 0) {
        res.sendStatus(200);
      } else {
        res.sendStatus(404);
      }
    })

    .catch((err) => {
      console.error(err);
      res.sendStatus(404);
    });
  }
);

app.delete('/comments/:messageId/:commentId',
  passport.authenticate('bearer', { session: false }),
  ({ user, params: { messageId, commentId } }, res) => {
    log(`DELETE /comments/:${messageId}/:${commentId}`);

    Messages.update(
      { _id: messageId },
      { $pull: { comments: { _id: commentId, from: user._id } } }
    )
    .then((status) => {
      if (status.nModified > 0) {
        res.sendStatus(202);
      } else {
        res.sendStatus(404);
      }
    })
    .catch((err) => {
      console.error(err.message);
      return res.sendStatus(404);
    });
  }
);

// ===== SERVER =====

let server;

function runServer(callback) {
  return new Promise((resolve, reject) => {
    mongoose.connect(process.env.DATABASE_URL, (err) => {
      if (err && callback) {
        log(err);
        return callback(err);
      }
      return null;
    });
    server = app.listen(process.env.PORT, process.env.HOST, () => {
      log(`Your app is listening on port ${process.env.PORT}`);
      if (callback) {
        callback();
      }
      resolve(server);
    }).on('error', (err) => {
      reject(err);
    });
  });
}

function closeServer() {
  return new Promise((resolve, reject) => {
    log('Closing server');
    server.close((err) => {
      if (err) {
        reject(err);
        return;
      }
      resolve();
    });
  });
}

if (require.main === module) {
  runServer();
}

module.exports = { app, runServer, closeServer };
<|endoftext|>


<commit_before>'use strict';
const chokidar = require('chokidar');
const ALY = require('aliyun-sdk');
const path = require('path');
const fs = require('fs');
const crypto = require('crypto');
module.exports = function (options) {
    var oss = new ALY.OSS(options.oss);
    const cwd = options.cwd || '';
    const prefix = cwd.replace(/\\/g, '/');
    var getObjects = function (cb) {
        var nextMarker = '';
        var bucketObjects = [];
        var getObjectsLoop = function () {
            if(typeof nextMarker === 'string'){
                oss.listObjects({
                    Bucket: options.bucket,
                    MaxKeys: 100,
                    Prefix: prefix,
                    Marker: nextMarker
                }, function (listObjectsErr, bucket) {
                    if(listObjectsErr){return console.log(listObjectsErr); }
                    nextMarker = bucket.NextMarker;
                    bucketObjects = bucketObjects.concat(bucket.Contents);
                    getObjectsLoop();
                });
            }else{
                cb(bucketObjects);
                return console.log('finish OSS request loop');
            }
        };
        getObjectsLoop();
    };
    getObjects(function (bucketObjects) {
        //get all path of the bucket
        var bucketPaths = [];
        var localPaths = [];
        for(let i = 0; i < bucketObjects.length; i++){
            bucketPaths.push(bucketObjects[i].Key);
        }
        const pathsArr = Array.isArray(options.src) ? options.src : options.src.split(' ');
        for(let i = 0; i < pathsArr.length; i++){
            pathsArr[i] = path.join(cwd, pathsArr[i]);
        }
        var filesWatcher = chokidar.watch(pathsArr, options.watch);
        //upload or update file function
        var upsertFile = function (localFilePath) {
            let standerFilePath = localFilePath.replace(/\\/g, '/');
            fs.readFile(localFilePath, function (readFileErr, fileData) {
                if (readFileErr) {
                    throw readFileErr;
                }
                oss.putObject({
                    Bucket: options.bucket,
                    Body: fileData,
                    Key: standerFilePath
                }, function (putObjectErr, uploadedFileInfo) {
                    if (putObjectErr) {
                        console.log('error:', putObjectErr);
                        return putObjectErr;
                    }
                    console.log('uploaded: ' + localFilePath);
                    console.log('Network info: ', uploadedFileInfo);
                    if(bucketPaths.indexOf(standerFilePath) === -1){
                        bucketPaths.push(standerFilePath);
                    }
                    if(localPaths.indexOf(standerFilePath) === -1){
                        localPaths.push(standerFilePath);
                    }
                });
            });
        };
        //delete bucket file function
        var deleteFile = function (filePath) {
            let standerPath = filePath.replace(/\\/g, '/');
            oss.deleteObject({
                Bucket: options.bucket,
                Key: standerPath
            }, function (err, data) {
                if(err){console.log('error:', err); return err; }
                let bucketIndex = bucketPaths.indexOf(standerPath);
                if(bucketIndex !== -1){
                    bucketPaths.splice(bucketIndex, 1);
                }
                let localIndex = localPaths.indexOf(standerPath);
                if(localIndex !== -1){
                    localPaths.splice(localIndex, 1);
                }
                console.log('delete success:' + standerPath);
                console.log('Network info:', data);
            });
        };
        //catch all events, just use for fun
        //filesWatcher.on('all', function (event, filePath) {
        //    console.log(path, event);
        //});
        //add new files
        filesWatcher.on('add', function (localFilePath) {
            let standerFilePath = localFilePath.replace(/\\/g, '/');
            let bucketIndex = bucketPaths.indexOf(standerFilePath);
            if(bucketIndex === -1){
                console.log('File not exist: ' + localFilePath);
                //upsertFile(localFilePath);
            }else{
                if(localPaths.indexOf(standerFilePath) === -1){
                    localPaths.push(standerFilePath);
                }
                fs.readFile(localFilePath, function (readFileErr, fileData) {
                    let fileMd5 = crypto.createHash('md5').update(fileData).digest('hex').toUpperCase();
                    for(let i = 0; i < bucketObjects.length; i++){
                        if(bucketObjects[i].Key === standerFilePath){
                            if(bucketObjects[i].ETag.replace(/"/g, '') !== fileMd5){
                                console.log('ETag different, now upload this local file: ' + localFilePath);
                                upsertFile(localFilePath);
                            }
                        }
                    }
                });
            }
        });
        //Initial scan complete.
        filesWatcher.on('ready', function () {
            //delete bucket object if local object is not exist.
            for(let i = 0; i < bucketPaths.length; i++){
                let index = localPaths.indexOf(bucketPaths[i]);
                if(index === -1){
                    let filePath = bucketPaths[i];
                    deleteFile(filePath);
                }
            }
        });
        //modify file
        filesWatcher.on('change', function (filePath) {
            console.log('file change: ' + filePath);
            upsertFile(filePath);
        });
        //delete file
        filesWatcher.on('unlink', function (filePath) {
            console.log('file unlink: ' + filePath);
            deleteFile(filePath);
        });
    });
};
<commit_msg>fix a content type issue<commit_after>'use strict';
const chokidar = require('chokidar');
const mime = require('mime');
const ALY = require('aliyun-sdk');
const path = require('path');
const fs = require('fs');
const crypto = require('crypto');
module.exports = function (options) {
    var oss = new ALY.OSS(options.oss);
    const cwd = options.cwd || '';
    const prefix = cwd.replace(/\\/g, '/');
    var getObjects = function (cb) {
        var nextMarker = '';
        var bucketObjects = [];
        var getObjectsLoop = function () {
            if(typeof nextMarker === 'string'){
                oss.listObjects({
                    Bucket: options.bucket,
                    MaxKeys: 100,
                    Prefix: prefix,
                    Marker: nextMarker
                }, function (listObjectsErr, bucket) {
                    if(listObjectsErr){return console.log(listObjectsErr); }
                    nextMarker = bucket.NextMarker;
                    bucketObjects = bucketObjects.concat(bucket.Contents);
                    getObjectsLoop();
                });
            }else{
                cb(bucketObjects);
                return console.log('finish OSS request loop');
            }
        };
        getObjectsLoop();
    };
    getObjects(function (bucketObjects) {
        //get all path of the bucket
        var bucketPaths = [];
        var localPaths = [];
        for(let i = 0; i < bucketObjects.length; i++){
            bucketPaths.push(bucketObjects[i].Key);
        }
        const pathsArr = Array.isArray(options.src) ? options.src : options.src.split(' ');
        for(let i = 0; i < pathsArr.length; i++){
            pathsArr[i] = path.join(cwd, pathsArr[i]);
        }
        var filesWatcher = chokidar.watch(pathsArr, options.watch);
        //upload or update file function
        var upsertFile = function (localFilePath) {
            let contentType = mime.lookup(localFilePath);
            let standerFilePath = localFilePath.replace(/\\/g, '/');
            fs.readFile(localFilePath, function (readFileErr, fileData) {
                if (readFileErr) {
                    throw readFileErr;
                }
                oss.putObject({
                    Bucket: options.bucket,
                    Body: fileData,
                    Key: standerFilePath,
                    ContentEncoding: 'utf-8',
                    ContentType: contentType
                }, function (putObjectErr, uploadedFileInfo) {
                    if (putObjectErr) {
                        console.log('error:', putObjectErr);
                        return putObjectErr;
                    }
                    console.log('uploaded: ' + localFilePath);
                    console.log('Network info: ', uploadedFileInfo);
                    if(bucketPaths.indexOf(standerFilePath) === -1){
                        bucketPaths.push(standerFilePath);
                    }
                    if(localPaths.indexOf(standerFilePath) === -1){
                        localPaths.push(standerFilePath);
                    }
                });
            });
        };
        //delete bucket file function
        var deleteFile = function (filePath) {
            let standerPath = filePath.replace(/\\/g, '/');
            oss.deleteObject({
                Bucket: options.bucket,
                Key: standerPath
            }, function (err, data) {
                if(err){console.log('error:', err); return err; }
                let bucketIndex = bucketPaths.indexOf(standerPath);
                if(bucketIndex !== -1){
                    bucketPaths.splice(bucketIndex, 1);
                }
                let localIndex = localPaths.indexOf(standerPath);
                if(localIndex !== -1){
                    localPaths.splice(localIndex, 1);
                }
                console.log('delete success:' + standerPath);
                console.log('Network info:', data);
            });
        };
        //catch all events, just use for fun
        //filesWatcher.on('all', function (event, filePath) {
        //    console.log(path, event);
        //});
        //add new files
        filesWatcher.on('add', function (localFilePath) {
            let standerFilePath = localFilePath.replace(/\\/g, '/');
            let bucketIndex = bucketPaths.indexOf(standerFilePath);
            if(bucketIndex === -1){
                console.log('File not exist: ' + localFilePath);
                upsertFile(localFilePath);
            }else{
                if(localPaths.indexOf(standerFilePath) === -1){
                    localPaths.push(standerFilePath);
                }
                fs.readFile(localFilePath, function (readFileErr, fileData) {
                    let fileMd5 = crypto.createHash('md5').update(fileData).digest('hex').toUpperCase();
                    for(let i = 0; i < bucketObjects.length; i++){
                        if(bucketObjects[i].Key === standerFilePath){
                            if(bucketObjects[i].ETag.replace(/"/g, '') !== fileMd5){
                                console.log('ETag different, now upload this local file: ' + localFilePath);
                                upsertFile(localFilePath);
                            }
                        }
                    }
                });
            }
        });
        //Initial scan complete.
        filesWatcher.on('ready', function () {
            //delete bucket object if local object is not exist.
            for(let i = 0; i < bucketPaths.length; i++){
                let index = localPaths.indexOf(bucketPaths[i]);
                if(index === -1){
                    let filePath = bucketPaths[i];
                    deleteFile(filePath);
                }
            }
        });
        //modify file
        filesWatcher.on('change', function (filePath) {
            console.log('file change: ' + filePath);
            upsertFile(filePath);
        });
        //delete file
        filesWatcher.on('unlink', function (filePath) {
            console.log('file unlink: ' + filePath);
            deleteFile(filePath);
        });
    });
};
<|endoftext|>