<commit_before>var http = Npm.require('http');
var hostname = Npm.require('os').hostname();
var logger = Npm.require('debug')('kadira:apm');
var Fibers = Npm.require('fibers');

Kadira.models = {};
Kadira.options = {};
Kadira.env = {
  currentSub: null, // keep current subscription inside ddp
  kadiraInfo: new Meteor.EnvironmentVariable(),
};
Kadira.waitTimeBuilder = new WaitTimeBuilder();
Kadira.errors = [];
Kadira.errors.addFilter = Kadira.errors.push.bind(Kadira.errors);

Kadira.connect = function(appId, appSecret, options) {
  options = options || {};
  options.appId = appId;
  options.appSecret = appSecret;
  options.payloadTimeout = options.payloadTimeout || 1000 * 20;
  options.endpoint = options.endpoint || "https://engine.kadira.io";
  options.thresholds = options.thresholds || {};

  // remove trailing slash from endpoint url (if any)
  if(_.last(options.endpoint) === '/') {
    options.endpoint = options.endpoint.substr(0, options.endpoint.length - 1);
  }

  // error tracking is enabled by default
  if(options.enableErrorTracking === undefined) {
    options.enableErrorTracking = true;
  }

  Kadira.options = options;
  Kadira.options.authHeaders = {
    'APM-APP-ID': Kadira.options.appId,
    'APM-APP-SECRET': Kadira.options.appSecret
  };

  Kadira.syncedDate = new Ntp(options.endpoint);
  Kadira.syncedDate.sync();
  Kadira.models.methods = new MethodsModel(options.thresholds.methods);
  Kadira.models.pubsub = new PubsubModel();
  Kadira.models.system = new SystemModel();
  Kadira.models.error = new ErrorModel(appId);
  // handle pre-added filters
  Kadira.errors.forEach(Kadira.models.error.addFilter.bind(Kadira.models.error));
  Kadira.errors = Kadira.models.error;

  Kadira.sendPayload = sendPayload;

  // setting runtime info, which will be sent to kadira
  __meteor_runtime_config__.kadira = {
    appId: appId,
    endpoint: options.endpoint
  };

  if(options.enableErrorTracking) {
    Kadira.enableErrorTracking();
  } else {
    Kadira.disableErrorTracking();
  }

  if(appId && appSecret) {
    appId = appId.trim();
    appSecret = appSecret.trim();

    pingToCheckAuth(function(){
      schedulePayloadSend();
    });
    logger('connected to app: ', appId);
  } else {
    throw new Error('Kadira: required appId and appSecret');
  }

  //start wrapping Meteor's internal methods
  Kadira._startInstrumenting(function() {
    console.log('Kadira: completed instrumenting the app')
    Kadira.connected = true;
  });

  Meteor.publish(null, function () {
    var options = __meteor_runtime_config__.kadira;
    this.added('kadira_settings', Random.id(), options);
    this.ready();
  });

  var payloadRetries = 0;
  var payloadRetry = new Retry({
      minCount: 0, // don't do any immediate payloadRetries
      baseTimeout: 5*1000,
      maxTimeout: 60000
  });

  function sendPayload(callback) {

    callHTTP();

    function callHTTP() {
      new Fibers(function() {
        var payload = Kadira._buildPayload();
        var headers = Kadira.options.authHeaders;
        var httpOptions = {headers: headers, data: payload};

        try {
          var response = HTTP.call('POST', options.endpoint, httpOptions);
          processResponse(response);
        } catch(err) {
          tryAgain(err);
        }
      }).run();
    }

    function processResponse(response) {
      if(response.statusCode == '401') {
        throw new Error('Kadira: AppId, AppSecret combination is invalid');
      } else if(response.statusCode == '200') {
        //success send again in 10 secs
        schedulePayloadSend();
        if(payloadRetries > 0) {
          logger('connected again and payload sent.')
        }
        cleaPayloadRetry();
        callback && callback();
      } else {
        tryAgain();
      }
    }

    function tryAgain(err) {
      err = err || {};
      logger('retrying to send payload to server')
      if(++payloadRetries < 5) {
        payloadRetry.retryLater(payloadRetries, callHTTP);
      } else {
        console.error('Kadira: Error sending payload(dropped after 5 tries) ', err.message);
        cleaPayloadRetry();
        schedulePayloadSend();
      }
    }

  }

  function cleaPayloadRetry() {
    payloadRetries = 0;
    payloadRetry.clear();
  }

  function schedulePayloadSend() {
    setTimeout(sendPayload, options.payloadTimeout);
  }

  var authCheckFailures = 0;
  function pingToCheckAuth(callback){
    var httpOptions = {headers: Kadira.options.authHeaders, data: {}};
    var endpoint = options.endpoint + '/ping'

    new Fibers(function() {
      HTTP.call('POST', endpoint, httpOptions, function(err, response){
        if(response) {
          if(response.statusCode == 200) {
            console.log('Kadira: successfully authenticated');
            authRetry.clear();
            callback();
          } else if(response.statusCode == 401) {
            console.error('Kadira: authenticatation failed - check your appId & appSecret')
          } else {
            retryPingToCheckAuth(callback);
          }
        } else {
          retryPingToCheckAuth();
        }
      });
    }).run();

    var authRetry = new Retry({
      minCount: 0, // don't do any immediate retries
      baseTimeout: 5*1000 // start with 30s
    });

    function retryPingToCheckAuth(){
      console.log('Kadira: retrying to authenticate');
      authRetry.retryLater(authCheckFailures, function(){
        pingToCheckAuth(callback)
      });
    }
  }
};

//track how many times we've sent the data (once per minute)
Kadira._buildPayload = function () {
  var payload = {host: hostname};
  var buildDetailedInfo = Kadira._isDetailedInfo();
  _.extend(payload, Kadira.models.methods.buildPayload(buildDetailedInfo));
  _.extend(payload, Kadira.models.pubsub.buildPayload(buildDetailedInfo));
  _.extend(payload, Kadira.models.system.buildPayload());
  if(Kadira.options.enableErrorTracking) {
    _.extend(payload, Kadira.models.error.buildPayload());
  }

  return payload;
}

Kadira._countDataSent = 0;
Kadira._detailInfoSentInterval = Math.ceil((1000*60) / Kadira.options.payloadTimeout);
Kadira._isDetailedInfo = function () {
  return (Kadira._countDataSent++ % Kadira._detailInfoSentInterval) == 0;
}

// this return the __kadiraInfo from the current Fiber by default
// if called with 2nd argument as true, it will get the kadira info from
// Meteor.EnvironmentVariable
//
// WARNNING: retunred info object is the reference object.
//  Changing it might cause issues when building traces. So use with care
Kadira._getInfo = function(currentFiber, useEnvironmentVariable) {
  currentFiber = currentFiber || Fibers.current;
  if(currentFiber) {
    if(useEnvironmentVariable) {
      return Kadira.env.kadiraInfo.get();
    }
    return currentFiber.__kadiraInfo;
  }
};

// this does not clone the info object. So, use with care
Kadira._setInfo = function(info) {
  Fibers.current.__kadiraInfo = info;
  var kadiraInfo = Kadira.env.kadiraInfo.get();
};

Kadira.enableErrorTracking = function () {
  __meteor_runtime_config__.kadira.enableErrorTracking = true;
  Kadira.options.enableErrorTracking = true;
};

Kadira.disableErrorTracking = function () {
  __meteor_runtime_config__.kadira.enableErrorTracking = false;
  Kadira.options.enableErrorTracking = false;
};

Kadira.trackError = function (type, message, options) {
  if(Kadira.options.enableErrorTracking && type && message) {
    options = options || {};
    options.subType = options.subType || 'server';
    options.stacks = options.stacks || '';
    var error = {message: message, stack: options.stacks};
    var trace = {
      type: type,
      subType: options.subType,
      name: message,
      errored: true,
      at: Kadira.syncedDate.getTime(),
      events: [['start', 0, {}], ['error', 0, {error: error}]],
      metrics: {total: 0}
    };
    Kadira.models.error.trackError(error, trace);
  }
}
<commit_msg>Refactor ping<commit_after>var http = Npm.require('http');
var hostname = Npm.require('os').hostname();
var logger = Npm.require('debug')('kadira:apm');
var Fibers = Npm.require('fibers');

Kadira.models = {};
Kadira.options = {};
Kadira.env = {
  currentSub: null, // keep current subscription inside ddp
  kadiraInfo: new Meteor.EnvironmentVariable(),
};
Kadira.waitTimeBuilder = new WaitTimeBuilder();
Kadira.errors = [];
Kadira.errors.addFilter = Kadira.errors.push.bind(Kadira.errors);

Kadira.connect = function(appId, appSecret, options) {
  options = options || {};
  options.appId = appId;
  options.appSecret = appSecret;
  options.payloadTimeout = options.payloadTimeout || 1000 * 20;
  options.endpoint = options.endpoint || "https://engine.kadira.io";
  options.thresholds = options.thresholds || {};

  // remove trailing slash from endpoint url (if any)
  if(_.last(options.endpoint) === '/') {
    options.endpoint = options.endpoint.substr(0, options.endpoint.length - 1);
  }

  // error tracking is enabled by default
  if(options.enableErrorTracking === undefined) {
    options.enableErrorTracking = true;
  }

  Kadira.options = options;
  Kadira.options.authHeaders = {
    'APM-APP-ID': Kadira.options.appId,
    'APM-APP-SECRET': Kadira.options.appSecret
  };

  Kadira.syncedDate = new Ntp(options.endpoint);
  Kadira.syncedDate.sync();
  Kadira.models.methods = new MethodsModel(options.thresholds.methods);
  Kadira.models.pubsub = new PubsubModel();
  Kadira.models.system = new SystemModel();
  Kadira.models.error = new ErrorModel(appId);
  // handle pre-added filters
  Kadira.errors.forEach(Kadira.models.error.addFilter.bind(Kadira.models.error));
  Kadira.errors = Kadira.models.error;

  Kadira.sendPayload = sendPayload;

  // setting runtime info, which will be sent to kadira
  __meteor_runtime_config__.kadira = {
    appId: appId,
    endpoint: options.endpoint
  };

  if(options.enableErrorTracking) {
    Kadira.enableErrorTracking();
  } else {
    Kadira.disableErrorTracking();
  }

  if(appId && appSecret) {
    appId = appId.trim();
    appSecret = appSecret.trim();

    Kadira._pingToCheckAuth(function(){
      schedulePayloadSend();
    });
    logger('connected to app: ', appId);
  } else {
    throw new Error('Kadira: required appId and appSecret');
  }

  //start wrapping Meteor's internal methods
  Kadira._startInstrumenting(function() {
    console.log('Kadira: completed instrumenting the app')
    Kadira.connected = true;
  });

  Meteor.publish(null, function () {
    var options = __meteor_runtime_config__.kadira;
    this.added('kadira_settings', Random.id(), options);
    this.ready();
  });

  var payloadRetries = 0;
  var payloadRetry = new Retry({
      minCount: 0, // don't do any immediate payloadRetries
      baseTimeout: 5*1000,
      maxTimeout: 60000
  });

  function sendPayload(callback) {

    callHTTP();

    function callHTTP() {
      new Fibers(function() {
        var payload = Kadira._buildPayload();
        var headers = Kadira.options.authHeaders;
        var httpOptions = {headers: headers, data: payload};

        try {
          var response = HTTP.call('POST', options.endpoint, httpOptions);
          processResponse(response);
        } catch(err) {
          tryAgain(err);
        }
      }).run();
    }

    function processResponse(response) {
      if(response.statusCode == '401') {
        throw new Error('Kadira: AppId, AppSecret combination is invalid');
      } else if(response.statusCode == '200') {
        //success send again in 10 secs
        schedulePayloadSend();
        if(payloadRetries > 0) {
          logger('connected again and payload sent.')
        }
        cleaPayloadRetry();
        callback && callback();
      } else {
        tryAgain();
      }
    }

    function tryAgain(err) {
      err = err || {};
      logger('retrying to send payload to server')
      if(++payloadRetries < 5) {
        payloadRetry.retryLater(payloadRetries, callHTTP);
      } else {
        console.error('Kadira: Error sending payload(dropped after 5 tries) ', err.message);
        cleaPayloadRetry();
        schedulePayloadSend();
      }
    }

  }

  function cleaPayloadRetry() {
    payloadRetries = 0;
    payloadRetry.clear();
  }

  function schedulePayloadSend() {
    setTimeout(sendPayload, options.payloadTimeout);
  }
};

//track how many times we've sent the data (once per minute)
Kadira._buildPayload = function () {
  var payload = {host: hostname};
  var buildDetailedInfo = Kadira._isDetailedInfo();
  _.extend(payload, Kadira.models.methods.buildPayload(buildDetailedInfo));
  _.extend(payload, Kadira.models.pubsub.buildPayload(buildDetailedInfo));
  _.extend(payload, Kadira.models.system.buildPayload());
  if(Kadira.options.enableErrorTracking) {
    _.extend(payload, Kadira.models.error.buildPayload());
  }

  return payload;
}

Kadira._countDataSent = 0;
Kadira._detailInfoSentInterval = Math.ceil((1000*60) / Kadira.options.payloadTimeout);
Kadira._isDetailedInfo = function () {
  return (Kadira._countDataSent++ % Kadira._detailInfoSentInterval) == 0;
}

Kadira.authCheckFailures = 0;
Kadira._pingToCheckAuth = function (callback) {
  var httpOptions = {headers: Kadira.options.authHeaders, data: {}};
  var endpoint = Kadira.options.endpoint + '/ping';
  var authRetry = new Retry({
    minCount: 0, // don't do any immediate retries
    baseTimeout: 5 * 1000
  });

  new Fibers(function() {
    HTTP.call('POST', endpoint, httpOptions, function(err, response){
      if(response) {
        if(response.statusCode == 200) {
          console.log('Kadira: successfully authenticated');
          authRetry.clear();
          callback();
        } else if(response.statusCode == 401) {
          console.error('Kadira: authentication failed - check your appId & appSecret')
        } else {
          retryPingToCheckAuth();
        }
      } else {
        retryPingToCheckAuth();
      }
    });
  }).run();

  function retryPingToCheckAuth(){
    console.log('Kadira: retrying to authenticate');
    authRetry.retryLater(Kadira.authCheckFailures, function(){
      Kadira._pingToCheckAuth(callback);
    });
  }
}

// this return the __kadiraInfo from the current Fiber by default
// if called with 2nd argument as true, it will get the kadira info from
// Meteor.EnvironmentVariable
//
// WARNNING: returned info object is the reference object.
//  Changing it might cause issues when building traces. So use with care
Kadira._getInfo = function(currentFiber, useEnvironmentVariable) {
  currentFiber = currentFiber || Fibers.current;
  if(currentFiber) {
    if(useEnvironmentVariable) {
      return Kadira.env.kadiraInfo.get();
    }
    return currentFiber.__kadiraInfo;
  }
};

// this does not clone the info object. So, use with care
Kadira._setInfo = function(info) {
  Fibers.current.__kadiraInfo = info;
  var kadiraInfo = Kadira.env.kadiraInfo.get();
};

Kadira.enableErrorTracking = function () {
  __meteor_runtime_config__.kadira.enableErrorTracking = true;
  Kadira.options.enableErrorTracking = true;
};

Kadira.disableErrorTracking = function () {
  __meteor_runtime_config__.kadira.enableErrorTracking = false;
  Kadira.options.enableErrorTracking = false;
};

Kadira.trackError = function (type, message, options) {
  if(Kadira.options.enableErrorTracking && type && message) {
    options = options || {};
    options.subType = options.subType || 'server';
    options.stacks = options.stacks || '';
    var error = {message: message, stack: options.stacks};
    var trace = {
      type: type,
      subType: options.subType,
      name: message,
      errored: true,
      at: Kadira.syncedDate.getTime(),
      events: [['start', 0, {}], ['error', 0, {error: error}]],
      metrics: {total: 0}
    };
    Kadira.models.error.trackError(error, trace);
  }
}
<|endoftext|>


<commit_before>'use strict';
var colors = require('ansicolors')
  , blocks = {}
  , inlineDirectChildren = {};

[ 'p',  'dl', 'dt', 'dd', 'ol', 'ul', 'li', 'address', 'blockquote', 'center', 'del', 'div', 'hr', 'pre' ]
  .forEach(function (k) { blocks[k] = { prefix: '\n', suffix: '\n' }; });

[ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6']
  .forEach(function (k) { blocks[k] = { prefix: '\n\n', suffix: '\n\n' };  });

[ 'li' ]
  .forEach(function (k) { inlineDirectChildren[k] = true;  });

var layout = module.exports = function layout(nodes, opts) {
  opts = opts || {};
  opts.listIndent = opts.listIndent || '  ';
  opts.listStyle = opts.listStyle || colors.red('\u25b8 ');

  function processNode(node) {
    var parent = node.parents.length ? node.parents[node.parents.length - 1] : 'html'
      , listParents = node.parents.filter(function (x) { return x === 'li'; })
      , block = blocks[node.tag]
      , prefix = ''
      , suffix = ''
      ;

    // prefix opened block elements with new line and add one after they close
    if (block && !inlineDirectChildren[parent]) {
      if (node.open) prefix += block.prefix;
      if (node.close) suffix += block.suffix;
    }

    // give list items indent
    if (node.open && node.tag === 'li') {
      // add list indent for current list item and any list item it is nested in (parents)
      node.text = opts.listIndent + listParents.reduce(function (acc, x) { return acc + opts.listIndent; }, '') + opts.listStyle;
    }

    // indent newlines of children under of list items
    if (listParents.length) {
      // indent them one more than the first line of the list item
      var indent = listParents.reduce(function (acc, x) { return acc + opts.listIndent; }, opts.listIndent);
      node.text = node.text.replace('\n', '\n' + indent);
    }

    node.text = prefix + node.text + suffix;
    return node;
  }

  return nodes.map(processNode);
};
<commit_msg>changing default list style<commit_after>'use strict';
var colors = require('ansicolors')
  , blocks = {}
  , inlineDirectChildren = {};

[ 'p',  'dl', 'dt', 'dd', 'ol', 'ul', 'li', 'address', 'blockquote', 'center', 'del', 'div', 'hr', 'pre', 'tr' ]
  .forEach(function (k) { blocks[k] = { prefix: '\n', suffix: '\n' }; });

[ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6']
  .forEach(function (k) { blocks[k] = { prefix: '\n\n', suffix: '\n\n' };  });

[ 'li' ]
  .forEach(function (k) { inlineDirectChildren[k] = true;  });

var layout = module.exports = function layout(nodes, opts) {
  opts = opts || {};
  opts.listIndent = opts.listIndent || '  ';
  opts.listStyle = opts.listStyle || colors.red('\u25aa ');

  function processNode(node) {
    var parent = node.parents.length ? node.parents[node.parents.length - 1] : 'html'
      , listParents = node.parents.filter(function (x) { return x === 'li'; })
      , block = blocks[node.tag]
      , prefix = ''
      , suffix = ''
      ;

    // prefix opened block elements with new line and add one after they close
    if (block && !inlineDirectChildren[parent]) {
      if (node.open) prefix += block.prefix;
      if (node.close) suffix += block.suffix;
    }

    // give list items indent
    if (node.open && node.tag === 'li') {
      // add list indent for current list item and any list item it is nested in (parents)
      node.text = opts.listIndent + listParents.reduce(function (acc, x) { return acc + opts.listIndent; }, '') + opts.listStyle;
    }

    // indent newlines of children under of list items
    if (listParents.length) {
      // indent them one more than the first line of the list item
      var indent = listParents.reduce(function (acc, x) { return acc + opts.listIndent; }, opts.listIndent);
      node.text = node.text.replace('\n', '\n' + indent);
    }

    node.text = prefix + node.text + suffix;
    return node;
  }

  return nodes.map(processNode);
};
<|endoftext|>


<commit_before>
module.exports = remotePackages

var registry = require("../registry")
  , containsSingleMatch = require("./contains-single-match")
  , getCompletions = require("./get-completions")

/*
  Looks up remote packages for CLI tab-completion.

  NOTE: If doVersion is true, versions in the form <name>@<version>
        will be completed.

        If doTag is true, tags in the form <name>@<tag> will be
        completed.

        If recurring in true, sequences of multiple packages can be
        completed. i.e. for schemes such as:
        npm <command> <name>[@<version> [<name>[@<version>] ...]
*/
function remotePackages (args, index, doVersion, doTag
                         , recurring, cb) {
  if (recurring || index < 3) {
    var name = (args.length + 1 == index) ? args[args.length - 1] : ""
    // use up-to 1 hour stale cache.  not super urgent.
    registry.get("/", null, 3600, function (er, d) {
      if (er) return cb(er)
      var remoteList = Object.keys(d)
      if (remoteList.indexOf(name) === -1 ||
          !containsSingleMatch(name, remoteList)) {
        if ((doVersion || doTag) && name.indexOf('@') !== -1) {
          var pieces = name.split('@')
            , pkgname = pieces[0]
            , lst = []
          if (d[pkgname]) {
            if (doVersion) lst = lst.concat(Object.keys(d[pkgname].versions))
            if (doTag) lst = lst.concat(Object.keys(d[pkgname]["dist-tags"]))
          }
          lst = lst.map(function(e) { return pkgname + '@' + e })
          cb(null, getCompletions(name, lst))
        } else cb(null, getCompletions(name, remoteList))
      }
    })
  }
}
<commit_msg>Handle the undefined .indexOf issue<commit_after>
module.exports = remotePackages

var registry = require("../registry")
  , containsSingleMatch = require("./contains-single-match")
  , getCompletions = require("./get-completions")

/*
  Looks up remote packages for CLI tab-completion.

  NOTE: If doVersion is true, versions in the form <name>@<version>
        will be completed.

        If doTag is true, tags in the form <name>@<tag> will be
        completed.

        If recurring in true, sequences of multiple packages can be
        completed. i.e. for schemes such as:
        npm <command> <name>[@<version> [<name>[@<version>] ...]
*/
function remotePackages (args, index, doVersion, doTag
                         , recurring, cb) {
  if (recurring || index < 3) {
    var name = (args.length + 1 === index) ? args[args.length - 1] : ""
    if (name === undefined) name = ""
    // use up-to 1 hour stale cache.  not super urgent.
    registry.get("/", null, 3600, function (er, d) {
      if (er) return cb(er)
      var remoteList = Object.keys(d)
      if (remoteList.indexOf(name) === -1 ||
          !containsSingleMatch(name, remoteList)) {
        if ((doVersion || doTag) && name.indexOf('@') !== -1) {
          var pieces = name.split('@')
            , pkgname = pieces[0]
            , lst = []
          if (d[pkgname]) {
            if (doVersion) lst = lst.concat(Object.keys(d[pkgname].versions))
            if (doTag) lst = lst.concat(Object.keys(d[pkgname]["dist-tags"]))
          }
          lst = lst.map(function(e) { return pkgname + '@' + e })
          cb(null, getCompletions(name, lst))
        } else cb(null, getCompletions(name, remoteList))
      }
    })
  }
}
<|endoftext|>


<commit_before>var W = require('WINSTON'),
    UTIL = require('util'),
    BEMUTIL = require('./util');

for(var i in W) exports[i] = W[i];

init();

exports.setLevel = function(level) {
    return init(level);
}

/**
 * Adds tracing before and after executing specified function or specified object's methods
 *
 * @param {hash} options The object with properties:
 * object - pass object the methods of which you want to trace
 * func - pass function you want to trace (the method will return wrapper function in this case)
 * object of func must be specified
 * objectName - this value is used in the traces to identify what object method is being executed (optional)
 * whiteList - in case object was specified only methods in the whiteList will be wrapped (optional)
 * blackList - in case object was specified the methods in blackList hash won't be wrapped (optional)
 * @return {function} The wrapped function in case options.func was specified or nothing otherwise
 */
exports.trace = function(options) {

    return attach(
        options,
        function(f) {
            exports.fsilly('>>> %s.%s', f.objectName || '?', f.functionName || '?');
        },

        function(f) {
            exports.fsilly('<<< %s.%s', f.objectName || '?', f.functionName || '?');
        }
    );
}

/**
 * @type {Function}
 * The same as trace but uses specified callbacks to do tracing
 *
 * @param {hash} options
 * @param {function} callbackBefore (optional)
 * @param {function} callbackAfter (optional)
 * @return {function} The wrapped function in case options.func was specified or nothing otherwise
 */
var attach = exports.attach = function(options, callbackBefore, callbackAfter) {
    if (options.object) {
        var c = options.object.prototype;
        if (!c) return;

        Object.keys(c)
            .filter(function(prop) {

                if (typeof c[prop] === 'function') {
                    if (options.whiteList) return options.whiteList[prop];

                    if (options.blackList) return !options.blackList[prop];

                    return true;
                }

                return false;
            })
            .map(function(f) {
                c[f] = wrapFunction(
                    {
                        objectName: options.objectName,
                        functionName: f,
                        func: c[f],
                        object: options.object
                    },
                    callbackBefore,
                    callbackAfter);
            });

    } else if (options.func) {
        return wrapFunction(options.func, callbackBefore, callbackAfter);
    }
}

function wrapFunction(options, callbackBefore, callbackAfter) {
    var f = (typeof options === 'function')? otions: options.func;

    return function() {
        callbackBefore && callbackBefore(options);
        var res = f.apply(this, arguments);
        callbackAfter && callbackAfter(options);

        return res;
    }
}

function init(level) {
    W.remove(W.transports.Console);
    W.add(W.transports.Console,
        {
            timestamp: function() {
                var d = new Date();

                return UTIL.format(
                    '%s:%s:%s.%s',
                    BEMUTIL.pad(d.getHours(), 2, '0'),
                    BEMUTIL.pad(d.getMinutes(), 2, '0'),
                    BEMUTIL.pad(d.getSeconds(), 2, '0'),
                    BEMUTIL.pad(d.getMilliseconds(), 3, '0'));
            },
            colorize: true,
            level: level
        });

    W.setLevels({
            silly: 0,
            debug: 1,
            verbose: 2,
            info: 3,
            warn: 4,
            error: 5
        });

    Object.keys(W.levels).forEach(function (level) {
        exports[level] = W[level];
        exports['f' + level] = function (msg) {
            var m = UTIL.format.apply(this, arguments);
            W[level](m);
        };
    });
}
<commit_msg>- jsdoc updated - internal filter added (to avoid wrapping of the properties like __self) - the white and black lists are arrays for now<commit_after>var W = require('WINSTON'),
    UTIL = require('util'),
    BEMUTIL = require('./util'),

    propertiesFilter = [
        '__self'
    ];

for(var i in W) exports[i] = W[i];

init();

/**
 * Sets the max logging level
 * @param level
 */
exports.setLevel = function(level) {
    init(level);
}

/**
 * Adds tracing before and after executing specified function or specified object's methods
 * @param {object} options The object with properties:
 * @param {class} options.object pass object the methods of which you want to trace
 * @param {function} options.func pass function you want to trace (the method will return wrapper function in this case)
 * @param {string} [options.objectName] this value is used in the traces to identify what object method is being executed
 * @param {array} [options.whiteList] in case object was specified only methods in the whiteList will be wrapped
 * @param {array} [options.blackList] in case object was specified the methods in blackList hash won't be wrapped
 * @return {function} The wrapped function in case options.func was specified or nothing otherwise
 */
var trace = exports.trace = function (options) {

    return attach(
        options,
        function(f) {
            exports.fsilly('>>> %s.%s', f.objectName || '?', f.functionName || '?');
        },

        function(f) {
            exports.fsilly('<<< %s.%s', f.objectName || '?', f.functionName || '?');
        }
    );
}

/**
 * The same as {@link trace} but uses specified callbacks to do tracing
 *
 * @param {hash} options
 * @param {function} callbackBefore (optional)
 * @param {function} callbackAfter (optional)
 * @return {function} The wrapped function in case options.func was specified or nothing otherwise
 */
var attach = exports.attach = function(options, callbackBefore, callbackAfter) {
    if (options.object) {
        var c = options.object.prototype;
        if (!c) throw new Error('object has no prototype');

        Object.keys(c)
            .filter(function(prop) {
                if (typeof c[prop] === 'function' && propertiesFilter.indexOf(prop) === -1) {
                    if (options.whiteList) return (options.whiteList.indexOf(prop) !== -1);

                    if (options.blackList) return !(options.blackList.indexOf(prop) !== -1);

                    return true;
                }

                return false;
            })
            .map(function(f) {
                c[f] = wrapFunction(
                    {
                        objectName: options.objectName,
                        functionName: f,
                        func: c[f],
                        object: options.object
                    },
                    callbackBefore,
                    callbackAfter);
            });

    } else if (options.func) {
        return wrapFunction(options.func, callbackBefore, callbackAfter);
    }
}

function wrapFunction(options, callbackBefore, callbackAfter) {
    var f = (typeof options === 'function')? otions: options.func;

    return function() {
        callbackBefore && callbackBefore(options);
        var res = f.apply(this, arguments);
        callbackAfter && callbackAfter(options);

        return res;
    }
}

function init(level) {
    W.remove(W.transports.Console);
    W.add(W.transports.Console,
        {
            timestamp: function() {
                var d = new Date();

                return UTIL.format(
                    '%s:%s:%s.%s',
                    BEMUTIL.pad(d.getHours(), 2, '0'),
                    BEMUTIL.pad(d.getMinutes(), 2, '0'),
                    BEMUTIL.pad(d.getSeconds(), 2, '0'),
                    BEMUTIL.pad(d.getMilliseconds(), 3, '0'));
            },
            colorize: true,
            level: level
        });

    W.setLevels({
            silly: 0,
            debug: 1,
            verbose: 2,
            info: 3,
            warn: 4,
            error: 5
        });

    Object.keys(W.levels).forEach(function (level) {
        exports[level] = W[level];
        exports['f' + level] = function (msg) {
            var m = UTIL.format.apply(this, arguments);
            W[level](m);
        };
    });
}
<|endoftext|>


<commit_before>
module.exports = remotePackages

var registry = require("../registry")
  , containsSingleMatch = require("./contains-single-match")
  , getCompletions = require("./get-completions")

/*
  Looks up remote packages for CLI tab-completion.

  NOTE: If doVersion is true, versions in the form <name>@<version>
        will be completed.

        If doTag is true, tags in the form <name>@<tag> will be
        completed.

        If recurring in true, sequences of multiple packages can be
        completed. i.e. for schemes such as:
        npm <command> <name>[@<version> [<name>[@<version>] ...]
*/
function remotePackages (args, index, doVersion, doTag
                         , recurring, cb) {
  if (recurring || index < 3) {
    var name = (args.length + 1 === index) ? args[args.length - 1] : ""
    if (name === undefined) name = ""
    // use up-to 1 hour stale cache.  not super urgent.
    registry.get("/", null, 3600, function (er, d) {
      if (er) return cb(er)
      var remoteList = Object.keys(d)
        , found = remoteList.indexOf(name)
        , unique = found && containsSingleMatch(name, remoteList)
        , simpleMatches = getCompletions(name, remoteList)
        , uniqueMatch = unique && simpleMatches[0]
        , addTag = doTag && (unique || found || name.indexOf("@") !== -1)
        , addVer = doVersion && (unique || found || name.indexOf("@") !== -1)
        , list = []
        , pieces = (uniqueMatch || name).split("@")
        , pkgname = pieces[0]
        , extras = []
      if (unique && !addTag && !addVer) return cb(null, [name])
      if (d[pkgname] && (addTag || addVer)) {
        if (d[pkgname].versions && addVer) {
          extras = extras.concat(Object.keys(d[pkgname].versions))
        }
        if (d[pkgname]["dist-tags"] && addTag) {
          extras = extras.concat(Object.keys(d[pkgname]["dist-tags"]))
        }
        list = list.concat(extras.map(function (e) {
          return pkgname + "@" + e
        }))
      }
      if (!unique) list = list.concat(getCompletions(name, remoteList))
      return cb(null, list)
    })
  }
}
<commit_msg>Fix bug where list of remote pkg <name>@<version> pairs aren't filtered properly.<commit_after>
module.exports = remotePackages

var registry = require("../registry")
  , containsSingleMatch = require("./contains-single-match")
  , getCompletions = require("./get-completions")

/*
  Looks up remote packages for CLI tab-completion.

  NOTE: If doVersion is true, versions in the form <name>@<version>
        will be completed.

        If doTag is true, tags in the form <name>@<tag> will be
        completed.

        If recurring in true, sequences of multiple packages can be
        completed. i.e. for schemes such as:
        npm <command> <name>[@<version> [<name>[@<version>] ...]
*/
function remotePackages (args, index, doVersion, doTag
                         , recurring, cb) {
  if (recurring || index < 3) {
    var name = (args.length + 1 === index) ? args[args.length - 1] : ""
    if (name === undefined) name = ""
    // use up-to 1 hour stale cache.  not super urgent.
    registry.get("/", null, 3600, function (er, d) {
      if (er) return cb(er)
      var remoteList = Object.keys(d)
        , found = remoteList.indexOf(name)
        , unique = found && containsSingleMatch(name, remoteList)
        , simpleMatches = getCompletions(name, remoteList)
        , uniqueMatch = unique && simpleMatches[0]
        , addTag = doTag && (unique || found || name.indexOf("@") !== -1)
        , addVer = doVersion && (unique || found || name.indexOf("@") !== -1)
        , list = []
        , pieces = (uniqueMatch || name).split("@")
        , pkgname = pieces[0]
        , extras = []
      if (unique && !addTag && !addVer) return cb(null, [name])
      if (d[pkgname] && (addTag || addVer)) {
        if (d[pkgname].versions && addVer) {
          extras = extras.concat(Object.keys(d[pkgname].versions))
        }
        if (d[pkgname]["dist-tags"] && addTag) {
          extras = extras.concat(Object.keys(d[pkgname]["dist-tags"]))
        }
        list = getCompletions(name, list.concat(extras.map(function (e) {
          return pkgname + "@" + e
        })))
      }
      if (!unique) list = list.concat(getCompletions(name, remoteList))
      return cb(null, list)
    })
  }
}
<|endoftext|>


<commit_before>hx.config(['$router'], function($router) {

    ko.utils.registerEventHandler(document, 'click', function(event) {
        if(event.target.tagName === 'A') {
            var element = event.target,
                routeName = ko.utils.domData.get(element, '__routeName'),
                parameters = ko.utils.domData.get(element, '__routeParameters');

            if(routeName) {
                $router.navigateTo(routeName, parameters);

                if (event.preventDefault)
                    event.preventDefault();
                else
                    event.returnValue = false;
            }
        }
    });

    /**
     * @bindingHandler navigate
     *
     * The navigate binding handler provides inter-page navigation. This binding
     * handler will typically be applied to an `a` tag, although can be applied to
     * any element as it will handle the click event on the element, it does not
     * depend on the browsers built-in linking functionality.
     *
     * The binding handler takes a single parameter, the name of the route that
     * should be navigated to, being a named route that has been registered in the
     * global $router module.
     *
     * If the route requires parameters then they can be provided by using the
     * `parameters` binding handler, which accepts an object of parameters to
     * be used to generate the URL and when navigating.
     *
     * @example
     *
     * View User 4"
     */
    koBindingHandlers.navigate = {
        /*init: function(element, valueAccessor, allBindingsAccessor) {
            var routeName = ko.utils.unwrapObservable(valueAccessor()),
                parameters = allBindingsAccessor()['parameters'];

            ko.utils.registerEventHandler(element, 'click', function(event) {
                $router.navigateTo(routeName, parameters);

                if (event.preventDefault)
                    event.preventDefault();
                else
                    event.returnValue = false;
            })
        },*/

        update: function(element, valueAccessor, allBindingsAccessor) {
            var routeName = ko.utils.unwrapObservable(valueAccessor()),
                parameters = allBindingsAccessor()['parameters'];
                url = $router.buildUrl(routeName, parameters);

            element.setAttribute('href', url || '#');

            ko.utils.domData.set(element, '__routeName', routeName);
            ko.utils.domData.set(element, '__routeParameters', parameters);
        }
    }
});<commit_msg>Remove commented-out code<commit_after>hx.config(['$router'], function($router) {
    ko.utils.registerEventHandler(document, 'click', function(event) {
        if(event.target.tagName === 'A') {
            var element = event.target,
                routeName = ko.utils.domData.get(element, '__routeName'),
                parameters = ko.utils.domData.get(element, '__routeParameters');

            if(routeName) {
                $router.navigateTo(routeName, parameters);

                if (event.preventDefault)
                    event.preventDefault();
                else
                    event.returnValue = false;
            }
        }
    });

    /**
     * @bindingHandler navigate
     *
     * The navigate binding handler provides inter-page navigation. This binding
     * handler will typically be applied to an `a` tag, although can be applied to
     * any element as it will handle the click event on the element, it does not
     * depend on the browsers built-in linking functionality.
     *
     * The binding handler takes a single parameter, the name of the route that
     * should be navigated to, being a named route that has been registered in the
     * global $router module.
     *
     * If the route requires parameters then they can be provided by using the
     * `parameters` binding handler, which accepts an object of parameters to
     * be used to generate the URL and when navigating.
     *
     * @example
     *
     * View User 4"
     */
    koBindingHandlers.navigate = {
        update: function(element, valueAccessor, allBindingsAccessor) {
            var routeName = ko.utils.unwrapObservable(valueAccessor()),
                parameters = allBindingsAccessor()['parameters'];
                url = $router.buildUrl(routeName, parameters);

            element.setAttribute('href', url || '#');

            ko.utils.domData.set(element, '__routeName', routeName);
            ko.utils.domData.set(element, '__routeParameters', parameters);
        }
    }
});<|endoftext|>


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

var levels = [
    'silly',
    'input',
    'verbose',
    'prompt',
    'debug',
    'http',
    'info',
    'data',
    'help',
    'warn',
    'error'
];

levels.forEach(function(level) {
    exports[level] = function(msg) {
        if (!exports.disabled) {
            console.log(
                level + ':',
                util.format.apply(
                    this,
                    [msg].concat([].slice.call(arguments, 1))));
        }
    };
});

exports.disabled = false;

exports.wrap = function(getPrefix, func) {
    if (typeof getPrefix != 'function') {
        var msg = getPrefix;
        getPrefix = function() {
            return msg;
        };
    }

    return function() {
        var args    = arguments,
            that    = this,
            prefix  = getPrefix.apply(that, args);
            wrapper = {};

        levels.forEach(function(level) {
            wrapper[level] = function(msg) {
                msg = (prefix ? prefix + ': ' : '') + msg;
                exports[level].apply(
                    this,
                    [msg].concat([].slice.call(arguments, 1)));
            };
        });

        return func.apply(that, [wrapper].concat([].slice.call(args)));
    };
};
<commit_msg>Logger improvements<commit_after>var util = require('util');

var levels = [
    'silly',
    'input',
    'verbose',
    'prompt',
    'debug',
    'http',
    'info',
    'data',
    'help',
    'warn',
    'error'
];

levels.forEach(function(level) {
    exports[level] = function(msg) {
        if (!exports.disabled) {
            console.error(
                level + ':',
                util.format.apply(
                    this,
                    [msg].concat([].slice.call(arguments, 1))));
        }
    };
});

exports.disabled = false;

exports.wrap = function(getPrefix, func) {
    if (typeof getPrefix != 'function') {
        var msg = getPrefix;
        getPrefix = function() {
            return msg;
        };
    }

    return function() {
        var args    = arguments,
            that    = this,
            prefix  = getPrefix.apply(that, args);
            wrapper = {};

        levels.forEach(function(level) {
            wrapper[level] = function(msg) {
                msg = (prefix ? prefix + ': ' : '') + msg;
                exports[level].apply(
                    this,
                    [msg].concat([].slice.call(arguments, 1)));
            };
        });

        return func.apply(that, [wrapper].concat([].slice.call(args)));
    };
};

exports.prefix = function() {
    var prefix  = util.format.apply(this, arguments),
        wrapper = {};

    levels.forEach(function(level) {
        wrapper[level] = function(msg) {
            msg = (prefix ? prefix + ': ' : '') + msg;
            exports[level].apply(
                this,
                [msg].concat([].slice.call(arguments, 1)));
        };
    });

    return wrapper;
};
<|endoftext|>


<commit_before>/**
 * This script does a stress test on the given domain.
 * Don't put a real domain here if you don't want to be blocked by some firewall.
 */
var Curl = require( '../lib/Curl' ),
    assert = require( 'assert' ),
    path = require( 'path' ),
    util = require( 'util' );

/*
 * Under a nginx running on a virtual box, I've got 12s, 368.155ms with the following config:
 */
var url = 'http://local.vm/', //local.vm in this case was the default nginx page.
    file= 'file:///' + path.join( __dirname, 'test.txt' ),
    instances   = 100,
    maxRequests = 10000,
    shouldTestFile = false,
    shouldUseHeaderRequest = true,
    precision = 3;

var calls   = 0,
    running = 0,
    i = 0,
    startTime,
    endTime;

function doRequest() {

    var curl = new Curl();
    curl.setOpt( Curl.option.URL, !shouldTestFile ? url : file  );
    curl.setOpt( Curl.option.ACCEPT_ENCODING, 'gzip' );
    curl.setOpt( Curl.option.TRANSFER_ENCODING, 1 );
    curl.setOpt( Curl.option.HTTP_CONTENT_DECODING, 0 );
    curl.setOpt( Curl.option.HTTP_TRANSFER_DECODING, 0 );
    curl.setOpt( Curl.option.NOBODY, shouldUseHeaderRequest );

    curl.on( 'end', function( code, body ) {

        --running;
        ++calls;

        this.close();

        if ( ( calls + running ) < maxRequests ) {

            doRequest();

        }

        if ( calls % 100 === 0 || maxRequests - calls <= instances )
            console.info( "Curl instances: ", Curl.getCount(), " -> Requests finished: ", calls );

        if ( running === 0 ) {

            //nano to milli
            endTime = process.hrtime( startTime );

            console.info( 'Request time: ',
                endTime[0] + "s, " + (endTime[1] / 1000000).toFixed( precision ) + "ms"
            );
        }
    });

    process.nextTick( curl.perform.bind( curl ) );
    ++running;
}

process.stdout.write( 'Press any key to start...' );
process.stdin.resume();
//start on any input.
process.stdin.once( 'data', function ( data ) {

    process.stdin.pause();

    startTime = process.hrtime();

    for ( i = 0; i <= instances; i++ ) {
        doRequest();
    }

});
<commit_msg>Update stress-test.js<commit_after>/**
 * This script does a stress test on the given domain.
 * Don't put a real domain here if you don't want to be blocked by some firewall.
 */
var Curl = require( '../lib/Curl' ),
    assert = require( 'assert' ),
    path = require( 'path' ),
    util = require( 'util' );

/*
 * Under a nginx running on a virtual box, I've got 15s, 245.152ms with the following config:
 */
var url = 'http://local.vm/', //local.vm in this case was the default nginx page.
    file= 'file:///' + path.join( __dirname, 'test.txt' ),
    instances   = 300,
    maxRequests = 10000,
    shouldTestFile = false,
    shouldUseHeaderRequest = true,
    precision = 3;

var calls   = 0,
    running = 0,
    i = 0,
    startTime,
    endTime;

function doRequest() {

    var curl = new Curl();
    curl.setOpt( Curl.option.URL, !shouldTestFile ? url : file  );
    curl.setOpt( Curl.option.ACCEPT_ENCODING, 'gzip' );
    curl.setOpt( Curl.option.TRANSFER_ENCODING, 1 );
    curl.setOpt( Curl.option.HTTP_CONTENT_DECODING, 0 );
    curl.setOpt( Curl.option.HTTP_TRANSFER_DECODING, 0 );
    curl.setOpt( Curl.option.NOBODY, shouldUseHeaderRequest );

    curl.on( 'end', function( code, body ) {

        --running;
        ++calls;

        this.close();

        if ( ( calls + running ) < maxRequests ) {

            doRequest();

        }

        if ( calls % 100 === 0 || maxRequests - calls <= instances )
            console.info( "Curl instances: ", Curl.getCount(), " -> Requests finished: ", calls );

        if ( running === 0 ) {

            //nano to milli
            endTime = process.hrtime( startTime );

            console.info( 'Request time: ',
                endTime[0] + "s, " + (endTime[1] / 1000000).toFixed( precision ) + "ms"
            );
        }
    });

    process.nextTick( curl.perform.bind( curl ) );
    ++running;
}

process.stdout.write( 'Press any key to start...' );
process.stdin.resume();
//start on any input.
process.stdin.once( 'data', function ( data ) {

    process.stdin.pause();

    startTime = process.hrtime();

    for ( i = 0; i <= instances; i++ ) {
        doRequest();
    }

});
<|endoftext|>


<commit_before>/* eslint-disable no-console */
const chalk = require('chalk')
const logSymbols = require('log-symbols')

exports.blank = () => {
  console.log('')
}

const tab = (msg, count = 1) => {
  const tabs = []
  for (let i = 0; i < count; i++) {
    tabs.push('    ')
  }
  console.log(`${tabs.join('')}${msg}`)
}
exports.tab = tab

const stdlog = (info, symbol) => {
  const line = `${info.line}:${info.column}`
  const fixable = info.fixable ? ` ${chalk.green('Fixable')}` : ''
  const message = info.message + fixable

  tab(`${logSymbols[symbol]}  ${line}\t${message}`)
}

exports.error = info => stdlog(info, 'error')
exports.warning = info => stdlog(info, 'warning')
<commit_msg>add: symbol and refactor position<commit_after>/* eslint-disable no-console */
const chalk = require('chalk')
const logSymbols = require('log-symbols')

exports.blank = () => {
  console.log('')
}

const tab = (msg, count = 1) => {
  const tabs = []
  for (let i = 0; i < count; i++) {
    tabs.push('    ')
  }
  console.log(`${tabs.join('')}${msg}`)
}

const symbol = (message, symbol) => {
  tab(`${logSymbols[symbol]}  ${message}`)
}

const stdlog = (info, symbol) => {
  const line = `${info.line}:${info.column}`
  const fixable = info.fixable ? ` ${chalk.green('Fixable')}` : ''
  const message = info.message + fixable
  tab(`${logSymbols[symbol]}  ${line}\t${message}`)
}

exports.error = info => stdlog(info, 'error')
exports.warning = info => stdlog(info, 'warning')
exports.symbol = symbol
exports.tab = tab
<|endoftext|>


<commit_before>/*global require*/
/*global module*/
/*global console*/
/*jslint nomen: true*/

(function () {

    'use strict';

    var League = {},
        util = require('./util'),
        authKey,
        region = 'na',
        endpoint = 'http://prod.api.pvp.net/api/lol',
        championUrl = '/v1.1/champion',
        gameUrl = '/v1.3/game/by-summoner',
        leagueUrl = '/v2.3/league/by-summoner',
        statsUrl = '/v1.2/stats/by-summoner',
        summonerUrl = '/v1.3/summoner',
        teamUrl = '/v2.2/team/by-summoner';

    League.Stats = {};

    League.Summoner = {};

    League.init = function (key, regionTag) {
        authKey = key;
        if (regionTag) {
            region = regionTag;
        }
    };

    League.getRegions = function (callback) {
        callback(null, {
            'na': 'North America',
            'euw': 'Europe West',
            'eune': 'Europe Nordic and East'
        });
    };

    League.getQueues = function (callback) {
        callback(null, {
            2: 'Normal 5v5 Blind Pick',
            4: 'Ranked Solo 5v5',
            7: 'Coop vs AI 5v5',
            8: 'Normal 3v3',
            14: 'Normal 5v5 Draft Pick',
            16: 'Dominion 5v5 Blind Pick',
            17: 'Dominion 5v5 Draft Pick',
            25: 'Dominion Coop vs AI',
            41: 'Ranked Team 3v3',
            42: 'Ranked Team 5v5',
            52: 'Twisted Treeline Coop vs AI',
            65: 'ARAM',
            67: 'ARAM Coop vs AI'
        });
    };

    League.getMapNames = function (callback) {
        callback(null, {
            1: 'Summoner\'s Rift Summer Variant ',
            2: 'Summoner\'s Rift Autumn Variant',
            3: 'The Proving Grounds',
            4: 'Twisted Treeline Original Version',
            8: 'The Crystal Scar',
            10: 'Twisted Treeline Current Version',
            12: 'Howling Abyss'
        });
    };

    League.getChampions = function (freeToPlay, regionOrFunction, callback) {
        var url,
            freetoPlayQuery = '',
            regionAndFunc = util.getCallbackAndRegion(regionOrFunction, region, callback);

        if (freeToPlay === null || !(typeof (freeToPlay) === 'boolean')) {
            console.log('Invalid query parameter for freeToPlay: ' + freeToPlay);
        }

        if (freeToPlay) {
            freetoPlayQuery = 'freeToPlay=true&';
        }

        url = util.craftUrl(endpoint, regionAndFunc.region, championUrl + '?' + freetoPlayQuery, authKey);
        util.makeRequest(url, 'Error getting champions: ', 'champions', regionAndFunc.callback);
    };

    League.getRecentGames = function (summonerId, regionOrFunction, callback) {
        var regionAndFunc = util.getCallbackAndRegion(regionOrFunction, region, callback),
            url = util.craftUrl(endpoint, regionAndFunc.region, gameUrl + '/' + summonerId + '/recent?', authKey);

        util.makeRequest(url, 'Error getting recent games: ', 'games', regionAndFunc.callback);
    };

    League.getLeagueData = function (summonerId, regionOrFunction, callback) {
        var regionAndFunc = util.getCallbackAndRegion(regionOrFunction, region, callback),
            url = util.craftUrl(endpoint, regionAndFunc.region, leagueUrl + '/' + summonerId + '?', authKey);

        util.makeRequest(url, 'Error getting league data: ', null, regionAndFunc.callback);
    };

    League.Stats.getPlayerSummary = function (summonerId, season, regionOrFunction, callback) {
        var regionAndFunc = util.getCallbackAndRegion(regionOrFunction, region, callback),
            seasonURL = '',
            url;

        if (util.getValidSeasonParam(season)) {
            if (season) {
                seasonURL = 'season=SEASON' + season + '&';
            }
        } else {
            console.log('Invalid query parameter for season: ' + season);
        }

        url = util.craftUrl(endpoint, regionAndFunc.region,
            statsUrl + '/' + summonerId + '/summary?' + seasonURL, authKey);
        util.makeRequest(url, 'Error getting summary data: ', 'playerStatSummaries', regionAndFunc.callback);
    };

    League.Stats.getRanked = function (summonerId, season, regionOrFunction, callback) {
        var regionAndFunc = util.getCallbackAndRegion(regionOrFunction, region, callback),
            seasonURL = '',
            url;

        if (util.getValidSeasonParam(season)) {
            if (season) {
                seasonURL = 'season=SEASON' + season + '&';
            }
        } else {
            console.log('Invalid query parameter for season: ' + season);
        }

        url = util.craftUrl(endpoint, regionAndFunc.region,
            statsUrl + '/' + summonerId + '/ranked?' + seasonURL, authKey);
        util.makeRequest(url, 'Error getting ranked data: ', 'champions', regionAndFunc.callback);
    };

    League.Summoner.getMasteries = function (summonerId, regionOrFunction, callback) {
        var regionAndFunc = util.getCallbackAndRegion(regionOrFunction,
            region,
            callback),
            url = util.craftUrl(endpoint, regionAndFunc.region,
                summonerUrl + '/' + summonerId + '/masteries?', authKey);

        util.makeRequest(url, 'Error getting mastery data: ', 'pages', regionAndFunc.callback);
    };

    League.Summoner.getRunes = function (summonerId, regionOrFunction, callback) {
        var regionAndFunc = util.getCallbackAndRegion(regionOrFunction, region, callback),
            url = util.craftUrl(endpoint, regionAndFunc.region, summonerUrl + '/' + summonerId + '/runes?', authKey);

        util.makeRequest(url, 'Error getting rune data: ', 'pages', regionAndFunc.callback);
    };

    League.Summoner.getByName = function (name, regionOrFunction, callback) {
        var regionAndFunc = util.getCallbackAndRegion(regionOrFunction, region, callback),
            url;

        name = name.split(' ').join('');
        url = util.craftUrl(endpoint, regionAndFunc.region, summonerUrl + '/by-name/' + name + '?', authKey);

        util.makeRequest(url, 'Error getting summoner data using name: ', null, regionAndFunc.callback);
    };

    League.Summoner.getByID = function (summonerId, regionOrFunction, callback) {
        var regionAndFunc = util.getCallbackAndRegion(regionOrFunction, region, callback),
            url = util.craftUrl(endpoint, regionAndFunc.region, summonerUrl + '/' + summonerId + '?', authKey);

        util.makeRequest(url, 'Error getting summoner data: ', null, regionAndFunc.callback);
    };

    League.Summoner.listNamesByIDs = function (ids, regionOrFunction, callback) {
        var regionAndFunc = util.getCallbackAndRegion(regionOrFunction, region, callback),
            url = util.craftUrl(endpoint, regionAndFunc.region, summonerUrl + '/' + ids + '/name?', authKey);

        util.makeRequest(url, 'Error getting summoner data using list of ids: ', 'summoners', regionAndFunc.callback);
    };

    League.getTeams = function (summonerId, regionOrFunction, callback) {
        var regionAndFunc = util.getCallbackAndRegion(regionOrFunction, region, callback),
            url = util.craftUrl(endpoint, regionAndFunc.region, teamUrl + '/' + summonerId + '?', authKey);

        util.makeRequest(url, 'Error getting summoner teams info: ', null, regionAndFunc.callback);
    };

    module.exports = League;
}());<commit_msg>Added getLeagueEntryData method<commit_after>/*global require*/
/*global module*/
/*global console*/
/*jslint nomen: true*/

(function () {

    'use strict';

    var League = {},
        util = require('./util'),
        authKey,
        region = 'na',
        endpoint = 'http://prod.api.pvp.net/api/lol',
        championUrl = '/v1.1/champion',
        gameUrl = '/v1.3/game/by-summoner',
        leagueUrl = '/v2.3/league/by-summoner',
        statsUrl = '/v1.2/stats/by-summoner',
        summonerUrl = '/v1.3/summoner',
        teamUrl = '/v2.2/team/by-summoner';

    League.Stats = {};

    League.Summoner = {};

    League.init = function (key, regionTag) {
        authKey = key;
        if (regionTag) {
            region = regionTag;
        }
    };

    League.getRegions = function (callback) {
        callback(null, {
            'na': 'North America',
            'euw': 'Europe West',
            'eune': 'Europe Nordic and East'
        });
    };

    League.getQueues = function (callback) {
        callback(null, {
            2: 'Normal 5v5 Blind Pick',
            4: 'Ranked Solo 5v5',
            7: 'Coop vs AI 5v5',
            8: 'Normal 3v3',
            14: 'Normal 5v5 Draft Pick',
            16: 'Dominion 5v5 Blind Pick',
            17: 'Dominion 5v5 Draft Pick',
            25: 'Dominion Coop vs AI',
            41: 'Ranked Team 3v3',
            42: 'Ranked Team 5v5',
            52: 'Twisted Treeline Coop vs AI',
            65: 'ARAM',
            67: 'ARAM Coop vs AI'
        });
    };

    League.getMapNames = function (callback) {
        callback(null, {
            1: 'Summoner\'s Rift Summer Variant ',
            2: 'Summoner\'s Rift Autumn Variant',
            3: 'The Proving Grounds',
            4: 'Twisted Treeline Original Version',
            8: 'The Crystal Scar',
            10: 'Twisted Treeline Current Version',
            12: 'Howling Abyss'
        });
    };

    League.getChampions = function (freeToPlay, regionOrFunction, callback) {
        var url,
            freetoPlayQuery = '',
            regionAndFunc = util.getCallbackAndRegion(regionOrFunction, region, callback);

        if (freeToPlay === null || !(typeof (freeToPlay) === 'boolean')) {
            console.log('Invalid query parameter for freeToPlay: ' + freeToPlay);
        }

        if (freeToPlay) {
            freetoPlayQuery = 'freeToPlay=true&';
        }

        url = util.craftUrl(endpoint, regionAndFunc.region, championUrl + '?' + freetoPlayQuery, authKey);
        util.makeRequest(url, 'Error getting champions: ', 'champions', regionAndFunc.callback);
    };

    League.getRecentGames = function (summonerId, regionOrFunction, callback) {
        var regionAndFunc = util.getCallbackAndRegion(regionOrFunction, region, callback),
            url = util.craftUrl(endpoint, regionAndFunc.region, gameUrl + '/' + summonerId + '/recent?', authKey);

        util.makeRequest(url, 'Error getting recent games: ', 'games', regionAndFunc.callback);
    };

    League.getLeagueData = function (summonerId, regionOrFunction, callback) {
        var regionAndFunc = util.getCallbackAndRegion(regionOrFunction, region, callback),
            url = util.craftUrl(endpoint, regionAndFunc.region, leagueUrl + '/' + summonerId + '?', authKey);

        util.makeRequest(url, 'Error getting league data: ', null, regionAndFunc.callback);
    };

	League.getLeagueEntryData = function (summonerId, regionOrFunction, callback) {
        var regionAndFunc = util.getCallbackAndRegion(regionOrFunction, region, callback),
            url = util.craftUrl(endpoint, regionAndFunc.region, leagueUrl + '/' + summonerId + '/entry?', authKey);

        util.makeRequest(url, 'Error getting league data: ', null, regionAndFunc.callback);
    };

    League.Stats.getPlayerSummary = function (summonerId, season, regionOrFunction, callback) {
        var regionAndFunc = util.getCallbackAndRegion(regionOrFunction, region, callback),
            seasonURL = '',
            url;

        if (util.getValidSeasonParam(season)) {
            if (season) {
                seasonURL = 'season=SEASON' + season + '&';
            }
        } else {
            console.log('Invalid query parameter for season: ' + season);
        }

        url = util.craftUrl(endpoint, regionAndFunc.region,
            statsUrl + '/' + summonerId + '/summary?' + seasonURL, authKey);
        util.makeRequest(url, 'Error getting summary data: ', 'playerStatSummaries', regionAndFunc.callback);
    };

    League.Stats.getRanked = function (summonerId, season, regionOrFunction, callback) {
        var regionAndFunc = util.getCallbackAndRegion(regionOrFunction, region, callback),
            seasonURL = '',
            url;

        if (util.getValidSeasonParam(season)) {
            if (season) {
                seasonURL = 'season=SEASON' + season + '&';
            }
        } else {
            console.log('Invalid query parameter for season: ' + season);
        }

        url = util.craftUrl(endpoint, regionAndFunc.region,
            statsUrl + '/' + summonerId + '/ranked?' + seasonURL, authKey);
        util.makeRequest(url, 'Error getting ranked data: ', 'champions', regionAndFunc.callback);
    };

    League.Summoner.getMasteries = function (summonerId, regionOrFunction, callback) {
        var regionAndFunc = util.getCallbackAndRegion(regionOrFunction,
            region,
            callback),
            url = util.craftUrl(endpoint, regionAndFunc.region,
                summonerUrl + '/' + summonerId + '/masteries?', authKey);

        util.makeRequest(url, 'Error getting mastery data: ', 'pages', regionAndFunc.callback);
    };

    League.Summoner.getRunes = function (summonerId, regionOrFunction, callback) {
        var regionAndFunc = util.getCallbackAndRegion(regionOrFunction, region, callback),
            url = util.craftUrl(endpoint, regionAndFunc.region, summonerUrl + '/' + summonerId + '/runes?', authKey);

        util.makeRequest(url, 'Error getting rune data: ', 'pages', regionAndFunc.callback);
    };

    League.Summoner.getByName = function (name, regionOrFunction, callback) {
        var regionAndFunc = util.getCallbackAndRegion(regionOrFunction, region, callback),
            url;

        name = name.split(' ').join('');
        url = util.craftUrl(endpoint, regionAndFunc.region, summonerUrl + '/by-name/' + name + '?', authKey);

        util.makeRequest(url, 'Error getting summoner data using name: ', null, regionAndFunc.callback);
    };

    League.Summoner.getByID = function (summonerId, regionOrFunction, callback) {
        var regionAndFunc = util.getCallbackAndRegion(regionOrFunction, region, callback),
            url = util.craftUrl(endpoint, regionAndFunc.region, summonerUrl + '/' + summonerId + '?', authKey);

        util.makeRequest(url, 'Error getting summoner data: ', null, regionAndFunc.callback);
    };

    League.Summoner.listNamesByIDs = function (ids, regionOrFunction, callback) {
        var regionAndFunc = util.getCallbackAndRegion(regionOrFunction, region, callback),
            url = util.craftUrl(endpoint, regionAndFunc.region, summonerUrl + '/' + ids + '/name?', authKey);

        util.makeRequest(url, 'Error getting summoner data using list of ids: ', 'summoners', regionAndFunc.callback);
    };

    League.getTeams = function (summonerId, regionOrFunction, callback) {
        var regionAndFunc = util.getCallbackAndRegion(regionOrFunction, region, callback),
            url = util.craftUrl(endpoint, regionAndFunc.region, teamUrl + '/' + summonerId + '?', authKey);

        util.makeRequest(url, 'Error getting summoner teams info: ', null, regionAndFunc.callback);
    };

    module.exports = League;
}());<|endoftext|>


<commit_before>/**
 * firecracker-mailer
 *
 * A module that handles the low-level details of rendering and
 * sending system emails.
 **/

var async           = require('async');
var path			= require("path");
var nodemailer		= require("nodemailer");
var SwigEmails		= require('swig-emails');
var swig			= require('swig');

_enabled = true;

///////////////////////
// MAIN INTERFACE
///////////////////////

var Mailer = function (config) {
	//Validate input...
	if (!config.fromName || !config.fromAddress) throw new Error("Must set fromName and fromAddress");
	if (!config.service || !config.auth) throw new Error("Must set service and auth");
	if (!config.templateDir) throw new Error("Must set templateDir");

	//Setup config...

	this._systemEmail = config.fromName + " <"+config.fromAddress+">"; //The address to mail from

	if (config.isTest && config.transport) {
		this._transport = config.transport;
	} else {
		this._transport = nodemailer.createTransport({
			service: config.service,
			auth: config.auth
		});
	}

	this._emailTemplatesDir = config.templateDir;
	this._isTest = config.isTest || false;
	this._testEnabledEmails = config.testEnabledEmails || [];

	//Setup stuff we'll ask for later

	this._swigEmails = new SwigEmails({
		root: this._emailTemplatesDir
	});

	this._lastHTML = null;
	this._lastText = null;
};
Mailer.prototype.constructor = Mailer;

Mailer.prototype.send = function (recipient, templateName, data, callback) {
	var thisMailer = this;

	//Clean up the data here
	data = thisMailer._prepareData(data);

	var results = {
		sent: 0,
		failed: []
	};

	thisMailer._renderMessage(templateName, data, function(err, html, text) {

		thisMailer._sendMessage(recipient, data.subject, html, text, function(err) {
			if (err) results.failed.push(data.recipient);
			else results.sent++;

			callback(err, results);
		});
	});
};

/**
 * Send an email to a group of recipients.
 *
 * @param {Array} recipients
 * @param {Object} data
 * @param {function} callback(err, results)
 */
Mailer.prototype.sendGroup = function(recipients, templateName, data, callback) {
	var thisMailer = this;

	//Clean up the data here
	data = thisMailer._prepareData(data);

	var results = {
		sent: 0,
		failed: []
	};

	thisMailer._renderMessage(templateName, data, function(err, html, text) {

		async.each(recipients,
			function (recipient, next) {

				thisMailer._sendMessage(recipient, data.subject, html, text, function(err) {
					if (err) results.failed.push(recipient);
					else results.sent++;

					if (err && data.abortOnError) return next(err);

					next(null);
				});
			},
			function (err) {
				callback(err, results);
			}
		);
	});
};

Mailer.prototype.setGlobalData = function (globalData) {

};

Mailer.setEnabled = function(enabledOrNot) {
	_enabled = enabledOrNot;
};

Mailer.prototype.getLastHTML = function() {
	return this._lastHTML;
};

Mailer.prototype.getLastText = function() {
	return this._lastText;
};

///////////////////
// HELPERS
///////////////////

Mailer.prototype._prepareData = function (data) {
	data = data || {};

	//TODO: implement

	//Insert the site config into the data.
	data.cssPath = path.resolve(this._emailTemplatesDir, "style.css");

	//TODO: merge with global data, so we always have homeUrl, etc.

	return data;
};

/**
 * Render an EJS email template,
 * Populating it with data,
 * and return it through a callback function.
 *
 * callback = function(err, html, text)
 */
Mailer.prototype._renderMessage = function (templateName, data, callback) {

	if (this._isTest) {
		console.log("Mailer.renderMessage()");
	}

	var thisMailer = this;

	thisMailer._renderHTML(templateName, data, function (err, html) {
		if (err) return callback(err, null, null);

		//Generate Text
		thisMailer._renderText(templateName, data, function (err, text) {
			if (err) {
				console.error("Error loading text:", err);
				return callback(err, null, null);
			}

			//Success!
			this._lastHTML = html;
			this._lastText = text;
			callback(null, html, text);
		});
	});

}; //Mailer.renderMessage()

/**
 * Render the HTML version of a template.
 */
Mailer.prototype._renderHTML = function (templateName, data, callback) {
	var templatePath = templateName+"/html.swig";	//relative path

	var renderOptions = {
		context: data,
		text: false	//don't render text here - we'll do that ourselves.
	};

	this._swigEmails.render(templatePath, renderOptions, function (err, html) {
		if (err) {
			console.error("Error loading template:", err);
			callback(err, null);
		} else {
			callback(null, html);
		}
	});
};

/**
 * Render the text version of a template.
 */
Mailer.prototype._renderText = function (templateName, data, callback) {
	var templatePath = path.resolve(this._emailTemplatesDir, templateName, "text.swig");	//absolute path
	swig.renderFile(templatePath, data, function (err, output) {
		callback(err, output);
	});
};

/**
 * Send a message with a specific recipient, subject, and body.
 *
 * @param {Object} options (optional) extra values to set in the message.
 * @param {Function} callback = function(err)
 */
Mailer.prototype._sendMessage = function (toEmail, subject, html, text, options, callback) {

	if (this._isTest) {
		console.log("Mailer.sendMessage(\"" + toEmail + "\",\"" + subject + "\", ...)");
	}

	//Configure parameters.
	if (!callback && typeof options == "function") {
		//options parameter not specified.
		callback = options;
		options = {};
	}

	//Cancel sending?
	if (!_enabled) {
		console.log("[Note: Mailer disabled. The message will not be sent.]");
		return callback(null);
	}
	if (this._isTest && !this._isTestEnabled(toEmail)) {
		console.log("["+toEmail+" is not a test-enabled address. The message will not be sent.]");
		return callback(null);
	}

	//Load options
	var sendOptions = this._loadSendOptions(toEmail, subject, html, text, options);

	//Send the email.
	this._transport.sendMail(sendOptions, function (err, responseStatus) {
		if (err) {
			console.log("Error: ", err, responseStatus);
		}
		callback(err);
	});

};	//Mailer.sendMessage()

Mailer.prototype._loadSendOptions = function (toEmail, subject, html, text, options) {

	//Start with the defaults
	var sendOptions = {
		from: this._systemEmail,
		to: toEmail,
		subject: subject,
		html: html,
		text: text
	};

	//Put in special fields
	if (options.headers) {
		options.headers = _serializeHeaders(options.headers);
	}
	for (var key in options) {
		sendOptions[key] = options[key];
	}

	return sendOptions;
};

Mailer.prototype._isTestEnabled = function (email) {
	for (var i = 0; i < this._testEnabledEmails.length; i++) {
		if (this._testEnabledEmails[i] == email) {
			return true;
		}
	}
	return false;
};

/***************
 * OTHER STUFF */

var _serializeHeaders = function (headers) {
	var result = "";
	for (var key in headers) {
		result += key + ": " + headers[key] + "\n";
	}
	return result;
};

//Export this class.
module.exports = Mailer;<commit_msg>Changed this to thisMailer because we're in a callback function.<commit_after>/**
 * firecracker-mailer
 *
 * A module that handles the low-level details of rendering and
 * sending system emails.
 **/

var async           = require('async');
var path			= require("path");
var nodemailer		= require("nodemailer");
var SwigEmails		= require('swig-emails');
var swig			= require('swig');

_enabled = true;

///////////////////////
// MAIN INTERFACE
///////////////////////

var Mailer = function (config) {
	//Validate input...
	if (!config.fromName || !config.fromAddress) throw new Error("Must set fromName and fromAddress");
	if (!config.service || !config.auth) throw new Error("Must set service and auth");
	if (!config.templateDir) throw new Error("Must set templateDir");

	//Setup config...

	this._systemEmail = config.fromName + " <"+config.fromAddress+">"; //The address to mail from

	if (config.isTest && config.transport) {
		this._transport = config.transport;
	} else {
		this._transport = nodemailer.createTransport({
			service: config.service,
			auth: config.auth
		});
	}

	this._emailTemplatesDir = config.templateDir;
	this._isTest = config.isTest || false;
	this._testEnabledEmails = config.testEnabledEmails || [];

	//Setup stuff we'll ask for later

	this._swigEmails = new SwigEmails({
		root: this._emailTemplatesDir
	});

	this._lastHTML = null;
	this._lastText = null;
};
Mailer.prototype.constructor = Mailer;

Mailer.prototype.send = function (recipient, templateName, data, callback) {
	var thisMailer = this;

	//Clean up the data here
	data = thisMailer._prepareData(data);

	var results = {
		sent: 0,
		failed: []
	};

	thisMailer._renderMessage(templateName, data, function(err, html, text) {

		thisMailer._sendMessage(recipient, data.subject, html, text, function(err) {
			if (err) results.failed.push(data.recipient);
			else results.sent++;

			callback(err, results);
		});
	});
};

/**
 * Send an email to a group of recipients.
 *
 * @param {Array} recipients
 * @param {Object} data
 * @param {function} callback(err, results)
 */
Mailer.prototype.sendGroup = function(recipients, templateName, data, callback) {
	var thisMailer = this;

	//Clean up the data here
	data = thisMailer._prepareData(data);

	var results = {
		sent: 0,
		failed: []
	};

	thisMailer._renderMessage(templateName, data, function(err, html, text) {

		async.each(recipients,
			function (recipient, next) {

				thisMailer._sendMessage(recipient, data.subject, html, text, function(err) {
					if (err) results.failed.push(recipient);
					else results.sent++;

					if (err && data.abortOnError) return next(err);

					next(null);
				});
			},
			function (err) {
				callback(err, results);
			}
		);
	});
};

Mailer.prototype.setGlobalData = function (globalData) {

};

Mailer.setEnabled = function(enabledOrNot) {
	_enabled = enabledOrNot;
};

Mailer.prototype.getLastHTML = function() {
	return this._lastHTML;
};

Mailer.prototype.getLastText = function() {
	return this._lastText;
};

///////////////////
// HELPERS
///////////////////

Mailer.prototype._prepareData = function (data) {
	data = data || {};

	//TODO: implement

	//Insert the site config into the data.
	data.cssPath = path.resolve(this._emailTemplatesDir, "style.css");

	//TODO: merge with global data, so we always have homeUrl, etc.

	return data;
};

/**
 * Render an EJS email template,
 * Populating it with data,
 * and return it through a callback function.
 *
 * callback = function(err, html, text)
 */
Mailer.prototype._renderMessage = function (templateName, data, callback) {

	if (this._isTest) {
		console.log("Mailer.renderMessage()");
	}

	var thisMailer = this;

	thisMailer._renderHTML(templateName, data, function (err, html) {
		if (err) return callback(err, null, null);

		//Generate Text
		thisMailer._renderText(templateName, data, function (err, text) {
			if (err) {
				console.error("Error loading text:", err);
				return callback(err, null, null);
			}

			//Success!
			thisMailer._lastHTML = html;
			thisMailer._lastText = text;
			callback(null, html, text);
		});
	});

}; //Mailer.renderMessage()

/**
 * Render the HTML version of a template.
 */
Mailer.prototype._renderHTML = function (templateName, data, callback) {
	var templatePath = templateName+"/html.swig";	//relative path

	var renderOptions = {
		context: data,
		text: false	//don't render text here - we'll do that ourselves.
	};

	this._swigEmails.render(templatePath, renderOptions, function (err, html) {
		if (err) {
			console.error("Error loading template:", err);
			callback(err, null);
		} else {
			callback(null, html);
		}
	});
};

/**
 * Render the text version of a template.
 */
Mailer.prototype._renderText = function (templateName, data, callback) {
	var templatePath = path.resolve(this._emailTemplatesDir, templateName, "text.swig");	//absolute path
	swig.renderFile(templatePath, data, function (err, output) {
		callback(err, output);
	});
};

/**
 * Send a message with a specific recipient, subject, and body.
 *
 * @param {Object} options (optional) extra values to set in the message.
 * @param {Function} callback = function(err)
 */
Mailer.prototype._sendMessage = function (toEmail, subject, html, text, options, callback) {

	if (this._isTest) {
		console.log("Mailer.sendMessage(\"" + toEmail + "\",\"" + subject + "\", ...)");
	}

	//Configure parameters.
	if (!callback && typeof options == "function") {
		//options parameter not specified.
		callback = options;
		options = {};
	}

	//Cancel sending?
	if (!_enabled) {
		console.log("[Note: Mailer disabled. The message will not be sent.]");
		return callback(null);
	}
	if (this._isTest && !this._isTestEnabled(toEmail)) {
		console.log("["+toEmail+" is not a test-enabled address. The message will not be sent.]");
		return callback(null);
	}

	//Load options
	var sendOptions = this._loadSendOptions(toEmail, subject, html, text, options);

	//Send the email.
	this._transport.sendMail(sendOptions, function (err, responseStatus) {
		if (err) {
			console.log("Error: ", err, responseStatus);
		}
		callback(err);
	});

};	//Mailer.sendMessage()

Mailer.prototype._loadSendOptions = function (toEmail, subject, html, text, options) {

	//Start with the defaults
	var sendOptions = {
		from: this._systemEmail,
		to: toEmail,
		subject: subject,
		html: html,
		text: text
	};

	//Put in special fields
	if (options.headers) {
		options.headers = _serializeHeaders(options.headers);
	}
	for (var key in options) {
		sendOptions[key] = options[key];
	}

	return sendOptions;
};

Mailer.prototype._isTestEnabled = function (email) {
	for (var i = 0; i < this._testEnabledEmails.length; i++) {
		if (this._testEnabledEmails[i] == email) {
			return true;
		}
	}
	return false;
};

/***************
 * OTHER STUFF */

var _serializeHeaders = function (headers) {
	var result = "";
	for (var key in headers) {
		result += key + ": " + headers[key] + "\n";
	}
	return result;
};

//Export this class.
module.exports = Mailer;<|endoftext|>


<commit_before>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

/*
 * BlendMode code ported from Context Blender JavaScript Library
 *
 * Copyright © 2010 Gavin Kistner
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

var BlendMode = {
	process: function(blendMode, sourceContext, destContext, alpha, offset) {
		var sourceCanvas = sourceContext.canvas,
			dstData = destContext.getImageData(offset.x, offset.y,
					sourceCanvas.width, sourceCanvas.height),
			dst  = dstData.data,
			src  = sourceContext.getImageData(0, 0,
					sourceCanvas.width, sourceCanvas.height).data,
			min = Math.min,
			max = Math.max,
			abs = Math.abs,
			sr, sg, sb, sa, // source
			br, bg, bb, ba, // backdrop
			dr, dg, db,     // destination
			hsb = [],
			// lookup table with indices for each hsb blend mode and hsb
			// component inside the hsb table: 0 = source, 1 = backdrop
			hsbIndices = {
				hue: [0, 1, 1],
				saturation: [1, 0, 1],
				luminosity: [1, 1, 0],
				color: [0, 0, 1]
			}[blendMode];

		function processHsb() {
			// Convert both source and backdrop to HSB and then use hsbIndices
			// to decide from which one to pick before converting back to RGB.
			hsb[0] = Color.RGBtoHSB(sr / 255, sg / 255, sb / 255);
			hsb[1] = Color.RGBtoHSB(br / 255, bg / 255, bb / 255);
			var rgb = Color.HSBtoRGB(
					hsb[hsbIndices[0]][0],
					hsb[hsbIndices[1]][1],
					hsb[hsbIndices[2]][2]);
			dr = rgb[0] * 255;
			dg = rgb[1] * 255;
			db = rgb[2] * 255;
		}

		var modes = {
			multiply: function() {
				dr = br * sr / 255;
				dg = bg * sg / 255;
				db = bb * sb / 255;
			},

			screen: function() {
				dr = 255 - (255 - br) * (255 - sr) / 255;
				dg = 255 - (255 - bg) * (255 - sg) / 255;
				db = 255 - (255 - bb) * (255 - sb) / 255;
			},

			overlay: function() {
				dr = br < 128 ? 2 * br * sr / 255 : 255 - 2 * (255 - br) * (255 - sr) / 255;
				dg = bg < 128 ? 2 * bg * sg / 255 : 255 - 2 * (255 - bg) * (255 - sg) / 255;
				db = bb < 128 ? 2 * bb * sb / 255 : 255 - 2 * (255 - bb) * (255 - sb) / 255;
			},

			'soft-light': function() {
				var t = sr * br / 255;
				dr = t + br * (255 - (255 - br) * (255 - sr) / 255 - t) / 255;
				t = sg * bg / 255;
				dg = t + bg * (255 - (255 - bg) * (255 - sg) / 255 - t) / 255;
				t = sb * bb / 255;
				db = t + bb * (255 - (255 - bb) * (255 - sb) / 255 - t) / 255;
			},

			'hard-light': function() {
				// = Reverse of overlay
				dr = sr < 128 ? 2 * sr * br / 255 : 255 - 2 * (255 - sr) * (255 - br) / 255;
				dg = sg < 128 ? 2 * sg * bg / 255 : 255 - 2 * (255 - sg) * (255 - bg) / 255;
				db = sb < 128 ? 2 * sb * bb / 255 : 255 - 2 * (255 - sb) * (255 - bb) / 255;
			},

			'color-dodge': function() {
				dr = sr == 255 ? sr : min(255, br * 255 / (255 - sr));
				dg = sg == 255 ? sg : min(255, bg * 255 / (255 - sg));
				db = sb == 255 ? sb : min(255, bb * 255 / (255 - sb));
			},

			'color-burn': function() {
				dr = sr == 0 ? 0 : max(255 - ((255 - br) * 255) / sr, 0);
				dg = sg == 0 ? 0 : max(255 - ((255 - bg) * 255) / sg, 0);
				db = sb == 0 ? 0 : max(255 - ((255 - bb) * 255) / sb, 0);
			},

			darken: function() {
				dr = br < sr ? br : sr;
				dg = bg < sg ? bg : sg;
				db = bb < sb ? bb : sb;
			},

			lighten: function() {
				dr = br > sr ? br : sr;
				dg = bg > sg ? bg : sg;
				db = bb > sb ? bb : sb;
			},

			difference: function() {
				dr = br - sr;
				if (dr < 0)
					dr = -dr;
				dg = bg - sg;
				if (dg < 0)
					dg = -dg;
				db = bb - sb;
				if (db < 0)
					db = -db;
			},

			exclusion: function() {
				dr = br + sr * (255 - br - br) / 255;
				dg = bg + sg * (255 - bg - bg) / 255;
				db = bb + sb * (255 - bb - bb) / 255;
			},

			// HSB Modes:
			hue: processHsb,
			saturation: processHsb,
			luminosity: processHsb,
			color: processHsb,

			// TODO: Not in Illustrator:
			add: function() {
				dr = min(br + sr, 255);
				dg = min(bg + sg, 255);
				db = min(bb + sb, 255);
			},

			subtract: function() {
				dr = max(br - sr, 0);
				dg = max(bg - sg, 0);
				db = max(bb - sb, 0);
			},

			average: function() {
				dr = (br + sr) / 2;
				dg = (bg + sg) / 2;
				db = (bb + sb) / 2;
			},

			'pin-light': function() {
				var op = sr < 128 ? min : max;
				dr = op(sr, br);
				dg = op(sg, bg);
				db = op(sb, bb);
			},

			negation: function() {
				dr = 255 - abs(255 - sr - br);
				dg = 255 - abs(255 - sg - bg);
				db = 255 - abs(255 - sb - bb);
			}
		};

		var process = modes[blendMode];
		if (!process)
			return;

		for (var i = 0, l = dst.length; i < l; i += 4) {
			sr = src[i];
			br = dst[i];
			sg = src[i + 1];
			bg = dst[i + 1];
			sb = src[i + 2];
			bb = dst[i + 2];
			sa = src[i + 3];
			ba = dst[i + 3];
			process();
			var a1 = sa * alpha / 255,
				a2 = 1 - a1;
			dst[i] = a1 * dr + a2 * br;
			dst[i + 1] = a1 * dg + a2 * bg;
			dst[i + 2] = a1 * db + a2 * bb;
			dst[i + 3] = sa * alpha + a2 * ba;
		}
		destContext.putImageData(dstData, offset.x, offset.y);
	}
};
<commit_msg>Implement HSL blend modes according to PDF specs.<commit_after>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

/*
 * BlendMode code ported from Context Blender JavaScript Library
 *
 * Copyright © 2010 Gavin Kistner
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

var BlendMode = {
	process: function(blendMode, sourceContext, destContext, alpha, offset) {
		var sourceCanvas = sourceContext.canvas,
			dstData = destContext.getImageData(offset.x, offset.y,
					sourceCanvas.width, sourceCanvas.height),
			dst  = dstData.data,
			src  = sourceContext.getImageData(0, 0,
					sourceCanvas.width, sourceCanvas.height).data,
			min = Math.min,
			max = Math.max,
			abs = Math.abs,
			sr, sg, sb, sa, // source
			br, bg, bb, ba, // backdrop
			dr, dg, db;     // destination

		// Conversion methods for HSL modes, as described by
		// http://www.aiim.org/documents/standards/pdf/blend_modes.pdf
		// The setters modify the variables dr, dg, db directly.

		function getLum(r, g, b) {
			return 0.2989 * r + 0.587 * g + 0.114 * b;
		}

		function setLum(r, g, b, l) {
			var d = l - getLum(r, g, b);
			dr = r + d;
			dg = g + d;
			db = b + d;
			var l = getLum(dr, dg, db),
				mn = min(dr, dg, db),
				mx = max(dr, dg, db);
			if (mn < 0) {
				var lmn = l - mn;
				dr = l + (dr - l) * l / lmn;
				dg = l + (dg - l) * l / lmn;
				db = l + (db - l) * l / lmn;
			}
			if (mx > 255) {
				var ln = 255 - l, mxl = mx - l;
				dr = l + (dr - l) * ln / mxl;
				dg = l + (dg - l) * ln / mxl;
				db = l + (db - l) * ln / mxl;
			}
		}

		function getSat(r, g, b) {
			return max(r, g, b) - min(r, g, b);
		}

		function setSat(r, g, b, s) {
			var col = [r, g, b],
				mx = max(r, g, b), // max
				mn = min(r, g, b), // min
				md; // mid
			// Determine indices for min and max in col:
			mn = mn == r ? 0 : mn == g ? 1 : 2;
			mx = mx == r ? 0 : mx == g ? 1 : 2;
			// Determine the index in col that is not used yet by min and max,
			// and assign it to mid:
			md = min(mn, mx) == 0 ? max(mn, mx) == 1 ? 2 : 1 : 0;
			if (col[mx] > col[mn]) {
				col[md] = (col[md] - col[mn]) * s / (col[mx] - col[mn]);
				col[mx] = s;
			} else {
				col[md] = col[mx] = 0;
			}
			col[mn] = 0;
			dr = col[0];
			dg = col[1];
			db = col[2];
		}

		var modes = {
			multiply: function() {
				dr = br * sr / 255;
				dg = bg * sg / 255;
				db = bb * sb / 255;
			},

			screen: function() {
				dr = 255 - (255 - br) * (255 - sr) / 255;
				dg = 255 - (255 - bg) * (255 - sg) / 255;
				db = 255 - (255 - bb) * (255 - sb) / 255;
			},

			overlay: function() {
				dr = br < 128 ? 2 * br * sr / 255 : 255 - 2 * (255 - br) * (255 - sr) / 255;
				dg = bg < 128 ? 2 * bg * sg / 255 : 255 - 2 * (255 - bg) * (255 - sg) / 255;
				db = bb < 128 ? 2 * bb * sb / 255 : 255 - 2 * (255 - bb) * (255 - sb) / 255;
			},

			'soft-light': function() {
				var t = sr * br / 255;
				dr = t + br * (255 - (255 - br) * (255 - sr) / 255 - t) / 255;
				t = sg * bg / 255;
				dg = t + bg * (255 - (255 - bg) * (255 - sg) / 255 - t) / 255;
				t = sb * bb / 255;
				db = t + bb * (255 - (255 - bb) * (255 - sb) / 255 - t) / 255;
			},

			'hard-light': function() {
				// = Reverse of overlay
				dr = sr < 128 ? 2 * sr * br / 255 : 255 - 2 * (255 - sr) * (255 - br) / 255;
				dg = sg < 128 ? 2 * sg * bg / 255 : 255 - 2 * (255 - sg) * (255 - bg) / 255;
				db = sb < 128 ? 2 * sb * bb / 255 : 255 - 2 * (255 - sb) * (255 - bb) / 255;
			},

			'color-dodge': function() {
				dr = sr == 255 ? sr : min(255, br * 255 / (255 - sr));
				dg = sg == 255 ? sg : min(255, bg * 255 / (255 - sg));
				db = sb == 255 ? sb : min(255, bb * 255 / (255 - sb));
			},

			'color-burn': function() {
				dr = sr == 0 ? 0 : max(255 - ((255 - br) * 255) / sr, 0);
				dg = sg == 0 ? 0 : max(255 - ((255 - bg) * 255) / sg, 0);
				db = sb == 0 ? 0 : max(255 - ((255 - bb) * 255) / sb, 0);
			},

			darken: function() {
				dr = br < sr ? br : sr;
				dg = bg < sg ? bg : sg;
				db = bb < sb ? bb : sb;
			},

			lighten: function() {
				dr = br > sr ? br : sr;
				dg = bg > sg ? bg : sg;
				db = bb > sb ? bb : sb;
			},

			difference: function() {
				dr = br - sr;
				if (dr < 0)
					dr = -dr;
				dg = bg - sg;
				if (dg < 0)
					dg = -dg;
				db = bb - sb;
				if (db < 0)
					db = -db;
			},

			exclusion: function() {
				dr = br + sr * (255 - br - br) / 255;
				dg = bg + sg * (255 - bg - bg) / 255;
				db = bb + sb * (255 - bb - bb) / 255;
			},

			// HSL Modes:
			hue: function() {
				setSat(sr, sg, sb, getSat(br, bg, bb));
				setLum(dr, dg, db, getLum(br, bg, bb));
			},

			saturation: function() {
				setSat(br, bg, bb, getSat(sr, sg, sb));
				setLum(dr, dg, db, getLum(br, bg, bb));
			},

			luminosity: function() {
				setLum(br, bg, bb, getLum(sr, sg, sb));
			},

			color: function() {
				setLum(sr, sg, sb, getLum(br, bg, bb));
			},

			// TODO: Not in Illustrator:
			add: function() {
				dr = min(br + sr, 255);
				dg = min(bg + sg, 255);
				db = min(bb + sb, 255);
			},

			subtract: function() {
				dr = max(br - sr, 0);
				dg = max(bg - sg, 0);
				db = max(bb - sb, 0);
			},

			average: function() {
				dr = (br + sr) / 2;
				dg = (bg + sg) / 2;
				db = (bb + sb) / 2;
			},

			'pin-light': function() {
				var op = sr < 128 ? min : max;
				dr = op(sr, br);
				dg = op(sg, bg);
				db = op(sb, bb);
			},

			negation: function() {
				dr = 255 - abs(255 - sr - br);
				dg = 255 - abs(255 - sg - bg);
				db = 255 - abs(255 - sb - bb);
			}
		};

		var process = modes[blendMode];
		if (!process)
			return;

		for (var i = 0, l = dst.length; i < l; i += 4) {
			sr = src[i];
			br = dst[i];
			sg = src[i + 1];
			bg = dst[i + 1];
			sb = src[i + 2];
			bb = dst[i + 2];
			sa = src[i + 3];
			ba = dst[i + 3];
			process();
			var a1 = sa * alpha / 255,
				a2 = 1 - a1;
			dst[i] = a1 * dr + a2 * br;
			dst[i + 1] = a1 * dg + a2 * bg;
			dst[i + 2] = a1 * db + a2 * bb;
			dst[i + 3] = sa * alpha + a2 * ba;
		}
		destContext.putImageData(dstData, offset.x, offset.y);
	}
};
<|endoftext|>


<commit_before>var binary = require('node-pre-gyp');
var path = require('path');
var binding_path = binary.find(path.resolve(path.join(__dirname,'../package.json')));
var settings_path = path.join(path.dirname(binding_path),'mapnik_settings.js');
var settings = require(settings_path);

var separator = (process.platform === 'win32') ? ';' : ':';

// set custom env settings before loading mapnik
if (settings.env) {
    var process_keys = Object.keys(process.env);
    for (key in settings.env) {
        if (process_keys.indexOf(key) == -1) {
            process.env[key] = settings.env[key];
        } else {
            if (key === 'PATH') {
                process.env[key] = settings.env[key] + separator + process.env[key];
            }
        }
    }
}

var binding = require(binding_path);
var mapnik = module.exports = exports = binding;

process.on('exit',function() {
    if (mapnik) mapnik.shutdown();
});

var exists = require('fs').existsSync || require('path').existsSync;

exports.settings = settings;

exports.version = require('../package').version;

exports.register_default_fonts = function() {
    if (settings.paths.fonts) {
        mapnik.register_fonts(settings.paths.fonts, {recurse: true});
    }
}

exports.register_default_input_plugins = function() {
    if (settings.paths.input_plugins) {
        mapnik.register_datasources(settings.paths.input_plugins);
    }
}

exports.register_system_fonts = function() {
    var num_faces = mapnik.fonts().length;
    var dirs = [];
    if (process.platform === 'linux' ||
       (process.platform === 'sunos') ||
       (process.platform.indexOf('bsd') != -1)) {
        dirs.push('/usr/share/fonts/');
        dirs.push('/usr/local/share/fonts/');
        dirs.push(path.join(process.env.HOME, '.fonts'));
    } else if (process.platform === 'darwin') {
        dirs.push('/Library/Fonts');
        dirs.push('/System/Library/Fonts');
        dirs.push(path.join(process.env.HOME, 'Library/Fonts'));
    } else if (process.platform === 'win32') {
       dirs.push('C:\\Windows\\Fonts');
    }
    dirs.forEach(function(p) {
        if (exists(p)) {
            mapnik.register_fonts(p, {recurse: true});
        }
    });
    if (mapnik.fonts().length == num_faces) {
       return false;
    } else {
       return true;
    }
};

// register paths from MAPNIK_FONT_PATH
if (process.env.MAPNIK_FONT_PATH) {
    process.env.MAPNIK_FONT_PATH.split(separator).forEach(function(p) {
        if (exists(p)) {
            mapnik.register_fonts(p);
        }
    });
}
<commit_msg>fix #302<commit_after>var binary = require('node-pre-gyp');
var path = require('path');
var binding_path = binary.find(path.resolve(path.join(__dirname,'../package.json')));
var settings_path = path.join(path.dirname(binding_path),'mapnik_settings.js');
var settings = require(settings_path);

var separator = (process.platform === 'win32') ? ';' : ':';

// set custom env settings before loading mapnik
if (settings.env) {
    var process_keys = Object.keys(process.env);
    for (key in settings.env) {
        if (process_keys.indexOf(key) == -1) {
            process.env[key] = settings.env[key];
        } else {
            if (key === 'PATH') {
                process.env[key] = settings.env[key] + separator + process.env[key];
            }
        }
    }
}

var binding = require(binding_path);
var mapnik = module.exports = exports = binding;

process.on('exit',function() {
    if (mapnik) mapnik.shutdown();
});

var exists = require('fs').existsSync || require('path').existsSync;

exports.settings = settings;

exports.version = require('../package').version;

exports.register_default_fonts = function() {
    if (settings.paths.fonts) {
        mapnik.register_fonts(settings.paths.fonts, {recurse: true});
    }
}

exports.register_default_input_plugins = function() {
    if (settings.paths.input_plugins) {
        mapnik.register_datasources(settings.paths.input_plugins);
    }
}

exports.register_system_fonts = function() {
    var num_faces = mapnik.fonts().length;
    var dirs = [];
    if (process.platform === 'linux' ||
       (process.platform === 'sunos') ||
       (process.platform.indexOf('bsd') != -1)) {
        dirs.push('/usr/share/fonts/');
        dirs.push('/usr/local/share/fonts/');
        if (process.env.hasOwnProperty('HOME')) dirs.push(path.join(process.env.HOME, '.fonts'));
    } else if (process.platform === 'darwin') {
        dirs.push('/Library/Fonts');
        dirs.push('/System/Library/Fonts');
        if (process.env.hasOwnProperty('HOME')) dirs.push(path.join(process.env.HOME, 'Library/Fonts'));
    } else if (process.platform === 'win32') {
       dirs.push('C:\\Windows\\Fonts');
    }
    dirs.forEach(function(p) {
        if (exists(p)) {
            mapnik.register_fonts(p, {recurse: true});
        }
    });
    if (mapnik.fonts().length == num_faces) {
       return false;
    } else {
       return true;
    }
};

// register paths from MAPNIK_FONT_PATH
if (process.env.MAPNIK_FONT_PATH) {
    process.env.MAPNIK_FONT_PATH.split(separator).forEach(function(p) {
        if (exists(p)) {
            mapnik.register_fonts(p);
        }
    });
}
<|endoftext|>