<commit_before>/*
 *  Ni - a minimalistic Node framework that makes setting up an MVC project
 *  a breeze. Inspired by CodeIgniter.
 *
 *  Since Ni is fully contained in a Node module, you can use it with Connect
 *  and your own choice of template engine, database, static file server, etc.
 *  No frills, no restrictions, no worries.
 */

/*
 *  Module dependencies
 */

var fs = require('fs'),
    Step = require('step');

/*
 *  Ni object
 */

var Ni = function() {
    var Ni = this;

    /*
     *  Registry for custom configuration variables.
     */

    this.config = {};

    this.automatic_views = false;

    /*
     *  Tells Ni what root directory to look into.
     *
     *  Call this function before calling boot.
     */

    this.setRoot = function(__root) {
        this.__root = __root;
    }

    /*
     *  Loads controllers, models, views, templates and helpers from the root
     *  directory, and makes them all available to the Ni object.
     */

    this.boot = function(callbackDone) {
        Step(
                function bootStrapEverything() {
                    bootStrapControllers(Ni.__root, this.parallel());
                    bootStrapModels(Ni.__root, this.parallel());
                    bootStrapViews(Ni.__root, this.parallel());
                    bootStrapLibraries(Ni.__root, this.parallel());
                },
                function buildNi(err, controllers, models, views, libraries) {
                    if (err) throw err;
                    Ni.controllers = controllers;
                    Ni.models = models;
                    Ni.views = views;
                    Ni.libraries = libraries;
                    callbackDone();
                }
            );
    }

    /*
     *  Provides router for Connect to automatically call the correct controller
     *  functions with the correct arguments based on the URL. If the controller
     *  or action is not found, it calls next() in the Connect list.
     *
     *  Add this to your Connect call as: Ni.router
     */

    this.router = function(req, res, next) {
        parsedUrl = require('url').parse(req.url, true);
        pathArr = parsedUrl.pathname.split('/');
        res.Ni = { view: Ni.automatic_views };

        var controller;
        if (pathArr[1]) {
            controller = Ni.controllers[pathArr[1]];
            if (controller) {
                res.Ni.controller = pathArr[1];
                var fn;
                if (pathArr[2]) {
                    res.Ni.action = pathArr[2];
                    fn = controller[pathArr[2]];
                }
                else {
                    res.Ni.action = 'index';
                    fn = controller.index;
                }

                if (fn) {
                    var args = pathArr.slice(3);
                    args.unshift(next);
                    args.unshift(res);
                    args.unshift(req);
                    fn.apply(null, args);
                }
                else {
                    res.Ni.controller = undefined;
                    res.Ni.action = undefined;
                    next();
                }
            }
            else {
                next();
            }
        }
        else {
            controller = Ni.controllers.home;
            if (controller && controller.index) {
                res.Ni.controller = 'home';
                res.Ni.action = 'index';
                controller.index(req, res, next);
            }
            else {
                next();
            }
        }
    }

    this.view = function (renderer) {
      if (typeof(renderer) === 'function') {
        Ni.automatic_views = true;
        return function (req, res, next) {
          if (res.Ni.view && typeof(res.Ni.action) !== 'undefined') {
            renderer(req, res, next, res.Ni.controller + '/' + res.Ni.action);
          } else {
            next();
          }
        }
      } else {
        throw new Error('Ni.view expects a function as the first argument');
      }
    }
};

/* Helper functions
*******************************************************************************/

/*
 *  Loads controllers.
 */

function bootStrapControllers(__root, callback) {
    bootStrapModules(__root + '/controllers', function(err, controllers) {
        if (err) throw err;
        callback(null, controllers);
    });
}

/*
 *  Loads models.
 */

function bootStrapModels(__root, callback) {
    bootStrapModules(__root + '/models', function(err, models) {
        if (err) throw err;
        callback(null, models);
    });
}

/*
 *  Loads views.
 */

function bootStrapViews(__root, callback) {
    var __views = __root + '/views';
    var views = {};

    loadFilesFromDir(__views, function(dir, file, name) {
        var view = {};
        view.path = dir + '/' + file;
        fs.readFile(view.path, 'utf-8', function(err, data) {
            view.template = data;
            views[name] = view;
        });
    }, function(err) {
        if (err) throw err;
        callback(null, views);
    });
}

/*
 *  Loads libraries.
 */

function bootStrapLibraries(__root, callback) {
    bootStrapModules(__root + '/libraries', function(err, libraries) {
        if (err) throw err;
        callback(null, libraries);
    });
}

/*
 *  Loads anything that is represented as a Node.js module.
 *  This includes controllers, models, libraries and helpers.
 */

function bootStrapModules(__root, callback) {
    var __modules = __root;
    var modules = {};

    loadFilesFromDir(__modules, function(dir, file, name) {
        var name = file.split('.')[0];
        modules[name] = require(dir + '/' + file);
    }, function(err) {
        if (err) callback(err);
        else callback(null, modules);
    });
}

/*
 *  Loads files from given directory and calls the given function on them.
 */

function loadFilesFromDir(dir, fnOnFile, callbackDone) {
    fs.readdir(dir, function(err, files){
        if (err || !files) callbackDone(null);
        else {
            Step(
                function readFiles() {
                    if (files.length > 0) {
                        var group = this.group();
                        files.forEach(function (file){
                            var name = file.split('.')[0];

                            fnOnFile(dir, file, name);
                            group()();
                        });
                    }
                    else {
                        return null;
                    }
                },
                function finish(err) {
                    if (err) callbackDone(err);
                    callbackDone(null);
                }
            );
        }
    });
}

/*
 *  Exports the Ni object to Node.js.
 */

module.exports = new Ni();<commit_msg>Added __init controller actions<commit_after>/*
 *  Ni - a minimalistic Node framework that makes setting up an MVC project
 *  a breeze. Inspired by CodeIgniter.
 *
 *  Since Ni is fully contained in a Node module, you can use it with Connect
 *  and your own choice of template engine, database, static file server, etc.
 *  No frills, no restrictions, no worries.
 */

/*
 *  Module dependencies
 */

var fs = require('fs'),
    Step = require('step');

/*
 *  Ni object
 */

var Ni = function() {
    var Ni = this;

    /*
     *  Registry for custom configuration variables.
     */

    this.config = {};

    this.automatic_views = false;

    /*
     *  Tells Ni what root directory to look into.
     *
     *  Call this function before calling boot.
     */

    this.setRoot = function(__root) {
        this.__root = __root;
    }

    /*
     *  Loads controllers, models, views, templates and helpers from the root
     *  directory, and makes them all available to the Ni object.
     */

    this.boot = function(callbackDone) {
        Step(
                function bootStrapEverything() {
                    bootStrapControllers(Ni.__root, this.parallel());
                    bootStrapModels(Ni.__root, this.parallel());
                    bootStrapViews(Ni.__root, this.parallel());
                    bootStrapLibraries(Ni.__root, this.parallel());
                },
                function buildNi(err, controllers, models, views, libraries) {
                    if (err) throw err;
                    Ni.controllers = controllers;
                    Ni.models = models;
                    Ni.views = views;
                    Ni.libraries = libraries;
                    callbackDone();
                }
            );
    }

    /*
     *  Provides router for Connect to automatically call the correct controller
     *  functions with the correct arguments based on the URL. If the controller
     *  or action is not found, it calls next() in the Connect list.
     *
     *  Add this to your Connect call as: Ni.router
     */

    this.router = function(req, res, next) {
        var parsedUrl = require('url').parse(req.url, true),
        pathArr = parsedUrl.pathname.split('/'),
        args = pathArr.slice(3),
        controller,
        fn;

        res.Ni = { view: Ni.automatic_views };

        args.unshift(next);
        args.unshift(res);
        args.unshift(req);
        if (pathArr[1]) {
            controller = Ni.controllers[pathArr[1]];
            if (controller) {
                res.Ni.controller = pathArr[1];
                var fn;
                if (pathArr[2]) {
                    res.Ni.action = pathArr[2];
                    fn = controller[pathArr[2]];
                }
                else {
                    res.Ni.action = 'index';
                    fn = controller.index;
                }

                if (typeof(controller.__init) === 'function' && fn) {
                  args.unshift(function () {
                    args.shift();
                    fn.apply(null, args);
                  });
                  controller.__init.apply(null, args);
                } else if (fn) {
                    fn.apply(null, args);
                }
                else {
                    res.Ni.controller = undefined;
                    res.Ni.action = undefined;
                    next();
                }
            }
            else {
                next();
            }
        }
        else {
            controller = Ni.controllers.home;
            if (controller && controller.index) {
                res.Ni.controller = 'home';
                res.Ni.action = 'index';
                if (typeof(controller.__init) === 'function') {
                  controller.__init(req, res, next, {}, function () {
                    controller.index(req, res, next);
                  });
                } else {
                  controller.index(req, res, next);
                }
            }
            else {
                next();
            }
        }
    }

    this.view = function (renderer) {
      if (typeof(renderer) === 'function') {
        Ni.automatic_views = true;
        return function (req, res, next) {
          if (res.Ni.view && typeof(res.Ni.action) !== 'undefined') {
            renderer(req, res, next, res.Ni.controller + '/' + res.Ni.action);
          } else {
            next();
          }
        }
      } else {
        throw new Error('Ni.view expects a function as the first argument');
      }
    }
};

/* Helper functions
*******************************************************************************/

/*
 *  Loads controllers.
 */

function bootStrapControllers(__root, callback) {
    bootStrapModules(__root + '/controllers', function(err, controllers) {
        if (err) throw err;
        callback(null, controllers);
    });
}

/*
 *  Loads models.
 */

function bootStrapModels(__root, callback) {
    bootStrapModules(__root + '/models', function(err, models) {
        if (err) throw err;
        callback(null, models);
    });
}

/*
 *  Loads views.
 */

function bootStrapViews(__root, callback) {
    var __views = __root + '/views';
    var views = {};

    loadFilesFromDir(__views, function(dir, file, name) {
        var view = {};
        view.path = dir + '/' + file;
        fs.readFile(view.path, 'utf-8', function(err, data) {
            view.template = data;
            views[name] = view;
        });
    }, function(err) {
        if (err) throw err;
        callback(null, views);
    });
}

/*
 *  Loads libraries.
 */

function bootStrapLibraries(__root, callback) {
    bootStrapModules(__root + '/libraries', function(err, libraries) {
        if (err) throw err;
        callback(null, libraries);
    });
}

/*
 *  Loads anything that is represented as a Node.js module.
 *  This includes controllers, models, libraries and helpers.
 */

function bootStrapModules(__root, callback) {
    var __modules = __root;
    var modules = {};

    loadFilesFromDir(__modules, function(dir, file, name) {
        var name = file.split('.')[0];
        modules[name] = require(dir + '/' + file);
    }, function(err) {
        if (err) callback(err);
        else callback(null, modules);
    });
}

/*
 *  Loads files from given directory and calls the given function on them.
 */

function loadFilesFromDir(dir, fnOnFile, callbackDone) {
    fs.readdir(dir, function(err, files){
        if (err || !files) callbackDone(null);
        else {
            Step(
                function readFiles() {
                    if (files.length > 0) {
                        var group = this.group();
                        files.forEach(function (file){
                            var name = file.split('.')[0];

                            fnOnFile(dir, file, name);
                            group()();
                        });
                    }
                    else {
                        return null;
                    }
                },
                function finish(err) {
                    if (err) callbackDone(err);
                    callbackDone(null);
                }
            );
        }
    });
}

/*
 *  Exports the Ni object to Node.js.
 */

module.exports = new Ni();<|endoftext|>


<commit_before>var request = require('request');

exports.defaultRegion = 'us';
exports.key = null;

// Makes request
function get(options, callback) {

    options.region = options.region || exports.defaultRegion;
    options.query = options.query || '';

    if (exports.key) {
        options.query = 'app=' + exports.key + '&' + options.query;
    }

    var uri = encodeURI('http://' + options.region + '.battle.net/api/wow/' +
        options.path + '?' + options.query);

    request({
        uri: uri,
        headers: { 'Connection': 'keep-alive' }

    }, function(err, res, body) {
        if (err) {
            callback(err);
        }

        try {
            body = JSON.parse(body);
        } catch (e) {
            return callback(e);
        }

        if (body.status) {
            return callback(new Error(body.reason));
        }

        callback(null, body);
    });
}

// Requests one or more API resources
function resource(method, options, callback) {

    var names;

    if (typeof options === 'string') {
        names = options;
        options = {};
    } else {
        names = options.names;
        delete options.names;
    }

    if (Array.isArray(options.fields)) {
        options.query = 'fields=' + options.fields.join(',');
        delete options.fields;
    }

    options.path = [method, options.realm, options.size];

    delete options.realm;
    delete options.size;

    var parse = function(name) {

        var parseOptions = {
            path: options.path.slice(0),
            query: options.query,
            region: options.region
        };

        if (name.indexOf('_') !== -1) {

            name = name.split('_').reverse();

            parseOptions.path.push(name.pop());

            if (name[0] && name[0].length > 3) {
                parseOptions.path[1] = name.shift();
            }

            if (name[0] && name[0].length === 3) {
                parseOptions.path[2] = name.shift();
            }

        } else {
            parseOptions.path.push(name);
        }

        parseOptions.path = parseOptions.path.filter(function(el) {
            return !!el;
        }).join('/');

        get(parseOptions, callback);
    };

    if (Array.isArray(names)) {
        names.forEach(parse);
    } else {
        parse(names);
    }
}

// Provides realm status information
exports.realmStatus = function() {

    var args = Array.prototype.slice.call(arguments),
        callback = args.pop(),
        options = { path: 'realm/status' };

    if (Array.isArray(args[0])) {
        args[0] = args[0].join('&realm=');
    }

    if (args[0] && args[0].length > 2) {
        options.query = 'realm=' + args.shift();
    }

    if (args[0] && args[0].length === 2) {
        options.region = args[0];
    }

    get(options, function(err, response) {
        if (err) {
            return callback(err);
        }

        callback(null, response.realms);
    });
};

// Exports resource API using generic function
['character', 'guild', 'arena'].forEach(function(method) {
    exports[method] = function(options, callback) {
        resource(method, options, callback);
    };
});
<commit_msg>Handling missing arguments.<commit_after>var request = require('request');

exports.defaultRegion = 'us';
exports.key = null;

// Makes request
function get(options, callback) {

    options.region = options.region || exports.defaultRegion;
    options.query = options.query || '';

    if (exports.key) {
        options.query = 'app=' + exports.key + '&' + options.query;
    }

    var uri = encodeURI('http://' + options.region + '.battle.net/api/wow/' +
        options.path + '?' + options.query);

    request({
        uri: uri,
        headers: { 'Connection': 'keep-alive' }

    }, function(err, res, body) {
        if (err) {
            callback(err);
        }

        try {
            body = JSON.parse(body);
        } catch (e) {
            return callback(e);
        }

        if (body.status) {
            return callback(new Error(body.reason));
        }

        callback(null, body);
    });
}

// Requests one or more API resources
function resource(method, options, callback) {

    var names;

    callback = typeof callback === 'function' ? callback : function() {};

    if (typeof options === 'string') {
        names = options;
        options = {};
    } else if (options.names) {
        names = options.names;
        delete options.names;
    } else {
        return callback(new Error('No character name(s) provided'));
    }

    if (Array.isArray(options.fields)) {
        options.query = 'fields=' + options.fields.join(',');
        delete options.fields;
    }

    options.path = [method, options.realm, options.size];

    delete options.realm;
    delete options.size;

    var parse = function(name) {

        var parseOptions = {
            path: options.path.slice(0),
            query: options.query,
            region: options.region
        };

        if (name.indexOf('_') !== -1) {

            name = name.split('_').reverse();

            parseOptions.path.push(name.pop());

            if (name[0] && name[0].length > 3) {
                parseOptions.path[1] = name.shift();
            }

            if (name[0] && name[0].length === 3) {
                parseOptions.path[2] = name.shift();
            }

        } else {
            parseOptions.path.push(name);
        }

        parseOptions.path = parseOptions.path.filter(function(el) {
            return !!el;
        }).join('/');

        get(parseOptions, callback);
    };

    if (Array.isArray(names)) {
        names.forEach(parse);
    } else {
        parse(names);
    }
}

// Provides realm status information
exports.realmStatus = function() {

    var args = Array.prototype.slice.call(arguments),
        callback = args.pop(),
        options = { path: 'realm/status' };

    callback = typeof callback === 'function' ? callback : function() {};

    if (Array.isArray(args[0])) {
        args[0] = args[0].join('&realm=');
    }

    if (args[0] && args[0].length > 2) {
        options.query = 'realm=' + args.shift();
    }

    if (args[0] && args[0].length === 2) {
        options.region = args[0];
    }

    get(options, function(err, response) {
        if (err) {
            return callback(err);
        }

        callback(null, response.realms);
    });
};

// Exports resource API using generic function
['character', 'guild', 'arena'].forEach(function(method) {
    exports[method] = function(options, callback) {
        resource(method, options, callback);
    };
});
<|endoftext|>


<commit_before>/*
 * logs.js: Commands related to user resources
 *
 * (C) 2010, Nodejitsu Inc.
 *
 */

var jitsu = require('../../jitsu'),
    dateformat = require('dateformat'),
    logs = exports,
    utile = jitsu.common;

logs.usage = [
  'The `jitsu logs` command will display logs related to the app',
  'The default number of lines to show is 10',
  '',
  'Example usages:',
  'jitsu logs all',
  'jitsu logs all <number of lines to show>',
  'jitsu logs app <app name>',
  'jitsu logs app <app name> <number of lines to show>'
];

//
// ### function all (callback)
// #### @callback {function} Continuation to pass control to when complete.
// Queries the log API and retrieves the logs for all of the user's apps
//
logs.all = function (amount, callback) {
  //
  // Allows arbitrary amount of arguments
  //
  if(arguments.length) {
    var args = utile.args(arguments);
    callback = args.callback;
    amount  = args[0] || null;
  }

  if (!amount) {
    amount = 10;
  }

  jitsu.logs.byUser(jitsu.config.get('username'), amount, function (err, apps) {
    if (err) {
      return callback(err);
    }

    if (apps.length === 0) {
      jitsu.log.warn('No logs for ' + jitsu.config.get('username').magenta + ' from timespan');
      return callback();
    }

    function sortLength (lname, rname) {
      var llength = apps[lname].data.length,
          rlength = apps[rname].data.length;

      if (llength === rlength) {
        return 0;
      }

      return llength > rlength ? 1 : -1;
    }

    Object.keys(apps).sort(sortLength).forEach(function (app) {
      putLogs(apps[app], app, amount, true);
    });

    callback();
  });
};

logs.all.usage = [
  'Print the logs from all applications. The default number of',
  'lines to show is 10.',
  'jits logs all <number of lines to show>',
  '',
  'Example usage:',
  'jitsu logs all',
  'jitsu logs all 5'
];

//
// ### function app (appName, callback)
// #### @appName {string} the application to get the logs for
// #### @callback {function} Continuation to pass control to when complete.
// Queries the log API and retrieves the logs for the specified application
//
logs.app = function (appName, amount, callback) {
  //
  // This is defined so that it can get called once all the arguments are
  // sorted out.
  //

  //
  // Allows arbitrary amount of arguments
  //
  if(arguments.length) {
    var args = utile.args(arguments);
    callback = args.callback;
    appName  = args[0] || null;
    amount   = args[1] || null;
  }

  function byApp(appName, amount, callback) {
    jitsu.logs.byApp(appName, amount, function (err, results) {
      if (err) {
        return callback(err);
      }

      jitsu.log.info('Listing logs for ' + appName.magenta);
      putLogs(results, appName, amount);
      callback();
    });
  }

  function getAppName(callback) {
    jitsu.package.read(process.cwd(), function (err, pkg) {
      if (!err) {
        jitsu.log.info('Attempting to load logs for ' + (process.cwd()+ '/package.json').grey);
        return callback(null, pkg.name);
      }
      callback(err);
    });
  }

  amount = amount || 100;

  if (!appName) {
    getAppName(function (err, name) {
      if (err) {
        jitsu.commands.list(function(){
          jitsu.log.info('Which application to view ' + 'logs'.magenta + ' for?');
          jitsu.prompt.get(["app name"], function (err, result) {
            if (err) {
              jitsu.log.error('Prompt error:');
              return callback(err);
            }
            appName = result["app name"];
            byApp(appName, amount, callback);
          });
        })
      } else {
        byApp(name, amount, callback);
      }
    });
  } else {
     byApp(appName, amount, callback);
  }

}

logs.app.usage = [
  'Print the logs from specified application. The default number of',
  'lines to show is 10.',
  'jits logs app <app name> <number of lines to show>',
  '',
  'Example usage:',
  'jitsu logs app test',
  'jitsu logs app test 40'
];

//
// ### function putLogs (results, appName, amount, showApp)
// #### @results {Object} Logs object to output.
// #### @appName {string} App name associated with the log text.
// #### @showApp {boolean} Value indicating if the app name should be output.
// Parses, formats, and outputs the specified `results` to the user.
//
function putLogs (results, appName, amount, showApp) { //TODO: utilize amount and showApp
  //
  // Allows arbitrary amount of arguments
  //
  if(arguments.length) {
    var args = utile.args(arguments);
    results  = args[0] || null;
    appName  = args[1] || null;
    amount   = args[2] || null;
    showApp  = args[3] || null;
  }

  results.data = results.data.filter(function (item) {
    return item.json && item.json.hasOwnProperty('message');
  });

  if (results.data.length === 0) {
    return jitsu.log.warn('No logs for ' + appName.magenta + ' in specified timespan');
  }

  var logLength = jitsu.config.get('loglength'),
      logged = 0;

  function sort(first, second) {
    return new Date(second.timestamp) - new Date(first.timestamp);
  }

  results.data.sort(sort).forEach(function (datum) {
    if (datum.json && datum.json.message != null) {
      // '[' + datum.json.app.magenta + ']
      datum.json.message.split('\n').forEach(function (line) {
        var now = new Date(datum.timestamp);
        now = dateformat(now, "mm/dd HH:MM:ss Z");
        if (line.length) {
          console.log('[' + now.toString().yellow + '] ' + line);
        }
      });
    }
  });
}
<commit_msg>[feature] app header<commit_after>/*
 * logs.js: Commands related to user resources
 *
 * (C) 2010, Nodejitsu Inc.
 *
 */

var jitsu = require('../../jitsu'),
    dateformat = require('dateformat'),
    logs = exports,
    utile = jitsu.common;

logs.usage = [
  'The `jitsu logs` command will display logs related to the app',
  'The default number of lines to show is 10',
  '',
  'Example usages:',
  'jitsu logs all',
  'jitsu logs all <number of lines to show>',
  'jitsu logs app <app name>',
  'jitsu logs app <app name> <number of lines to show>'
];

//
// ### function all (callback)
// #### @callback {function} Continuation to pass control to when complete.
// Queries the log API and retrieves the logs for all of the user's apps
//
logs.all = function (amount, callback) {
  //
  // Allows arbitrary amount of arguments
  //
  if(arguments.length) {
    var args = utile.args(arguments);
    callback = args.callback;
    amount  = args[0] || null;
  }

  if (!amount) {
    amount = 10;
  }

  jitsu.logs.byUser(jitsu.config.get('username'), amount, function (err, apps) {
    if (err) {
      return callback(err);
    }

    if (apps.length === 0) {
      jitsu.log.warn('No logs for ' + jitsu.config.get('username').magenta + ' from timespan');
      return callback();
    }

    function sortLength (lname, rname) {
      var llength = apps[lname].data.length,
          rlength = apps[rname].data.length;

      if (llength === rlength) {
        return 0;
      }

      return llength > rlength ? 1 : -1;
    }

    Object.keys(apps).sort(sortLength).forEach(function (app) {
      console.log('App: '.yellow + app);
      putLogs(apps[app], app, amount, true);
    });

    callback();
  });
};

logs.all.usage = [
  'Print the logs from all applications. The default number of',
  'lines to show is 10.',
  'jits logs all <number of lines to show>',
  '',
  'Example usage:',
  'jitsu logs all',
  'jitsu logs all 5'
];

//
// ### function app (appName, callback)
// #### @appName {string} the application to get the logs for
// #### @callback {function} Continuation to pass control to when complete.
// Queries the log API and retrieves the logs for the specified application
//
logs.app = function (appName, amount, callback) {
  //
  // This is defined so that it can get called once all the arguments are
  // sorted out.
  //

  //
  // Allows arbitrary amount of arguments
  //
  if(arguments.length) {
    var args = utile.args(arguments);
    callback = args.callback;
    appName  = args[0] || null;
    amount   = args[1] || null;
  }

  function byApp(appName, amount, callback) {
    jitsu.logs.byApp(appName, amount, function (err, results) {
      if (err) {
        return callback(err);
      }

      jitsu.log.info('Listing logs for ' + appName.magenta);
      putLogs(results, appName, amount);
      callback();
    });
  }

  function getAppName(callback) {
    jitsu.package.read(process.cwd(), function (err, pkg) {
      if (!err) {
        jitsu.log.info('Attempting to load logs for ' + (process.cwd()+ '/package.json').grey);
        return callback(null, pkg.name);
      }
      callback(err);
    });
  }

  amount = amount || 100;

  if (!appName) {
    getAppName(function (err, name) {
      if (err) {
        jitsu.commands.list(function(){
          jitsu.log.info('Which application to view ' + 'logs'.magenta + ' for?');
          jitsu.prompt.get(["app name"], function (err, result) {
            if (err) {
              jitsu.log.error('Prompt error:');
              return callback(err);
            }
            appName = result["app name"];
            byApp(appName, amount, callback);
          });
        })
      } else {
        byApp(name, amount, callback);
      }
    });
  } else {
     byApp(appName, amount, callback);
  }

}

logs.app.usage = [
  'Print the logs from specified application. The default number of',
  'lines to show is 10.',
  'jits logs app <app name> <number of lines to show>',
  '',
  'Example usage:',
  'jitsu logs app test',
  'jitsu logs app test 40'
];

//
// ### function putLogs (results, appName, amount, showApp)
// #### @results {Object} Logs object to output.
// #### @appName {string} App name associated with the log text.
// #### @showApp {boolean} Value indicating if the app name should be output.
// Parses, formats, and outputs the specified `results` to the user.
//
function putLogs (results, appName, amount, showApp) { //TODO: utilize amount and showApp
  //
  // Allows arbitrary amount of arguments
  //
  if(arguments.length) {
    var args = utile.args(arguments);
    results  = args[0] || null;
    appName  = args[1] || null;
    amount   = args[2] || null;
    showApp  = args[3] || null;
  }

  results.data = results.data.filter(function (item) {
    return item.json && item.json.hasOwnProperty('message');
  });

  if (results.data.length === 0) {
    return jitsu.log.warn('No logs for ' + appName.magenta + ' in specified timespan');
  }

  var logLength = jitsu.config.get('loglength'),
      logged = 0;

  function sort(first, second) {
    return new Date(second.timestamp) - new Date(first.timestamp);
  }

  results.data.sort(sort).forEach(function (datum) {
    if (datum.json && datum.json.message != null) {
      // '[' + datum.json.app.magenta + ']
      datum.json.message.split('\n').forEach(function (line) {
        var now = new Date(datum.timestamp);
        now = dateformat(now, "mm/dd HH:MM:ss Z");
        if (line.length) {
          console.log('[' + now.toString().yellow + '] ' + line);
        }
      });
    }
  });
}
<|endoftext|>


<commit_before>'use strict'; // eslint-disable-line strict

const writeOptions = { sync: true };

/**
 * Like Error, but with a property set to true.
 * TODO: this is copied from kineticlib, should consolidate with the
 * future errors module
 *
 * Example: instead of:
 *     const err = new Error("input is not a buffer");
 *     err.badTypeInput = true;
 *     throw err;
 * use:
 *     throw propError("badTypeInput", "input is not a buffer");
 *
 * @param {String} propName - the property name.
 * @param {String} message - the Error message.
 * @returns {Error} the Error object.
 */
function propError(propName, message) {
    const err = new Error(message);
    err[propName] = true;
    return err;
}

/**
 * Running transaction with multiple updates to be committed atomically
 */
class IndexTransaction {
    /**
     * Builds a new transaction
     *
     * @argument {Leveldb} db an open database to which the updates
     *                     will be applied
     *
     * @returns {IndexTransaction} a new empty transaction
     */
    constructor(db) {
        this.operations = [];
        this.db = db;
        this.closed = false;
    }

    /**
     * Adds a new operation to participate in this running transaction
     *
     * @argument {object} op an object with the following attributes:
     *                    {
     *                      type: 'put' or 'del',
     *                      key: the object key,
     *                      value: (optional for del) the value to store,
     *                    }
     *
     * @throws {Error} an error described by the following properties
     *                 - invalidTransactionVerb if op is not put or del
     *                 - pushOnCommittedTransaction if already committed
     *                 - missingKey if the key is missing from the op
     *                 - missingValue if putting without a value
     *
     * @returns {undefined}
     */
    push(op) {
        if (this.closed) {
            throw propError('pushOnCommittedTransaction',
                            'can not add ops to already committed transaction');
        }

        if (op.type !== 'put' && op.type !== 'del') {
            throw propError('invalidTransactionVerb',
                            `unknown action type: ${op.type}`);
        }

        if (op.key === undefined) {
            throw propError('missingKey', 'missing key');
        }

        if (op.type === 'put' && op.value === undefined) {
            throw propError('missingValue', 'missing value');
        }

        this.operations.push(op);
    }

    /**
     * Adds a new put operation to this running transaction
     *
     * @argument {string} key - the key of the object to put
     * @argument {string} value - the value to put
     *
     * @throws {Error} an error described by the following properties
     *                 - pushOnCommittedTransaction if already committed
     *                 - missingKey if the key is missing from the op
     *                 - missingValue if putting without a value
     *
     * @returns {undefined}
     *
     * @see push
     */
    put(key, value) {
        this.push({ type: 'put', key, value, });
    }

    /**
     * Adds a new del operation to this running transaction
     *
     * @argument {string} key - the key of the object to delete
     *
     * @throws {Error} an error described by the following properties
     *                 - pushOnCommittedTransaction if already committed
     *                 - missingKey if the key is missing from the op
     *
     * @returns {undefined}
     *
     * @see push
     */
    del(key) {
        this.push({ type: 'del', key, });
    }

    /**
     * Applies the queued updates in this transaction atomically.
     *
     * @argument {function} cb function to be called when the commit
     *              finishes, taking an optional error argument
     *
     * @returns {undefined}
     */
    commit(cb) {
        if (this.closed) {
            return cb(propError('alreadyCommitted',
                                'transaction was already committed'));
        }

        if (this.operations.length === 0) {
            return cb(propError('emptyTransaction',
                                'tried to commit an empty transaction'));
        }

        this.closed = true;

        // The array-of-operations variant of the `batch` method
        // allows passing options such has `sync: true` whereas the
        // chained form does not.
        this.db.batch(this.operations, writeOptions, cb);
    }
}

module.exports = {
    IndexTransaction,
};
<commit_msg>(db) clean trailing commas<commit_after>'use strict'; // eslint-disable-line strict

const writeOptions = { sync: true };

/**
 * Like Error, but with a property set to true.
 * TODO: this is copied from kineticlib, should consolidate with the
 * future errors module
 *
 * Example: instead of:
 *     const err = new Error("input is not a buffer");
 *     err.badTypeInput = true;
 *     throw err;
 * use:
 *     throw propError("badTypeInput", "input is not a buffer");
 *
 * @param {String} propName - the property name.
 * @param {String} message - the Error message.
 * @returns {Error} the Error object.
 */
function propError(propName, message) {
    const err = new Error(message);
    err[propName] = true;
    return err;
}

/**
 * Running transaction with multiple updates to be committed atomically
 */
class IndexTransaction {
    /**
     * Builds a new transaction
     *
     * @argument {Leveldb} db an open database to which the updates
     *                     will be applied
     *
     * @returns {IndexTransaction} a new empty transaction
     */
    constructor(db) {
        this.operations = [];
        this.db = db;
        this.closed = false;
    }

    /**
     * Adds a new operation to participate in this running transaction
     *
     * @argument {object} op an object with the following attributes:
     *                    {
     *                      type: 'put' or 'del',
     *                      key: the object key,
     *                      value: (optional for del) the value to store,
     *                    }
     *
     * @throws {Error} an error described by the following properties
     *                 - invalidTransactionVerb if op is not put or del
     *                 - pushOnCommittedTransaction if already committed
     *                 - missingKey if the key is missing from the op
     *                 - missingValue if putting without a value
     *
     * @returns {undefined}
     */
    push(op) {
        if (this.closed) {
            throw propError('pushOnCommittedTransaction',
                            'can not add ops to already committed transaction');
        }

        if (op.type !== 'put' && op.type !== 'del') {
            throw propError('invalidTransactionVerb',
                            `unknown action type: ${op.type}`);
        }

        if (op.key === undefined) {
            throw propError('missingKey', 'missing key');
        }

        if (op.type === 'put' && op.value === undefined) {
            throw propError('missingValue', 'missing value');
        }

        this.operations.push(op);
    }

    /**
     * Adds a new put operation to this running transaction
     *
     * @argument {string} key - the key of the object to put
     * @argument {string} value - the value to put
     *
     * @throws {Error} an error described by the following properties
     *                 - pushOnCommittedTransaction if already committed
     *                 - missingKey if the key is missing from the op
     *                 - missingValue if putting without a value
     *
     * @returns {undefined}
     *
     * @see push
     */
    put(key, value) {
        this.push({ type: 'put', key, value });
    }

    /**
     * Adds a new del operation to this running transaction
     *
     * @argument {string} key - the key of the object to delete
     *
     * @throws {Error} an error described by the following properties
     *                 - pushOnCommittedTransaction if already committed
     *                 - missingKey if the key is missing from the op
     *
     * @returns {undefined}
     *
     * @see push
     */
    del(key) {
        this.push({ type: 'del', key });
    }

    /**
     * Applies the queued updates in this transaction atomically.
     *
     * @argument {function} cb function to be called when the commit
     *              finishes, taking an optional error argument
     *
     * @returns {undefined}
     */
    commit(cb) {
        if (this.closed) {
            return cb(propError('alreadyCommitted',
                                'transaction was already committed'));
        }

        if (this.operations.length === 0) {
            return cb(propError('emptyTransaction',
                                'tried to commit an empty transaction'));
        }

        this.closed = true;

        // The array-of-operations variant of the `batch` method
        // allows passing options such has `sync: true` whereas the
        // chained form does not.
        this.db.batch(this.operations, writeOptions, cb);
    }
}

module.exports = {
    IndexTransaction,
};
<|endoftext|>


<commit_before>// Library for talk with owserver
// Usage:
// var ownet = require("./lib/ow");
// var owserver = new ownet.owserver('owserver.host',owserver.port);
// owserver.ls('/', function(data){ console.log(data) });
// owserver.read('/28.97CA2E020000/temperature10', function(data){ console.log(data) });
// owserver.write('/3A.C64F07000000/PIO.A', 0, function(data){ console.log(data) });
//

var net, ntohl, htonl;
net = require('net');
ntohl = require('network-byte-order').ntohl;
htonl = require('network-byte-order').htonl;

// owserver message types
var OW_READ, OW_WRITE, OW_DIR, OW_DIRALL, OW_GET;
OW_READ = 2;
OW_WRITE = 3;
OW_DIR = 4;
OW_DIRALL = 7;
OW_GET = 8;

// owserver header structure
var owserver_header_struct, owserver_header_lenght;
owserver_header_struct = ['version', 'payload', 'type', 'control_flag', 'size', 'offset'];
owserver_header_lenght = 24;

exports.owserver = function (server, port){
    server = server != null ? server : 'localhost';
    port = port != null ? port : 4304;

    this.request = function(path, type, value, callback){
        var message = [];
        var socket = new net.Socket({ type: 'tcp4'});

        socket.on('error', function(error){
            console.log(error.toString('utf8'));
        });

        socket.on('end', function(){
            if (callback && typeof(callback) === "function"){
                callback(message);
            }
        });

        socket.on('data', function(data) {
            var header, payload, i;
            header = {};
            for(i = 0; i < owserver_header_struct.length; i++ ){
                header[owserver_header_struct[i]] = ntohl(data.slice(i * 4), 0);
            }
            payload = data.slice(owserver_header_lenght).toString('utf8');
            message.push({
                header: header,
                payload: payload
            });
        });

        socket.connect(port, server, function(){
            path += '\x00';
            value = (type == OW_WRITE) ? value.toString() + '\x00' : '';
            var buffer = new Buffer(path.length + value.length + owserver_header_lenght);
            htonl(buffer, 0, 0);
            htonl(buffer, 4, path.length + value.length);
            htonl(buffer, 8, type);
            htonl(buffer, 12, 0x00000020);
            htonl(buffer, 16, value.length ? value.length : 8192);
            htonl(buffer, 20, 0);
            buffer.write(path + value, owserver_header_lenght);
            return socket.end(buffer);
        });
    };

    this.ls = function(path, callback){
        this.request(path, OW_DIRALL, 0, function(data){
            data = (data[data.length - 1].payload.replace(new RegExp("[\u0000-\u001F]", "g"), "").split(","));
            callback(data);
         });
     };

    this.read = function(path, callback){
        this.request(path, OW_READ, 0, function(data){
            data = (data[data.length - 1].payload.replace(new RegExp("[\u0000-\u001F]", "g"), "").replace(new RegExp(" ", "g"), ""));
            callback(data);
        });
    };

    this.write = function(path, value, callback){
        this.request(path, OW_WRITE, value, function(data){
            data = (data[data.length - 1].header.type);
            callback(data);
        });
    };

};
<commit_msg>v0.0.2<commit_after>// I use code part from vkfont/owjs and benediktarnold/owfs libraries.
// Library for talk with owserver
// Usage:
// var ownet = require("./lib/ow");
// var owserver = new ownet.owserver('owserver.host',owserver.port);
// owserver.ls('/', function(data){ console.log(data) });
// owserver.read('/28.97CA2E020000/temperature10', function(data){ console.log(data) });
// owserver.write('/3A.C64F07000000/PIO.A', 0, function(data){ console.log(data) });
//

var net, ntohl, htonl;
net = require('net');
ntohl = require('network-byte-order').ntohl;
htonl = require('network-byte-order').htonl;

// owserver message types
var OW_READ, OW_WRITE, OW_DIR, OW_DIRALL, OW_GET;
OW_READ = 2;
OW_WRITE = 3;
OW_DIR = 4;
OW_DIRALL = 7;
OW_GET = 8;

// owserver header structure
var owserver_header_struct, owserver_header_lenght;
owserver_header_struct = ['version', 'payload', 'type', 'control_flag', 'size', 'offset'];
owserver_header_lenght = 24;

exports.owserver = function (server, port){
    server = server != null ? server : 'localhost';
    port = port != null ? port : 4304;

    this.request = function(path, type, value, callback){
        var message = [];
        var socket = new net.Socket({ type: 'tcp4'});

        socket.on('error', function(error){
            console.log(error.toString('utf8'));
        });

        socket.on('end', function(){
            if (callback && typeof(callback) === "function"){
                callback(message);
            }
        });

        socket.on('data', function(data) {
            var header, payload, i;
            header = {};
            for(i = 0; i < owserver_header_struct.length; i++ ){
                header[owserver_header_struct[i]] = ntohl(data.slice(i * 4), 0);
            }
            payload = data.slice(owserver_header_lenght).toString('utf8');
            message.push({
                header: header,
                payload: payload
            });
        });

        socket.connect(port, server, function(){
            path += '\x00';
            value = (type == OW_WRITE) ? value.toString() + '\x00' : '';
            var buffer = new Buffer(path.length + value.length + owserver_header_lenght);
            htonl(buffer, 0, 0);
            htonl(buffer, 4, path.length + value.length);
            htonl(buffer, 8, type);
            htonl(buffer, 12, 0x00000020);
            htonl(buffer, 16, value.length ? value.length : 8192);
            htonl(buffer, 20, 0);
            buffer.write(path + value, owserver_header_lenght);
            return socket.end(buffer);
        });
    };

    this.ls = function(path, callback){
        this.request(path, OW_DIRALL, 0, function(data){
            data = (data[data.length - 1].payload.replace(new RegExp("[\u0000-\u001F]", "g"), "").split(","));
            callback(data);
         });
     };

    this.read = function(path, callback){
        this.request(path, OW_READ, 0, function(data){
            data = (data[data.length - 1].payload.replace(new RegExp("[\u0000-\u001F]", "g"), "").replace(new RegExp(" ", "g"), ""));
            callback(data);
        });
    };

    this.write = function(path, value, callback){
        this.request(path, OW_WRITE, value, function(data){
            data = (data[data.length - 1].header.type);
            callback(data);
        });
    };

};
<|endoftext|>


<commit_before>'use strict';

var traverse = require('traverse');
var ObjectID = require('mongodb').ObjectID;

var TWO_DAYS = 172800000;
/**
 * @module query utilities
 * Assist in translating objects from query-string representation into
 * mongo-style queries by performing type translation.
 */

/**
  * Options for query.
  * Interpret and return the options to use for building our query.
  *
  * @returns {Object} Options for create, below.
```
  * { deltaAgo: <ms> // ms ago to constrain queries missing any query body
    , dateField: "date" // name of field to ensure there is a valid query body
    , walker: <walker-spec> // a mapping of names to types
    }
```
  */
function default_options (opts) {
  opts = opts || { };
  if (opts) {
    var keys = [null].concat(Object.keys(opts));

    // default at least TWO_DAYS of data
    // TODO: discuss/consensus on right value/ENV?
    if (keys.indexOf('deltaAgo') < 1) {
      opts.deltaAgo = ( TWO_DAYS * 2 );
    }

    // default at `date` and `sgv` properties are both int-types.
    if (keys.indexOf('walker') < 1) {
      opts.walker = { date: parseInt, sgv: parseInt };
    }

    // The default field to constrain is called 'date' for entries module.
    // Allow other models/backends to use other fields names.
    opts.dateField = opts.dateField || 'date';
  }
  return opts;
}

/**
  * Enforce rule that says that the query must express some constraint on the
  * configured `dateField` or against the field named `dateString`.  If the
  * configured option `useEpoch` is set, the naive JS epoch is used, otherwise
  * ISO 8601 is used.  The rule ensures that records must have a date field
  * with a date and time greater than or equal to the configured `deltaAgo`
  * option, (`opts.deltaAgo`).
  */
function enforceDateFilter (query, opts) {
  var dateValue = query[opts.dateField];

  if (!dateValue && !query.dateString) {
    var minDate = Date.now( ) - opts.deltaAgo;
    query[opts.dateField] = {
      $gte: opts.useEpoch ? minDate : new Date(minDate).toISOString()
    };
  }
}

/**
  * Helper to set ObjectID type for `_id` queries.
  * Forces anything named `_id` to be the `ObjectID` type.
  */
function updateIdQuery (query) {
  if (query._id && query._id.length) {
    query._id = ObjectID(query._id);
  }
}

/**
  * @param QueryParams params Object returned by qs.parse or https://github.com/hapijs/qs
  * @param BuilderOpts opts Options for how to translate types.
  *
  * Allows performing logic described by a model's attributes.
  * Specifically, we try to ensure that all queries have some kind of query
  * body to filter the rows mongodb will spool.  The defaults, such as name and
  * representation of a date field can be configured via the `opts` passed in.
  *
  * @returns Object An object which can be passed to `mongodb.find( )`
  */
function create (params, opts) {
  // setup default options for what/how to do things
  opts = default_options(opts);
  // Build the iterator, pass it our initial params to et the results.
  var finder = walker(opts.walker)(params);
  // Get the final query to pass to mongodb.
  var query = finder && finder.find ? finder.find : { };

  // Ensure some kind of sane date constraint tied to an index is expressed in the query.
  enforceDateFilter(query, opts);
  // Help queries for _id.
  updateIdQuery(query);

  console.info('query:', query);
  // Ready for mongodb.find( ) and friends.
  return query;
}

/**
  * Configure a single iterator given a specification of named mapped to types.
  * @params Object spec A simple mapping of field names to function to create that type.
  *
  * Example spec: { sgv: parseInt }
  * @returns function Function will translate types expressed in query.
  */
function walker (spec) {
  // empty queue
  var fns = [ ];

  // for each key/value pair in the spec
  var keys = Object.keys(spec);
  keys.forEach(function config (prop) {
    var typer = spec[prop];
    // add function from walk_prop to the queue
    fns.push(walk_prop(prop, typer));
  });

  /**
    * Execute all configured mappings in single step.
    * @param Object obj QueryString object
    * @returns Object for mongodb queries, with fields set to appropriate type
        described by previous mapping.
    */
  function exec (obj) {
    var fn;
    // for each mapping in the queue
    while (fns.length > 0) {
      fn = fns.shift( );
      // do each mapping
      obj = fn(obj);
    }
    return obj;
  }
  // return a function that can execute the configured queue of translations
  return exec;
}

/**
  * Given a name and a type, return a function which will transform any value
  * on a leaf-node into that type.
  * @param String prop Property name to to translate.
  * @param function typer Function to convert to type, eg `parseInt`
  */
function walk_prop (prop, typer) {
  function iter (opts) {
    // This is specifically configured to match the `find` convention in our REST API.
    // Query parameters are the ones attached to the `find` object.
    if (opts && opts.find && opts.find[prop]) {
      if (typeof opts.find[prop] === 'string') {
        //simple string property, no need to traverse
        opts.find[prop] = typer(opts.find[prop]);
      } else {
        // Traverse any query elements associated with this property.
        traverse(opts.find[prop]).forEach(function (x) {
          // In Mongo queries, the leaf nodes are always the values to search for.
          // Ignore any interstitial arrays/objects to represent
          // greater-than-or-equal-to, etc.
          if (this.isLeaf) {
            // Leaf nodes should be converted to this type.
            this.update(typer(x));
          }
        });
      }
    }
    // Return opts after modifying in place.
    return opts;
  }
  return iter;
}

function parseRegEx (str) {
  var regtest = /\/(.*)\/(.*)/.exec(str);
  if (regtest) {
    return new RegExp(regtest[1],regtest[2]);
  }
  return str;
}

// attach helpers and utilities to main function for testing
walker.walk_prop = walk_prop;
create.walker = walker;
create.parseRegEx = parseRegEx;
create.default_options = default_options;

// expose module as single high level function
exports = module.exports = create;

<commit_msg>disable logging of queries<commit_after>'use strict';

var traverse = require('traverse');
var ObjectID = require('mongodb').ObjectID;

var TWO_DAYS = 172800000;
/**
 * @module query utilities
 * Assist in translating objects from query-string representation into
 * mongo-style queries by performing type translation.
 */

/**
  * Options for query.
  * Interpret and return the options to use for building our query.
  *
  * @returns {Object} Options for create, below.
```
  * { deltaAgo: <ms> // ms ago to constrain queries missing any query body
    , dateField: "date" // name of field to ensure there is a valid query body
    , walker: <walker-spec> // a mapping of names to types
    }
```
  */
function default_options (opts) {
  opts = opts || { };
  if (opts) {
    var keys = [null].concat(Object.keys(opts));

    // default at least TWO_DAYS of data
    // TODO: discuss/consensus on right value/ENV?
    if (keys.indexOf('deltaAgo') < 1) {
      opts.deltaAgo = ( TWO_DAYS * 2 );
    }

    // default at `date` and `sgv` properties are both int-types.
    if (keys.indexOf('walker') < 1) {
      opts.walker = { date: parseInt, sgv: parseInt };
    }

    // The default field to constrain is called 'date' for entries module.
    // Allow other models/backends to use other fields names.
    opts.dateField = opts.dateField || 'date';
  }
  return opts;
}

/**
  * Enforce rule that says that the query must express some constraint on the
  * configured `dateField` or against the field named `dateString`.  If the
  * configured option `useEpoch` is set, the naive JS epoch is used, otherwise
  * ISO 8601 is used.  The rule ensures that records must have a date field
  * with a date and time greater than or equal to the configured `deltaAgo`
  * option, (`opts.deltaAgo`).
  */
function enforceDateFilter (query, opts) {
  var dateValue = query[opts.dateField];

  if (!dateValue && !query.dateString) {
    var minDate = Date.now( ) - opts.deltaAgo;
    query[opts.dateField] = {
      $gte: opts.useEpoch ? minDate : new Date(minDate).toISOString()
    };
  }
}

/**
  * Helper to set ObjectID type for `_id` queries.
  * Forces anything named `_id` to be the `ObjectID` type.
  */
function updateIdQuery (query) {
  if (query._id && query._id.length) {
    query._id = ObjectID(query._id);
  }
}

/**
  * @param QueryParams params Object returned by qs.parse or https://github.com/hapijs/qs
  * @param BuilderOpts opts Options for how to translate types.
  *
  * Allows performing logic described by a model's attributes.
  * Specifically, we try to ensure that all queries have some kind of query
  * body to filter the rows mongodb will spool.  The defaults, such as name and
  * representation of a date field can be configured via the `opts` passed in.
  *
  * @returns Object An object which can be passed to `mongodb.find( )`
  */
function create (params, opts) {
  // setup default options for what/how to do things
  opts = default_options(opts);
  // Build the iterator, pass it our initial params to et the results.
  var finder = walker(opts.walker)(params);
  // Get the final query to pass to mongodb.
  var query = finder && finder.find ? finder.find : { };

  // Ensure some kind of sane date constraint tied to an index is expressed in the query.
  enforceDateFilter(query, opts);
  // Help queries for _id.
  updateIdQuery(query);

  //console.info('query:', query);
  // Ready for mongodb.find( ) and friends.
  return query;
}

/**
  * Configure a single iterator given a specification of named mapped to types.
  * @params Object spec A simple mapping of field names to function to create that type.
  *
  * Example spec: { sgv: parseInt }
  * @returns function Function will translate types expressed in query.
  */
function walker (spec) {
  // empty queue
  var fns = [ ];

  // for each key/value pair in the spec
  var keys = Object.keys(spec);
  keys.forEach(function config (prop) {
    var typer = spec[prop];
    // add function from walk_prop to the queue
    fns.push(walk_prop(prop, typer));
  });

  /**
    * Execute all configured mappings in single step.
    * @param Object obj QueryString object
    * @returns Object for mongodb queries, with fields set to appropriate type
        described by previous mapping.
    */
  function exec (obj) {
    var fn;
    // for each mapping in the queue
    while (fns.length > 0) {
      fn = fns.shift( );
      // do each mapping
      obj = fn(obj);
    }
    return obj;
  }
  // return a function that can execute the configured queue of translations
  return exec;
}

/**
  * Given a name and a type, return a function which will transform any value
  * on a leaf-node into that type.
  * @param String prop Property name to to translate.
  * @param function typer Function to convert to type, eg `parseInt`
  */
function walk_prop (prop, typer) {
  function iter (opts) {
    // This is specifically configured to match the `find` convention in our REST API.
    // Query parameters are the ones attached to the `find` object.
    if (opts && opts.find && opts.find[prop]) {
      if (typeof opts.find[prop] === 'string') {
        //simple string property, no need to traverse
        opts.find[prop] = typer(opts.find[prop]);
      } else {
        // Traverse any query elements associated with this property.
        traverse(opts.find[prop]).forEach(function (x) {
          // In Mongo queries, the leaf nodes are always the values to search for.
          // Ignore any interstitial arrays/objects to represent
          // greater-than-or-equal-to, etc.
          if (this.isLeaf) {
            // Leaf nodes should be converted to this type.
            this.update(typer(x));
          }
        });
      }
    }
    // Return opts after modifying in place.
    return opts;
  }
  return iter;
}

function parseRegEx (str) {
  var regtest = /\/(.*)\/(.*)/.exec(str);
  if (regtest) {
    return new RegExp(regtest[1],regtest[2]);
  }
  return str;
}

// attach helpers and utilities to main function for testing
walker.walk_prop = walk_prop;
create.walker = walker;
create.parseRegEx = parseRegEx;
create.default_options = default_options;

// expose module as single high level function
exports = module.exports = create;

<|endoftext|>


<commit_before>var Sylvester = require("sylvester");

var ParamHelper = require("./param-helper"),
    constants = require("./constants"),
    UniversalFormulation = require("./universal-formulation"),
    Lagrange = require("./lagrange"),
    Laguerre = require("./laguerre");

module.exports = Orbit;

function Orbit(r, v, opts) {
  this.r = r;
  this.v = v;
  this.mu = (opts && opts.mu) || constants.MU;
  this.centralBodyRadius = (opts && opts.centralBodyRadius) || constants.EARTH_RADIUS;
}

Orbit.fromParams = function fromParams(params) {
  var state = ParamHelper.stateFromParams(params);

  return new Orbit(state.r, state.v, {
    mu: params.mu,
    centralBodyRadius: params.centralBodyRadius
  });
};

Orbit.prototype.angularMomentum = function angularMomentum() {
  return this.r.cross(this.v);
};

Orbit.prototype.radialVelocity = function radialVelocity() {
  return this.r.dot(this.v) / this.r.norm();
};

Orbit.prototype.eccentricity = function eccentricity() {
  return this.r.x(
    Math.pow(this.v.norm(), 2) - (this.mu / this.r.norm())
  ).subtract(
    this.v.x(this.r.norm() * this.radialVelocity())
  ).x(1 / this.mu);
};

Orbit.prototype.semimajorAxis = function semimajorAxis() {
  var h = this.angularMomentum().norm(),
      e = this.eccentricity().norm();
  return (Math.pow(h, 2) / this.mu) *
    (1 / (1 - Math.pow(e, 2)));
};

Orbit.prototype.semiminorAxis = function semiminorAxis() {
  var a = this.semimajorAxis(),
      e = this.eccentricity().norm();
  return a * Math.sqrt(1 - Math.pow(e, 2));
}

Orbit.prototype.semilatusRectum = function semilatusRectum() {
  return Math.pow(this.angularMomentum().norm(), 2) / this.mu;
};

Orbit.prototype.inclination = function inclination() {
  var h = this.angularMomentum();
  return toDeg(Math.acos(constants.K.dot(h) / h.norm()));
};

Orbit.prototype.nodeLine = function nodeLine() {
  return constants.K.cross(this.angularMomentum());
};

Orbit.prototype.rightAscension = function rightAscension() {
  var n = this.nodeLine();
  if (n.norm() === 0) { return 0; }
  var omega = toDeg(Math.acos(n.elements[0] / n.norm()));
  return n.elements[1] < 0 ? (360 - omega) : omega;
};

Orbit.prototype.argumentOfPeriapsis = function argumentOfPeriapsis() {
  var n = this.nodeLine();
  if (n.norm() === 0) { return 0; }
  var e = this.eccentricity(),
      w = toDeg(Math.acos(n.dot(e) / (n.norm() * e.norm())));
  return n.elements[2] < 0 ? (360 - w) : w;
};

Orbit.prototype.trueAnomaly = function trueAnomaly() {
  var e = this.eccentricity();
  var u = toDeg(Math.acos(Math.min(1, e.dot(this.r) / (e.norm() * this.r.norm()))));
  return this.r.dot(this.v) < 0 ? (360 - u) : u;
};

Orbit.prototype.periapsis = function periapsis() {
  var h = this.angularMomentum(),
      e = this.eccentricity();
  return (Math.pow(h.norm(), 2) / this.mu) * (1 / (1 + e.norm() * Math.cos(0)));
};

Orbit.prototype.apoapsis = function apoapsis() {
  var h = this.angularMomentum(),
      e = this.eccentricity();
  return (Math.pow(h.norm(), 2) / this.mu) * (1 / (1 + e.norm() * Math.cos(Math.PI)));
};

Orbit.prototype.period = function period() {
  var a = this.semimajorAxis();
  return (2 * Math.PI / Math.sqrt(this.mu)) * Math.sqrt(Math.pow(a, 3));
};

Orbit.prototype.universalAnomaly = function universalAnomaly(dt) {
  var a = this.semimajorAxis(),
      // initial guess of x
      x = Math.sqrt(this.mu) * (dt / a),
      r = this.r,
      v = this.v,
      mu = this.mu,
      f   = function(x) { return UniversalFormulation.f(x, a, r, v, mu, dt); },
      df  = function(x) { return UniversalFormulation.dfdt(x, a, r, v, mu); },
      d2f = function(x) { return UniversalFormulation.d2fdt(x, a, r, v, mu); };

  return Laguerre.solve(x, f, df, d2f);
};

Orbit.prototype.update = function update(dt) {
  var x = this.universalAnomaly(dt),
      a = this.semimajorAxis(),
      z = UniversalFormulation.z(x, a),
      r0 = this.r,
      v0 = this.v,
      mu = this.mu,

      // make sure you use the same `z` for calculating `this.r` and
      // `this.v`. this can be tricky because `z` depends on `this.r`
      // via `a` so we must be careful to not recalculate `z` between
      // updating `this.r` and updating `this.v`.
      r = r0.x(Lagrange.f(x, z, this.r)).add(v0.x(Lagrange.g(x, z, mu, dt))),
      v = r0.x(Lagrange.df(x, z, r, r0, mu)).add(v0.x(Lagrange.dg(x, z, r)));

  return new Orbit(r, v, {
    mu: mu,
    centralBodyRadius: this.centralBodyRadius
  });
};

function toDeg(rad) {
  return rad * (180 / Math.PI);
}

<commit_msg>fix true anomaly for 0 inclination and 0 eccentricity<commit_after>var Sylvester = require("sylvester");

var ParamHelper = require("./param-helper"),
    constants = require("./constants"),
    UniversalFormulation = require("./universal-formulation"),
    Lagrange = require("./lagrange"),
    Laguerre = require("./laguerre");

module.exports = Orbit;

function Orbit(r, v, opts) {
  this.r = r;
  this.v = v;
  this.mu = (opts && opts.mu) || constants.MU;
  this.centralBodyRadius = (opts && opts.centralBodyRadius) || constants.EARTH_RADIUS;
}

Orbit.fromParams = function fromParams(params) {
  var state = ParamHelper.stateFromParams(params);

  return new Orbit(state.r, state.v, {
    mu: params.mu,
    centralBodyRadius: params.centralBodyRadius
  });
};

Orbit.prototype.angularMomentum = function angularMomentum() {
  return this.r.cross(this.v);
};

Orbit.prototype.radialVelocity = function radialVelocity() {
  return this.r.dot(this.v) / this.r.norm();
};

Orbit.prototype.eccentricity = function eccentricity() {
  return this.r.x(
    Math.pow(this.v.norm(), 2) - (this.mu / this.r.norm())
  ).subtract(
    this.v.x(this.r.norm() * this.radialVelocity())
  ).x(1 / this.mu);
};

Orbit.prototype.semimajorAxis = function semimajorAxis() {
  var h = this.angularMomentum().norm(),
      e = this.eccentricity().norm();
  return (Math.pow(h, 2) / this.mu) *
    (1 / (1 - Math.pow(e, 2)));
};

Orbit.prototype.semiminorAxis = function semiminorAxis() {
  var a = this.semimajorAxis(),
      e = this.eccentricity().norm();
  return a * Math.sqrt(1 - Math.pow(e, 2));
}

Orbit.prototype.semilatusRectum = function semilatusRectum() {
  return Math.pow(this.angularMomentum().norm(), 2) / this.mu;
};

Orbit.prototype.inclination = function inclination() {
  var h = this.angularMomentum();
  return toDeg(Math.acos(constants.K.dot(h) / h.norm()));
};

Orbit.prototype.nodeLine = function nodeLine() {
  return constants.K.cross(this.angularMomentum());
};

Orbit.prototype.rightAscension = function rightAscension() {
  var n = this.nodeLine();
  if (n.norm() === 0) { return 0; }
  var omega = toDeg(Math.acos(n.elements[0] / n.norm()));
  return n.elements[1] < 0 ? (360 - omega) : omega;
};

Orbit.prototype.argumentOfPeriapsis = function argumentOfPeriapsis() {
  var n = this.nodeLine();
  if (n.norm() === 0) { return 0; }
  var e = this.eccentricity(),
      w = toDeg(Math.acos(n.dot(e) / (n.norm() * e.norm())));
  return n.elements[2] < 0 ? (360 - w) : w;
};

Orbit.prototype.trueAnomaly = function trueAnomaly() {
  var e = this.eccentricity(),
      eNorm = parseFloat(e.norm().toFixed(5)),
      n = this.nodeLine(),
      nNorm = parseFloat(e.norm().toFixed(5)),
      l, u;

  if (eNorm === 0 && nNorm === 0) {
    u = toDeg(Math.acos(Math.min(1, this.r.elements[0] / this.r.norm())));
  } else {
    l = (eNorm === 0) ? n : e;
    u = toDeg(Math.acos(Math.min(1, l.dot(this.r) / (l.norm() * this.r.norm()))));
  }

  return this.r.dot(this.v) < 0 ? (360 - u) : u;
};

Orbit.prototype.periapsis = function periapsis() {
  var h = this.angularMomentum(),
      e = this.eccentricity();
  return (Math.pow(h.norm(), 2) / this.mu) * (1 / (1 + e.norm() * Math.cos(0)));
};

Orbit.prototype.apoapsis = function apoapsis() {
  var h = this.angularMomentum(),
      e = this.eccentricity();
  return (Math.pow(h.norm(), 2) / this.mu) * (1 / (1 + e.norm() * Math.cos(Math.PI)));
};

Orbit.prototype.period = function period() {
  var a = this.semimajorAxis();
  return (2 * Math.PI / Math.sqrt(this.mu)) * Math.sqrt(Math.pow(a, 3));
};

Orbit.prototype.universalAnomaly = function universalAnomaly(dt) {
  var a = this.semimajorAxis(),
      // initial guess of x
      x = Math.sqrt(this.mu) * (dt / a),
      r = this.r,
      v = this.v,
      mu = this.mu,
      f   = function(x) { return UniversalFormulation.f(x, a, r, v, mu, dt); },
      df  = function(x) { return UniversalFormulation.dfdt(x, a, r, v, mu); },
      d2f = function(x) { return UniversalFormulation.d2fdt(x, a, r, v, mu); };

  return Laguerre.solve(x, f, df, d2f);
};

Orbit.prototype.update = function update(dt) {
  var x = this.universalAnomaly(dt),
      a = this.semimajorAxis(),
      z = UniversalFormulation.z(x, a),
      r0 = this.r,
      v0 = this.v,
      mu = this.mu,

      // make sure you use the same `z` for calculating `this.r` and
      // `this.v`. this can be tricky because `z` depends on `this.r`
      // via `a` so we must be careful to not recalculate `z` between
      // updating `this.r` and updating `this.v`.
      r = r0.x(Lagrange.f(x, z, this.r)).add(v0.x(Lagrange.g(x, z, mu, dt))),
      v = r0.x(Lagrange.df(x, z, r, r0, mu)).add(v0.x(Lagrange.dg(x, z, r)));

  return new Orbit(r, v, {
    mu: mu,
    centralBodyRadius: this.centralBodyRadius
  });
};

function toDeg(rad) {
  return rad * (180 / Math.PI);
}

<|endoftext|>