<commit_before>'use strict';

var uuid = require('node-uuid'),
  Q = require('q'),
  _ = require('lodash'),
  path = require('path'),
  config = require(path.join(__dirname,'../config')),
  platforms = config.platforms;

function PWABuilder(pwabuilderLib){
  this.lib = pwabuilderLib;
  var platformsConfig = path.resolve(__dirname, '..', '..', 'platforms.json');
  this.lib.platformTools.configurePlatforms(platformsConfig);
}

PWABuilder.prototype.createManifestFromUrl = function(url,client){
  var self = this;

  if(url.indexOf('http') === -1){
    url = 'http://'+url;
  }

  return Q.Promise(function(resolve,reject){

    var callback = function(err, manifestInfo) {
      if (err) {
        return reject(err);
      }

      var manifest = _.assign(manifestInfo,{ id: uuid.v4().slice(0,8) });

      self.validateManifest(manifest)
      .then(function(manifest){
        client.set(manifest.id,JSON.stringify(manifest), 'EX', 60*60*24*7);
        return resolve(manifest);
      })
      .fail(reject);
    }

    var resolveStartUrl =  function (err, manifestInfo) {
    if (err) {
      return callback(err, manifestInfo);
    }

    if (manifestInfo.format === self.lib.constants.BASE_MANIFEST_FORMAT) {
      return self.lib.manifestTools.validateAndNormalizeStartUrl(url, manifestInfo, callback);
    } else {
      return callback(undefined, manifestInfo);
    }
  }
    self.lib.manifestTools.getManifestFromSite(url, undefined, resolveStartUrl);
  });
};

PWABuilder.prototype.createManifestFromFile = function(file,client){
  var self = this;

  return Q.Promise(function(resolve,reject){
    self.lib.manifestTools.getManifestFromFile(file.path, function (err, manifestInfo) {
      if (err) { return reject(err); }

      var manifest = _.assign(manifestInfo,{ id: uuid.v4().slice(0,8) });
      self.validateManifest(manifest)
      .then(function(manifest){
        client.set(manifest.id,JSON.stringify(manifest), 'EX', 60*60*24*7);
        return resolve(manifest);
      })
      .fail(reject);
    });
  });
};

PWABuilder.prototype.validateManifest = function(manifest){
  var self = this;

  var originalIcons = manifest.content.icons;
  manifest = self.cleanGeneratedIcons(manifest);

  return Q.Promise(function(resolve,reject){
    self.lib.manifestTools.validateManifest(manifest, platforms, function(err,results){
      if(err){ return reject(err); }

      var errors = _.filter(results,{level: 'error'}),
        suggestions = _.filter(results,{level: 'suggestion'}),
        warnings = _.filter(results,{level: 'warning'});

      self.assignValidationErrors(errors,manifest);
      self.assignSuggestions(suggestions,manifest);
      self.assignWarnings(warnings,manifest);

      // restore original icons
      manifest.content.icons = originalIcons;

      return resolve(manifest);
    });
  });
};

PWABuilder.prototype.updateManifest = function(client,manifestId,updates,assets) {
  var self = this;

  return Q.Promise(function(resolve,reject){
    client.get(manifestId,function(err,reply){
      if(err) return reject(err);
      if(!reply) return reject(new Error('Manifest not found'));

      var manifest = JSON.parse(reply);
      manifest.content = updates;

      if (assets) {
        manifest.assets = assets;
      } else {
        if ((updates.icons || []).filter(function(icon) { return icon.generated; }).length === 0) {
          delete manifest.assets;
        }
      }

      return self.validateManifest(manifest)
      .then(function(manifest){
        client.set(manifest.id,JSON.stringify(manifest), 'EX', 60*60*24*7);

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

PWABuilder.prototype.normalize = function(manifest){
  var self = this;

  return Q.Promise(function(resolve,reject){
    console.log('Validating start url...');
    self.lib.manifestTools.validateAndNormalizeStartUrl(manifest.content.start_url,manifest,function(err,normManifest){
      if(err){
        console.log('Normalizing Error',err);
        return reject(err);
      }

      manifest = _.assign(manifest,normManifest);

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

PWABuilder.prototype.cleanGeneratedIcons = function(manifest){
  var self = this;

// remove properties in the manifest to track generated icons
  manifest.content.icons = (manifest.content.icons || []).map(function (icon) {
    return _.omit(icon, 'generated', 'fileName');
  });

  return manifest;
};

PWABuilder.prototype.createProject = function(manifest,outputDir,platforms){
  var self = this;

  return Q.Promise(function(resolve, reject){
    var cleanManifest = _.omit(manifest,'id');
    cleanManifest = _.assign(cleanManifest,{ generatedFrom: 'Website Wizard' });
    console.log('Building the project...',cleanManifest,outputDir,platforms);
    try{
      if (!manifest.assets) {
        manifest.assets = [];
      }
      manifest.assets.map(function (asset) {
        asset.data = new Buffer(asset.data, 'hex');
      });

      var options = {
        'crosswalk' : false,
        'build'     : false,
        'assets'    : manifest.assets
      };

      self.lib.projectBuilder.createApps(cleanManifest, outputDir, platforms, options, function (err, projectDir) {

        if(err){
          console.log('Create Projects Errors!!!',err);
          return reject(err);
        }

        return resolve(projectDir);
      });
    }catch(e){
      return reject(e);
    }
  });
};

PWABuilder.prototype.packageProject = function(platforms,outputDir,options){
  var self = this;

  return Q.Promise(function(resolve, reject){
    console.log('Packaging the project...',outputDir,platforms);
    try{

      self.lib.projectBuilder.packageApps(platforms, outputDir, options, function (err, packagePaths) {

        if(err){
          console.log('Package Project Errors!!!',err);
          return reject(err);
        }

        return resolve(packagePaths);
      });
    }catch(e){
      return reject(e);
    }
  });
};

PWABuilder.prototype.getServiceWorkers = function(id) {
  var self = this;

  return Q.Promise(function (resolve, reject) {
    self.lib.serviceWorkerTools.getAssetsFolders(id, function (err, resultURL) {
      return resolve(resultURL);
    });
  });
};

PWABuilder.prototype.getServiceWorkersDescription = function() {
  var self = this;

  return Q.Promise(function (resolve, reject) {
    self.lib.serviceWorkerTools.getServiceWorkersDescription(function (err, resultURL) {
      return resolve(resultURL);
    });
  });
};

PWABuilder.prototype.assignValidationErrors = function(errors,manifest){
  var data = { errors: []};

  _.each(errors,function(e){
    if(_.any(data.errors,'member',e.member)){
      var error = _.find(data.errors,'member',e.member);
      error.issues = error.issues || [];
      error.issues.push({ description: e.description, platform: e.platform, code: e.code });
    }else{
      data.errors.push({
        member: e.member,
        issues: [{
          description: e.description,
          platform: e.platform,
          code: e.code
        }]
      });
    }
  });

  manifest = _.assign(manifest,data);
};

PWABuilder.prototype.assignSuggestions = function(suggestions,manifest){
  var data = { suggestions: []};

  _.each(suggestions,function(s){
    if(_.any(data.suggestions,'member',s.member)){
      var suggestion = _.find(data.suggestions,'member',s.member);
      suggestion.issues = suggestion.issues || [];
      suggestion.issues.push({ description: s.description, platform: s.platform, code: s.code });
    }else{
      data.suggestions.push({
        member: s.member,
        issues: [{
          description: s.description,
          platform: s.platform,
          code: s.code
        }]
      });
    }
  });

  manifest = _.assign(manifest,data);
};

PWABuilder.prototype.assignWarnings = function(warnings,manifest){
  var data = { warnings: []};

  _.each(warnings,function(w){
    if(_.any(data.warnings,'member',w.member)){
      var warning = _.find(data.warnings,'member',w.member);
      warning.issues = warning.issues || [];
      warning.issues.push({ description: w.description, platform: w.platform, code: w.code });
    }else{
      data.warnings.push({
        member: w.member,
        issues: [{
          description: w.description,
          platform: w.platform,
          code: w.code
        }]
      });
    }
  });

  manifest = _.assign(manifest,data);
};

PWABuilder.prototype.generateImagesForManifest = function(image, manifestInfo, client) {
  var self = this;

  var options = {
    generationSvcUrl: config.images.generationSvcUrl
  };

  return Q.Promise(function(resolve, reject) {
    self.lib.manifestTools.generateImagesForManifest(image, manifestInfo.content, options, function(err, resultManifestInfo) {
      if (err) {
        return reject(err);
      } else {
        return resolve(resultManifestInfo);
      }
    });
  });
}

exports.create = function(pwabuilderLib){
  return new PWABuilder(pwabuilderLib);
};
<commit_msg>Add const variable for the expiring time<commit_after>'use strict';

var uuid = require('node-uuid'),
  Q = require('q'),
  _ = require('lodash'),
  path = require('path'),
  config = require(path.join(__dirname,'../config')),
  platforms = config.platforms;

function PWABuilder(pwabuilderLib){
  this.lib = pwabuilderLib;
  var platformsConfig = path.resolve(__dirname, '..', '..', 'platforms.json');
  this.lib.platformTools.configurePlatforms(platformsConfig);
}

const expirationTime = 604800;

PWABuilder.prototype.createManifestFromUrl = function(url,client){
  var self = this;

  if(url.indexOf('http') === -1){
    url = 'http://'+url;
  }

  return Q.Promise(function(resolve,reject){

    var callback = function(err, manifestInfo) {
      if (err) {
        return reject(err);
      }

      var manifest = _.assign(manifestInfo,{ id: uuid.v4().slice(0,8) });

      self.validateManifest(manifest)
      .then(function(manifest){
        client.set(manifest.id,JSON.stringify(manifest), 'EX', expirationTime);
        return resolve(manifest);
      })
      .fail(reject);
    }

    var resolveStartUrl =  function (err, manifestInfo) {
    if (err) {
      return callback(err, manifestInfo);
    }

    if (manifestInfo.format === self.lib.constants.BASE_MANIFEST_FORMAT) {
      return self.lib.manifestTools.validateAndNormalizeStartUrl(url, manifestInfo, callback);
    } else {
      return callback(undefined, manifestInfo);
    }
  }
    self.lib.manifestTools.getManifestFromSite(url, undefined, resolveStartUrl);
  });
};

PWABuilder.prototype.createManifestFromFile = function(file,client){
  var self = this;

  return Q.Promise(function(resolve,reject){
    self.lib.manifestTools.getManifestFromFile(file.path, function (err, manifestInfo) {
      if (err) { return reject(err); }

      var manifest = _.assign(manifestInfo,{ id: uuid.v4().slice(0,8) });
      self.validateManifest(manifest)
      .then(function(manifest){
        client.set(manifest.id,JSON.stringify(manifest), 'EX', expirationTime);
        return resolve(manifest);
      })
      .fail(reject);
    });
  });
};

PWABuilder.prototype.validateManifest = function(manifest){
  var self = this;

  var originalIcons = manifest.content.icons;
  manifest = self.cleanGeneratedIcons(manifest);

  return Q.Promise(function(resolve,reject){
    self.lib.manifestTools.validateManifest(manifest, platforms, function(err,results){
      if(err){ return reject(err); }

      var errors = _.filter(results,{level: 'error'}),
        suggestions = _.filter(results,{level: 'suggestion'}),
        warnings = _.filter(results,{level: 'warning'});

      self.assignValidationErrors(errors,manifest);
      self.assignSuggestions(suggestions,manifest);
      self.assignWarnings(warnings,manifest);

      // restore original icons
      manifest.content.icons = originalIcons;

      return resolve(manifest);
    });
  });
};

PWABuilder.prototype.updateManifest = function(client,manifestId,updates,assets) {
  var self = this;

  return Q.Promise(function(resolve,reject){
    client.get(manifestId,function(err,reply){
      if(err) return reject(err);
      if(!reply) return reject(new Error('Manifest not found'));

      var manifest = JSON.parse(reply);
      manifest.content = updates;

      if (assets) {
        manifest.assets = assets;
      } else {
        if ((updates.icons || []).filter(function(icon) { return icon.generated; }).length === 0) {
          delete manifest.assets;
        }
      }

      return self.validateManifest(manifest)
      .then(function(manifest){
        client.set(manifest.id,JSON.stringify(manifest), 'EX', expirationTime);

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

PWABuilder.prototype.normalize = function(manifest){
  var self = this;

  return Q.Promise(function(resolve,reject){
    console.log('Validating start url...');
    self.lib.manifestTools.validateAndNormalizeStartUrl(manifest.content.start_url,manifest,function(err,normManifest){
      if(err){
        console.log('Normalizing Error',err);
        return reject(err);
      }

      manifest = _.assign(manifest,normManifest);

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

PWABuilder.prototype.cleanGeneratedIcons = function(manifest){
  var self = this;

// remove properties in the manifest to track generated icons
  manifest.content.icons = (manifest.content.icons || []).map(function (icon) {
    return _.omit(icon, 'generated', 'fileName');
  });

  return manifest;
};

PWABuilder.prototype.createProject = function(manifest,outputDir,platforms){
  var self = this;

  return Q.Promise(function(resolve, reject){
    var cleanManifest = _.omit(manifest,'id');
    cleanManifest = _.assign(cleanManifest,{ generatedFrom: 'Website Wizard' });
    console.log('Building the project...',cleanManifest,outputDir,platforms);
    try{
      if (!manifest.assets) {
        manifest.assets = [];
      }
      manifest.assets.map(function (asset) {
        asset.data = new Buffer(asset.data, 'hex');
      });

      var options = {
        'crosswalk' : false,
        'build'     : false,
        'assets'    : manifest.assets
      };

      self.lib.projectBuilder.createApps(cleanManifest, outputDir, platforms, options, function (err, projectDir) {

        if(err){
          console.log('Create Projects Errors!!!',err);
          return reject(err);
        }

        return resolve(projectDir);
      });
    }catch(e){
      return reject(e);
    }
  });
};

PWABuilder.prototype.packageProject = function(platforms,outputDir,options){
  var self = this;

  return Q.Promise(function(resolve, reject){
    console.log('Packaging the project...',outputDir,platforms);
    try{

      self.lib.projectBuilder.packageApps(platforms, outputDir, options, function (err, packagePaths) {

        if(err){
          console.log('Package Project Errors!!!',err);
          return reject(err);
        }

        return resolve(packagePaths);
      });
    }catch(e){
      return reject(e);
    }
  });
};

PWABuilder.prototype.getServiceWorkers = function(id) {
  var self = this;

  return Q.Promise(function (resolve, reject) {
    self.lib.serviceWorkerTools.getAssetsFolders(id, function (err, resultURL) {
      return resolve(resultURL);
    });
  });
};

PWABuilder.prototype.getServiceWorkersDescription = function() {
  var self = this;

  return Q.Promise(function (resolve, reject) {
    self.lib.serviceWorkerTools.getServiceWorkersDescription(function (err, resultURL) {
      return resolve(resultURL);
    });
  });
};

PWABuilder.prototype.assignValidationErrors = function(errors,manifest){
  var data = { errors: []};

  _.each(errors,function(e){
    if(_.any(data.errors,'member',e.member)){
      var error = _.find(data.errors,'member',e.member);
      error.issues = error.issues || [];
      error.issues.push({ description: e.description, platform: e.platform, code: e.code });
    }else{
      data.errors.push({
        member: e.member,
        issues: [{
          description: e.description,
          platform: e.platform,
          code: e.code
        }]
      });
    }
  });

  manifest = _.assign(manifest,data);
};

PWABuilder.prototype.assignSuggestions = function(suggestions,manifest){
  var data = { suggestions: []};

  _.each(suggestions,function(s){
    if(_.any(data.suggestions,'member',s.member)){
      var suggestion = _.find(data.suggestions,'member',s.member);
      suggestion.issues = suggestion.issues || [];
      suggestion.issues.push({ description: s.description, platform: s.platform, code: s.code });
    }else{
      data.suggestions.push({
        member: s.member,
        issues: [{
          description: s.description,
          platform: s.platform,
          code: s.code
        }]
      });
    }
  });

  manifest = _.assign(manifest,data);
};

PWABuilder.prototype.assignWarnings = function(warnings,manifest){
  var data = { warnings: []};

  _.each(warnings,function(w){
    if(_.any(data.warnings,'member',w.member)){
      var warning = _.find(data.warnings,'member',w.member);
      warning.issues = warning.issues || [];
      warning.issues.push({ description: w.description, platform: w.platform, code: w.code });
    }else{
      data.warnings.push({
        member: w.member,
        issues: [{
          description: w.description,
          platform: w.platform,
          code: w.code
        }]
      });
    }
  });

  manifest = _.assign(manifest,data);
};

PWABuilder.prototype.generateImagesForManifest = function(image, manifestInfo, client) {
  var self = this;

  var options = {
    generationSvcUrl: config.images.generationSvcUrl
  };

  return Q.Promise(function(resolve, reject) {
    self.lib.manifestTools.generateImagesForManifest(image, manifestInfo.content, options, function(err, resultManifestInfo) {
      if (err) {
        return reject(err);
      } else {
        return resolve(resultManifestInfo);
      }
    });
  });
}

exports.create = function(pwabuilderLib){
  return new PWABuilder(pwabuilderLib);
};
<|endoftext|>


<commit_before>'use strict';

/**
 * Token generation.
 * (C) 2013 Alex Fernández.
 */

// requires
require('prototypes');
var Log = require('log');
var crypto = require('crypto');
var testing = require('testing');

// globals
var log = new Log('info');
// log = new Log('debug');

// constants
var SHORT_LENGTH = 4;

/**
 * Create a random token, for tests.
 * It is a pseudo-random value so don't use for anything sensitive.
 */
exports.create = function()
{
	var bytes;
	try
	{
		bytes = crypto.pseudoRandomBytes(SHORT_LENGTH);
		log.debug('Generated %d bytes of random data', bytes.length);
	}
	catch (exception)
	{
		log.error('Could not generate random bytes: %s', exception);
		return '0123456789';
	}
	var random = Math.abs(intFromBytes(bytes));
	log.debug('Integer: %s', random);
	return random.toString(36);
};

/**
 * Generate an int from an array of bytes.
 */
function intFromBytes(bytes)
{
	var val = 0;
	for (var i = 0; i < bytes.length; ++i)
	{
		val += bytes[i];
		if (i < bytes.length - 1)
		{
			val = val << 8;
		}
	}
	return val;
}

/**
 * Test basic randomicity of tokens.
 */
function testToken(callback)
{
	var frequencies = {};
	var characters = '0123456789abcdefghijklmnopqrstuvwxyz';
	var c;
	for (var i = 0; i < characters.length; i++)
	{
		c = characters[i];
		frequencies[c] = 0;
	}
	var TRIALS = 100000;
	var totalLength = 0;
	for (var trial = 0; trial < TRIALS; trial++)
	{
		var random = exports.create();
		log.debug('Generated: %s', random);
		totalLength += random.length;
		for (i = 0; i < random.length; i++)
		{
			c = random[i];
			testing.assert(c in frequencies, 'Character ' + c + ' not in frequencies', callback);
			frequencies[c] += 1;
		}
	}
	log.debug('Trials: %s, total length: %s', TRIALS, totalLength);
	var expectedFrequency = totalLength / characters.length;
	var expectedDeviation = 5 * Math.sqrt(expectedFrequency);
	// do not count 0 or z
	delete frequencies['0'];
	delete frequencies.z;
	for (c in frequencies)
	{
		var deviation = Math.abs(expectedFrequency - frequencies[c]);
		log.debug('Frequency for %s: %s, deviation: %s', c, frequencies[c], deviation);
		testing.assert(deviation < expectedDeviation, 'Deviation for ' + c + ' is too high: ' + deviation + ' > ' + expectedDeviation, callback);
	}
	testing.success(callback);
}

/**
 * Run all tests.
 */
exports.test = function(callback)
{
	testing.run({
		token: testToken,
	}, callback);
};

// start if invoked directly
if (__filename == process.argv[1])
{
	exports.test(testing.show);
}

<commit_msg>Longer timeout for token tests.<commit_after>'use strict';

/**
 * Token generation.
 * (C) 2013 Alex Fernández.
 */

// requires
require('prototypes');
var Log = require('log');
var crypto = require('crypto');
var testing = require('testing');

// globals
var log = new Log('info');
// log = new Log('debug');

// constants
var SHORT_LENGTH = 4;

/**
 * Create a random token, for tests.
 * It is a pseudo-random value so don't use for anything sensitive.
 */
exports.create = function()
{
	var bytes;
	try
	{
		bytes = crypto.pseudoRandomBytes(SHORT_LENGTH);
		log.debug('Generated %d bytes of random data', bytes.length);
	}
	catch (exception)
	{
		log.error('Could not generate random bytes: %s', exception);
		return '0123456789';
	}
	var random = Math.abs(intFromBytes(bytes));
	log.debug('Integer: %s', random);
	return random.toString(36);
};

/**
 * Generate an int from an array of bytes.
 */
function intFromBytes(bytes)
{
	var val = 0;
	for (var i = 0; i < bytes.length; ++i)
	{
		val += bytes[i];
		if (i < bytes.length - 1)
		{
			val = val << 8;
		}
	}
	return val;
}

/**
 * Test basic randomicity of tokens.
 */
function testToken(callback)
{
	var frequencies = {};
	var characters = '0123456789abcdefghijklmnopqrstuvwxyz';
	var c;
	for (var i = 0; i < characters.length; i++)
	{
		c = characters[i];
		frequencies[c] = 0;
	}
	var TRIALS = 100000;
	var totalLength = 0;
	for (var trial = 0; trial < TRIALS; trial++)
	{
		var random = exports.create();
		log.debug('Generated: %s', random);
		totalLength += random.length;
		for (i = 0; i < random.length; i++)
		{
			c = random[i];
			testing.assert(c in frequencies, 'Character ' + c + ' not in frequencies', callback);
			frequencies[c] += 1;
		}
	}
	log.debug('Trials: %s, total length: %s', TRIALS, totalLength);
	var expectedFrequency = totalLength / characters.length;
	var expectedDeviation = 5 * Math.sqrt(expectedFrequency);
	// do not count 0 or z
	delete frequencies['0'];
	delete frequencies.z;
	for (c in frequencies)
	{
		var deviation = Math.abs(expectedFrequency - frequencies[c]);
		log.debug('Frequency for %s: %s, deviation: %s', c, frequencies[c], deviation);
		testing.assert(deviation < expectedDeviation, 'Deviation for ' + c + ' is too high: ' + deviation + ' > ' + expectedDeviation, callback);
	}
	testing.success(callback);
}

/**
 * Run all tests.
 */
exports.test = function(callback)
{
	testing.run(testToken, 2000, callback);
};

// start if invoked directly
if (__filename == process.argv[1])
{
	exports.test(testing.show);
}

<|endoftext|>


<commit_before>
// Modules
var _      = require('lodash');
var http   = require('http');
var https  = require('https');
var moment = require('moment');
var xml2js = require('xml2js');
var uuid   = require('node-uuid');
var vCard  = require('vcards-js')();
_.mixin(require("lodash-deep"));

// Variables
var parseOptions = {
	explicitRoot : false,
	normalizeTags : true,
	tagNameProcessors : [xml2js.processors.stripPrefix],
	//explicitArray : false
};

// Functions
var escapeString = function( str ){
  return ( str || '' ).toString().replace( ';' , '\\;' ).replace( ',' , '\\,' );
};

var escapeStringWithLines = function( str ){
  return ( str || '' ).toString().replace( '\n' , '\\n' ).replace( ';' , '\\;' ).replace( ',' , '\\,' );
};

var telFamily = function( type ){

  type = ( type || '' ).toString().toLowerCase();

  switch( type ){
    case 'cell': return 'type=CELL;type=VOICE'; break;
    case 'iphone': return 'type=IPHONE;type=CELL;type=VOICE'; break;
    case 'home': return 'type=HOME;type=VOICE'; break;
    case 'work': return 'type=WORK;type=VOICE'; break;
    case 'main': return 'type=MAIN'; break;
    case 'homefax': return 'type=HOME;type=FAX'; break;
    case 'workfax': return 'ttype=WORK;type=FAX'; break;
    case 'otherfax': return 'type=OTHER;type=FAX'; break;
    case 'pager': return 'type=PAGER'; break;
    default: return 'type=OTHER;type=VOICE'; break;

  }

};

var emailFamily = function( type ){

  type = ( type || '' ).toString().toLowerCase();

  switch( type ){
    case 'home': return 'type=INTERNET;type=HOME'; break;
    case 'work': return 'type=INTERNET;type=WORK'; break;
    default: return 'type=INTERNET'; break;

  }

};

var urlFamily = function( type ){

  type = ( type || '' ).toString().toLowerCase();

  switch( type ){
    case 'home': return ';type=HOME'; break;
    case 'work': return ';type=WORK'; break;
    default: return ''; break;

  }

};

var adrFamily = function( type ){

  type = ( type || '' ).toString().toLowerCase();

  switch( type ){
    case 'home': return 'type=HOME'; break;
    case 'work': return 'type=WORK'; break;
    default: return 'type=OTHER'; break;

  }

};

var vcardTelFamily = function( type ){

	type = ( type || '' ).toString().toLowerCase();

	if( type.indexOf('iphone') !== -1 ){
		return 'iphone';
	}else if( type.indexOf('cell') !== -1 ){
		return 'cell';
	}else if( type.indexOf('home') !== -1 && type.indexOf('fax') !== -1 ){
		return 'homefax';
	}else if( type.indexOf('work') !== -1 && type.indexOf('fax') !== -1 ){
		return 'workfax';
	}else if( type.indexOf('other') !== -1 && type.indexOf('fax') !== -1 ){
		return 'otherfax';
	}else if( type.indexOf('fax') !== -1 ){
		return 'workfax';
	}else if( type.indexOf('main') !== -1 ){
		return 'main';
	}else if( type.indexOf('work') !== -1 ){
		return 'work';
	}else if( type.indexOf('home') !== -1 ){
		return 'home';
	}else if( type.indexOf('pager') !== -1 ){
		return 'pager';
	}else{
		return 'other';
	}

};

var vcardEmailFamily = function( type ){

	type = ( type || '' ).toString().toLowerCase();

	if( type.indexOf('work') !== -1 ){
		return 'work';
	}else if( type.indexOf('home') !== -1 ){
		return 'home';
	}else{
		return 'other';
	}

};

var vcardAdrFamily = function( type ){

	type = ( type || '' ).toString().toLowerCase();

	if( type.indexOf('work') !== -1 ){
		return 'work';
	}else if( type.indexOf('home') !== -1 ){
		return 'home';
	}else{
		return 'other';
	}

};

var vcardUrlFamily = function( type ){

	type = ( type || '' ).toString().toLowerCase();

	if( type.indexOf('work') !== -1 ){
		return 'work';
	}else if( type.indexOf('home') !== -1 ){
		return 'home';
	}else{
		return 'other';
	}

};

// Export module
module.exports = {

	request : function( opts, secure, callback ){

		var protocol = secure ? https : http;

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

			var buffer = '';

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

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

				res.body = buffer;

				callback( null, res );

			});

		}).on( 'error', function( err ){
			console.log(err);
		});

		req.write( opts.data );
		req.end();
	},

	parseXML : function( xmlString, callback ){
		xml2js.parseString(xmlString, parseOptions,callback);
	},

	cloneObject : function( obj ){
		return JSON.parse( JSON.stringify( obj ) );
	},

	uuid : function (string) {
		return uuid.v4();
	},

	normalizeAddressbookAttribute : function( result, value, key ){

		if(!value || !value[0] || !value[0] === 'undefined'){
			return result;
		}

		value = value[0];

		switch( key ){

			case 'resourcetype':
				value = Object.keys( value );
				break;

			case 'getctag':
				value = value.replace(/^"(.+(?="$))"$/, '$1');
				break;

		}

		result[key] = value;
		return result;

	},

	jsonToVCard : function( data ){

		var list = [];

		list.push('BEGIN:VCARD');
		list.push('VERSION:3.0');
		list.push(
			'N:' +
			escapeString( data.name.last ) + ';' +
			escapeString( data.name.first ) + ';' +
			escapeString( data.name.middle ) + ';' +
			escapeString( data.name.prefix ) + ';' +
			escapeString( data.name.suffix )
		);

		list.push(
			'FN:' +
			( data.name.prefix ? escapeString( data.name.prefix ) + ' ' : '' ) +
			( data.name.first ? escapeString( data.name.first ) + ' ' : '' ) +
			( data.name.middle ? escapeString( data.name.middle ) + ' ' : '' ) +
			( data.name.last ? escapeString( data.name.last ) + ' ' : '' ) +
			( data.name.suffix ? escapeString( data.name.suffix ) + ' ' : '' )
		);

		if( data.nickname ){
			list.push( 'NICKNAME:' + escapeString( data.nickname ) );
		}

		if( data.org ){

			list.push(
				'ORG:' +
				escapeString( data.org.company ) + ';' +
				escapeString( data.org.department )
			);

		}

		if( data.title ){
			list.push( 'TITLE:' + escapeString( data.title ) );
		}

		if( data.phone && data.phone instanceof Array ){

			for( var i = 0; i < data.phone.length; i++ ){
				list.push( 'TEL;' + telFamily( data.phone[ i ].type ) + ':' + escapeString( data.phone[ i ].value ) );
			}

		}

		if( data.email && data.email instanceof Array ){

			for( var i = 0; i < data.email.length; i++ ){
				list.push( 'EMAIL;' + emailFamily( data.email[ i ].type ) + ':' + escapeString( data.email[ i ].value ) );
			}

		}

		if( data.address && data.address instanceof Array ){

			for( var i = 0; i < data.address.length; i++ ){

				list.push(
					'ADR;' +
					adrFamily( data.address[ i ].type ) + ':' +
					';;' +
					escapeString( data.address[ i ].street ) + ';' +
					escapeString( data.address[ i ].city ) + ';' +
					escapeString( data.address[ i ].region ) + ';' +
					escapeString( data.address[ i ].code ) + ';' +
					escapeString( data.address[ i ].country )
				);

			}

		}

		if( data.url && data.url instanceof Array ){

			for( var i = 0; i < data.url.length; i++ ){
				list.push( 'URL' + urlFamily( data.url[ i ].type ) + ':' + escapeString( data.url[ i ].value ) );
			}

		}

		if( data.birthday ){
			list.push( 'BDAY:' + data.birthday.year + '-' + ( '0' + data.birthday.month ).slice(-2) + '-' + ( '0' + data.birthday.day ).slice(-2) );
		}

		if( data.note ){
			list.push( 'NOTE:' + escapeStringWithLines( data.note ) );
		}

		list.push( 'REV:' + moment().format() );

		list.push('END:VCARD');

		return list.join('\r\n');

	},

	VCardToJson : function( data ){

		var res = {

			name : {
				last   : data.n.last || '',
				first  : data.n.first || '',
				middle : data.n.middle || '',
				prefix : data.n.prefix || '',
				suffix : data.n.suffix || ''
			},

			org : {
				company    : data.org ? data.org.name || '' : '',
				department : data.org ? data.org.dept || '' : ''
			},

			title    : data.title || '',
			nickname : data.nickname || '',
			phone    : [],
			email    : [],
			address  : [],
			url      : []

		};

		if( data.tel && data.tel.length ){

			data.tel.forEach( function( tel ){
				res.phone.push({ type : vcardTelFamily( tel.type[ 0 ] ), value : tel.value });
			});

		}

		if( data.email && data.email.length ){

			data.email.forEach( function( email ){
				res.email.push({ type : vcardEmailFamily( email.type[ 0 ] ), value : email.value });
			});

		}

		if( data.adr && data.adr.length ){

			data.adr.forEach( function( adr ){

				res.address.push({

					type    : vcardAdrFamily( adr.type[ 0 ] ),
					street  : adr.value.street || '',
					city    : adr.value.city || '',
					region  : adr.value.region || '',
					code    : adr.value.zip || '',
					country : adr.value.country || ''

				});

			});

		}

		if( data.url && data.url.length ){

			data.url.forEach( function( url ){
				res.url.push({ type : vcardUrlFamily( url.type[ 0 ] ), value : url.value });
			});

		}

		return res;

	}

};
<commit_msg>Support special chars<commit_after>
// Modules
var _      = require('lodash');
var http   = require('http');
var https  = require('https');
var moment = require('moment');
var xml2js = require('xml2js');
var uuid   = require('node-uuid');
var vCard  = require('vcards-js')();
_.mixin(require("lodash-deep"));

// Variables
var parseOptions = {
	explicitRoot : false,
	normalizeTags : true,
	tagNameProcessors : [xml2js.processors.stripPrefix],
	//explicitArray : false
};

// Functions
var escapeString = function( str ){
  return ( str || '' ).toString().replace( ';' , '\\;' ).replace( ',' , '\\,' );
};

var escapeStringWithLines = function( str ){
  return ( str || '' ).toString().replace( '\n' , '\\n' ).replace( ';' , '\\;' ).replace( ',' , '\\,' );
};

var telFamily = function( type ){

  type = ( type || '' ).toString().toLowerCase();

  switch( type ){
    case 'cell': return 'type=CELL;type=VOICE'; break;
    case 'iphone': return 'type=IPHONE;type=CELL;type=VOICE'; break;
    case 'home': return 'type=HOME;type=VOICE'; break;
    case 'work': return 'type=WORK;type=VOICE'; break;
    case 'main': return 'type=MAIN'; break;
    case 'homefax': return 'type=HOME;type=FAX'; break;
    case 'workfax': return 'ttype=WORK;type=FAX'; break;
    case 'otherfax': return 'type=OTHER;type=FAX'; break;
    case 'pager': return 'type=PAGER'; break;
    default: return 'type=OTHER;type=VOICE'; break;

  }

};

var emailFamily = function( type ){

  type = ( type || '' ).toString().toLowerCase();

  switch( type ){
    case 'home': return 'type=INTERNET;type=HOME'; break;
    case 'work': return 'type=INTERNET;type=WORK'; break;
    default: return 'type=INTERNET'; break;

  }

};

var urlFamily = function( type ){

  type = ( type || '' ).toString().toLowerCase();

  switch( type ){
    case 'home': return ';type=HOME'; break;
    case 'work': return ';type=WORK'; break;
    default: return ''; break;

  }

};

var adrFamily = function( type ){

  type = ( type || '' ).toString().toLowerCase();

  switch( type ){
    case 'home': return 'type=HOME'; break;
    case 'work': return 'type=WORK'; break;
    default: return 'type=OTHER'; break;

  }

};

var vcardTelFamily = function( type ){

	type = ( type || '' ).toString().toLowerCase();

	if( type.indexOf('iphone') !== -1 ){
		return 'iphone';
	}else if( type.indexOf('cell') !== -1 ){
		return 'cell';
	}else if( type.indexOf('home') !== -1 && type.indexOf('fax') !== -1 ){
		return 'homefax';
	}else if( type.indexOf('work') !== -1 && type.indexOf('fax') !== -1 ){
		return 'workfax';
	}else if( type.indexOf('other') !== -1 && type.indexOf('fax') !== -1 ){
		return 'otherfax';
	}else if( type.indexOf('fax') !== -1 ){
		return 'workfax';
	}else if( type.indexOf('main') !== -1 ){
		return 'main';
	}else if( type.indexOf('work') !== -1 ){
		return 'work';
	}else if( type.indexOf('home') !== -1 ){
		return 'home';
	}else if( type.indexOf('pager') !== -1 ){
		return 'pager';
	}else{
		return 'other';
	}

};

var vcardEmailFamily = function( type ){

	type = ( type || '' ).toString().toLowerCase();

	if( type.indexOf('work') !== -1 ){
		return 'work';
	}else if( type.indexOf('home') !== -1 ){
		return 'home';
	}else{
		return 'other';
	}

};

var vcardAdrFamily = function( type ){

	type = ( type || '' ).toString().toLowerCase();

	if( type.indexOf('work') !== -1 ){
		return 'work';
	}else if( type.indexOf('home') !== -1 ){
		return 'home';
	}else{
		return 'other';
	}

};

var vcardUrlFamily = function( type ){

	type = ( type || '' ).toString().toLowerCase();

	if( type.indexOf('work') !== -1 ){
		return 'work';
	}else if( type.indexOf('home') !== -1 ){
		return 'home';
	}else{
		return 'other';
	}

};

// Export module
module.exports = {

	request : function( opts, secure, callback ){

		var protocol = secure ? https : http;

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

			var buffer = '';

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

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

				res.body = buffer;

				callback( null, res );

			});

		}).on( 'error', function( err ){
			console.log(err);
		});

		req.write( opts.data );
		req.end();
	},

	parseXML : function( xmlString, callback ){
		xml2js.parseString(xmlString, parseOptions,callback);
	},

	cloneObject : function( obj ){
		return JSON.parse( JSON.stringify( obj ) );
	},

	uuid : function (string) {
		return uuid.v4();
	},

	normalizeAddressbookAttribute : function( result, value, key ){

		if(!value || !value[0] || !value[0] === 'undefined'){
			return result;
		}

		value = value[0];

		switch( key ){

			case 'resourcetype':
				value = Object.keys( value );
				break;

			case 'getctag':
				value = value.replace(/^"(.+(?="$))"$/, '$1');
				break;

		}

		result[key] = value;
		return result;

	},

	jsonToVCard : function( data ){

		var list = [];

		list.push('BEGIN:VCARD');
		list.push('VERSION:3.0');
		list.push(
			'N:' +
			escapeString( data.name.last ) + ';' +
			escapeString( data.name.first ) + ';' +
			escapeString( data.name.middle ) + ';' +
			escapeString( data.name.prefix ) + ';' +
			escapeString( data.name.suffix )
		);

		list.push(
			'FN:' +
			( data.name.prefix ? escapeString( data.name.prefix ) + ' ' : '' ) +
			( data.name.first ? escapeString( data.name.first ) + ' ' : '' ) +
			( data.name.middle ? escapeString( data.name.middle ) + ' ' : '' ) +
			( data.name.last ? escapeString( data.name.last ) + ' ' : '' ) +
			( data.name.suffix ? escapeString( data.name.suffix ) + ' ' : '' )
		);

		if( data.nickname ){
			list.push( 'NICKNAME:' + escapeString( data.nickname ) );
		}

		if( data.org ){

			list.push(
				'ORG:' +
				escapeString( data.org.company ) + ';' +
				escapeString( data.org.department )
			);

		}

		if( data.title ){
			list.push( 'TITLE:' + escapeString( data.title ) );
		}

		if( data.phone && data.phone instanceof Array ){

			for( var i = 0; i < data.phone.length; i++ ){
				list.push( 'TEL;' + telFamily( data.phone[ i ].type ) + ':' + escapeString( data.phone[ i ].value ) );
			}

		}

		if( data.email && data.email instanceof Array ){

			for( var i = 0; i < data.email.length; i++ ){
				list.push( 'EMAIL;' + emailFamily( data.email[ i ].type ) + ':' + escapeString( data.email[ i ].value ) );
			}

		}

		if( data.address && data.address instanceof Array ){

			for( var i = 0; i < data.address.length; i++ ){

				list.push(
					'ADR;' +
					adrFamily( data.address[ i ].type ) + ':' +
					';;' +
					escapeString( data.address[ i ].street ) + ';' +
					escapeString( data.address[ i ].city ) + ';' +
					escapeString( data.address[ i ].region ) + ';' +
					escapeString( data.address[ i ].code ) + ';' +
					escapeString( data.address[ i ].country )
				);

			}

		}

		if( data.url && data.url instanceof Array ){

			for( var i = 0; i < data.url.length; i++ ){
				list.push( 'URL' + urlFamily( data.url[ i ].type ) + ':' + escapeString( data.url[ i ].value ) );
			}

		}

		if( data.birthday ){
			list.push( 'BDAY:' + data.birthday.year + '-' + ( '0' + data.birthday.month ).slice(-2) + '-' + ( '0' + data.birthday.day ).slice(-2) );
		}

		if( data.note ){
			list.push( 'NOTE:' + escapeStringWithLines( data.note ) );
		}

		list.push( 'REV:' + moment().format() );

		list.push('END:VCARD');

		return new Buffer( list.join('\r\n') );

	},

	VCardToJson : function( data ){

		var res = {

			name : {
				last   : data.n.last || '',
				first  : data.n.first || '',
				middle : data.n.middle || '',
				prefix : data.n.prefix || '',
				suffix : data.n.suffix || ''
			},

			org : {
				company    : data.org ? data.org.name || '' : '',
				department : data.org ? data.org.dept || '' : ''
			},

			title    : data.title || '',
			nickname : data.nickname || '',
			phone    : [],
			email    : [],
			address  : [],
			url      : []

		};

		if( data.tel && data.tel.length ){

			data.tel.forEach( function( tel ){
				res.phone.push({ type : vcardTelFamily( tel.type[ 0 ] ), value : tel.value });
			});

		}

		if( data.email && data.email.length ){

			data.email.forEach( function( email ){
				res.email.push({ type : vcardEmailFamily( email.type[ 0 ] ), value : email.value });
			});

		}

		if( data.adr && data.adr.length ){

			data.adr.forEach( function( adr ){

				res.address.push({

					type    : vcardAdrFamily( adr.type[ 0 ] ),
					street  : adr.value.street || '',
					city    : adr.value.city || '',
					region  : adr.value.region || '',
					code    : adr.value.zip || '',
					country : adr.value.country || ''

				});

			});

		}

		if( data.url && data.url.length ){

			data.url.forEach( function( url ){
				res.url.push({ type : vcardUrlFamily( url.type[ 0 ] ), value : url.value });
			});

		}

		return res;

	}

};
<|endoftext|>


<commit_before>'use strict';

// TODO: Find a way to set options file

var activity = {};
try {
    /* global _opt */
    var opts = _opt || {};
} catch (err) {

}

function initTracking(opts) {
    var Activity = require('../../sdk-js-event-tracking/lib/activity');

    activity = new Activity(opts);

    window.addEventListener('load', function() {

        var pageEvents = require('./pageLoad');
        pageEvents.pageLoad(activity);
        pageEvents.hashChange(activity);
        pageEvents.pageUnload(activity);

        var click = require('./click');
        click.button(activity);
        click.submit(activity);

        var scrollT = require('./scroll');
        scrollT.trackScrollRelative(activity, 25);
        scrollT.trackScrollItems(activity);

        var social = require('./social');
        social.trackFacebookLikes(activity);
        social.trackFacebookUnlikes(activity);
        social.trackFacebookShares(activity);
        social.trackTwitterShares(activity);

    }, false);

    return activity.getPageViewId();
}

module.exports.initTracking = function(opts) {
    initTracking(opts);
};

module.exports.getPageViewId = function() {
    return activity.getPageViewId();
};

module.exports.getVisitorId = function() {
    return activity.getVisitorId();
};

module.exports.getSessionId = function() {
    return activity.getSessionId();
};

module.exports.logoutEvent = function() {
    activity.refreshUserIds();
};

module.exports.loginEvent = function(userId) {
    activity.refreshUserIds(userId);
};

try {
    initTracking(opts);
} catch (err) {

}
<commit_msg>new function for tracking<commit_after>'use strict';

var activity = {};
try {
    /* global _opt */
    var opts = _opt || {};
} catch (err) {

}

function initTracking(opts) {
    var Activity = require('../../sdk-js-event-tracking/lib/activity');
    activity = new Activity(opts);

	if (document.readyState === 'complete') {
		trackingFunctions();
	} else {
		window.addEventListener('load', function() {
			trackingFunctions();
		}, false);
	}

    return activity.getPageViewId();
}

module.exports.initTracking = function(opts) {
    initTracking(opts);
};

module.exports.getPageViewId = function() {
    return activity.getPageViewId();
};

module.exports.getVisitorId = function() {
    return activity.getVisitorId();
};

module.exports.getSessionId = function() {
    return activity.getSessionId();
};

module.exports.logoutEvent = function() {
    activity.refreshUserIds();
};

module.exports.loginEvent = function(userId) {
    activity.refreshUserIds(userId);
};

module.exports.activity = function() {
    return activity;
};

function trackingFunctions() {
	console.log('Track page load init');
    var pageEvents = require('./pageLoad');
    pageEvents.pageLoad(activity);
    pageEvents.hashChange(activity);
    pageEvents.pageUnload(activity);

    var click = require('./click');
    click.button(activity);
    click.submit(activity);

    var scrollT = require('./scroll');
    scrollT.trackScrollRelative(activity, 25);
    scrollT.trackScrollItems(activity);

    var social = require('./social');
    social.trackFacebookLikes(activity);
    social.trackFacebookUnlikes(activity);
    social.trackFacebookShares(activity);
    social.trackTwitterShares(activity);
}

try {
    initTracking(opts);
} catch (err) {

}
<|endoftext|>


<commit_before>var Facade    = require('./facade')
  , component = require('require-component')(require)
  , clone     = component('clone')
  , inherit   = component('inherit')
  , isEmail   = component('is-email');

module.exports = Track;

function Track(track) {
  Facade.call(this, track);
}

inherit(Track, Facade);

Track.prototype.action = function () {
  return 'track';
};

/**
 * Property fields
 */

Track.prototype.userId     = Facade.field('userId');
Track.prototype.sessionId  = Facade.field('sessionId');
Track.prototype.event      = Facade.field('event');

/**
 * Return properties or an empty object
 */

Track.prototype.properties = function () {
  return this.field('properties') || {};
};

/**
 * Backwards compat, should probably re-examine where these come from.
 */

Track.prototype.referrer   = Facade.proxy('properties.referrer');
Track.prototype.username   = Facade.proxy('properties.username');

Track.prototype.query      = Facade.proxy('options.query');

/**
 * Parse the revenue from a number or a string matching '$45.00'
 */

Track.prototype.revenue = function () {
  var proxy   = Facade.proxy('properties.revenue')
    , revenue = proxy.call(this);

  if (!revenue) return;
  if (typeof revenue === 'number') return revenue;
  if (typeof revenue !== 'string') return;

  revenue = revenue.replace(/\$/g, '');
  revenue = parseFloat(revenue);

  if (!isNaN(revenue)) return revenue;
};

/**
 * Use the email if the userId matches it
 */

Track.prototype.email = function () {
  var userId = this.userId() || this.sessionId();
  if (isEmail(userId)) return userId;
};

/**
 * Adds the ability to send 'super properties' as part of a track
 * TODO: remove me eventually and just use state on the server
 */

Track.prototype.traits = function () {
  return this.proxy('options.traits') || {};
};<commit_msg>Adding identify<commit_after>var Facade    = require('./facade')
  , component = require('require-component')(require)
  , clone     = component('clone')
  , Identify  = component('./identify')
  , inherit   = component('inherit')
  , isEmail   = component('is-email');

module.exports = Track;

function Track(track) {
  Facade.call(this, track);
}

inherit(Track, Facade);

Track.prototype.action = function () {
  return 'track';
};

/**
 * Property fields
 */

Track.prototype.userId     = Facade.field('userId');
Track.prototype.sessionId  = Facade.field('sessionId');
Track.prototype.event      = Facade.field('event');

/**
 * Return properties or an empty object
 */

Track.prototype.properties = function () {
  return this.field('properties') || {};
};

/**
 * Backwards compat, should probably re-examine where these come from.
 */

Track.prototype.referrer   = Facade.proxy('properties.referrer');
Track.prototype.username   = Facade.proxy('properties.username');

Track.prototype.query      = Facade.proxy('options.query');

/**
 * Parse the revenue from a number or a string matching '$45.00'
 */

Track.prototype.revenue = function () {
  var proxy   = Facade.proxy('properties.revenue')
    , revenue = proxy.call(this);

  if (!revenue) return;
  if (typeof revenue === 'number') return revenue;
  if (typeof revenue !== 'string') return;

  revenue = revenue.replace(/\$/g, '');
  revenue = parseFloat(revenue);

  if (!isNaN(revenue)) return revenue;
};

/**
 * Use the email if the userId matches it
 */

Track.prototype.email = function () {
  var userId = this.userId() || this.sessionId();
  if (isEmail(userId)) return userId;
};

/**
 * Adds the ability to send 'super properties' as part of a track
 * TODO: remove me eventually and just use state on the server
 */

Track.prototype.traits = function () {
  return this.proxy('options.traits') || {};
};

/**
 * A utility to turn the pieces of a track call into an identify. Used for
 * integrations with super properties or rate limits.
 * TODO: remove me.
 */

Track.prototype.identify = function () {
  var json = this.json();
  json.traits = this.traits();
  return new Identify(json);
};<|endoftext|>


<commit_before>define(function(require, exports, module) {
"use strict";

var inherits = require("util").inherits;

exports.Types = function() {
    this.types = {};

    this.register("string", new exports.String());
    this.register("number", new exports.Number());
    this.register("boolean", new exports.Boolean());
    this.register("int", new exports.Integer());
    this.register("json", new exports.Json());
    this.register("array", new exports.Array());
    this.register("array[string]", new exports.Array(new exports.String()));
};
exports.Types.prototype.register = function(name, type) {
    type.name = name;
    if (type instanceof RegExp)
        type = new exports.RegExp(type);

    this.types[name] = type;
    return this;
};
exports.Types.prototype.get = function(name) {
    // if it already is a type return it
    if (name.check && name.parse)
        return name;

    var type = this.types[name];
    if (!type)
        throw new Error("Unknown type ", name);

    return type;
};

exports.Type = function() {};
exports.Type.prototype.parse = function(string) {
    return string;
};
exports.Type.prototype.check = function(value) {
    return true;
};
exports.Type.prototype.toString = function() {
    return this.name;
};

exports.RegExp = function(re) {
    this.re = re;
};
inherits(exports.RegExp, exports.Type);
exports.RegExp.prototype.parse = function(value) {
    return value.toString();
};
exports.RegExp.prototype.check = function(value) {
    value = value.toString();
    var match = value.match(this.re);
    return match && value === match[0];
};
exports.RegExp.prototype.toString = function() {
    return (this.name ? this.name + " " : "") + this.re.toString();
};

exports.Json = function() {};
inherits(exports.Json, exports.Type);
exports.Json.prototype.parse = function(string) {
    return JSON.parse(string);
};

exports.Array = function(itemType) {
    this.itemType = itemType;
};
inherits(exports.Array, exports.Json);
exports.Array.prototype.check = function(value) {
    if (!Array.isArray(value))
        return false;

    if (!this.itemType)
        return true;

    for (var i = 0; i < value.length; i++) {
        if (!this.itemType.check(value[i]))
            return false;
    }
    return true;
};

exports.String = function() {};
inherits(exports.String, exports.Type);
exports.String.prototype.check = function(value) {
    return typeof value == "string";
};

exports.Number = function() {};
inherits(exports.Number, exports.Type);
exports.Number.prototype.parse = function(string) {
    var value = parseFloat(string);
    if (isNaN(value))
        throw new TypeError("Could not parse string as number");
    return value;
};
exports.Number.prototype.check = function(value) {
    return typeof value == "number" || !isNaN(parseFloat(value));
};

exports.Integer = function(min, max) {
    this.min = min === undefined ? Number.MIN_VALUE : min;
    this.max - max === undefined ? Number.MAX_VALUE : max;
};
inherits(exports.Integer, exports.Type);
exports.Integer.prototype.parse = function(string) {
    return parseInt(string, 10);
};
exports.Integer.prototype.check = function(value) {
    return (
        typeof value == "number" && Math.round(value) == value
    );
};

exports.Boolean = function() {};
inherits(exports.Boolean, exports.Type);
exports.Boolean.prototype.parse = function(string) {
    if (string !== "true" && string !== "false")
        throw new Error("Could not parse '" +  string +"' as a boolean");

    return string == "true";
};
exports.Boolean.prototype.check = function(value) {
    return typeof value == "boolean";
};

});<commit_msg>prevent frontdoor from crashing<commit_after>define(function(require, exports, module) {
"use strict";

var inherits = require("util").inherits;

exports.Types = function() {
    this.types = {};

    this.register("string", new exports.String());
    this.register("number", new exports.Number());
    this.register("boolean", new exports.Boolean());
    this.register("int", new exports.Integer());
    this.register("json", new exports.Json());
    this.register("array", new exports.Array());
    this.register("array[string]", new exports.Array(new exports.String()));
};
exports.Types.prototype.register = function(name, type) {
    type.name = name;
    if (type instanceof RegExp)
        type = new exports.RegExp(type);

    this.types[name] = type;
    return this;
};
exports.Types.prototype.get = function(name) {
    // if it already is a type return it
    if (name.check && name.parse)
        return name;

    var type = this.types[name];
    if (!type)
        throw new Error("Unknown type ", name);

    return type;
};

exports.Type = function() {};
exports.Type.prototype.parse = function(string) {
    return string;
};
exports.Type.prototype.check = function(value) {
    return true;
};
exports.Type.prototype.toString = function() {
    return this.name;
};

exports.RegExp = function(re) {
    this.re = re;
};
inherits(exports.RegExp, exports.Type);
exports.RegExp.prototype.parse = function(value) {
    return value.toString();
};
exports.RegExp.prototype.check = function(value) {
    if (typeof value !== "string") return false;
    value = value.toString();
    var match = value.match(this.re);
    return match && value === match[0];
};
exports.RegExp.prototype.toString = function() {
    return (this.name ? this.name + " " : "") + this.re.toString();
};

exports.Json = function() {};
inherits(exports.Json, exports.Type);
exports.Json.prototype.parse = function(string) {
    return JSON.parse(string);
};

exports.Array = function(itemType) {
    this.itemType = itemType;
};
inherits(exports.Array, exports.Json);
exports.Array.prototype.check = function(value) {
    if (!Array.isArray(value))
        return false;

    if (!this.itemType)
        return true;

    for (var i = 0; i < value.length; i++) {
        if (!this.itemType.check(value[i]))
            return false;
    }
    return true;
};

exports.String = function() {};
inherits(exports.String, exports.Type);
exports.String.prototype.check = function(value) {
    return typeof value == "string";
};

exports.Number = function() {};
inherits(exports.Number, exports.Type);
exports.Number.prototype.parse = function(string) {
    var value = parseFloat(string);
    if (isNaN(value))
        throw new TypeError("Could not parse string as number");
    return value;
};
exports.Number.prototype.check = function(value) {
    return typeof value == "number" || !isNaN(parseFloat(value));
};

exports.Integer = function(min, max) {
    this.min = min === undefined ? Number.MIN_VALUE : min;
    this.max - max === undefined ? Number.MAX_VALUE : max;
};
inherits(exports.Integer, exports.Type);
exports.Integer.prototype.parse = function(string) {
    return parseInt(string, 10);
};
exports.Integer.prototype.check = function(value) {
    return (
        typeof value == "number" && Math.round(value) == value
    );
};

exports.Boolean = function() {};
inherits(exports.Boolean, exports.Type);
exports.Boolean.prototype.parse = function(string) {
    if (string !== "true" && string !== "false")
        throw new Error("Could not parse '" +  string +"' as a boolean");

    return string == "true";
};
exports.Boolean.prototype.check = function(value) {
    return typeof value == "boolean";
};

});<|endoftext|>


<commit_before>var util = require('util')
  , EventEmitter = require('events')
  , winston = require('winston')
  , blessed = require('blessed');

var logger = require('../logger')
  , config = require('../config')
  , session = require('../app');

const createScreen = () => {
    var screen = blessed.screen({
        autoPadding: true,
        fullUnicode: true,
        fastCSR: true,
        title: "steam-chat"
    });

    return screen;
}

const handleSteam = (steam) => {
    steam.on('connected', () => {
        session.connected = true;
        this.statusbar.statusUpdate('d0');
    });
    steam.on('disconnected', () => {
        session.connected = false;
        this.statusbar.statusUpdate('d1');
    });

    steam.on('updateNick', () => this.statusbar.statusUpdate('n'));

    steam.on('rejoinGroupChats', () => {});
    steam.on('autojoinGroupChats', () => {});

    steam.on('isTyping', (steamID, user, persona) =>
        this.statusbar.statusUpdate('w1' + steamID));
    steam.on('message', (steamID, user, persona, msg) => {
        this.statusbar.statusUpdate('w0' + steamID);
        this.chatwin.message(steamID, user, persona, msg);
    });
    steam.on('groupMessage', (chatID, user, persona, msg) => {
        this.chatwin.message(chatID, user, persona, msg);
    });

    steam.on('enteredChat', (chatID) => {});
    steam.on('activity', (chatID, persona, user, actorUser) => {});
}

const formatTime = (date) => {
    var hour = ('0' + date.getHours()).slice(-2);
    var minute = ('0' + date.getMinutes()).slice(-2);
    var midabb = "";
    if (config.get('24hour') === false) {
        var raw = date.getHours();
        if (raw == 0) {
            hour = 12;
            midabb = " AM";
        } else if (raw < 12) {
            hour = raw;
            midabb = " AM";
        } else if (raw == 12) {
            hour = raw;
            midabb = " PM";
        } else {
            hour = raw - 12;
            midabb = " PM";
        }
    }
    return `${hour}:${minute}${midabb}`;
}

const clock = () => {
    var date = new Date();
    this.statusbar.statusUpdate(`t${formatTime(date)}`);
    setTimeout(clock.bind(this), 1000 - date.getMilliseconds());
}

var SteamChatClient = require('../steam/steam');

exports.screen = {};
exports.inputbar = require('./inputbar');
exports.statusbar = require('./statusbar');
exports.userwin = require('./userwin');
exports.chatwin = require('./chatwin');
exports.cmd = require('./cmd');
exports.steam = new SteamChatClient();

exports.init = () => {
    this.screen = createScreen();

    this.inputbar.createBox(this.screen);
    this.statusbar.createBox(this.screen);
    this.userwin.createBox(this.screen);

    this.chatwin.newChat('log');
    this.chatwin.switchChat('log');

    logger.loadUiLogger();

    this.inputbar.read();
    this.steam.connect();

    handleSteam.call(this, this.steam);
    clock.call(this);
}
<commit_msg>Update event listeners<commit_after>var util = require('util')
  , EventEmitter = require('events')
  , winston = require('winston')
  , blessed = require('blessed');

var logger = require('../logger')
  , config = require('../config')
  , session = require('../app')
  , { CHATIDLEN } = require('../const');

const createScreen = () => {
    var screen = blessed.screen({
        autoPadding: true,
        fullUnicode: true,
        fastCSR: true,
        title: "steam-chat"
    });

    return screen;
}

const handleSteam = (steam) => {
    steam.on('connected', () => {
        session.connected = true;
        this.statusbar.statusUpdate('d0');
    });
    steam.on('disconnected', () => {
        session.connected = false;
        this.statusbar.statusUpdate('d1');
    });

    steam.on('updateNick', () => {
        this.statusbar.statusUpdate('n')
    });

    steam.on('autojoin', () => {
        this.cmd(['autojoin', 'run']);
    });

    steam.on('isTyping', (steamID, user, persona) => {
        this.statusbar.statusUpdate('w1' + steamID)
    });
    steam.on('message', (steamID, user, persona, msg) => {
        this.statusbar.statusUpdate('w0' + steamID);
        this.chatwin.message(steamID, user, persona, msg);
    });
    steam.on('groupMessage', (chatID, user, persona, msg) => {
        this.chatwin.message(chatID, user, persona, msg);
    });

    steam.on('listUpdate', () => {
        if (session.currentChat.length === CHATIDLEN)
            this.userwin.updateGroup(session.currentChat);
        else
            this.userwin.updateFriend();
    });
    steam.on('enteredChat', (chatID) => {
        this.chatwin.switchChat(chatID);
    });
    steam.on('activity', (chatID, text) => {
        this.chatwin.print(chatID, text);
    });
}

const formatTime = (date) => {
    var hour = ('0' + date.getHours()).slice(-2);
    var minute = ('0' + date.getMinutes()).slice(-2);
    var midabb = "";
    if (config.get('24hour') === false) {
        var raw = date.getHours();
        if (raw == 0) {
            hour = 12;
            midabb = " AM";
        } else if (raw < 12) {
            hour = raw;
            midabb = " AM";
        } else if (raw == 12) {
            hour = raw;
            midabb = " PM";
        } else {
            hour = raw - 12;
            midabb = " PM";
        }
    }
    return `${hour}:${minute}${midabb}`;
}

const clock = () => {
    var date = new Date();
    this.statusbar.statusUpdate(`t${formatTime(date)}`);
    setTimeout(clock.bind(this), 1000 - date.getMilliseconds());
}

var SteamChatClient = require('../steam/steam');

exports.screen = {};
exports.inputbar = require('./inputbar');
exports.statusbar = require('./statusbar');
exports.userwin = require('./userwin');
exports.chatwin = require('./chatwin');
exports.cmd = require('./cmd');
exports.steam = new SteamChatClient();

exports.init = () => {
    this.screen = createScreen();

    this.inputbar.createBox(this.screen);
    this.statusbar.createBox(this.screen);
    this.userwin.createBox(this.screen);

    this.chatwin.newChat('log');
    this.chatwin.switchChat('log');

    logger.loadUiLogger();

    this.inputbar.read();
    this.steam.connect();

    handleSteam.call(this, this.steam);
    clock.call(this);
}
<|endoftext|>


<commit_before>(function () {
  'use strict';

  function ready () {
    $.removeNodes('iframe, #adblock_detect, .popupOverlay');

    var node = $.$('#continuetoimage > form input');
    if (node) {
      // first pass
      _.wait(500).then(function () {
        node.removeAttribute('disabled');
        return _.wait(500);
      }).then(function () {
        // tricky hack, some sites can not receive the click event without focus
        node.focus();
        node.click();
      });
      return;
    }

    // second pass
    var i = $('img[class^=centred]');
    $.openImage(i.src);
  }

  $.register({
    rule: [
      {
        host: [
          // com
          // starts with image
          /^image(ontime|corn|picsa|horse)\.com$/,
          // ends with image
          /^(zonezeed|zelje|croft|myhot|bok|hostur|greasy)image\.com$/,
          // starts with img
          /^img(icy|next|savvy|\.spicyzilla|twyti|xyz|devil|tzar|ban|pu|beer|wet|tornado|kicks|-pay|nimz|binbou|2share|22|cover|hit|main)\.com$/,
          // starts with img-
          /^img-(zone|planet)\.com$/,
          // starts with www
          /^www\.(imagefolks|img(blow|lemon))\.com$/,
          // starts with xxx
          /^xxx(\.pornprimehd|imagenow|screens)\.com$/,
          // else
          /^(picstwist|ericsony|wpc8|uplimg|lexiit|thumbnailus|newimagepost|fapingpics|dimtus|tinizo)\.com$/,
          /^((i|hentai)\.)?imgslip\.com$/,
          /^(i|xxx)\.hentaiyoutube\.com$/,
          /^(go|er)imge\.com$/,
          /^(like\.)?08lkk\.com$/,
          /^(www\.)?\.imgult\.com$/,
          /^nim(plus|zshare)\.com$/,
          /^nudeximg\.com$/,
          /imgseeds?\.com$/,
          /xxxsparrow?\.com$/,
          /damimage\.com$/,
          /imagedecode\.com$/,
          // net
          /^img(serve|coin|fap|candy|master|-view|run|boom|project|python|pics)\.net$/,
          /^(gallerycloud|imagelaser|picture-bang|project-photo|pix-link|funimg|golfpit|xximg)\.net$/,
          // org
          /^(shot|adult)img\.org$/,
          /^img(studio|spot)\.org$/,
          /^image(\.adlock|on|team)\.org$/,
          /^(drag|teen|mega)image\.org$/,
          /^teenshot\.org$/,
          // else
          /^(hotimages|55888)\.eu$/,
          /^img(cloud|mag)\.co$/,
          /^pixup\.us$/,
          /^(bulkimg|photo-up|myimg|pop-img|img-pop|ads-img)\.info$/,
          /^img\.yt$/,
          /^vava\.in$/,
          /^(pixxx|picspornfree|imgload|fapat)\.me$/,
          /^(porno-pirat|24avarii|loftlm|18pron)\.ru$/,
          /^www\.hotimage\.uk$/,
          /^imgease\.re$/,
          /^goimg\.xyz$/,
          /^pic2pic\.site$/,
          /^darpix\.ga$/,
          /^sxpics\.nl$/,
          /^darpix\.desi$/,
          /^pic4you\.top$/,
        ],
        path: /^\/img-.*\.html/,
      },
      {
        host: [
          /^img(run|twyti)\.net$/,
          /^imgtwyti\.com$/,
        ],
        path: /^\/t\/img-.*\.html/,
      },
      {
        host: /^imgking\.co$/,
        path: /^\/img-.*\.html/,
      },
      {
        host: /^imgbb\.net$/,
        path: /^\/.-.+$/,
      },
    ],
    ready: ready,
  });

  // TODO need to refactor the cookie rule
  $.register({
    rule: {
      host: [
        /^www\.img(taxi|adult|wallet)\.com$/,
        /^www\.imgdrive\.net$/,
      ],
      path: /^\/img-.*\.html$/,
    },
    start: function () {
      var c = $.getCookie('img_c_d') || $.getCookie('img_p_d');
      if (c) {
        return;
      }
      $.post(window.location.href.toString(), {
        cti: 1,
        ref: '',
        rc: 1,
      }).then(function (data) {
        window.location.reload();
      });
    },
    ready: function () {
      $.removeNodes('iframe');

      var node = $.$('#continuetoimage > form input');
      if (node) {
        // first pass
        node.click();
        // somehow imgrun.net need to click twice
        node.click();
        return;
      }

      // the cookies are shared in the whole domain
      // we have to reset cookies to prevent wrong state
      $.resetCookies();

      // second pass
      var i = $('img[class^=centred]');
      $.openImage(i.src);
    },
  });

  function helper () {
    // crack the shitty qqc.co visitScript 5440
    $.window.setTimeout = _.nop;

    // this site checks cookie that caculate from session
    // do an AJAX to skip checking
    return $.get(window.location.toString()).then(function (data) {
      return $.toDOM(data);
    });
  }

  $.register({
    rule: {
      host: /^08lkk\.com$/,
      path: /^\/Photo\/img-.+\.html$/,
    },
    start: function () {
      helper().then(function (page) {
        var i = $('img[class^=centred]', page);
        $.openImage(i.src);
      });
    },
  });

  $.register({
    rule: {
      host: /^08lkk\.com$/,
      path: /^\/\d+\/img-.*\.html$/,
    },
    start: function () {
      helper().then(function (page) {
        var bbcode = $.$('#imagecodes input', page);
        bbcode = bbcode.value.match(/.+\[IMG\]([^\[]+)\[\/IMG\].+/);
        bbcode = bbcode[1];
        bbcode = bbcode.replace('small', 'big');

        $.openImage(bbcode);
      });
    },
  });

  $.register({
    rule: {
      host: /^imgking\.co$/,
      path: /^\/img3-.*\.html/,
    },
    ready: function () {
      var url = $.window.linkid;
      $.openImage(url);
    },
  });

  $.register({
    rule: {
      host: /^imgking\.co$/,
      path: /^\/img4-.*\.html/,
    },
    ready: ready,
  });

})();

// ex: ts=2 sts=2 sw=2 et
// sublime: tab_size 2; translate_tabs_to_spaces true; detect_indentation false; use_tab_stops true;
// kate: space-indent on; indent-width 2;
<commit_msg>imgplus.ru<commit_after>(function () {
  'use strict';

  function ready () {
    $.removeNodes('iframe, #adblock_detect, .popupOverlay');

    var node = $.$('#continuetoimage > form input');
    if (node) {
      // first pass
      _.wait(500).then(function () {
        node.removeAttribute('disabled');
        return _.wait(500);
      }).then(function () {
        // tricky hack, some sites can not receive the click event without focus
        node.focus();
        node.click();
      });
      return;
    }

    // second pass
    var i = $('img[class^=centred]');
    $.openImage(i.src);
  }

  $.register({
    rule: [
      {
        host: [
          // com
          // starts with image
          /^image(ontime|corn|picsa|horse)\.com$/,
          // ends with image
          /^(zonezeed|zelje|croft|myhot|bok|hostur|greasy)image\.com$/,
          // starts with img
          /^img(icy|next|savvy|\.spicyzilla|twyti|xyz|devil|tzar|ban|pu|beer|wet|tornado|kicks|-pay|nimz|binbou|2share|22|cover|hit|main)\.com$/,
          // starts with img-
          /^img-(zone|planet)\.com$/,
          // starts with www
          /^www\.(imagefolks|img(blow|lemon))\.com$/,
          // starts with xxx
          /^xxx(\.pornprimehd|imagenow|screens)\.com$/,
          // else
          /^(picstwist|ericsony|wpc8|uplimg|lexiit|thumbnailus|newimagepost|fapingpics|dimtus|tinizo)\.com$/,
          /^((i|hentai)\.)?imgslip\.com$/,
          /^(i|xxx)\.hentaiyoutube\.com$/,
          /^(go|er)imge\.com$/,
          /^(like\.)?08lkk\.com$/,
          /^(www\.)?\.imgult\.com$/,
          /^nim(plus|zshare)\.com$/,
          /^nudeximg\.com$/,
          /imgseeds?\.com$/,
          /xxxsparrow?\.com$/,
          /damimage\.com$/,
          /imagedecode\.com$/,
          // net
          /^img(serve|coin|fap|candy|master|-view|run|boom|project|python|pics)\.net$/,
          /^(gallerycloud|imagelaser|picture-bang|project-photo|pix-link|funimg|golfpit|xximg)\.net$/,
          // org
          /^(shot|adult)img\.org$/,
          /^img(studio|spot)\.org$/,
          /^image(\.adlock|on|team)\.org$/,
          /^(drag|teen|mega)image\.org$/,
          /^teenshot\.org$/,
          // else
          /^(hotimages|55888)\.eu$/,
          /^img(cloud|mag)\.co$/,
          /^pixup\.us$/,
          /^(bulkimg|photo-up|myimg|pop-img|img-pop|ads-img)\.info$/,
          /^img\.yt$/,
          /^vava\.in$/,
          /^(pixxx|picspornfree|imgload|fapat)\.me$/,
          /^(porno-pirat|24avarii|loftlm|18pron|imgplus)\.ru$/,
          /^www\.hotimage\.uk$/,
          /^imgease\.re$/,
          /^goimg\.xyz$/,
          /^pic2pic\.site$/,
          /^darpix\.ga$/,
          /^sxpics\.nl$/,
          /^darpix\.desi$/,
          /^pic4you\.top$/,
        ],
        path: /^\/img-.*\.html/,
      },
      {
        host: [
          /^img(run|twyti)\.net$/,
          /^imgtwyti\.com$/,
        ],
        path: /^\/t\/img-.*\.html/,
      },
      {
        host: /^imgking\.co$/,
        path: /^\/img-.*\.html/,
      },
      {
        host: /^imgbb\.net$/,
        path: /^\/.-.+$/,
      },
    ],
    ready: ready,
  });

  // TODO need to refactor the cookie rule
  $.register({
    rule: {
      host: [
        /^www\.img(taxi|adult|wallet)\.com$/,
        /^www\.imgdrive\.net$/,
      ],
      path: /^\/img-.*\.html$/,
    },
    start: function () {
      var c = $.getCookie('img_c_d') || $.getCookie('img_p_d');
      if (c) {
        return;
      }
      $.post(window.location.href.toString(), {
        cti: 1,
        ref: '',
        rc: 1,
      }).then(function (data) {
        window.location.reload();
      });
    },
    ready: function () {
      $.removeNodes('iframe');

      var node = $.$('#continuetoimage > form input');
      if (node) {
        // first pass
        node.click();
        // somehow imgrun.net need to click twice
        node.click();
        return;
      }

      // the cookies are shared in the whole domain
      // we have to reset cookies to prevent wrong state
      $.resetCookies();

      // second pass
      var i = $('img[class^=centred]');
      $.openImage(i.src);
    },
  });

  function helper () {
    // crack the shitty qqc.co visitScript 5440
    $.window.setTimeout = _.nop;

    // this site checks cookie that caculate from session
    // do an AJAX to skip checking
    return $.get(window.location.toString()).then(function (data) {
      return $.toDOM(data);
    });
  }

  $.register({
    rule: {
      host: /^08lkk\.com$/,
      path: /^\/Photo\/img-.+\.html$/,
    },
    start: function () {
      helper().then(function (page) {
        var i = $('img[class^=centred]', page);
        $.openImage(i.src);
      });
    },
  });

  $.register({
    rule: {
      host: /^08lkk\.com$/,
      path: /^\/\d+\/img-.*\.html$/,
    },
    start: function () {
      helper().then(function (page) {
        var bbcode = $.$('#imagecodes input', page);
        bbcode = bbcode.value.match(/.+\[IMG\]([^\[]+)\[\/IMG\].+/);
        bbcode = bbcode[1];
        bbcode = bbcode.replace('small', 'big');

        $.openImage(bbcode);
      });
    },
  });

  $.register({
    rule: {
      host: /^imgking\.co$/,
      path: /^\/img3-.*\.html/,
    },
    ready: function () {
      var url = $.window.linkid;
      $.openImage(url);
    },
  });

  $.register({
    rule: {
      host: /^imgking\.co$/,
      path: /^\/img4-.*\.html/,
    },
    ready: ready,
  });

})();

// ex: ts=2 sts=2 sw=2 et
// sublime: tab_size 2; translate_tabs_to_spaces true; detect_indentation false; use_tab_stops true;
// kate: space-indent on; indent-width 2;
<|endoftext|>


<commit_before>var assert        = require("assert");
var request       = require("request");
var _             = require("lodash");
var addressparser = require("addressparser");
var pkg           = require("../package.json");

// SendinBlue api codes. The code is included in the response body under 'code'.
var ApiCodes = {
    Success: "success",
    Failure: "failure",
    Error:   "error"
};

function checkOptions(options) {
    var apiKey = options.apiKey;
    var apiUrl = options.apiUrl;

    assert(apiKey && _.isString(apiKey), "apiKey: must be a non-empty string");
    assert(apiUrl && _.isString(apiUrl), "apiUrl: must be a non-empty string");
}

function addAddress(obj, address) {
    obj[address.address] = address.name || "";
    return obj;
}

function flattenGroups(addresses) {
    var flattened = [];

    function traverse(obj) {
        if (obj.group) {
            obj.group.forEach(traverse);
        } else {
            flattened.push(obj);
        }
    }

    addresses.forEach(traverse);

    return flattened;
}

function transformAddresses(addresses) {
    return flattenGroups(addressparser(addresses)).reduce(function (obj, address) {
        return addAddress(obj, address);
    }, {});
}

function transformFromAdresses(addresses) {
    var fromAddress = flattenGroups(addressparser(addresses))[0];

    return [fromAddress.address, fromAddress.name];
}

function isErrorCode(code) {
    switch (code) {
        case ApiCodes.Failure:
        case ApiCodes.Error:
            return true;
        default:
            return false;
    }
}

function SendinBlueTransport(options) {
    checkOptions(options);

    this.options = options;
    this.name    = "SendinBlue";
    this.version = pkg.version;
}

SendinBlueTransport.prototype.send = function (mail, callback) {
    request({
        uri: this.sendUrl(),
        method: "POST",
        headers: {
            'api-key': this.options.apiKey
        },
        json: true,
        body: this.transformData(mail.data)
    }, function (err, response, body) {
        if (err) {
            return callback(err);
        }

        if (isErrorCode(body.code)) {
            return callback(new Error(body.message));
        }

        callback(null, { data: body.data });
    });
};

SendinBlueTransport.prototype.sendUrl = function () {
    return this.options.apiUrl + "/email";
};

SendinBlueTransport.prototype.transformData = function (data) {
    return {
        from:    transformFromAdresses(data.from),
        to:      transformAddresses(data.to),
        cc:      transformAddresses(data.cc),
        bcc:     transformAddresses(data.bcc),
        replyto: data.replyTo,
        subject: data.subject,
        text:    data.text,
        html:    data.html
    }
};

module.exports = function (options) {
    return new SendinBlueTransport(options);
};
<commit_msg>Check response status instead of just body.code<commit_after>var assert        = require("assert");
var request       = require("request");
var _             = require("lodash");
var addressparser = require("addressparser");
var pkg           = require("../package.json");

// SendinBlue api codes. The code is included in the response body under 'code'.
var ApiCodes = {
    Success: "success",
    Failure: "failure",
    Error:   "error"
};

var STATUS_OK = 200;

function checkOptions(options) {
    var apiKey = options.apiKey;
    var apiUrl = options.apiUrl;

    assert(apiKey && _.isString(apiKey), "apiKey: must be a non-empty string");
    assert(apiUrl && _.isString(apiUrl), "apiUrl: must be a non-empty string");
}

function addAddress(obj, address) {
    obj[address.address] = address.name || "";
    return obj;
}

function flattenGroups(addresses) {
    var flattened = [];

    function traverse(obj) {
        if (obj.group) {
            obj.group.forEach(traverse);
        } else {
            flattened.push(obj);
        }
    }

    addresses.forEach(traverse);

    return flattened;
}

function transformAddresses(addresses) {
    return flattenGroups(addressparser(addresses)).reduce(function (obj, address) {
        return addAddress(obj, address);
    }, {});
}

function transformFromAdresses(addresses) {
    var fromAddress = flattenGroups(addressparser(addresses))[0];

    return [fromAddress.address, fromAddress.name];
}

function isErrorResponse(response) {
    if (response.statusCode !== STATUS_OK) {
        return true;
    }

    return false;
}

function responseError(response, body) {
    var msg = [body.message || "server error", "(", body.code, response.statusCode, ")"].join(" ");
    return new Error(msg);
}

function SendinBlueTransport(options) {
    checkOptions(options);

    this.options = options;
    this.name    = "SendinBlue";
    this.version = pkg.version;
}

SendinBlueTransport.prototype.send = function (mail, callback) {
    request({
        uri: this.sendUrl(),
        method: "POST",
        headers: {
            'api-key': this.options.apiKey
        },
        json: true,
        body: this.transformData(mail.data)
    }, function (err, response, body) {
        if (err) {
            return callback(err);
        }

        if (isErrorResponse(response)) {
            return callback(responseError(response, body));
        }

        callback(null, { data: body.data });
    });
};

SendinBlueTransport.prototype.sendUrl = function () {
    return this.options.apiUrl + "/email";
};

SendinBlueTransport.prototype.transformData = function (data) {
    return {
        from:    transformFromAdresses(data.from),
        to:      transformAddresses(data.to),
        cc:      transformAddresses(data.cc),
        bcc:     transformAddresses(data.bcc),
        replyto: data.replyTo,
        subject: data.subject,
        text:    data.text,
        html:    data.html
    }
};

module.exports = function (options) {
    return new SendinBlueTransport(options);
};
<|endoftext|>


<commit_before>var assert        = require("assert");
var fs            = require("fs");
var stream        = require("stream");
var util          = require("util");
var http          = require("http");
var https         = require("https");
var url           = require("url");
var addressparser = require("addressparser");
var Promise       = require("promise");
var pkg           = require("../package.json");

//
// Constants
//
var STATUS_OK = 200;

//
// Helper
//
function isString(v) {
    return typeof v === "string" || v instanceof String;
}

function isObject(v) {
    return !isUndefined(v) && v.toString() === "[object Object]";
}

function isArray(v) {
    return v instanceof Array;
}

function isUndefined(v) {
    return typeof v === "undefined";
}

function isEmpty(v) {
    return !(v.length || Object.keys(v).length)
}

function prefixedErr(err, prefix) {
    err.message = [prefix, err.message].join(": ");
    return err;
}

function checkOptions(options) {
    var apiKey = options.apiKey;
    var apiUrl = options.apiUrl;

    assert(apiKey && isString(apiKey), "apiKey: must be a non-empty string");
    assert(apiUrl && isString(apiUrl), "apiUrl: must be a non-empty string");
}

function addAddress(obj, address) {
    obj[address.address] = address.name || "";
    return obj;
}

function flattenGroups(addresses) {
    var flattened = [];

    function traverse(obj) {
        if (obj.group) {
            obj.group.forEach(traverse);
        } else {
            flattened.push(obj);
        }
    }

    addresses.forEach(traverse);

    return flattened;
}

function transformAddress(a) {
    if (isString(a)) {
        return addressparser(a);
    }

    if (isObject(a)) {
        return [a];
    }

    throw new Error("invalid address: " + a);
}

function transformAddresses(addresses) {
    if (!addresses) {
        return undefined;
    }

    var parsed = [];
    if (isString(addresses)) {
        parsed = addressparser(addresses);
    } else if (isArray(addresses)) {
        addresses.forEach(function (address) {
            parsed = parsed.concat(transformAddress(address));
        });
    } else if (isObject(addresses)) {
        parsed.push(addresses);
    } else {
        throw new Error("invalid address: " + addresses);
    }

    return flattenGroups(parsed).reduce(addAddress, {});
}

function transformFromAddresses(addresses) {
    if (!addresses) {
        return undefined;
    }

    var transformed = transformAddresses(addresses);
    var from = Object.keys(transformed)[0];

    return [from, transformed[from]];
}

function buildAttachment(attachment, remote, generated) {
    return new Promise(function (resolve, reject) {
        // Raw -> not supported
        if (!isUndefined(attachment.raw)) {
            return reject(new Error("raw attachments not supported"));
        }

        // Remote attachment.
        if (isString(attachment.href)) {
            if (!isEmpty(generated)) {
                return reject(new Error("mixed remote and generated attachments"));
            }
            remote.push(attachment.href);
            return resolve();
        }

        // Generated attachment.
        if (!isEmpty(remote)) {
            return reject(new Error("mixed remote and generated attachments"));
        }

        var filename = attachment.filename;
        if (!isString(filename)) {
            return reject(new Error("missing filename for attachment"));
        }

        // Local file.
        if (isString(attachment.path)) {
            fs.readFile(attachment.path, function (err, data) {
                if (err) {
                    return reject(err);
                }
                generated[filename] = data.toString("base64");
                resolve();
            });
            return;
        }

        var content = attachment.content;
        var encoding = attachment.encoding;

        if (isString(content)) {
            generated[filename] = encoding === "base64" ? content : (new Buffer(content, encoding).toString("base64"));
            return resolve();
        }

        if (Buffer.isBuffer(content)) {
            generated[filename] = content.toString("base64");
            return resolve();
        }

        if (content instanceof stream.Readable) {
            var chunks = [];
            content.on("data", function (chunk) {
                chunks.push(chunk);
            }).on("close", function () {
                generated[filename] = Buffer.concat(chunks).toString("base64");
                resolve();
            }).on("error", reject);
            return;
        }

        reject(new Error("invalid attachment format"));
    });
}

function buildAttachments(attachments) {
    var remote = [];
    var generated = {};

    var promises = attachments.map(function (attachment) {
        return buildAttachment(attachment, remote, generated);
    });

    return Promise.all(promises).then(function () {
        if (remote.length > 0) {
            return remote;
        }

        return generated;
    });
}

function isErrorResponse(response) {
    if (response.statusCode !== STATUS_OK) {
        return true;
    }

    return false;
}

function responseError(response, body) {
    return new Error(
        util.format("%s (%s, %d)",
            body.message || "server error",
            body.code || "-",
            response.statusCode));
}

function makeInfo(body) {
    return {
        messageId: body.data["message-id"] || "",
        code: body.code,
        message: body.message
    };
}

//
// Transport class
//
function SendinBlueTransport(options) {
    checkOptions(options);

    this.name    = "SendinBlue";
    this.version = pkg.version;

    this.reqOptions = url.parse(options.apiUrl + "/email");
    this.reqOptions.method = "POST";
    this.reqOptions.headers = {
        "api-key": options.apiKey,
        "Content-Type": "application/json"
    };

    this.reqBuilder = this.reqOptions.protocol === "https:" ? https.request : http.request;
}

SendinBlueTransport.prototype.send = function (mail, callback) {
    var req = this.reqBuilder(this.reqOptions, function (res) {
        res.setEncoding("utf-8");

        var chunks = [];
        res.on("data", function (chunk) {
            chunks.push(chunk);
        }).on("end", function () {
            var body = {};

            try {
                var data = chunks.join("");
                body = JSON.parse(data);
            } catch (err) { /* Ignore error */ }

            if (isErrorResponse(res)) {
                return callback(responseError(res, body));
            }

            callback(undefined, makeInfo(body));
        });
    });

    req.on("error", function (err) {
        callback(prefixedErr(err, "error sending request"));
    });

    this.buildBody(mail).then(function (body) {
        req.write(JSON.stringify(body));
        req.end();
    }).catch(function (err) {
        callback(prefixedErr(err, "unable to build body"));
    });
};

SendinBlueTransport.prototype.buildBody = function (mail) {
    var data = mail.data;
    var body = {
        from:    transformFromAddresses(data.from),
        to:      transformAddresses(data.to),
        cc:      transformAddresses(data.cc),
        bcc:     transformAddresses(data.bcc),
        replyto: transformFromAddresses(data.replyTo),
        subject: data.subject,
        text:    data.text,
        html:    data.html,
        headers: data.headers
    };

    if (!data.attachments) {
        return Promise.resolve(body);
    }

    return buildAttachments(data.attachments).then(function (attachments) {
        body.attachment = attachments;
        return body;
    });
};

module.exports = function (options) {
    return new SendinBlueTransport(options);
};
<commit_msg>Remove checkOptions and add default API URL<commit_after>var assert        = require("assert");
var fs            = require("fs");
var stream        = require("stream");
var util          = require("util");
var http          = require("http");
var https         = require("https");
var url           = require("url");
var addressparser = require("addressparser");
var Promise       = require("promise");
var pkg           = require("../package.json");

//
// Constants
//
var STATUS_OK = 200;

//
// Helper
//
function isString(v) {
    return typeof v === "string" || v instanceof String;
}

function isObject(v) {
    return !isUndefined(v) && v.toString() === "[object Object]";
}

function isArray(v) {
    return v instanceof Array;
}

function isUndefined(v) {
    return typeof v === "undefined";
}

function isEmpty(v) {
    return !(v.length || Object.keys(v).length)
}

function prefixedErr(err, prefix) {
    err.message = [prefix, err.message].join(": ");
    return err;
}

function addAddress(obj, address) {
    obj[address.address] = address.name || "";
    return obj;
}

function flattenGroups(addresses) {
    var flattened = [];

    function traverse(obj) {
        if (obj.group) {
            obj.group.forEach(traverse);
        } else {
            flattened.push(obj);
        }
    }

    addresses.forEach(traverse);

    return flattened;
}

function transformAddress(a) {
    if (isString(a)) {
        return addressparser(a);
    }

    if (isObject(a)) {
        return [a];
    }

    throw new Error("invalid address: " + a);
}

function transformAddresses(addresses) {
    if (!addresses) {
        return undefined;
    }

    var parsed = [];
    if (isString(addresses)) {
        parsed = addressparser(addresses);
    } else if (isArray(addresses)) {
        addresses.forEach(function (address) {
            parsed = parsed.concat(transformAddress(address));
        });
    } else if (isObject(addresses)) {
        parsed.push(addresses);
    } else {
        throw new Error("invalid address: " + addresses);
    }

    return flattenGroups(parsed).reduce(addAddress, {});
}

function transformFromAddresses(addresses) {
    if (!addresses) {
        return undefined;
    }

    var transformed = transformAddresses(addresses);
    var from = Object.keys(transformed)[0];

    return [from, transformed[from]];
}

function buildAttachment(attachment, remote, generated) {
    return new Promise(function (resolve, reject) {
        // Raw -> not supported
        if (!isUndefined(attachment.raw)) {
            return reject(new Error("raw attachments not supported"));
        }

        // Remote attachment.
        if (isString(attachment.href)) {
            if (!isEmpty(generated)) {
                return reject(new Error("mixed remote and generated attachments"));
            }
            remote.push(attachment.href);
            return resolve();
        }

        // Generated attachment.
        if (!isEmpty(remote)) {
            return reject(new Error("mixed remote and generated attachments"));
        }

        var filename = attachment.filename;
        if (!isString(filename)) {
            return reject(new Error("missing filename for attachment"));
        }

        // Local file.
        if (isString(attachment.path)) {
            fs.readFile(attachment.path, function (err, data) {
                if (err) {
                    return reject(err);
                }
                generated[filename] = data.toString("base64");
                resolve();
            });
            return;
        }

        var content = attachment.content;
        var encoding = attachment.encoding;

        if (isString(content)) {
            generated[filename] = encoding === "base64" ? content : (new Buffer(content, encoding).toString("base64"));
            return resolve();
        }

        if (Buffer.isBuffer(content)) {
            generated[filename] = content.toString("base64");
            return resolve();
        }

        if (content instanceof stream.Readable) {
            var chunks = [];
            content.on("data", function (chunk) {
                chunks.push(chunk);
            }).on("close", function () {
                generated[filename] = Buffer.concat(chunks).toString("base64");
                resolve();
            }).on("error", reject);
            return;
        }

        reject(new Error("invalid attachment format"));
    });
}

function buildAttachments(attachments) {
    var remote = [];
    var generated = {};

    var promises = attachments.map(function (attachment) {
        return buildAttachment(attachment, remote, generated);
    });

    return Promise.all(promises).then(function () {
        if (remote.length > 0) {
            return remote;
        }

        return generated;
    });
}

function isErrorResponse(response) {
    if (response.statusCode !== STATUS_OK) {
        return true;
    }

    return false;
}

function responseError(response, body) {
    return new Error(
        util.format("%s (%s, %d)",
            body.message || "server error",
            body.code || "-",
            response.statusCode));
}

function makeInfo(body) {
    return {
        messageId: body.data["message-id"] || "",
        code: body.code,
        message: body.message
    };
}

//
// Transport class
//
function SendinBlueTransport(options) {
    this.name    = "SendinBlue";
    this.version = pkg.version;

    if (isUndefined(options.apiUrl)) {
        options.apiUrl = "https://api.sendinblue.com/v2.0"
    }

    this.reqOptions = url.parse(options.apiUrl + "/email");
    this.reqOptions.method = "POST";
    this.reqOptions.headers = {
        "api-key": options.apiKey,
        "Content-Type": "application/json"
    };

    this.reqBuilder = this.reqOptions.protocol === "https:" ? https.request : http.request;
}

SendinBlueTransport.prototype.send = function (mail, callback) {
    var req = this.reqBuilder(this.reqOptions, function (res) {
        res.setEncoding("utf-8");

        var chunks = [];
        res.on("data", function (chunk) {
            chunks.push(chunk);
        }).on("end", function () {
            var body = {};

            try {
                var data = chunks.join("");
                body = JSON.parse(data);
            } catch (err) { /* Ignore error */ }

            if (isErrorResponse(res)) {
                return callback(responseError(res, body));
            }

            callback(undefined, makeInfo(body));
        });
    });

    req.on("error", function (err) {
        callback(prefixedErr(err, "error sending request"));
    });

    this.buildBody(mail).then(function (body) {
        req.write(JSON.stringify(body));
        req.end();
    }).catch(function (err) {
        callback(prefixedErr(err, "unable to build body"));
    });
};

SendinBlueTransport.prototype.buildBody = function (mail) {
    var data = mail.data;
    var body = {
        from:    transformFromAddresses(data.from),
        to:      transformAddresses(data.to),
        cc:      transformAddresses(data.cc),
        bcc:     transformAddresses(data.bcc),
        replyto: transformFromAddresses(data.replyTo),
        subject: data.subject,
        text:    data.text,
        html:    data.html,
        headers: data.headers
    };

    if (!data.attachments) {
        return Promise.resolve(body);
    }

    return buildAttachments(data.attachments).then(function (attachments) {
        body.attachment = attachments;
        return body;
    });
};

module.exports = function (options) {
    return new SendinBlueTransport(options);
};
<|endoftext|>