<commit_before>/*
 * index.js: Top-level include for the `utile` module.
 *
 * (C) 2011, Nodejitsu Inc.
 * MIT LICENSE
 *
 */

var fs = require('fs'),
    path = require('path'),
    util = require('util');

var utile = module.exports;

//
// Extend the `utile` object with all methods from the
// core node `util` methods.
//
Object.keys(util).forEach(function (key) {
  utile[key] = util[key];
});

//
// ### function async
// Simple wrapper to `require('async')`.
//
utile.__defineGetter__('async', function () {
  delete utile.async;
  return utile.async = require('async');
});

//
// ### function inflect
// Simple wrapper to `require('i')`.
//
utile.__defineGetter__('inflect', function () {
  delete utile.inflect;
  return utile.inflect = require('i')();
});

//
// ### function mkdirp
// Simple wrapper to `require('mkdirp')`
//
utile.__defineGetter__('mkdirp', function () {
  delete utile.mkdirp;
  return utile.mkdirp = require('mkdirp');
});

//
// ### function deepEqual
// Simple wrapper to `require('deep-equal')`
// Remark: deepEqual is 4x faster then using assert.deepEqual
//         see: https://gist.github.com/2790507
//
utile.__defineGetter__('deepEqual', function () {
  delete utile.deepEqual;
  return utile.deepEqual = require('deep-equal');
});

//
// ### function rimraf
// Simple wrapper to `require('rimraf')`
//
utile.__defineGetter__('rimraf', function () {
  delete utile.rimraf;
  return utile.rimraf = require('rimraf');
});

//
// ### function cpr
// Simple wrapper to `require('ncp').ncp`
//
utile.__defineGetter__('cpr', function () {
  delete utile.cpr;
  return utile.cpr = require('ncp').ncp;
});

//
// ### @file {Object}
// Lazy-loaded `file` module
//
utile.__defineGetter__('file', function () {
  delete utile.file;
  return utile.file = require('./file');
});

//
// ### @args {Object}
// Lazy-loaded `args` module
//
utile.__defineGetter__('args', function () {
  delete utile.args;
  return utile.args = require('./args');
});

//
// ### @base64 {Object}
// Lazy-loaded `base64` object
//
utile.__defineGetter__('base64', function () {
  delete utile.base64;
  return utile.base64 = require('./base64');
});

//
// ### function rargs(_args)
// #### _args {Arguments} Original function arguments
//
// Top-level method will accept a javascript "arguments" object
// (the actual keyword "arguments" inside any scope) and return
// back an Array.
//
utile.rargs = function (_args, slice) {
  if (!slice) {
    slice = 0;
  }

  var len = (_args || []).length,
      args = new Array(len - slice),
      i;

  //
  // Convert the raw `_args` to a proper Array.
  //
  for (i = slice; i < len; i++) {
    args[i - slice] = _args[i];
  }

  return args;
};

//
// ### function each (obj, iterator)
// #### @obj {Object} Object to iterate over
// #### @iterator {function} Continuation to use on each key. `function (value, key, object)`
// Iterate over the keys of an object.
//
utile.each = function (obj, iterator) {
  Object.keys(obj).forEach(function (key) {
    iterator(obj[key], key, obj);
  });
};

//
// ### function find (o)
//
//
utile.find = function (obj, pred) {
  var value, key;

  for (key in obj) {
    value = obj[key];
    if (pred(value, key)) {
      return value;
    }
  }
};

//
// ### function pad (str, len, chr)
// ### @str {String} String to pad
// ### @len {Number} Number of chars to pad str with
// ### @chr {String} Optional replacement character, defaults to empty space
// Appends chr to str until it reaches a length of len
//
utile.pad = function pad(str, len, chr) {
  var s;
  if (!chr) {
    chr = ' ';
  }
  str = str || '';
  s = str;
  if (str.length < len) {
    for (var i = 0; i < (len - str.length); i++) {
      s += chr;
    }
  }
  return s;
}

//
// ### function path (obj, path, value)
// ### @obj {Object} Object to insert value into
// ### @path {Array} List of nested keys to insert value at
// Retreives a value from given Object, `obj`, located at the
// nested keys, `path`.
//
utile.path = function (obj, path) {
  var key, i;

  for (i in path) {
    if (typeof obj === 'undefined') {
      return undefined;
    }

    key = path[i];
    obj = obj[key];
  }

  return obj;
};

//
// ### function createPath (obj, path, value)
// ### @obj {Object} Object to insert value into
// ### @path {Array} List of nested keys to insert value at
// ### @value {*} Value to insert into the object.
// Inserts the `value` into the given Object, `obj`, creating
// any keys in `path` along the way if necessary.
//
utile.createPath = function (obj, path, value) {
  var key, i;

  for (i in path) {
    key = path[i];
    if (!obj[key]) {
      obj[key] = ((+i + 1 === path.length) ? value : {});
    }

    obj = obj[key];
  }
};

//
// ### function mixin (target [source0, source1, ...])
// Copies enumerable properties from `source0 ... sourceN`
// onto `target` and returns the resulting object.
//
utile.mixin = function (target) {
  utile.rargs(arguments, 1).forEach(function (o) {
    Object.keys(o).forEach(function (attr) {
      var getter = o.__lookupGetter__(attr),
          setter = o.__lookupSetter__(attr);

      if (!getter && !setter) {
        target[attr] = o[attr];
      }
      else {
        if (setter) { target.__defineSetter__(attr, setter) }
        if (getter) { target.__defineGetter__(attr, getter) }
      }
    });
  });

  return target;
};

//
// ### function capitalize (str)
// #### @str {string} String to capitalize
// Capitalizes the specified `str`.
//
utile.capitalize = utile.inflect.camelize;

//
// ### function escapeRegExp (str)
// #### @str {string} String to be escaped
// Escape string for use in Javascript regex
//
utile.escapeRegExp = function (str) {
  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
};

//
// ### function randomString (length)
// #### @length {integer} The number of bits for the random base64 string returned to contain
// randomString returns a pseude-random ASCII string (subset)
// the return value is a string of length ⌈bits/6⌉ of characters
// from the base64 alphabet.
//
utile.randomString = function (length) {
  var chars, rand, i, ret, mod, bits;

  chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-';
  ret = '';
  // standard 4
  mod = 4;
  // default is 16
  bits = length * mod || 64;

  // in v8, Math.random() yields 32 pseudo-random bits (in spidermonkey it gives 53)
  while (bits > 0) {
    // 32-bit integer
    rand = Math.floor(Math.random() * 0x100000000);
    //we use the top bits
    for (i = 26; i > 0 && bits > 0; i -= mod, bits -= mod) {
      ret += chars[0x3F & rand >>> i];
    }
  }

  return ret;
};

//
// ### function filter (object, test)
// #### @obj {Object} Object to iterate over
// #### @pred {function} Predicate applied to each property. `function (value, key, object)`
// Returns an object with properties from `obj` which satisfy
// the predicate `pred`
//
utile.filter = function (obj, pred) {
  var copy = Array.isArray(obj) ? [] : {};
  utile.each(obj, function (val, key) {
    if (pred(val, key, obj)) {
      copy[key] = val;
    }
  });

  return copy;
};

//
// ### function requireDir (directory)
// #### @directory {string} Directory to require
// Requires all files and directories from `directory`, returning an object
// with keys being filenames (without trailing `.js`) and respective values
// being return values of `require(filename)`.
//
utile.requireDir = function (directory) {
  var result = {},
      files = fs.readdirSync(directory);

  files.forEach(function (file) {
    if (file.substr(-3) === '.js') {
      file = file.substr(0, file.length - 3);
    }
    result[file] = require(path.resolve(directory, file));
  });
  return result;
};

//
// ### function requireDirLazy (directory)
// #### @directory {string} Directory to require
// Lazily requires all files and directories from `directory`, returning an
// object with keys being filenames (without trailing `.js`) and respective
// values (getters) being return values of `require(filename)`.
//
utile.requireDirLazy = function (directory) {
  var result = {},
      files = fs.readdirSync(directory);

  files.forEach(function (file) {
    if (file.substr(-3) === '.js') {
      file = file.substr(0, file.length - 3);
    }
    result.__defineGetter__(file, function () {
      delete result[file];
      return result[file] = require(path.resolve(directory, file));
    });
  });
  return result;
};

//
// ### function clone (object, filter)
// #### @object {Object} Object to clone
// #### @filter {Function} Filter to be used
// Shallow clones the specified object.
//
utile.clone = function (object, filter) {
  return Object.keys(object).reduce(filter ? function (obj, k) {
    if (filter(k)) obj[k] = object[k];
    return obj;
  } : function (obj, k) {
    obj[k] = object[k];
    return obj;
  }, {});
};

//
// ### function camelToUnderscore (obj)
// #### @obj {Object} Object to convert keys on.
// Converts all keys of the type `keyName` to `key_name` on the
// specified `obj`.
//
utile.camelToUnderscore = function (obj) {
  if (Array.isArray(obj)) {
    return obj.forEach(utile.camelToUnderscore);
  }

  Object.keys(obj || {}).forEach(function (key) {
    var k = utile.inflect.underscore(key);
    if (k != key) {
      obj[k] = obj[key];
      delete obj[key];
      key = k;
    }

    if (obj[key] && !Array.isArray(obj[key])
      && typeof obj[key] === 'object') {
      utile.camelToUnderscore(obj[key]);
    }
  });

  return obj;
};

//
// ### function underscoreToCamel (obj)
// #### @obj {Object} Object to convert keys on.
// Converts all keys of the type `key_name` to `keyName` on the
// specified `obj`.
//
utile.underscoreToCamel = function (obj) {
  if (Array.isArray(obj)) {
    return obj.forEach(utile.underscoreToCamel);
  }

  Object.keys(obj || {}).forEach(function (key) {
    var k = utile.inflect.camelize(key, false);
    if (k != key) {
      obj[k] = obj[key];
      delete obj[key];
      key = k;
    }

    if (obj[key] && !Array.isArray(obj[key])
      && typeof obj[key] === 'object') {
      utile.underscoreToCamel(obj[key]);
    }
  });

  return obj;
}
<commit_msg>[fix] handle types properly for underscoreToCamel/camelToUnderscore.<commit_after>/*
 * index.js: Top-level include for the `utile` module.
 *
 * (C) 2011, Nodejitsu Inc.
 * MIT LICENSE
 *
 */

var fs = require('fs'),
    path = require('path'),
    util = require('util');

var utile = module.exports;

//
// Extend the `utile` object with all methods from the
// core node `util` methods.
//
Object.keys(util).forEach(function (key) {
  utile[key] = util[key];
});

//
// ### function async
// Simple wrapper to `require('async')`.
//
utile.__defineGetter__('async', function () {
  delete utile.async;
  return utile.async = require('async');
});

//
// ### function inflect
// Simple wrapper to `require('i')`.
//
utile.__defineGetter__('inflect', function () {
  delete utile.inflect;
  return utile.inflect = require('i')();
});

//
// ### function mkdirp
// Simple wrapper to `require('mkdirp')`
//
utile.__defineGetter__('mkdirp', function () {
  delete utile.mkdirp;
  return utile.mkdirp = require('mkdirp');
});

//
// ### function deepEqual
// Simple wrapper to `require('deep-equal')`
// Remark: deepEqual is 4x faster then using assert.deepEqual
//         see: https://gist.github.com/2790507
//
utile.__defineGetter__('deepEqual', function () {
  delete utile.deepEqual;
  return utile.deepEqual = require('deep-equal');
});

//
// ### function rimraf
// Simple wrapper to `require('rimraf')`
//
utile.__defineGetter__('rimraf', function () {
  delete utile.rimraf;
  return utile.rimraf = require('rimraf');
});

//
// ### function cpr
// Simple wrapper to `require('ncp').ncp`
//
utile.__defineGetter__('cpr', function () {
  delete utile.cpr;
  return utile.cpr = require('ncp').ncp;
});

//
// ### @file {Object}
// Lazy-loaded `file` module
//
utile.__defineGetter__('file', function () {
  delete utile.file;
  return utile.file = require('./file');
});

//
// ### @args {Object}
// Lazy-loaded `args` module
//
utile.__defineGetter__('args', function () {
  delete utile.args;
  return utile.args = require('./args');
});

//
// ### @base64 {Object}
// Lazy-loaded `base64` object
//
utile.__defineGetter__('base64', function () {
  delete utile.base64;
  return utile.base64 = require('./base64');
});

//
// ### function rargs(_args)
// #### _args {Arguments} Original function arguments
//
// Top-level method will accept a javascript "arguments" object
// (the actual keyword "arguments" inside any scope) and return
// back an Array.
//
utile.rargs = function (_args, slice) {
  if (!slice) {
    slice = 0;
  }

  var len = (_args || []).length,
      args = new Array(len - slice),
      i;

  //
  // Convert the raw `_args` to a proper Array.
  //
  for (i = slice; i < len; i++) {
    args[i - slice] = _args[i];
  }

  return args;
};

//
// ### function each (obj, iterator)
// #### @obj {Object} Object to iterate over
// #### @iterator {function} Continuation to use on each key. `function (value, key, object)`
// Iterate over the keys of an object.
//
utile.each = function (obj, iterator) {
  Object.keys(obj).forEach(function (key) {
    iterator(obj[key], key, obj);
  });
};

//
// ### function find (o)
//
//
utile.find = function (obj, pred) {
  var value, key;

  for (key in obj) {
    value = obj[key];
    if (pred(value, key)) {
      return value;
    }
  }
};

//
// ### function pad (str, len, chr)
// ### @str {String} String to pad
// ### @len {Number} Number of chars to pad str with
// ### @chr {String} Optional replacement character, defaults to empty space
// Appends chr to str until it reaches a length of len
//
utile.pad = function pad(str, len, chr) {
  var s;
  if (!chr) {
    chr = ' ';
  }
  str = str || '';
  s = str;
  if (str.length < len) {
    for (var i = 0; i < (len - str.length); i++) {
      s += chr;
    }
  }
  return s;
}

//
// ### function path (obj, path, value)
// ### @obj {Object} Object to insert value into
// ### @path {Array} List of nested keys to insert value at
// Retreives a value from given Object, `obj`, located at the
// nested keys, `path`.
//
utile.path = function (obj, path) {
  var key, i;

  for (i in path) {
    if (typeof obj === 'undefined') {
      return undefined;
    }

    key = path[i];
    obj = obj[key];
  }

  return obj;
};

//
// ### function createPath (obj, path, value)
// ### @obj {Object} Object to insert value into
// ### @path {Array} List of nested keys to insert value at
// ### @value {*} Value to insert into the object.
// Inserts the `value` into the given Object, `obj`, creating
// any keys in `path` along the way if necessary.
//
utile.createPath = function (obj, path, value) {
  var key, i;

  for (i in path) {
    key = path[i];
    if (!obj[key]) {
      obj[key] = ((+i + 1 === path.length) ? value : {});
    }

    obj = obj[key];
  }
};

//
// ### function mixin (target [source0, source1, ...])
// Copies enumerable properties from `source0 ... sourceN`
// onto `target` and returns the resulting object.
//
utile.mixin = function (target) {
  utile.rargs(arguments, 1).forEach(function (o) {
    Object.keys(o).forEach(function (attr) {
      var getter = o.__lookupGetter__(attr),
          setter = o.__lookupSetter__(attr);

      if (!getter && !setter) {
        target[attr] = o[attr];
      }
      else {
        if (setter) { target.__defineSetter__(attr, setter) }
        if (getter) { target.__defineGetter__(attr, getter) }
      }
    });
  });

  return target;
};

//
// ### function capitalize (str)
// #### @str {string} String to capitalize
// Capitalizes the specified `str`.
//
utile.capitalize = utile.inflect.camelize;

//
// ### function escapeRegExp (str)
// #### @str {string} String to be escaped
// Escape string for use in Javascript regex
//
utile.escapeRegExp = function (str) {
  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
};

//
// ### function randomString (length)
// #### @length {integer} The number of bits for the random base64 string returned to contain
// randomString returns a pseude-random ASCII string (subset)
// the return value is a string of length ⌈bits/6⌉ of characters
// from the base64 alphabet.
//
utile.randomString = function (length) {
  var chars, rand, i, ret, mod, bits;

  chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-';
  ret = '';
  // standard 4
  mod = 4;
  // default is 16
  bits = length * mod || 64;

  // in v8, Math.random() yields 32 pseudo-random bits (in spidermonkey it gives 53)
  while (bits > 0) {
    // 32-bit integer
    rand = Math.floor(Math.random() * 0x100000000);
    //we use the top bits
    for (i = 26; i > 0 && bits > 0; i -= mod, bits -= mod) {
      ret += chars[0x3F & rand >>> i];
    }
  }

  return ret;
};

//
// ### function filter (object, test)
// #### @obj {Object} Object to iterate over
// #### @pred {function} Predicate applied to each property. `function (value, key, object)`
// Returns an object with properties from `obj` which satisfy
// the predicate `pred`
//
utile.filter = function (obj, pred) {
  var copy = Array.isArray(obj) ? [] : {};
  utile.each(obj, function (val, key) {
    if (pred(val, key, obj)) {
      copy[key] = val;
    }
  });

  return copy;
};

//
// ### function requireDir (directory)
// #### @directory {string} Directory to require
// Requires all files and directories from `directory`, returning an object
// with keys being filenames (without trailing `.js`) and respective values
// being return values of `require(filename)`.
//
utile.requireDir = function (directory) {
  var result = {},
      files = fs.readdirSync(directory);

  files.forEach(function (file) {
    if (file.substr(-3) === '.js') {
      file = file.substr(0, file.length - 3);
    }
    result[file] = require(path.resolve(directory, file));
  });
  return result;
};

//
// ### function requireDirLazy (directory)
// #### @directory {string} Directory to require
// Lazily requires all files and directories from `directory`, returning an
// object with keys being filenames (without trailing `.js`) and respective
// values (getters) being return values of `require(filename)`.
//
utile.requireDirLazy = function (directory) {
  var result = {},
      files = fs.readdirSync(directory);

  files.forEach(function (file) {
    if (file.substr(-3) === '.js') {
      file = file.substr(0, file.length - 3);
    }
    result.__defineGetter__(file, function () {
      delete result[file];
      return result[file] = require(path.resolve(directory, file));
    });
  });
  return result;
};

//
// ### function clone (object, filter)
// #### @object {Object} Object to clone
// #### @filter {Function} Filter to be used
// Shallow clones the specified object.
//
utile.clone = function (object, filter) {
  return Object.keys(object).reduce(filter ? function (obj, k) {
    if (filter(k)) obj[k] = object[k];
    return obj;
  } : function (obj, k) {
    obj[k] = object[k];
    return obj;
  }, {});
};

//
// ### function camelToUnderscore (obj)
// #### @obj {Object} Object to convert keys on.
// Converts all keys of the type `keyName` to `key_name` on the
// specified `obj`.
//
utile.camelToUnderscore = function (obj) {
  if (typeof obj !== 'object' || obj === null) {
    return obj;
  }

  if (Array.isArray(obj)) {
    obj.forEach(utile.camelToUnderscore);
    return obj;
  }

  Object.keys(obj).forEach(function (key) {
    var k = utile.inflect.underscore(key);
    if (k !== key) {
      obj[k] = obj[key];
      delete obj[key];
      key = k;
    }
    utile.camelToUnderscore(obj[key]);
  });

  return obj;
};

//
// ### function underscoreToCamel (obj)
// #### @obj {Object} Object to convert keys on.
// Converts all keys of the type `key_name` to `keyName` on the
// specified `obj`.
//
utile.underscoreToCamel = function (obj) {
  if (typeof obj !== 'object' || obj === null) {
    return obj;
  }

  if (Array.isArray(obj)) {
    obj.forEach(utile.underscoreToCamel);
    return obj;
  }

  Object.keys(obj).forEach(function (key) {
    var k = utile.inflect.camelize(key, false);
    if (k !== key) {
      obj[k] = obj[key];
      delete obj[key];
      key = k;
    }
    utile.underscoreToCamel(obj[key]);
  });

  return obj;
};
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 10sr <8.slashes@gmail.com>
 * Licensed under the Apache License, Version 2.0
 */

var readline = require("readline");
var fs = require("fs");
var childProcess = require("child_process");
var os = require("os");

var CronJob = require("cron").CronJob;
var nodemailer = require("nodemailer");
var logger = require("log4js").getLogger();
var argparse = require("argparse");

var parseCrontabRe = new RegExp(/^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.+)$/);

var SENDER_DEFAULT = os.userInfo().username + "@" + os.hostname();

function createMailTransporter(opts){
    if (!opts.mailto) {
        return null;
    }

    logger.info("Setting up email notification");
    logger.info("Sender: " + SENDER_DEFAULT);
    logger.info("Mailto: " + opts.mailto);
    var mailDefaults = {
        from: SENDER_DEFAULT,
        to: opts.mailto
    };

    if (opts.smtpHost || opts.smtpPort ||
        opts.smtpUser || opts.smtpPass) {
        logger.info("Use SMTP to send emails");
        return nodemailer.createTransport({
            host: opts.smtpHost,
            port: opts.smtpPort,
            secure: opts.smtpSecure,
            auth: {
                user: opts.smtpUser,
                pass: opts.smtpPass
            }
        }, mailDefaults);
    } else {
        logger.info("Use sendmail to send emails");
        return nodemailer.createTransport({
            sendmail: true,
            newline: "unix"
        }, mailDefaults);
    }
}

function parseCrontab(line){
    var matched = parseCrontabRe.exec(line);
    if (!matched) {
        throw Error("Failed to parse crontab line: " + line);
    }
    return {
        cronTime: [
            matched[1], matched[2], matched[3],
            matched[4], matched[5], matched[6]
        ].join(" "),
        command: matched[7]
    }
}

var start = exports.start = function start(crontab, opts){
    var exitOnFailure = Boolean(opts.exitOnFailure);
    var timeZone = opts.timeZone || null;
    var mailTransporter = createMailTransporter(opts);

    var rl = readline.createInterface({
        input: fs.createReadStream(crontab)
    });

    rl.on("line", function(line){
        if (line.match(/^#/)) {
            return;
        }
        var parsed = parseCrontab(line);
        var cronJobOpts = {
            cronTime: parsed.cronTime,
            onTick: function(){
                var currentTime = new Date();
                // TODO: use timezone
                var dateStr = currentTime.toISOString();
                var leadingMarker = dateStr + " | " + parsed.command + " | ";
                var proc = childProcess.exec(
                    parsed.command,
                    {},
                    function(err, stdout, stderr){
                        logger.info(leadingMarker + "stdout: " + stdout.trim());
                        logger.info(leadingMarker + "stderr: " + stderr.trim());
                        if (err) {
                            logger.warn(leadingMarker + "error:  " + err.toString())
                            logger.warn(leadingMarker + "exited with code " +
                                        err.code.toString());
                        } else {
                            logger.info(leadingMarker + "exited with code 0")
                        }

                        if (mailTransporter) {
                            logger.debug(leadingMarker +
                                        "Sending email to " + opts.mailto);
                            var mailText = "stdout:\n\n" + stdout +
                                "\n\nstderr:\n\n" + stderr;
                            if (err) {
                                mailText = mailText + "\n\nerror: " + err.toString() +
                                    "\n\nExit code: " + err.code.toString();
                            }
                            var mailSubject = "Cron-JS <" + SENDER_DEFAULT +
                                "> " + parsed.command;
                            mailTransporter.sendMail({
                                subject: mailSubject,
                                text: mailText
                            }, function(err, info){
                                if (err) {
                                    logger.warn(leadingMarker +
                                                "Failed to send mail: " + err.toString());
                                }
                            });
                        }

                        if (err && exitOnFailure) {
                            logger.warn("Aborting.");
                            process.exit(err.code);
                        }
                    }
                );
            },
            start: true
        };
        if (timeZone) {
            cronJobOpts.timeZone = timeZone;
        }

        var job = new CronJob(cronJobOpts);
        logger.info(parsed);
    });
};

var main = exports.main = function main(argv){
    var parser = new argparse.ArgumentParser({
        addHelp: true,
    });

    parser.addArgument("crontab", {
        help: "crontab file that defines jobs to schedule, one per line"
    });

    parser.addArgument("--exit-on-failure", {
        help: "Any of jobs ends with status code other than 0, exit with that code",
        action: "storeTrue",
        defaultValue: false
    });

    parser.addArgument("--timezone", {
        help: "Timezone of cron job definitions"
    });

    parser.addArgument("--mailto", {
        help: "Email address to send result to",
        metavar: "ADDRESS"
    });

    parser.addArgument("--smtp-host", {
        help: "SMTP host to use to send emails",
        metavar: "HOST"
    });
    parser.addArgument("--smtp-port", {
        help: "SMTP port to use to send emails",
        type: "int",
        metavar: "PORT"
    });
    parser.addArgument("--smtp-user", {
        help: "SMTP username to use to send emails",
        metavar: "USERNAME"
    });
    parser.addArgument("--smtp-pass", {
        help: "SMTP password to use to send emails",
        metavar: "PASSWORD"
    });

    var args = parser.parseArgs(argv.slice(2));

    var crontab = args.crontab;
    var exitOnFailure = args.exit_on_failure;
    var timeZone = args.timezone;

    // Mail configurations
    var mailto = args.mailto || process.env.CRON_JS_MAILTO || null;
    var smtpHost = args.smtp_host || process.env.CRON_JS_SMTP_HOST || null;
    var smtpPort = args.smtp_port || parseInt(process.env.CRON_JS_SMTP_PORT, 10) || 0;
    var smtpUser = args.smtp_user || process.env.CRON_JS_SMTP_USER || null;
    var smtpPass = args.smtp_pass || process.env.CRON_JS_SMTP_PASS || null;

    var smtpSecure = (smtpPort === 465);

    start(crontab, {
        exitOnFailure: exitOnFailure,
        timeZone: timeZone,
        mailto: mailto,
        smtpHost: smtpHost,
        smtpPort: smtpPort,
        smtpSecure: smtpSecure,
        smtpUser: smtpUser,
        smtpPass: smtpPass
    })
    return 0;
};
<commit_msg>Update outputs<commit_after>/*
 * Copyright (c) 2017 10sr <8.slashes@gmail.com>
 * Licensed under the Apache License, Version 2.0
 */

var readline = require("readline");
var fs = require("fs");
var childProcess = require("child_process");
var os = require("os");

var CronJob = require("cron").CronJob;
var nodemailer = require("nodemailer");
var logger = require("log4js").getLogger();
var argparse = require("argparse");

var parseCrontabRe = new RegExp(/^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.+)$/);

var SENDER_DEFAULT = os.userInfo().username + "@" + os.hostname();

function createMailTransporter(opts){
    if (!opts.mailto) {
        return null;
    }

    logger.info("Setting up email notification");
    logger.info("Sender: " + SENDER_DEFAULT);
    logger.info("Mailto: " + opts.mailto);
    var mailDefaults = {
        from: SENDER_DEFAULT,
        to: opts.mailto
    };

    if (opts.smtpHost || opts.smtpPort ||
        opts.smtpUser || opts.smtpPass) {
        logger.info("Use SMTP to send emails");
        return nodemailer.createTransport({
            host: opts.smtpHost,
            port: opts.smtpPort,
            secure: opts.smtpSecure,
            auth: {
                user: opts.smtpUser,
                pass: opts.smtpPass
            }
        }, mailDefaults);
    } else {
        logger.info("Use sendmail to send emails");
        return nodemailer.createTransport({
            sendmail: true,
            newline: "unix"
        }, mailDefaults);
    }
}

function parseCrontab(line){
    var matched = parseCrontabRe.exec(line);
    if (!matched) {
        throw Error("Failed to parse crontab line: " + line);
    }
    return {
        cronTime: [
            matched[1], matched[2], matched[3],
            matched[4], matched[5], matched[6]
        ].join(" "),
        command: matched[7]
    }
}

var start = exports.start = function start(crontab, opts){
    var exitOnFailure = Boolean(opts.exitOnFailure);
    var timeZone = opts.timeZone || null;
    var mailTransporter = createMailTransporter(opts);

    var rl = readline.createInterface({
        input: fs.createReadStream(crontab)
    });

    rl.on("line", function(line){
        if (line.match(/^#/)) {
            return;
        }
        var parsed = parseCrontab(line);
        var cronJobOpts = {
            cronTime: parsed.cronTime,
            onTick: function(){
                var leadingMarker = null;
                var proc = childProcess.exec(
                    parsed.command,
                    {},
                    function(err, stdout, stderr){
                        logger.info(leadingMarker + "Stdout: " + stdout.trim());
                        logger.info(leadingMarker + "Stderr: " + stderr.trim());
                        if (err) {
                            logger.warn(leadingMarker + "Error:  " + err.toString())
                            logger.warn(leadingMarker + "Exited with code " +
                                        err.code.toString());
                        } else {
                            logger.info(leadingMarker + "Exited with code 0")
                        }

                        if (mailTransporter) {
                            logger.debug(leadingMarker +
                                        "Sending email to " + opts.mailto);
                            var mailText = "stdout:\n\n" + stdout +
                                "\n\nstderr:\n\n" + stderr;
                            if (err) {
                                mailText = mailText + "\n\nerror: " + err.toString() +
                                    "\n\nExit code: " + err.code.toString();
                            }
                            var mailSubject = "Cron-JS <" + SENDER_DEFAULT +
                                "> " + parsed.command;
                            mailTransporter.sendMail({
                                subject: mailSubject,
                                text: mailText
                            }, function(err, info){
                                if (err) {
                                    logger.warn(leadingMarker +
                                                "Failed to send mail: " + err.toString());
                                }
                            });
                        }

                        if (err && exitOnFailure) {
                            logger.warn("Aborting.");
                            process.exit(err.code);
                        }
                    }

                );
                leadingMarker = parsed.command +
                    " (pid=" + proc.pid.toString() + ")" + " | ";
                logger.info(leadingMarker + "Started.")
            },
            start: true
        };
        if (timeZone) {
            cronJobOpts.timeZone = timeZone;
        }

        var job = new CronJob(cronJobOpts);
        logger.info("Job registered: " + JSON.stringify(parsed));
    });
};

var main = exports.main = function main(argv){
    var parser = new argparse.ArgumentParser({
        addHelp: true,
    });

    parser.addArgument("crontab", {
        help: "crontab file that defines jobs to schedule, one per line"
    });

    parser.addArgument("--exit-on-failure", {
        help: "Any of jobs ends with status code other than 0, exit with that code",
        action: "storeTrue",
        defaultValue: false
    });

    parser.addArgument("--timezone", {
        help: "Timezone of cron job definitions"
    });

    parser.addArgument("--mailto", {
        help: "Email address to send result to",
        metavar: "ADDRESS"
    });

    parser.addArgument("--smtp-host", {
        help: "SMTP host to use to send emails",
        metavar: "HOST"
    });
    parser.addArgument("--smtp-port", {
        help: "SMTP port to use to send emails",
        type: "int",
        metavar: "PORT"
    });
    parser.addArgument("--smtp-user", {
        help: "SMTP username to use to send emails",
        metavar: "USERNAME"
    });
    parser.addArgument("--smtp-pass", {
        help: "SMTP password to use to send emails",
        metavar: "PASSWORD"
    });

    var args = parser.parseArgs(argv.slice(2));

    var crontab = args.crontab;
    var exitOnFailure = args.exit_on_failure;
    var timeZone = args.timezone;

    // Mail configurations
    var mailto = args.mailto || process.env.CRON_JS_MAILTO || null;
    var smtpHost = args.smtp_host || process.env.CRON_JS_SMTP_HOST || null;
    var smtpPort = args.smtp_port || parseInt(process.env.CRON_JS_SMTP_PORT, 10) || 0;
    var smtpUser = args.smtp_user || process.env.CRON_JS_SMTP_USER || null;
    var smtpPass = args.smtp_pass || process.env.CRON_JS_SMTP_PASS || null;

    var smtpSecure = (smtpPort === 465);

    start(crontab, {
        exitOnFailure: exitOnFailure,
        timeZone: timeZone,
        mailto: mailto,
        smtpHost: smtpHost,
        smtpPort: smtpPort,
        smtpSecure: smtpSecure,
        smtpUser: smtpUser,
        smtpPass: smtpPass
    })
    return 0;
};
<|endoftext|>


<commit_before>exports = module.exports = function express(id) {
  var map = {
    'service': './service',
    'authenticator': './authenticator',
    'boot/httpserver': './boot/httpserver'
  };

  var mid = map[id];
  if (mid) {
    return require(mid);
  }
};

exports.main = function() {
  console.log('bixby express main!');

  // TODO: clean this up
  function pre(IoC) {
    console.log('PRE RUN!');

    IoC.use('http', require('bixby-http'));
    IoC.use(exports);
  }

  // TODO: clean this up
  function post(IoC) {
    console.log('POST!');

    var server = IoC.create('http/server');
    var handler = IoC.create('service');
    server.on('request', handler);

    server.listen(8080);
  }

  require('bixby').main(pre, post);
}<commit_msg>Refactor to latest bixby changes.<commit_after>exports = module.exports = function express(id) {
  var map = {
    'service': './service',
    'authenticator': './authenticator',
    'boot/httpserver': './boot/httpserver'
  };

  var mid = map[id];
  if (mid) {
    return require(mid);
  }
};

exports.main = function() {
  function pre(IoC) {
    IoC.use('http', require('bixby-http'));
    IoC.use(exports);
  }

  function post(IoC) {
    var server = IoC.create('http/server');
    var service = IoC.create('service');

    var init = IoC.create('initializer');
    init.phase(require('bootable').di.routes('app/routes'), service);
    // TODO: Create this phase via IoC
    init.phase(require('./init.d/listen')(server, service));
  }

  require('bixby').main(pre, post);
}
<|endoftext|>


<commit_before>(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define('lisplate.core', ['lisplate.runtime', 'lisplate.utils'], factory);
  } else if (typeof exports === 'object') {
    module.exports = factory(require('./runtime'), require('./util'));
  } else {
    root.Lisplate = factory(root.Lisplate.Runtime, root.Lisplate.Utils);
  }
}(this, function(runtime, utils) {
  'use strict';

  var _thenable = utils.thenable;

  function _callbackify(fn) {
    var expectedArgs = fn.length;

    return function() {
      var totalArgs = arguments.length;
      var callback = totalArgs > expectedArgs ? arguments[totalArgs - 1] : null;
      var args = null;
      if (typeof callback === 'function') {
        args = Array.prototype.slice.call(arguments, 0, totalArgs - 1);
      } else {
        args = Array.prototype.slice.call(arguments, 0, totalArgs);
        callback = null;
      }

      var output = fn.apply(this, args);

      if (_thenable(output)) {
        if (!callback) {
          return output;
        }

        output.then(function(str) {
          callback(null, str);
        }).catch(function(err) {
          callback(err);
        });
      } else {
        if (callback) {
          callback(null, output);
          return undefined;
        }
        return output;
      }

      return undefined;
    };
  }

  function _promisifyPossibleAsync(fn) {
    var fnArgCount = fn.length;
    return function() {
      var args = Array.prototype.slice.apply(arguments);
      var argsLength = args.length;

      if (fnArgCount === argsLength + 1) {
        // if callback, promisify
        return new Promise(function(resolve, reject) {
          args.push(function(err, out) {
            if (err) {
              reject(err);
              return;
            }

            resolve(out);
          });

          fn.apply(null, args);
        });
      } else {
        // could be promise or sync
        return Promise.resolve(fn.apply(null, args));
      }
    };
  }

  function Lisplate(options) {
    if (!options) {
      options = {};
    }

    // cacheEnabled must be explicitly set to false to disable
    this.cacheEnabled = !(options.cacheEnabled === false);

    this.sourceLoader = options.sourceLoader;
    this.viewModelLoader = options.viewModelLoader;
    this.stringsLoader = options.stringsLoader;

    this.helpers = {};
    this.cache = {};
  }
  Lisplate.Runtime = runtime;
  Lisplate.Utils = utils;

  Lisplate.prototype.addHelper = function addHelper(helperName, fn) {
    this.helpers[helperName] = fn;
  };

  Lisplate.prototype.loadTemplate = _callbackify(function loadTemplate(templateInfo) {
    var _self = this;

    if (!templateInfo) {
      return Promise.reject(new Error('Must specify template information to load'));
    }

    var templateName = typeof templateInfo === 'string' ? templateInfo : templateInfo.templateName;
    var renderFactory = templateInfo.renderFactory;

    if (templateName === '') {
      return Promise.reject(new Error('Must specify a valid template name to load'));
    }

    if (renderFactory) {
      renderFactory = Promise.resolve(renderFactory);
    } else {
      if (_self.cache[templateName]) {
        return Promise.resolve(_self.cache[templateName]);
      }

      if (!_self.sourceLoader) {
        return Promise.reject(new Error('Must define a sourceLoader'));
      }

      if (!Lisplate.Compiler || !Lisplate.Compiler.compile) {
        return Promise.reject('Compiler is not loaded to compile loaded source');
      }

      renderFactory = _promisifyPossibleAsync(_self
        .sourceLoader)(templateName)
        .then(function(src) {
          var compiled = null;
          var factory = null;

          try {
            compiled = Lisplate.Compiler.compile(templateName, src);
            factory = Lisplate.Utils.loadCompiledSource(compiled);
          } catch (e) {
            return Promise.reject(e);
          }

          return Promise.resolve(factory);
        });
    }

    return renderFactory.then(function(factory) {
      var promise = null;
      if (_self.viewModelLoader) {
        promise = _promisifyPossibleAsync(_self.viewModelLoader)(templateName);
      } else {
        promise = Promise.resolve(null);
      }

      return promise.then(function(viewModelClass) {
        var fn = factory(_self, viewModelClass);
        fn.templateName = templateName;
        _self.cache[templateName] = fn;
        return fn;
      });
    });
  });

  Lisplate.prototype.render = _callbackify(function render(template, data) {
    var _self = this;
    if (_self.stringsLoader) {
      return _promisifyPossibleAsync(_self
        .stringsLoader)(template.templateName)
        .then(function(strings) {
          return template(data, strings, Lisplate.Runtime);
        });
    } else {
      // done this way for non-async optimization
      return template(data, null, Lisplate.Runtime);
    }
  });

  Lisplate.prototype.renderTemplate = _callbackify(function renderTemplate(templateName, data) {
    var _self = this;

    return _self.loadTemplate(templateName).then(function(template) {
      return _self.render(template, data);
    });
  });

  return Lisplate;
}));
<commit_msg>Add factory-level caching and ability to disable caching entirely<commit_after>(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define('lisplate.core', ['lisplate.runtime', 'lisplate.utils'], factory);
  } else if (typeof exports === 'object') {
    module.exports = factory(require('./runtime'), require('./util'));
  } else {
    root.Lisplate = factory(root.Lisplate.Runtime, root.Lisplate.Utils);
  }
}(this, function(runtime, utils) {
  'use strict';

  var _thenable = utils.thenable;

  function _callbackify(fn) {
    var expectedArgs = fn.length;

    return function() {
      var totalArgs = arguments.length;
      var callback = totalArgs > expectedArgs ? arguments[totalArgs - 1] : null;
      var args = null;
      if (typeof callback === 'function') {
        args = Array.prototype.slice.call(arguments, 0, totalArgs - 1);
      } else {
        args = Array.prototype.slice.call(arguments, 0, totalArgs);
        callback = null;
      }

      var output = fn.apply(this, args);

      if (_thenable(output)) {
        if (!callback) {
          return output;
        }

        output.then(function(str) {
          callback(null, str);
        }).catch(function(err) {
          callback(err);
        });
      } else {
        if (callback) {
          callback(null, output);
          return undefined;
        }
        return output;
      }

      return undefined;
    };
  }

  function _promisifyPossibleAsync(fn) {
    var fnArgCount = fn.length;
    return function() {
      var args = Array.prototype.slice.apply(arguments);
      var argsLength = args.length;

      if (fnArgCount === argsLength + 1) {
        // if callback, promisify
        return new Promise(function(resolve, reject) {
          args.push(function(err, out) {
            if (err) {
              reject(err);
              return;
            }

            resolve(out);
          });

          fn.apply(null, args);
        });
      } else {
        // could be promise or sync
        return Promise.resolve(fn.apply(null, args));
      }
    };
  }

  function Lisplate(options) {
    if (!options) {
      options = {};
    }

    // cacheEnabled must be explicitly set to false to disable
    this.cacheEnabled = !(options.cacheEnabled === false);

    this.sourceLoader = options.sourceLoader;
    this.viewModelLoader = options.viewModelLoader;
    this.stringsLoader = options.stringsLoader;

    this.helpers = {};
    this.cache = {};
  }
  Lisplate.Runtime = runtime;
  Lisplate.Utils = utils;
  Lisplate.FactoryCache = {};

  Lisplate.prototype.addHelper = function addHelper(helperName, fn) {
    this.helpers[helperName] = fn;
  };

  Lisplate.prototype.loadTemplate = _callbackify(function loadTemplate(templateInfo) {
    var _self = this;

    if (!templateInfo) {
      return Promise.reject(new Error('Must specify template information to load'));
    }

    var templateName = typeof templateInfo === 'string' ? templateInfo : templateInfo.templateName;
    var renderFactory = templateInfo.renderFactory;

    if (templateName === '') {
      return Promise.reject(new Error('Must specify a valid template name to load'));
    }

    if (renderFactory) {
      renderFactory = Promise.resolve(renderFactory);
    } else if (_self.cacheEnabled && _self.cache[templateName]) {
      return Promise.resolve(_self.cache[templateName]);
    } else if (_self.cacheEnabled && Lisplate.FactoryCache[templateName]) {
      renderFactory = Promise.resolve(Lisplate.FactoryCache[templateName]);
    } else {
      if (!_self.sourceLoader) {
        return Promise.reject(new Error('Must define a sourceLoader'));
      }

      if (!Lisplate.Compiler || !Lisplate.Compiler.compile) {
        return Promise.reject('Compiler is not loaded to compile loaded source');
      }

      renderFactory = _promisifyPossibleAsync(_self
        .sourceLoader)(templateName)
        .then(function(src) {
          var compiled = null;
          var factory = null;

          try {
            compiled = Lisplate.Compiler.compile(templateName, src);
            factory = Lisplate.Utils.loadCompiledSource(compiled);
          } catch (e) {
            return Promise.reject(e);
          }

          return Promise.resolve(factory);
        });
    }

    return renderFactory.then(function(factory) {
      if (_self.cacheEnabled) {
        Lisplate.FactoryCache[templateName] = factory;
      }

      var promise = null;
      if (_self.viewModelLoader) {
        promise = _promisifyPossibleAsync(_self.viewModelLoader)(templateName);
      } else {
        promise = Promise.resolve(null);
      }

      return promise.then(function(viewModelClass) {
        var fn = factory(_self, viewModelClass);
        fn.templateName = templateName;

        if (_self.cacheEnabled) {
          _self.cache[templateName] = fn;
        }
        return fn;
      });
    });
  });

  Lisplate.prototype.render = _callbackify(function render(template, data) {
    var _self = this;
    if (_self.stringsLoader) {
      return _promisifyPossibleAsync(_self
        .stringsLoader)(template.templateName)
        .then(function(strings) {
          return template(data, strings, Lisplate.Runtime);
        });
    } else {
      // done this way for non-async optimization
      return template(data, null, Lisplate.Runtime);
    }
  });

  Lisplate.prototype.renderTemplate = _callbackify(function renderTemplate(templateName, data) {
    var _self = this;

    return _self.loadTemplate(templateName).then(function(template) {
      return _self.render(template, data);
    });
  });

  return Lisplate;
}));
<|endoftext|>


<commit_before>var Accounts = require('./accounts')
  , Broadcasts = require('./broadcasts')
  , Campaigns = require('./campaigns')
  , Conversions = require('./conversions.js')
  , Events = require('./events')
  , Fields = require('./custom_fields')
  , Forms = require('./forms')
  , Purchases = require('./purchases')
  , Subscribers = require('./subscribers')
  , Subscriptions = require('./subscriptions')
  , Tags = require('./tags')
  , Triggers = require('./workflow_triggers')
  , Users = require('./users')
  , Workflows = require('./workflows')
  , Webhooks = require('./webhooks');

function Client (options) {
  if (!(this instanceof Client)) {
    return new Client(options);
  }

  var token = this.token = options.token;
  var tokenType = options.tokenType || "Basic";
  if(tokenType === "Basic") {
    // Encode the token before setting headers
    token = new Buffer(this.token).toString('base64');
  }
  this.headers = {
    "content-type": "application/vnd.api+json",
    "authorization": tokenType + " " + token,
    "User-Agent": "Drip NodeJS Wrapper"
  }
}

// Account methods
Client.prototype.listAccounts = Accounts.listAccounts;
Client.prototype.fetchAccount = Accounts.fetchAccount;
Client.prototype.testAccounts = Accounts.testAccounts;

// Broadcast methods
Client.prototype.listBroadcasts = Broadcasts.listBroadcasts;
Client.prototype.fetchBroadcast = Broadcasts.fetchBroadcast;

// Campaign methods
Client.prototype.listCampaigns = Campaigns.listCampaigns;
Client.prototype.fetchCampaign = Campaigns.fetchCampaign;
Client.prototype.activateCampaign = Campaigns.activateCampaign;
Client.prototype.pauseCampaign = Campaigns.pauseCampaign;
Client.prototype.listAllSubscribesToCampaign = Campaigns.listAllSubscribesToCampaign;
Client.prototype.subscribeToCampaign = Campaigns.subscribeToCampaign;

// Campaign subscrpition methods
Client.prototype.subscriberCampaignSubscriptions = Subscriptions.subscriberCampaignSubscriptions;

// Conversion methods
Client.prototype.listConversions = Conversions.listConversions;
Client.prototype.fetchConversion = Conversions.fetchConversion;

// Custom field methods
Client.prototype.listAllCustomFields = Fields.listAllCustomFields;

// Event methods
Client.prototype.recordEvent = Events.recordEvent;
Client.prototype.recordBatchEvents = Events.recordBatchEvents;
Client.prototype.listEventActions = Events.listEventActions;

// Form methods
Client.prototype.listForms = Forms.listForms;
Client.prototype.fetchForm = Forms.fetchForm;

// Purchases methods
Client.prototype.createPurchase = Purchases.createPurchase;
Client.prototype.listPurchases = Purchases.listPurchases;
Client.prototype.fetchPurchase = Purchases.fetchPurchase;

// Subscriber methods
Client.prototype.listSubscribers = Subscribers.listSubscribers;
Client.prototype.updateSubscriber = Subscribers.updateSubscriber;
Client.prototype.fetchSubscriber = Subscribers.fetchSubscriber;
Client.prototype.unsubscribeFromCampaign = Subscribers.unsubscribeFromCampaign;
Client.prototype.unsubscribeFromAllMailings = Subscribers.unsubscribeFromAllMailings;
Client.prototype.deleteSubscriber = Subscribers.deleteSubscriber;
Client.prototype.updateBatchSubscribers = Subscribers.updateBatchSubscribers;

// Tag methods
Client.prototype.listAllTags = Tags.listAllTags;
Client.prototype.tagSubscriber = Tags.tagSubscriber;
Client.prototype.removeSubscriberTag = Tags.removeSubscriberTag;

// User methods
Client.prototype.fetchUser = Users.fetchUser;

// Webhook methods
Client.prototype.listWebhooks = Webhooks.listWebhooks;
Client.prototype.fetchWebhook = Webhooks.fetchWebhook;
Client.prototype.createWebhook = Webhooks.createWebhook;
Client.prototype.destroyWebhook = Webhooks.destroyWebhook;

// Workflow methods
Client.prototype.listAllWorkflows = Workflows.listAllWorkflows;
Client.prototype.fetchWorkflow = Workflows.fetchWorkflow;
Client.prototype.activateWorkflow = Workflows.activateWorkflow;
Client.prototype.pauseWorkflow = Workflows.pauseWorkflow;
Client.prototype.startOnWorkflow = Workflows.startOnWorkflow;
Client.prototype.removeFromWorkflow = Workflows.removeFromWorkflow;

// Workflow trigger methods
Client.prototype.listTriggers = Triggers.listTriggers;
Client.prototype.createTrigger = Triggers.createTrigger;
Client.prototype.updateTrigger = Triggers.updateTrigger; // <- To do: Revisit this

module.exports = Client

// Todo: create error logging function
// Todo: Handle auth errors separately from server errors
<commit_msg>Small var style change<commit_after>let Accounts = require('./accounts');
let Broadcasts = require('./broadcasts');
let Campaigns = require('./campaigns');
let Conversions = require('./conversions.js');
let Events = require('./events');
let Fields = require('./custom_fields');
let Forms = require('./forms');
let Purchases = require('./purchases');
let Subscribers = require('./subscribers');
let Subscriptions = require('./subscriptions');
let Tags = require('./tags');
let Triggers = require('./workflow_triggers');
let Users = require('./users');
let Workflows = require('./workflows');
let Webhooks = require('./webhooks');

function Client (options) {
  if (!(this instanceof Client)) {
    return new Client(options);
  }

  var token = this.token = options.token;
  var tokenType = options.tokenType || "Basic";
  if(tokenType === "Basic") {
    // Encode the token before setting headers
    token = new Buffer(this.token).toString('base64');
  }
  this.headers = {
    "content-type": "application/vnd.api+json",
    "authorization": tokenType + " " + token,
    "User-Agent": "Drip NodeJS Wrapper"
  }
}

// Account methods
Client.prototype.listAccounts = Accounts.listAccounts;
Client.prototype.fetchAccount = Accounts.fetchAccount;
Client.prototype.testAccounts = Accounts.testAccounts;

// Broadcast methods
Client.prototype.listBroadcasts = Broadcasts.listBroadcasts;
Client.prototype.fetchBroadcast = Broadcasts.fetchBroadcast;

// Campaign methods
Client.prototype.listCampaigns = Campaigns.listCampaigns;
Client.prototype.fetchCampaign = Campaigns.fetchCampaign;
Client.prototype.activateCampaign = Campaigns.activateCampaign;
Client.prototype.pauseCampaign = Campaigns.pauseCampaign;
Client.prototype.listAllSubscribesToCampaign = Campaigns.listAllSubscribesToCampaign;
Client.prototype.subscribeToCampaign = Campaigns.subscribeToCampaign;

// Campaign subscrpition methods
Client.prototype.subscriberCampaignSubscriptions = Subscriptions.subscriberCampaignSubscriptions;

// Conversion methods
Client.prototype.listConversions = Conversions.listConversions;
Client.prototype.fetchConversion = Conversions.fetchConversion;

// Custom field methods
Client.prototype.listAllCustomFields = Fields.listAllCustomFields;

// Event methods
Client.prototype.recordEvent = Events.recordEvent;
Client.prototype.recordBatchEvents = Events.recordBatchEvents;
Client.prototype.listEventActions = Events.listEventActions;

// Form methods
Client.prototype.listForms = Forms.listForms;
Client.prototype.fetchForm = Forms.fetchForm;

// Purchases methods
Client.prototype.createPurchase = Purchases.createPurchase;
Client.prototype.listPurchases = Purchases.listPurchases;
Client.prototype.fetchPurchase = Purchases.fetchPurchase;

// Subscriber methods
Client.prototype.listSubscribers = Subscribers.listSubscribers;
Client.prototype.updateSubscriber = Subscribers.updateSubscriber;
Client.prototype.fetchSubscriber = Subscribers.fetchSubscriber;
Client.prototype.unsubscribeFromCampaign = Subscribers.unsubscribeFromCampaign;
Client.prototype.unsubscribeFromAllMailings = Subscribers.unsubscribeFromAllMailings;
Client.prototype.deleteSubscriber = Subscribers.deleteSubscriber;
Client.prototype.updateBatchSubscribers = Subscribers.updateBatchSubscribers;

// Tag methods
Client.prototype.listAllTags = Tags.listAllTags;
Client.prototype.tagSubscriber = Tags.tagSubscriber;
Client.prototype.removeSubscriberTag = Tags.removeSubscriberTag;

// User methods
Client.prototype.fetchUser = Users.fetchUser;

// Webhook methods
Client.prototype.listWebhooks = Webhooks.listWebhooks;
Client.prototype.fetchWebhook = Webhooks.fetchWebhook;
Client.prototype.createWebhook = Webhooks.createWebhook;
Client.prototype.destroyWebhook = Webhooks.destroyWebhook;

// Workflow methods
Client.prototype.listAllWorkflows = Workflows.listAllWorkflows;
Client.prototype.fetchWorkflow = Workflows.fetchWorkflow;
Client.prototype.activateWorkflow = Workflows.activateWorkflow;
Client.prototype.pauseWorkflow = Workflows.pauseWorkflow;
Client.prototype.startOnWorkflow = Workflows.startOnWorkflow;
Client.prototype.removeFromWorkflow = Workflows.removeFromWorkflow;

// Workflow trigger methods
Client.prototype.listTriggers = Triggers.listTriggers;
Client.prototype.createTrigger = Triggers.createTrigger;
Client.prototype.updateTrigger = Triggers.updateTrigger; // <- To do: Revisit this

module.exports = Client

// Todo: create error logging function
// Todo: Handle auth errors separately from server errors
<|endoftext|>


<commit_before>'use strict';

var http = require('http');
var https = require('https');

function RpcClient(opts) {
  opts = opts || {};
  this.host = opts.host || '127.0.0.1';
  this.port = opts.port || 8332;
  this.user = opts.user || 'user';
  this.pass = opts.pass || 'pass';
  this.protocol = opts.protocol === 'http' ? http : https;
  this.batchedCalls = null;
  this.disableAgent  = opts.disableAgent || false;

  var isRejectUnauthorized = typeof opts.rejectUnauthorized !== 'undefined';
  this.rejectUnauthorized = isRejectUnauthorized ? opts.rejectUnauthorized : true;

  if(RpcClient.config.log) {
    this.log = RpcClient.config.log;
  } else {
    this.log = RpcClient.loggers[RpcClient.config.logger || 'normal'];
  }

}

var cl = console.log.bind(console);

var noop = function() {};

RpcClient.loggers = {
  none: {info: noop, warn: noop, err: noop, debug: noop},
  normal: {info: cl, warn: cl, err: cl, debug: noop},
  debug: {info: cl, warn: cl, err: cl, debug: cl}
};

RpcClient.config = {
  logger: 'normal' // none, normal, debug
};

function rpc(request, callback) {

  var self = this;
  request = JSON.stringify(request);
  var auth = new Buffer(self.user + ':' + self.pass).toString('base64');

  var options = {
    host: self.host,
    path: '/',
    method: 'POST',
    port: self.port,
    rejectUnauthorized: self.rejectUnauthorized,
    agent: self.disableAgent ? false : undefined
  };

  if (self.httpOptions) {
    for (var k in self.httpOptions) {
      options[k] = self.httpOptions[k];
    }
  }

  var called = false;

  var errorMessage = 'Bitcoin JSON-RPC: ';

  var req = this.protocol.request(options, function(res) {

    var buf = '';
    res.on('data', function(data) {
      buf += data;
    });

    res.on('end', function() {

      if (called) {
        return;
      }
      called = true;

      if (res.statusCode === 401) {
        callback(new Error(errorMessage + 'Connection Rejected: 401 Unnauthorized'));
        return;
      }
      if (res.statusCode === 403) {
        callback(new Error(errorMessage + 'Connection Rejected: 403 Forbidden'));
        return;
      }
      if (res.statusCode === 500 && buf.toString('utf8') === 'Work queue depth exceeded') {
        var exceededError = new Error('Bitcoin JSON-RPC: ' + buf.toString('utf8'));
        exceededError.code = 429; // Too many requests
        callback(exceededError);
        return;
      }

      var parsedBuf;
      try {
        parsedBuf = JSON.parse(buf);
      } catch(e) {
        self.log.err(e.stack);
        self.log.err(buf);
        self.log.err('HTTP Status code:' + res.statusCode);
        var err = new Error(errorMessage + 'Error Parsing JSON: ' + e.message);
        callback(err);
        return;
      }

      callback(parsedBuf.error, parsedBuf);

    });
  });

  req.on('error', function(e) {
    var err = new Error(errorMessage + 'Request Error: ' + e.message);
    if (!called) {
      called = true;
      callback(err);
    }
  });

  req.setHeader('Content-Length', request.length);
  req.setHeader('Content-Type', 'application/json');
  req.setHeader('Authorization', 'Basic ' + auth);
  req.write(request);
  req.end();
}

RpcClient.prototype.batch = function(batchCallback, resultCallback) {
  this.batchedCalls = [];
  batchCallback();
  rpc.call(this, this.batchedCalls, resultCallback);
  this.batchedCalls = null;
};

RpcClient.callspec = {
  addMultiSigAddress: '',
  addNode: '',
  backupWallet: '',
  createMultiSig: '',
  createRawTransaction: '',
  decodeRawTransaction: '',
  dumpPrivKey: '',
  encryptWallet: '',
  estimateFee: 'int',
  estimatePriority: 'int',
  generate: 'int',
  getAccount: '',
  getAccountAddress: 'str',
  getAddedNodeInfo: '',
  getAddressMempool: 'obj',
  getAddressUtxos: 'obj',
  getAddressBalance: 'obj',
  getAddressDeltas: 'obj',
  getAddressTxids: 'obj',
  getAddressesByAccount: '',
  getBalance: 'str int',
  getBestBlockHash: '',
  getBlock: 'str bool',
  getBlockchainInfo: '',
  getBlockCount: '',
  getBlockHashes: 'int int',
  getBlockHash: 'int',
  getBlockHeader: 'str',
  getBlockNumber: '',
  getBlockTemplate: '',
  getConnectionCount: '',
  getChainTips: '',
  getDifficulty: '',
  getGenerate: '',
  getHashesPerSec: '',
  getInfo: '',
  getMemoryPool: '',
  getMemPoolInfo: '',
  getMiningInfo: '',
  getNewAddress: '',
  getPeerInfo: '',
  getRawMemPool: '',
  getRawTransaction: 'str int',
  getReceivedByAccount: 'str int',
  getReceivedByAddress: 'str int',
  getSpentInfo: 'obj',
  getTransaction: '',
  getTxOut: 'str int bool',
  getTxOutSetInfo: '',
  getWork: '',
  help: '',
  importAddress: 'str str bool',
  importPrivKey: 'str str bool',
  invalidateBlock: 'str',
  keyPoolRefill: '',
  listAccounts: 'int',
  listAddressGroupings: '',
  listReceivedByAccount: 'int bool',
  listReceivedByAddress: 'int bool',
  listSinceBlock: 'str int',
  listTransactions: 'str int int',
  listUnspent: 'int int',
  listLockUnspent: 'bool',
  lockUnspent: '',
  move: 'str str float int str',
  prioritiseTransaction: 'str float int',
  sendFrom: 'str str float int str str',
  sendMany: 'str obj int str',  //not sure this is will work
  sendRawTransaction: 'str',
  sendToAddress: 'str float str str',
  setAccount: '',
  setGenerate: 'bool int',
  setTxFee: 'float',
  signMessage: '',
  signRawTransaction: '',
  stop: '',
  submitBlock: '',
  validateAddress: '',
  verifyMessage: '',
  walletLock: '',
  walletPassPhrase: 'string int',
  walletPassphraseChange: '',
};

var slice = function(arr, start, end) {
  return Array.prototype.slice.call(arr, start, end);
};

function generateRPCMethods(constructor, apiCalls, rpc) {

  function createRPCMethod(methodName, argMap) {
    return function() {

      var limit = arguments.length - 1;

      if (this.batchedCalls) {
        limit = arguments.length;
      }

      for (var i = 0; i < limit; i++) {
        if(argMap[i]) {
          arguments[i] = argMap[i](arguments[i]);
        }
      }

      if (this.batchedCalls) {
        this.batchedCalls.push({
          jsonrpc: '2.0',
          method: methodName,
          params: slice(arguments),
          id: getRandomId()
        });
      } else {
        rpc.call(this, {
          method: methodName,
          params: slice(arguments, 0, arguments.length - 1),
          id: getRandomId()
        }, arguments[arguments.length - 1]);
      }

    };
  };

  var types = {
    str: function(arg) {
      return arg.toString();
    },
    int: function(arg) {
      return parseFloat(arg);
    },
    float: function(arg) {
      return parseFloat(arg);
    },
    bool: function(arg) {
      return (arg === true || arg == '1' || arg == 'true' || arg.toString().toLowerCase() == 'true');
    },
    obj: function(arg) {
      if(typeof arg === 'string') {
        return JSON.parse(arg);
      }
      return arg;
    }
  };

  for(var k in apiCalls) {
    var spec = apiCalls[k].split(' ');
    for (var i = 0; i < spec.length; i++) {
      if(types[spec[i]]) {
        spec[i] = types[spec[i]];
      } else {
        spec[i] = types.str;
      }
    }
    var methodName = k.toLowerCase();
    constructor.prototype[k] = createRPCMethod(methodName, spec);
    constructor.prototype[methodName] = constructor.prototype[k];
  }

}

function getRandomId() {
  return parseInt(Math.random() * 100000);
}

generateRPCMethods(RpcClient, RpcClient.callspec, rpc);

module.exports = RpcClient;
<commit_msg>Add getblockdeltas to spec<commit_after>'use strict';

var http = require('http');
var https = require('https');

function RpcClient(opts) {
  opts = opts || {};
  this.host = opts.host || '127.0.0.1';
  this.port = opts.port || 8332;
  this.user = opts.user || 'user';
  this.pass = opts.pass || 'pass';
  this.protocol = opts.protocol === 'http' ? http : https;
  this.batchedCalls = null;
  this.disableAgent  = opts.disableAgent || false;

  var isRejectUnauthorized = typeof opts.rejectUnauthorized !== 'undefined';
  this.rejectUnauthorized = isRejectUnauthorized ? opts.rejectUnauthorized : true;

  if(RpcClient.config.log) {
    this.log = RpcClient.config.log;
  } else {
    this.log = RpcClient.loggers[RpcClient.config.logger || 'normal'];
  }

}

var cl = console.log.bind(console);

var noop = function() {};

RpcClient.loggers = {
  none: {info: noop, warn: noop, err: noop, debug: noop},
  normal: {info: cl, warn: cl, err: cl, debug: noop},
  debug: {info: cl, warn: cl, err: cl, debug: cl}
};

RpcClient.config = {
  logger: 'normal' // none, normal, debug
};

function rpc(request, callback) {

  var self = this;
  request = JSON.stringify(request);
  var auth = new Buffer(self.user + ':' + self.pass).toString('base64');

  var options = {
    host: self.host,
    path: '/',
    method: 'POST',
    port: self.port,
    rejectUnauthorized: self.rejectUnauthorized,
    agent: self.disableAgent ? false : undefined
  };

  if (self.httpOptions) {
    for (var k in self.httpOptions) {
      options[k] = self.httpOptions[k];
    }
  }

  var called = false;

  var errorMessage = 'Bitcoin JSON-RPC: ';

  var req = this.protocol.request(options, function(res) {

    var buf = '';
    res.on('data', function(data) {
      buf += data;
    });

    res.on('end', function() {

      if (called) {
        return;
      }
      called = true;

      if (res.statusCode === 401) {
        callback(new Error(errorMessage + 'Connection Rejected: 401 Unnauthorized'));
        return;
      }
      if (res.statusCode === 403) {
        callback(new Error(errorMessage + 'Connection Rejected: 403 Forbidden'));
        return;
      }
      if (res.statusCode === 500 && buf.toString('utf8') === 'Work queue depth exceeded') {
        var exceededError = new Error('Bitcoin JSON-RPC: ' + buf.toString('utf8'));
        exceededError.code = 429; // Too many requests
        callback(exceededError);
        return;
      }

      var parsedBuf;
      try {
        parsedBuf = JSON.parse(buf);
      } catch(e) {
        self.log.err(e.stack);
        self.log.err(buf);
        self.log.err('HTTP Status code:' + res.statusCode);
        var err = new Error(errorMessage + 'Error Parsing JSON: ' + e.message);
        callback(err);
        return;
      }

      callback(parsedBuf.error, parsedBuf);

    });
  });

  req.on('error', function(e) {
    var err = new Error(errorMessage + 'Request Error: ' + e.message);
    if (!called) {
      called = true;
      callback(err);
    }
  });

  req.setHeader('Content-Length', request.length);
  req.setHeader('Content-Type', 'application/json');
  req.setHeader('Authorization', 'Basic ' + auth);
  req.write(request);
  req.end();
}

RpcClient.prototype.batch = function(batchCallback, resultCallback) {
  this.batchedCalls = [];
  batchCallback();
  rpc.call(this, this.batchedCalls, resultCallback);
  this.batchedCalls = null;
};

RpcClient.callspec = {
  addMultiSigAddress: '',
  addNode: '',
  backupWallet: '',
  createMultiSig: '',
  createRawTransaction: '',
  decodeRawTransaction: '',
  dumpPrivKey: '',
  encryptWallet: '',
  estimateFee: 'int',
  estimatePriority: 'int',
  generate: 'int',
  getAccount: '',
  getAccountAddress: 'str',
  getAddedNodeInfo: '',
  getAddressMempool: 'obj',
  getAddressUtxos: 'obj',
  getAddressBalance: 'obj',
  getAddressDeltas: 'obj',
  getAddressTxids: 'obj',
  getAddressesByAccount: '',
  getBalance: 'str int',
  getBestBlockHash: '',
  getBlockDeltas: 'str',
  getBlock: 'str bool',
  getBlockchainInfo: '',
  getBlockCount: '',
  getBlockHashes: 'int int',
  getBlockHash: 'int',
  getBlockHeader: 'str',
  getBlockNumber: '',
  getBlockTemplate: '',
  getConnectionCount: '',
  getChainTips: '',
  getDifficulty: '',
  getGenerate: '',
  getHashesPerSec: '',
  getInfo: '',
  getMemoryPool: '',
  getMemPoolInfo: '',
  getMiningInfo: '',
  getNewAddress: '',
  getPeerInfo: '',
  getRawMemPool: '',
  getRawTransaction: 'str int',
  getReceivedByAccount: 'str int',
  getReceivedByAddress: 'str int',
  getSpentInfo: 'obj',
  getTransaction: '',
  getTxOut: 'str int bool',
  getTxOutSetInfo: '',
  getWork: '',
  help: '',
  importAddress: 'str str bool',
  importPrivKey: 'str str bool',
  invalidateBlock: 'str',
  keyPoolRefill: '',
  listAccounts: 'int',
  listAddressGroupings: '',
  listReceivedByAccount: 'int bool',
  listReceivedByAddress: 'int bool',
  listSinceBlock: 'str int',
  listTransactions: 'str int int',
  listUnspent: 'int int',
  listLockUnspent: 'bool',
  lockUnspent: '',
  move: 'str str float int str',
  prioritiseTransaction: 'str float int',
  sendFrom: 'str str float int str str',
  sendMany: 'str obj int str',  //not sure this is will work
  sendRawTransaction: 'str',
  sendToAddress: 'str float str str',
  setAccount: '',
  setGenerate: 'bool int',
  setTxFee: 'float',
  signMessage: '',
  signRawTransaction: '',
  stop: '',
  submitBlock: '',
  validateAddress: '',
  verifyMessage: '',
  walletLock: '',
  walletPassPhrase: 'string int',
  walletPassphraseChange: '',
};

var slice = function(arr, start, end) {
  return Array.prototype.slice.call(arr, start, end);
};

function generateRPCMethods(constructor, apiCalls, rpc) {

  function createRPCMethod(methodName, argMap) {
    return function() {

      var limit = arguments.length - 1;

      if (this.batchedCalls) {
        limit = arguments.length;
      }

      for (var i = 0; i < limit; i++) {
        if(argMap[i]) {
          arguments[i] = argMap[i](arguments[i]);
        }
      }

      if (this.batchedCalls) {
        this.batchedCalls.push({
          jsonrpc: '2.0',
          method: methodName,
          params: slice(arguments),
          id: getRandomId()
        });
      } else {
        rpc.call(this, {
          method: methodName,
          params: slice(arguments, 0, arguments.length - 1),
          id: getRandomId()
        }, arguments[arguments.length - 1]);
      }

    };
  };

  var types = {
    str: function(arg) {
      return arg.toString();
    },
    int: function(arg) {
      return parseFloat(arg);
    },
    float: function(arg) {
      return parseFloat(arg);
    },
    bool: function(arg) {
      return (arg === true || arg == '1' || arg == 'true' || arg.toString().toLowerCase() == 'true');
    },
    obj: function(arg) {
      if(typeof arg === 'string') {
        return JSON.parse(arg);
      }
      return arg;
    }
  };

  for(var k in apiCalls) {
    var spec = apiCalls[k].split(' ');
    for (var i = 0; i < spec.length; i++) {
      if(types[spec[i]]) {
        spec[i] = types[spec[i]];
      } else {
        spec[i] = types.str;
      }
    }
    var methodName = k.toLowerCase();
    constructor.prototype[k] = createRPCMethod(methodName, spec);
    constructor.prototype[methodName] = constructor.prototype[k];
  }

}

function getRandomId() {
  return parseInt(Math.random() * 100000);
}

generateRPCMethods(RpcClient, RpcClient.callspec, rpc);

module.exports = RpcClient;
<|endoftext|>


<commit_before>var DocumentClient = require('documentdb').DocumentClient;
var Hoek = require('hoek');

var internals = {};
var externals = {};

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

	Hoek.assert(options.endpoint !== undefined, 'endpoint must be defined');
	Hoek.assert(options.masterKey !== undefined, 'masterKey must be defined');

	externals.client = new DocumentClient(options.endpoint, {'masterKey': options.masterKey});
	externals.methods = {
		getOrCreateDatabase: getOrCreateDatabase,
		getOrCreateCollection: getOrCreateCollection
	},

	plugin.expose('client', externals.client);
	plugin.expose('methods', externals.methods);

	next();
};

exports.register.attributes = {
	pkg: require('../package.json')
};

function getOrCreateDatabase(databaseId, callback) {

	var querySpec = {
		query: 'SELECT * FROM root r WHERE r.id=@id',
		parameters: [{
			name: '@id',
			value: databaseId
		}]
	};

	externals.client.queryDatabases(querySpec).toArray(function (err, results) {

		if (err) {
			callback(err);
		} else {
			if (results.length === 0) {
				var databaseSpec = {
					id: databaseId
				};

				internals.documentDb.client.createDatabase(databaseSpec, function (err, created) {

					if (err) {
						return callback(err);
					}
					return callback(null, created);
				});
			} else {
				return callback(null, results[0]);
			}
		}
	});
}

function getOrCreateCollection(databaseLink, collectionId, callback) {

	var querySpec = {
		query: "SELECT * FROM root r WHERE r.id='articles'"
	};

	externals.client.queryCollections(databaseLink, querySpec).toArray(function (err, results) {

		if (err) {
			callback(err);
		} else {
			if (results.length === 0) {
				var collectionSpec = {
					id: collectionId
				};

				internals.documentDb.client.createCollection(databaseLink, collectionSpec, function (err, created) {

					callback(null, created);
				});

			} else {
				callback(null, results[0]);
			}
		}
	});
}
<commit_msg>Add getDocuments method<commit_after>var DocumentClient = require('documentdb').DocumentClient;
var Hoek = require('hoek');

var internals = {};
var externals = {};

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

	Hoek.assert(options.endpoint !== undefined, 'endpoint must be defined');
	Hoek.assert(options.masterKey !== undefined, 'masterKey must be defined');

	externals.client = new DocumentClient(options.endpoint, {'masterKey': options.masterKey});
	externals.methods = {
		getOrCreateDatabase: getOrCreateDatabase,
		getOrCreateCollection: getOrCreateCollection,
		getDocuments: getDocuments
	},

	plugin.expose('client', externals.client);
	plugin.expose('methods', externals.methods);

	next();
};

exports.register.attributes = {
	pkg: require('../package.json')
};

function getOrCreateDatabase(databaseId, callback) {

	var querySpec = {
		query: 'SELECT * FROM root r WHERE r.id=@id',
		parameters: [{
			name: '@id',
			value: databaseId
		}]
	};

	externals.client.queryDatabases(querySpec).toArray(function (err, results) {

		if (err) {
			callback(err);
		} else {
			if (results.length === 0) {
				var databaseSpec = {
					id: databaseId
				};

				internals.documentDb.client.createDatabase(databaseSpec, function (err, created) {

					if (err) {
						return callback(err);
					}
					return callback(null, created);
				});
			} else {
				return callback(null, results[0]);
			}
		}
	});
}

function getOrCreateCollection(databaseLink, collectionId, callback) {

	var querySpec = {
		query: "SELECT * FROM root r WHERE r.id='articles'"
	};

	externals.client.queryCollections(databaseLink, querySpec).toArray(function (err, results) {

		if (err) {
			callback(err);
		} else {
			if (results.length === 0) {
				var collectionSpec = {
					id: collectionId
				};

				internals.documentDb.client.createCollection(databaseLink, collectionSpec, function (err, created) {

					callback(null, created);
				});

			} else {
				callback(null, results[0]);
			}
		}
	});
}

function getDocuments(collection, querySpec, callback) {

	client.queryDocuments(collection._self, querySpec).toArray(function (err, results) {

		if (err) {
			return callback(err);
		}
		callback(null, results);
	});
}
<|endoftext|>


<commit_before>'use strict';

const util = require('./util');
const collect = require('./collect');
const sitespeed = require('./sitespeed');
const webpagetest = require('./webpagetest');
const Statistics = require('./statistics').Statistics;

function cleanupStatistics(pages, config, firstParty) {
  pages.forEach(page => {
    page.expireStats = page.expireStats.summarize();
    page.lastModifiedStats = page.lastModifiedStats.summarize();
    page.cookieStats = page.cookieStats.summarize();
    page.totalDomains = Object.keys(page.domains).length;
    if (!config.includeAssets) {
      page.assets = [];
    }
    if (!firstParty) {
      page.firstParty = {};
      page.thirdParty = {};
    } else {
      page.firstParty.cookieStats = page.firstParty.cookieStats.summarize();
      page.thirdParty.cookieStats = page.thirdParty.cookieStats.summarize();
    }
  });
}
/**
 * Convert a HAR object to a better page summary.
 * @module PageXray
 */

module.exports = {
  /**
   * Convert one HAR to a page. Use this when you are interested
   * of one specific run in a HAR.
   * @param {Object} har The HAR to process.
   * @param {Number} index The index of the HAR file of the run that will be converted.
   * @param {Object} config The config object.
   * @returns {Array} The converted page object.
   */
  convertIndex: (har, index, config) => {
    // TODO in the future only convert that specific run to save time
    const pages = module.exports.convert(har, config);
    return pages[index];
  },

  /**
   * Convert a HAR object to an array of pages.
   * @param {Object} har The HAR to process.
   * @param {Object} config The config object.
   * @returns {Array} The converted page objects.
   */

  convert: (har, config) => {
    config = config || {};

    const pages = [];
    let currentPage = {};
    const testedPages = {};
    let firstParty;

    if (
      config.firstParty ||
      (har.log.pages[0]._meta && har.log.pages[0]._meta.firstParty)
    ) {
      firstParty = config.firstParty || har.log.pages[0]._meta.firstParty;
    }

    function sortByTime(a, b) {
      // We can "fix" this later by checking entry.pageref
      // and for WebPagetest use entry._run
      return (
        new Date(a.startedDateTime).getTime() -
        new Date(b.startedDateTime).getTime()
      );
    }

    const entries = Array.from(har.log.entries);
    // Sometimes WebPageTest has request in run number 2
    // that has timings from run number 1
    if (har.log.creator.name !== 'WebPagetest') {
      entries.sort(sortByTime);
    }

    // Summarize the timings for all pages
    const pageTimings = {};
    const pageUrls = {};
    for (let page of har.log.pages) {
      const pageStartTime = new Date(page.startedDateTime).getTime();
      pageTimings[page.id] = {
        onLoad: pageStartTime + page.pageTimings.onLoad,
        onContentLoad: pageStartTime + page.pageTimings.onContentLoad
      };
      // Browsertime adds the URL to make sure we use the browsers URL
      // for SPA:s
      if (page._url) {
        pageUrls[page.id] = page._url;
      }
    }
    entries.forEach(entry => {
      if (!testedPages[entry.pageref]) {
        const requests = util.getDocumentRequests(entries, entry.pageref);

        const finalEntry = requests.pop();
        const redirectChain = requests.map(entry => entry.request.url);
        const httpVersion = finalEntry.response.httpVersion;
        const finalUrl = finalEntry.request.url;
        const baseDomain = util.getHostname(finalUrl);
        // If there is no setup for a first party setup,
        // then use a default one
        if (!firstParty) {
          firstParty = '.*' + util.getMainDomain(baseDomain) + '.*';
        }
        currentPage = {
          url: pageUrls[entry.pageref]
            ? pageUrls[entry.pageref]
            : entry.request.url,
          meta: { browser: {}, startedDateTime: entry.startedDateTime },
          finalUrl,
          baseDomain: baseDomain,
          firstPartyRegEx: firstParty,
          documentRedirects: redirectChain.length,
          redirectChain,
          transferSize: 0,
          contentSize: 0,
          headerSize: 0,
          requests: 0,
          missingCompression: 0,
          fullyLoaded: util.getFullyLoaded(
            entry.pageref,
            entries,
            entry.startedDateTime
          ),
          httpType: util.getConnectionType(httpVersion),
          httpVersion: util.getHTTPVersion(httpVersion),
          contentTypes: collect.defaultContentTypes(),
          assets: [],
          responseCodes: {},
          firstParty: {
            cookieStats: new Statistics(),
            contentTypes: collect.defaultContentTypes()
          },
          thirdParty: {
            cookieStats: new Statistics(),
            contentTypes: collect.defaultContentTypes()
          },
          domains: {},
          expireStats: new Statistics(),
          lastModifiedStats: new Statistics(),
          cookieStats: new Statistics(),
          afterOnContentLoad: {
            requests: 0,
            transferSize: 0,
            contentTypes: collect.defaultContentTypes()
          },
          afterOnLoad: {
            requests: 0,
            transferSize: 0,
            contentTypes: collect.defaultContentTypes()
          }
        };

        if (har.log.browser && har.log.browser.name) {
          currentPage.meta.browser.name = har.log.browser.name;
        }
        if (har.log.browser && har.log.browser.version) {
          currentPage.meta.browser.version = har.log.browser.version;
        }

        testedPages[entry.pageref] = currentPage;
        pages.push(currentPage);
      }
      const asset = collect.asset(entry);
      currentPage.expireStats.add(asset.expires);
      if (asset.timeSinceLastModified !== -1) {
        currentPage.lastModifiedStats.add(asset.timeSinceLastModified);
      }
      currentPage.cookieStats.add(asset.cookies);

      currentPage.assets.push(asset);
      collect.domainInfo(asset, currentPage.domains, config);
      collect.responseCode(asset, currentPage.responseCodes);
      collect.contentType(asset, currentPage.contentTypes);
      collect.missingCompression(asset, currentPage);

      currentPage.transferSize += entry.response.bodySize;
      currentPage.contentSize +=
        entry.response.content.size < 0
          ? entry.response.bodySize
          : entry.response.content.size;
      currentPage.headerSize += Math.max(entry.response.headersSize, 0);

      const entryStart = new Date(entry.startedDateTime).getTime();
      if (
        pageTimings[entry.pageref] &&
        entryStart > pageTimings[entry.pageref].onLoad
      ) {
        currentPage.afterOnLoad.requests += 1;
        currentPage.afterOnLoad.transferSize += entry.response.bodySize;
        collect.contentType(asset, currentPage.afterOnLoad.contentTypes);
      }
      if (
        pageTimings[entry.pageref] &&
        entryStart > pageTimings[entry.pageref].onContentLoad
      ) {
        currentPage.afterOnContentLoad.requests += 1;
        currentPage.afterOnContentLoad.transferSize += entry.response.bodySize;
        collect.contentType(asset, currentPage.afterOnContentLoad.contentTypes);
      }
      // add first/third party info
      if (firstParty) {
        // is it a third party asset?

        let stats = currentPage.thirdParty;

        if (asset.url.match(firstParty)) {
          stats = currentPage.firstParty;
        }

        stats.requests = stats.requests + 1 || 1;
        stats.transferSize =
          stats.transferSize + asset.transferSize || asset.transferSize;
        stats.contentSize =
          stats.contentSize + asset.contentSize || asset.contentSize;
        stats.headerSize =
          stats.headerSize + asset.headerSize || asset.headerSize;
        stats.cookieStats.add(asset.cookies);
        collect.contentType(asset, stats.contentTypes);
      }

      currentPage.requests += 1;
    });

    // cleanup the stats
    cleanupStatistics(pages, config, firstParty);

    // If we have that extra meta field in the HAR, we are pretty sure
    // it is generated using sitespeed.io/browsertime, so add those
    // extra metrics
    if (har.log.pages[0]._meta) {
      sitespeed.addMetrics(har, pages);
    } else if (har.log.creator.name === 'WebPagetest') {
      webpagetest.addMetrics(har, pages);
    }
    return pages;
  }
};
<commit_msg>Test first party rtegex on domain not URL #72 (#73)<commit_after>'use strict';

const util = require('./util');
const collect = require('./collect');
const sitespeed = require('./sitespeed');
const webpagetest = require('./webpagetest');
const Statistics = require('./statistics').Statistics;

function cleanupStatistics(pages, config, firstParty) {
  pages.forEach(page => {
    page.expireStats = page.expireStats.summarize();
    page.lastModifiedStats = page.lastModifiedStats.summarize();
    page.cookieStats = page.cookieStats.summarize();
    page.totalDomains = Object.keys(page.domains).length;
    if (!config.includeAssets) {
      page.assets = [];
    }
    if (!firstParty) {
      page.firstParty = {};
      page.thirdParty = {};
    } else {
      page.firstParty.cookieStats = page.firstParty.cookieStats.summarize();
      page.thirdParty.cookieStats = page.thirdParty.cookieStats.summarize();
    }
  });
}
/**
 * Convert a HAR object to a better page summary.
 * @module PageXray
 */

module.exports = {
  /**
   * Convert one HAR to a page. Use this when you are interested
   * of one specific run in a HAR.
   * @param {Object} har The HAR to process.
   * @param {Number} index The index of the HAR file of the run that will be converted.
   * @param {Object} config The config object.
   * @returns {Array} The converted page object.
   */
  convertIndex: (har, index, config) => {
    // TODO in the future only convert that specific run to save time
    const pages = module.exports.convert(har, config);
    return pages[index];
  },

  /**
   * Convert a HAR object to an array of pages.
   * @param {Object} har The HAR to process.
   * @param {Object} config The config object.
   * @returns {Array} The converted page objects.
   */

  convert: (har, config) => {
    config = config || {};

    const pages = [];
    let currentPage = {};
    const testedPages = {};
    let firstParty;

    if (
      config.firstParty ||
      (har.log.pages[0]._meta && har.log.pages[0]._meta.firstParty)
    ) {
      firstParty = config.firstParty || har.log.pages[0]._meta.firstParty;
    }

    function sortByTime(a, b) {
      // We can "fix" this later by checking entry.pageref
      // and for WebPagetest use entry._run
      return (
        new Date(a.startedDateTime).getTime() -
        new Date(b.startedDateTime).getTime()
      );
    }

    const entries = Array.from(har.log.entries);
    // Sometimes WebPageTest has request in run number 2
    // that has timings from run number 1
    if (har.log.creator.name !== 'WebPagetest') {
      entries.sort(sortByTime);
    }

    // Summarize the timings for all pages
    const pageTimings = {};
    const pageUrls = {};
    for (let page of har.log.pages) {
      const pageStartTime = new Date(page.startedDateTime).getTime();
      pageTimings[page.id] = {
        onLoad: pageStartTime + page.pageTimings.onLoad,
        onContentLoad: pageStartTime + page.pageTimings.onContentLoad
      };
      // Browsertime adds the URL to make sure we use the browsers URL
      // for SPA:s
      if (page._url) {
        pageUrls[page.id] = page._url;
      }
    }
    entries.forEach(entry => {
      if (!testedPages[entry.pageref]) {
        const requests = util.getDocumentRequests(entries, entry.pageref);

        const finalEntry = requests.pop();
        const redirectChain = requests.map(entry => entry.request.url);
        const httpVersion = finalEntry.response.httpVersion;
        const finalUrl = finalEntry.request.url;
        const baseDomain = util.getHostname(finalUrl);
        // If there is no setup for a first party setup,
        // then use a default one
        if (!firstParty) {
          firstParty = '.*' + util.getMainDomain(baseDomain) + '.*';
        }
        currentPage = {
          url: pageUrls[entry.pageref]
            ? pageUrls[entry.pageref]
            : entry.request.url,
          meta: { browser: {}, startedDateTime: entry.startedDateTime },
          finalUrl,
          baseDomain: baseDomain,
          firstPartyRegEx: firstParty,
          documentRedirects: redirectChain.length,
          redirectChain,
          transferSize: 0,
          contentSize: 0,
          headerSize: 0,
          requests: 0,
          missingCompression: 0,
          fullyLoaded: util.getFullyLoaded(
            entry.pageref,
            entries,
            entry.startedDateTime
          ),
          httpType: util.getConnectionType(httpVersion),
          httpVersion: util.getHTTPVersion(httpVersion),
          contentTypes: collect.defaultContentTypes(),
          assets: [],
          responseCodes: {},
          firstParty: {
            cookieStats: new Statistics(),
            contentTypes: collect.defaultContentTypes()
          },
          thirdParty: {
            cookieStats: new Statistics(),
            contentTypes: collect.defaultContentTypes()
          },
          domains: {},
          expireStats: new Statistics(),
          lastModifiedStats: new Statistics(),
          cookieStats: new Statistics(),
          afterOnContentLoad: {
            requests: 0,
            transferSize: 0,
            contentTypes: collect.defaultContentTypes()
          },
          afterOnLoad: {
            requests: 0,
            transferSize: 0,
            contentTypes: collect.defaultContentTypes()
          }
        };

        if (har.log.browser && har.log.browser.name) {
          currentPage.meta.browser.name = har.log.browser.name;
        }
        if (har.log.browser && har.log.browser.version) {
          currentPage.meta.browser.version = har.log.browser.version;
        }

        testedPages[entry.pageref] = currentPage;
        pages.push(currentPage);
      }
      const asset = collect.asset(entry);
      currentPage.expireStats.add(asset.expires);
      if (asset.timeSinceLastModified !== -1) {
        currentPage.lastModifiedStats.add(asset.timeSinceLastModified);
      }
      currentPage.cookieStats.add(asset.cookies);

      currentPage.assets.push(asset);
      collect.domainInfo(asset, currentPage.domains, config);
      collect.responseCode(asset, currentPage.responseCodes);
      collect.contentType(asset, currentPage.contentTypes);
      collect.missingCompression(asset, currentPage);

      currentPage.transferSize += entry.response.bodySize;
      currentPage.contentSize +=
        entry.response.content.size < 0
          ? entry.response.bodySize
          : entry.response.content.size;
      currentPage.headerSize += Math.max(entry.response.headersSize, 0);

      const entryStart = new Date(entry.startedDateTime).getTime();
      if (
        pageTimings[entry.pageref] &&
        entryStart > pageTimings[entry.pageref].onLoad
      ) {
        currentPage.afterOnLoad.requests += 1;
        currentPage.afterOnLoad.transferSize += entry.response.bodySize;
        collect.contentType(asset, currentPage.afterOnLoad.contentTypes);
      }
      if (
        pageTimings[entry.pageref] &&
        entryStart > pageTimings[entry.pageref].onContentLoad
      ) {
        currentPage.afterOnContentLoad.requests += 1;
        currentPage.afterOnContentLoad.transferSize += entry.response.bodySize;
        collect.contentType(asset, currentPage.afterOnContentLoad.contentTypes);
      }
      // add first/third party info
      if (firstParty) {
        // is it a third party asset?
        let stats = currentPage.thirdParty;
        if (util.getHostname(asset.url).match(firstParty)) {
          stats = currentPage.firstParty;
        }

        stats.requests = stats.requests + 1 || 1;
        stats.transferSize =
          stats.transferSize + asset.transferSize || asset.transferSize;
        stats.contentSize =
          stats.contentSize + asset.contentSize || asset.contentSize;
        stats.headerSize =
          stats.headerSize + asset.headerSize || asset.headerSize;
        stats.cookieStats.add(asset.cookies);
        collect.contentType(asset, stats.contentTypes);
      }

      currentPage.requests += 1;
    });

    // cleanup the stats
    cleanupStatistics(pages, config, firstParty);

    // If we have that extra meta field in the HAR, we are pretty sure
    // it is generated using sitespeed.io/browsertime, so add those
    // extra metrics
    if (har.log.pages[0]._meta) {
      sitespeed.addMetrics(har, pages);
    } else if (har.log.creator.name === 'WebPagetest') {
      webpagetest.addMetrics(har, pages);
    }
    return pages;
  }
};
<|endoftext|>


<commit_before><<<<<<< HEAD
'use strict'

const BroccoliFilter = require('broccoli-filter')

const tag = require('./tag')
const Injector = require('./injector')
const livereload = require('livereload')

class BroccoliLivereload extends BroccoliFilter {

    constructor(inputNodes, options) {
        super(inputNodes, options)

        this.inputEncoding = null
        this.outputEncoding = null

        this._building = process.argv.indexOf('build') > 0
        this._serving = process.argv.indexOf('serve') > 0

        options.options = options.options || {}
        options.options.port = options.options.port || 35729
        options.options.delay = options.options.delay || 100 // debounce changes

        this._livereloadPort = options.options.port
        this._injector = new Injector(options.target, tag(this._livereloadPort))

        if (this._serving) {
            this._livereload = livereload.createServer(options.options)
        }
    }

    processString(contents, path) {

        if (this._building) {
            return contents
        }

        // Notify live reload server that file changed
        this._livereload.filterRefresh(path)

        const inject = this._injector.matches(path)

        if (inject) {
            return this._injector.inject(contents)
        }

        return contents
    }
}

module.exports = BroccoliLivereload
=======
'use strict'

const BroccoliFilter = require('broccoli-filter')

const tag = require('./tag')
const Injector = require('./injector')
const livereload = require('livereload')

class BroccoliLivereload extends BroccoliFilter {

    constructor(inputNodes, options) {
        super(inputNodes, options)

        this.inputEncoding = null
        this.outputEncoding = null

        this._building = process.argv.indexOf('build') > 0
        this._serving = process.argv.indexOf('serve') > 0

        this._livereloadPort = options.options && options.options.port || 35729
        this._injector = new Injector(options.target, tag(this._livereloadPort))

        if (this._serving) {
            this._livereload = livereload.createServer(options.options)
        }
    }

    processString(contents, path) {

        if (this._building) {
            return contents
        }

        this._lastRefreshed = path

        const inject = this._injector.matches(path)

        if (inject) {
            return this._injector.inject(contents)
        } else {
            return contents
        }
    }

    build() {
        return super.build().then(() => {
            this._serving && this._livereload.filterRefresh(this._lastRefreshed)
        })
    }
}

module.exports = BroccoliLivereload
>>>>>>> chore: remove some line breaks
<commit_msg>chroe: remove git merge annotations<commit_after>'use strict'

const BroccoliFilter = require('broccoli-filter')

const tag = require('./tag')
const Injector = require('./injector')
const livereload = require('livereload')

class BroccoliLivereload extends BroccoliFilter {

    constructor(inputNodes, options) {
        super(inputNodes, options)

        this.inputEncoding = null
        this.outputEncoding = null

        this._building = process.argv.indexOf('build') > 0
        this._serving = process.argv.indexOf('serve') > 0

        options.options = options.options || {}
        options.options.port = options.options.port || 35729
        options.options.delay = options.options.delay || 100 // debounce changes

        this._livereloadPort = options.options.port
        this._injector = new Injector(options.target, tag(this._livereloadPort))

        if (this._serving) {
            this._livereload = livereload.createServer(options.options)
        }
    }

    processString(contents, path) {

        if (this._building) {
            return contents
        }

        // Notify live reload server that file changed
        this._livereload.filterRefresh(path)

        const inject = this._injector.matches(path)

        if (inject) {
            return this._injector.inject(contents)
        }

        return contents
    }
}

module.exports = BroccoliLivereload
<|endoftext|>